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

Change-Id: I0f9b6777fd1cb121ad21bce0f2c52f142be2eb6f
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index b5e709e..14214b0 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -122,7 +122,7 @@
 Brian Gitonga Marete <marete@toshnix.com>
 Brian Ketelsen <bketelsen@gmail.com>
 Brian Slesinsky <skybrian@google.com>
-Burcu Dogan <jbd@google.com>
+Burcu Dogan <jbd@google.com> <burcujdogan@gmail.com>
 Caine Tighe <arctanofyourface@gmail.com>
 Caleb Spare <cespare@gmail.com>
 Carl Chatfield <carlchatfield@gmail.com>
diff --git a/api/next.txt b/api/next.txt
index b79d7a8..cebbe87 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -1,3 +1,53 @@
+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, method (*Buffer) Cap() int
+pkg bytes, method (*Reader) Size() int64
+pkg crypto, type Decrypter interface { Decrypt, Public }
+pkg crypto, type Decrypter interface, Decrypt(io.Reader, []uint8, DecrypterOpts) ([]uint8, error)
+pkg crypto, type Decrypter interface, Public() PublicKey
+pkg crypto, type DecrypterOpts interface {}
+pkg crypto/elliptic, type CurveParams struct, Name string
+pkg crypto/rsa, method (*PrivateKey) Decrypt(io.Reader, []uint8, crypto.DecrypterOpts) ([]uint8, error)
+pkg crypto/rsa, type OAEPOptions struct
+pkg crypto/rsa, type OAEPOptions struct, Hash crypto.Hash
+pkg crypto/rsa, type OAEPOptions struct, Label []uint8
+pkg crypto/rsa, type PKCS1v15DecryptOptions struct
+pkg crypto/rsa, type PKCS1v15DecryptOptions struct, SessionKeyLen int
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 49196
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 49200
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16
+pkg crypto/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, method (*Data) LineReader(*Entry) (*LineReader, error)
+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, type LineEntry struct
+pkg debug/dwarf, type LineEntry struct, Address uint64
+pkg debug/dwarf, type LineEntry struct, BasicBlock bool
+pkg debug/dwarf, type LineEntry struct, Column int
+pkg debug/dwarf, type LineEntry struct, Discriminator int
+pkg debug/dwarf, type LineEntry struct, EndSequence bool
+pkg debug/dwarf, type LineEntry struct, EpilogueBegin bool
+pkg debug/dwarf, type LineEntry struct, File *LineFile
+pkg debug/dwarf, type LineEntry struct, ISA int
+pkg debug/dwarf, type LineEntry struct, IsStmt bool
+pkg debug/dwarf, type LineEntry struct, Line int
+pkg debug/dwarf, type LineEntry struct, OpIndex int
+pkg debug/dwarf, type LineEntry struct, PrologueEnd bool
+pkg debug/dwarf, type LineFile struct
+pkg debug/dwarf, type LineFile struct, Length int
+pkg debug/dwarf, type LineFile struct, Mtime uint64
+pkg debug/dwarf, type LineFile struct, Name string
+pkg debug/dwarf, type LineReader struct
+pkg debug/dwarf, type LineReaderPos struct
+pkg debug/dwarf, var ErrUnknownPC error
 pkg debug/elf, const R_PPC64_ADDR14 = 7
 pkg debug/elf, const R_PPC64_ADDR14 R_PPC64
 pkg debug/elf, const R_PPC64_ADDR14_BRNTAKEN = 9
@@ -167,3 +217,646 @@
 pkg debug/elf, method (R_PPC64) GoString() string
 pkg debug/elf, method (R_PPC64) String() string
 pkg debug/elf, type R_PPC64 int
+pkg encoding/base64, const NoPadding = -1
+pkg encoding/base64, const NoPadding int32
+pkg encoding/base64, const StdPadding = 61
+pkg encoding/base64, const StdPadding int32
+pkg encoding/base64, method (Encoding) WithPadding(int32) *Encoding
+pkg encoding/base64, var RawStdEncoding *Encoding
+pkg encoding/base64, var RawURLEncoding *Encoding
+pkg encoding/json, type UnmarshalTypeError struct, Offset int64
+pkg flag, func UnquoteUsage(*Flag) (string, string)
+pkg go/ast, type EmptyStmt struct, Implicit bool
+pkg go/exact, const Bool = 1
+pkg go/exact, const Bool Kind
+pkg go/exact, const Complex = 5
+pkg go/exact, const Complex Kind
+pkg go/exact, const Float = 4
+pkg go/exact, const Float Kind
+pkg go/exact, const Int = 3
+pkg go/exact, const Int Kind
+pkg go/exact, const String = 2
+pkg go/exact, const String Kind
+pkg go/exact, const Unknown = 0
+pkg go/exact, const Unknown Kind
+pkg go/exact, func BinaryOp(Value, token.Token, Value) Value
+pkg go/exact, func BitLen(Value) int
+pkg go/exact, func BoolVal(Value) bool
+pkg go/exact, func Bytes(Value) []uint8
+pkg go/exact, func Compare(Value, token.Token, Value) bool
+pkg go/exact, func Denom(Value) Value
+pkg go/exact, func Float32Val(Value) (float32, bool)
+pkg go/exact, func Float64Val(Value) (float64, bool)
+pkg go/exact, func Imag(Value) Value
+pkg go/exact, func Int64Val(Value) (int64, bool)
+pkg go/exact, func MakeBool(bool) Value
+pkg go/exact, func MakeFloat64(float64) Value
+pkg go/exact, func MakeFromBytes([]uint8) Value
+pkg go/exact, func MakeFromLiteral(string, token.Token) Value
+pkg go/exact, func MakeImag(Value) Value
+pkg go/exact, func MakeInt64(int64) Value
+pkg go/exact, func MakeString(string) Value
+pkg go/exact, func MakeUint64(uint64) Value
+pkg go/exact, func MakeUnknown() Value
+pkg go/exact, func Num(Value) Value
+pkg go/exact, func Real(Value) Value
+pkg go/exact, func Shift(Value, token.Token, uint) Value
+pkg go/exact, func Sign(Value) int
+pkg go/exact, func StringVal(Value) string
+pkg go/exact, func Uint64Val(Value) (uint64, bool)
+pkg go/exact, func UnaryOp(token.Token, Value, int) Value
+pkg go/exact, type Kind int
+pkg go/exact, type Value interface, Kind() Kind
+pkg go/exact, type Value interface, String() string
+pkg go/exact, type Value interface, unexported methods
+pkg go/types, const Bool = 1
+pkg go/types, const Bool BasicKind
+pkg go/types, const Byte = 8
+pkg go/types, const Byte BasicKind
+pkg go/types, const Complex128 = 16
+pkg go/types, const Complex128 BasicKind
+pkg go/types, const Complex64 = 15
+pkg go/types, const Complex64 BasicKind
+pkg go/types, const FieldVal = 0
+pkg go/types, const FieldVal SelectionKind
+pkg go/types, const Float32 = 13
+pkg go/types, const Float32 BasicKind
+pkg go/types, const Float64 = 14
+pkg go/types, const Float64 BasicKind
+pkg go/types, const Int = 2
+pkg go/types, const Int BasicKind
+pkg go/types, const Int16 = 4
+pkg go/types, const Int16 BasicKind
+pkg go/types, const Int32 = 5
+pkg go/types, const Int32 BasicKind
+pkg go/types, const Int64 = 6
+pkg go/types, const Int64 BasicKind
+pkg go/types, const Int8 = 3
+pkg go/types, const Int8 BasicKind
+pkg go/types, const Invalid = 0
+pkg go/types, const Invalid BasicKind
+pkg go/types, const IsBoolean = 1
+pkg go/types, const IsBoolean BasicInfo
+pkg go/types, const IsComplex = 16
+pkg go/types, const IsComplex BasicInfo
+pkg go/types, const IsConstType = 59
+pkg go/types, const IsConstType BasicInfo
+pkg go/types, const IsFloat = 8
+pkg go/types, const IsFloat BasicInfo
+pkg go/types, const IsInteger = 2
+pkg go/types, const IsInteger BasicInfo
+pkg go/types, const IsNumeric = 26
+pkg go/types, const IsNumeric BasicInfo
+pkg go/types, const IsOrdered = 42
+pkg go/types, const IsOrdered BasicInfo
+pkg go/types, const IsString = 32
+pkg go/types, const IsString BasicInfo
+pkg go/types, const IsUnsigned = 4
+pkg go/types, const IsUnsigned BasicInfo
+pkg go/types, const IsUntyped = 64
+pkg go/types, const IsUntyped BasicInfo
+pkg go/types, const MethodExpr = 2
+pkg go/types, const MethodExpr SelectionKind
+pkg go/types, const MethodVal = 1
+pkg go/types, const MethodVal SelectionKind
+pkg go/types, const RecvOnly = 2
+pkg go/types, const RecvOnly ChanDir
+pkg go/types, const Rune = 5
+pkg go/types, const Rune BasicKind
+pkg go/types, const SendOnly = 1
+pkg go/types, const SendOnly ChanDir
+pkg go/types, const SendRecv = 0
+pkg go/types, const SendRecv ChanDir
+pkg go/types, const String = 17
+pkg go/types, const String BasicKind
+pkg go/types, const Uint = 7
+pkg go/types, const Uint BasicKind
+pkg go/types, const Uint16 = 9
+pkg go/types, const Uint16 BasicKind
+pkg go/types, const Uint32 = 10
+pkg go/types, const Uint32 BasicKind
+pkg go/types, const Uint64 = 11
+pkg go/types, const Uint64 BasicKind
+pkg go/types, const Uint8 = 8
+pkg go/types, const Uint8 BasicKind
+pkg go/types, const Uintptr = 12
+pkg go/types, const Uintptr BasicKind
+pkg go/types, const UnsafePointer = 18
+pkg go/types, const UnsafePointer BasicKind
+pkg go/types, const UntypedBool = 19
+pkg go/types, const UntypedBool BasicKind
+pkg go/types, const UntypedComplex = 23
+pkg go/types, const UntypedComplex BasicKind
+pkg go/types, const UntypedFloat = 22
+pkg go/types, const UntypedFloat BasicKind
+pkg go/types, const UntypedInt = 20
+pkg go/types, const UntypedInt BasicKind
+pkg go/types, const UntypedNil = 25
+pkg go/types, const UntypedNil BasicKind
+pkg go/types, const UntypedRune = 21
+pkg go/types, const UntypedRune BasicKind
+pkg go/types, const UntypedString = 24
+pkg go/types, const UntypedString BasicKind
+pkg go/types, func AssertableTo(*Interface, Type) bool
+pkg go/types, func AssignableTo(Type, Type) bool
+pkg go/types, func Check(string, *token.FileSet, []*ast.File) (*Package, error)
+pkg go/types, func Comparable(Type) bool
+pkg go/types, func ConvertibleTo(Type, Type) bool
+pkg go/types, func DefPredeclaredTestFuncs()
+pkg go/types, func Eval(string, *Package, *Scope) (TypeAndValue, error)
+pkg go/types, func EvalNode(*token.FileSet, ast.Expr, *Package, *Scope) (TypeAndValue, error)
+pkg go/types, func ExprString(ast.Expr) string
+pkg go/types, func Id(*Package, string) string
+pkg go/types, func Identical(Type, Type) bool
+pkg go/types, func Implements(Type, *Interface) bool
+pkg go/types, func IsInterface(Type) bool
+pkg go/types, func LookupFieldOrMethod(Type, bool, *Package, string) (Object, []int, bool)
+pkg go/types, func MissingMethod(Type, *Interface, bool) (*Func, bool)
+pkg go/types, func New(string) Type
+pkg go/types, func NewArray(Type, int64) *Array
+pkg go/types, func NewChan(ChanDir, Type) *Chan
+pkg go/types, func NewChecker(*Config, *token.FileSet, *Package, *Info) *Checker
+pkg go/types, func NewConst(token.Pos, *Package, string, Type, 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
+pkg go/types, func NewInterface([]*Func, []*Named) *Interface
+pkg go/types, func NewLabel(token.Pos, *Package, string) *Label
+pkg go/types, func NewMap(Type, Type) *Map
+pkg go/types, func NewMethodSet(Type) *MethodSet
+pkg go/types, func NewNamed(*TypeName, Type, []*Func) *Named
+pkg go/types, func NewPackage(string, string) *Package
+pkg go/types, func NewParam(token.Pos, *Package, string, Type) *Var
+pkg go/types, func NewPkgName(token.Pos, *Package, string, *Package) *PkgName
+pkg go/types, func NewPointer(Type) *Pointer
+pkg go/types, func NewScope(*Scope, string) *Scope
+pkg go/types, func NewSignature(*Scope, *Var, *Tuple, *Tuple, bool) *Signature
+pkg go/types, func NewSlice(Type) *Slice
+pkg go/types, func NewStruct([]*Var, []string) *Struct
+pkg go/types, func NewTuple(...*Var) *Tuple
+pkg go/types, func NewTypeName(token.Pos, *Package, string, Type) *TypeName
+pkg go/types, func NewVar(token.Pos, *Package, string, Type) *Var
+pkg go/types, func ObjectString(*Package, Object) string
+pkg go/types, func SelectionString(*Package, *Selection) string
+pkg go/types, func TypeString(*Package, Type) string
+pkg go/types, func WriteExpr(*bytes.Buffer, ast.Expr)
+pkg go/types, func WriteSignature(*bytes.Buffer, *Package, *Signature)
+pkg go/types, func WriteType(*bytes.Buffer, *Package, Type)
+pkg go/types, method (*Array) Elem() Type
+pkg go/types, method (*Array) Len() int64
+pkg go/types, method (*Array) String() string
+pkg go/types, method (*Array) Underlying() Type
+pkg go/types, method (*Basic) Info() BasicInfo
+pkg go/types, method (*Basic) Kind() BasicKind
+pkg go/types, method (*Basic) Name() string
+pkg go/types, method (*Basic) String() string
+pkg go/types, method (*Basic) Underlying() Type
+pkg go/types, method (*Builtin) Exported() bool
+pkg go/types, method (*Builtin) Id() string
+pkg go/types, method (*Builtin) Name() string
+pkg go/types, method (*Builtin) Parent() *Scope
+pkg go/types, method (*Builtin) Pkg() *Package
+pkg go/types, method (*Builtin) Pos() token.Pos
+pkg go/types, method (*Builtin) String() string
+pkg go/types, method (*Builtin) Type() Type
+pkg go/types, method (*Chan) Dir() ChanDir
+pkg go/types, method (*Chan) Elem() Type
+pkg go/types, method (*Chan) String() string
+pkg go/types, method (*Chan) Underlying() Type
+pkg go/types, method (*Checker) Files([]*ast.File) error
+pkg go/types, method (*Config) Check(string, *token.FileSet, []*ast.File, *Info) (*Package, error)
+pkg go/types, method (*Const) Exported() bool
+pkg go/types, method (*Const) Id() string
+pkg go/types, method (*Const) Name() string
+pkg go/types, method (*Const) Parent() *Scope
+pkg go/types, method (*Const) Pkg() *Package
+pkg go/types, method (*Const) Pos() token.Pos
+pkg go/types, method (*Const) String() string
+pkg go/types, method (*Const) Type() Type
+pkg go/types, method (*Const) Val() exact.Value
+pkg go/types, method (*Func) Exported() bool
+pkg go/types, method (*Func) FullName() string
+pkg go/types, method (*Func) Id() string
+pkg go/types, method (*Func) Name() string
+pkg go/types, method (*Func) Parent() *Scope
+pkg go/types, method (*Func) Pkg() *Package
+pkg go/types, method (*Func) Pos() token.Pos
+pkg go/types, method (*Func) Scope() *Scope
+pkg go/types, method (*Func) String() string
+pkg go/types, method (*Func) Type() Type
+pkg go/types, method (*Info) ObjectOf(*ast.Ident) Object
+pkg go/types, method (*Info) TypeOf(ast.Expr) Type
+pkg go/types, method (*Initializer) String() string
+pkg go/types, method (*Interface) Complete() *Interface
+pkg go/types, method (*Interface) Embedded(int) *Named
+pkg go/types, method (*Interface) Empty() bool
+pkg go/types, method (*Interface) ExplicitMethod(int) *Func
+pkg go/types, method (*Interface) Method(int) *Func
+pkg go/types, method (*Interface) NumEmbeddeds() int
+pkg go/types, method (*Interface) NumExplicitMethods() int
+pkg go/types, method (*Interface) NumMethods() int
+pkg go/types, method (*Interface) String() string
+pkg go/types, method (*Interface) Underlying() Type
+pkg go/types, method (*Label) Exported() bool
+pkg go/types, method (*Label) Id() string
+pkg go/types, method (*Label) Name() string
+pkg go/types, method (*Label) Parent() *Scope
+pkg go/types, method (*Label) Pkg() *Package
+pkg go/types, method (*Label) Pos() token.Pos
+pkg go/types, method (*Label) String() string
+pkg go/types, method (*Label) Type() Type
+pkg go/types, method (*Map) Elem() Type
+pkg go/types, method (*Map) Key() Type
+pkg go/types, method (*Map) String() string
+pkg go/types, method (*Map) Underlying() Type
+pkg go/types, method (*MethodSet) At(int) *Selection
+pkg go/types, method (*MethodSet) Len() int
+pkg go/types, method (*MethodSet) Lookup(*Package, string) *Selection
+pkg go/types, method (*MethodSet) String() string
+pkg go/types, method (*MethodSetCache) MethodSet(Type) *MethodSet
+pkg go/types, method (*Named) AddMethod(*Func)
+pkg go/types, method (*Named) Method(int) *Func
+pkg go/types, method (*Named) NumMethods() int
+pkg go/types, method (*Named) Obj() *TypeName
+pkg go/types, method (*Named) SetUnderlying(Type)
+pkg go/types, method (*Named) String() string
+pkg go/types, method (*Named) Underlying() Type
+pkg go/types, method (*Nil) Exported() bool
+pkg go/types, method (*Nil) Id() string
+pkg go/types, method (*Nil) Name() string
+pkg go/types, method (*Nil) Parent() *Scope
+pkg go/types, method (*Nil) Pkg() *Package
+pkg go/types, method (*Nil) Pos() token.Pos
+pkg go/types, method (*Nil) String() string
+pkg go/types, method (*Nil) Type() Type
+pkg go/types, method (*Package) Complete() bool
+pkg go/types, method (*Package) Imports() []*Package
+pkg go/types, method (*Package) MarkComplete()
+pkg go/types, method (*Package) Name() string
+pkg go/types, method (*Package) Path() string
+pkg go/types, method (*Package) Scope() *Scope
+pkg go/types, method (*Package) SetImports([]*Package)
+pkg go/types, method (*Package) String() string
+pkg go/types, method (*PkgName) Exported() bool
+pkg go/types, method (*PkgName) Id() string
+pkg go/types, method (*PkgName) Imported() *Package
+pkg go/types, method (*PkgName) Name() string
+pkg go/types, method (*PkgName) Parent() *Scope
+pkg go/types, method (*PkgName) Pkg() *Package
+pkg go/types, method (*PkgName) Pos() token.Pos
+pkg go/types, method (*PkgName) String() string
+pkg go/types, method (*PkgName) Type() Type
+pkg go/types, method (*Pointer) Elem() Type
+pkg go/types, method (*Pointer) String() string
+pkg go/types, method (*Pointer) Underlying() Type
+pkg go/types, method (*Scope) Child(int) *Scope
+pkg go/types, method (*Scope) Insert(Object) Object
+pkg go/types, method (*Scope) Len() int
+pkg go/types, method (*Scope) Lookup(string) Object
+pkg go/types, method (*Scope) LookupParent(string) (*Scope, Object)
+pkg go/types, method (*Scope) Names() []string
+pkg go/types, method (*Scope) NumChildren() int
+pkg go/types, method (*Scope) Parent() *Scope
+pkg go/types, method (*Scope) String() string
+pkg go/types, method (*Scope) WriteTo(io.Writer, int, bool)
+pkg go/types, method (*Selection) Index() []int
+pkg go/types, method (*Selection) Indirect() bool
+pkg go/types, method (*Selection) Kind() SelectionKind
+pkg go/types, method (*Selection) Obj() Object
+pkg go/types, method (*Selection) Recv() Type
+pkg go/types, method (*Selection) String() string
+pkg go/types, method (*Selection) Type() Type
+pkg go/types, method (*Signature) Params() *Tuple
+pkg go/types, method (*Signature) Recv() *Var
+pkg go/types, method (*Signature) Results() *Tuple
+pkg go/types, method (*Signature) String() string
+pkg go/types, method (*Signature) Underlying() Type
+pkg go/types, method (*Signature) Variadic() bool
+pkg go/types, method (*Slice) Elem() Type
+pkg go/types, method (*Slice) String() string
+pkg go/types, method (*Slice) Underlying() Type
+pkg go/types, method (*StdSizes) Alignof(Type) int64
+pkg go/types, method (*StdSizes) Offsetsof([]*Var) []int64
+pkg go/types, method (*StdSizes) Sizeof(Type) int64
+pkg go/types, method (*Struct) Field(int) *Var
+pkg go/types, method (*Struct) NumFields() int
+pkg go/types, method (*Struct) String() string
+pkg go/types, method (*Struct) Tag(int) string
+pkg go/types, method (*Struct) Underlying() Type
+pkg go/types, method (*Tuple) At(int) *Var
+pkg go/types, method (*Tuple) Len() int
+pkg go/types, method (*Tuple) String() string
+pkg go/types, method (*Tuple) Underlying() Type
+pkg go/types, method (*TypeName) Exported() bool
+pkg go/types, method (*TypeName) Id() string
+pkg go/types, method (*TypeName) Name() string
+pkg go/types, method (*TypeName) Parent() *Scope
+pkg go/types, method (*TypeName) Pkg() *Package
+pkg go/types, method (*TypeName) Pos() token.Pos
+pkg go/types, method (*TypeName) String() string
+pkg go/types, method (*TypeName) Type() Type
+pkg go/types, method (*Var) Anonymous() bool
+pkg go/types, method (*Var) Exported() bool
+pkg go/types, method (*Var) Id() string
+pkg go/types, method (*Var) IsField() bool
+pkg go/types, method (*Var) Name() string
+pkg go/types, method (*Var) Parent() *Scope
+pkg go/types, method (*Var) Pkg() *Package
+pkg go/types, method (*Var) Pos() token.Pos
+pkg go/types, method (*Var) String() string
+pkg go/types, method (*Var) Type() Type
+pkg go/types, method (Checker) ObjectOf(*ast.Ident) Object
+pkg go/types, method (Checker) TypeOf(ast.Expr) Type
+pkg go/types, method (Error) Error() string
+pkg go/types, method (TypeAndValue) Addressable() bool
+pkg go/types, method (TypeAndValue) Assignable() bool
+pkg go/types, method (TypeAndValue) HasOk() bool
+pkg go/types, method (TypeAndValue) IsBuiltin() bool
+pkg go/types, method (TypeAndValue) IsNil() bool
+pkg go/types, method (TypeAndValue) IsType() bool
+pkg go/types, method (TypeAndValue) IsValue() bool
+pkg go/types, method (TypeAndValue) IsVoid() bool
+pkg go/types, type Array struct
+pkg go/types, type Basic struct
+pkg go/types, type BasicInfo int
+pkg go/types, type BasicKind int
+pkg go/types, type Builtin struct
+pkg go/types, type Chan struct
+pkg go/types, type ChanDir int
+pkg go/types, type Checker struct
+pkg go/types, type Checker struct, embedded *Info
+pkg go/types, type Config struct
+pkg go/types, type Config struct, DisableUnusedImportCheck bool
+pkg go/types, type Config struct, Error func(error)
+pkg go/types, type Config struct, FakeImportC bool
+pkg go/types, type Config struct, IgnoreFuncBodies bool
+pkg go/types, type Config struct, Import Importer
+pkg go/types, type Config struct, Packages map[string]*Package
+pkg go/types, type Config struct, Sizes Sizes
+pkg go/types, type Const struct
+pkg go/types, type Error struct
+pkg go/types, type Error struct, Fset *token.FileSet
+pkg go/types, type Error struct, Msg string
+pkg go/types, type Error struct, Pos token.Pos
+pkg go/types, type Error struct, Soft bool
+pkg go/types, type Func struct
+pkg go/types, type Importer func(map[string]*Package, string) (*Package, error)
+pkg go/types, type Info struct
+pkg go/types, type Info struct, Defs map[*ast.Ident]Object
+pkg go/types, type Info struct, Implicits map[ast.Node]Object
+pkg go/types, type Info struct, InitOrder []*Initializer
+pkg go/types, type Info struct, Scopes map[ast.Node]*Scope
+pkg go/types, type Info struct, Selections map[*ast.SelectorExpr]*Selection
+pkg go/types, type Info struct, Types map[ast.Expr]TypeAndValue
+pkg go/types, type Info struct, Uses map[*ast.Ident]Object
+pkg go/types, type Initializer struct
+pkg go/types, type Initializer struct, Lhs []*Var
+pkg go/types, type Initializer struct, Rhs ast.Expr
+pkg go/types, type Interface struct
+pkg go/types, type Label struct
+pkg go/types, type Map struct
+pkg go/types, type MethodSet struct
+pkg go/types, type MethodSetCache struct
+pkg go/types, type Named struct
+pkg go/types, type Nil struct
+pkg go/types, type Object interface, Exported() bool
+pkg go/types, type Object interface, Id() string
+pkg go/types, type Object interface, Name() string
+pkg go/types, type Object interface, Parent() *Scope
+pkg go/types, type Object interface, Pkg() *Package
+pkg go/types, type Object interface, Pos() token.Pos
+pkg go/types, type Object interface, String() string
+pkg go/types, type Object interface, Type() Type
+pkg go/types, type Object interface, unexported methods
+pkg go/types, type Package struct
+pkg go/types, type PkgName struct
+pkg go/types, type Pointer struct
+pkg go/types, type Scope struct
+pkg go/types, type Selection struct
+pkg go/types, type SelectionKind int
+pkg go/types, type Signature struct
+pkg go/types, type Sizes interface { Alignof, Offsetsof, Sizeof }
+pkg go/types, type Sizes interface, Alignof(Type) int64
+pkg go/types, type Sizes interface, Offsetsof([]*Var) []int64
+pkg go/types, type Sizes interface, Sizeof(Type) int64
+pkg go/types, type Slice struct
+pkg go/types, type StdSizes struct
+pkg go/types, type StdSizes struct, MaxAlign int64
+pkg go/types, type StdSizes struct, WordSize int64
+pkg go/types, type Struct struct
+pkg go/types, type Tuple struct
+pkg go/types, type Type interface { String, Underlying }
+pkg go/types, type Type interface, String() string
+pkg go/types, type Type interface, Underlying() Type
+pkg go/types, type TypeAndValue struct
+pkg go/types, type TypeAndValue struct, Type Type
+pkg go/types, type TypeAndValue struct, Value exact.Value
+pkg go/types, type TypeName struct
+pkg go/types, type Var struct
+pkg go/types, var DefaultImport Importer
+pkg go/types, var GcCompatibilityMode bool
+pkg go/types, var Typ [26]*Basic
+pkg go/types, var Universe *Scope
+pkg go/types, var UniverseByte *Basic
+pkg go/types, var UniverseRune *Basic
+pkg go/types, var Unsafe *Package
+pkg html/template, method (*Template) Option(...string) *Template
+pkg image, const YCbCrSubsampleRatio410 = 5
+pkg image, const YCbCrSubsampleRatio410 YCbCrSubsampleRatio
+pkg image, const YCbCrSubsampleRatio411 = 4
+pkg image, const YCbCrSubsampleRatio411 YCbCrSubsampleRatio
+pkg image, func NewCMYK(Rectangle) *CMYK
+pkg image, method (*CMYK) At(int, int) color.Color
+pkg image, method (*CMYK) Bounds() Rectangle
+pkg image, method (*CMYK) CMYKAt(int, int) color.CMYK
+pkg image, method (*CMYK) ColorModel() color.Model
+pkg image, method (*CMYK) Opaque() bool
+pkg image, method (*CMYK) PixOffset(int, int) int
+pkg image, method (*CMYK) Set(int, int, color.Color)
+pkg image, method (*CMYK) SetCMYK(int, int, color.CMYK)
+pkg image, method (*CMYK) SubImage(Rectangle) Image
+pkg image, method (Rectangle) At(int, int) color.Color
+pkg image, method (Rectangle) Bounds() Rectangle
+pkg image, method (Rectangle) ColorModel() color.Model
+pkg image, type CMYK struct
+pkg image, type CMYK struct, Pix []uint8
+pkg image, type CMYK struct, Rect Rectangle
+pkg image, type CMYK struct, Stride int
+pkg image/color, func CMYKToRGB(uint8, uint8, uint8, uint8) (uint8, uint8, uint8)
+pkg image/color, func RGBToCMYK(uint8, uint8, uint8) (uint8, uint8, uint8, uint8)
+pkg image/color, method (CMYK) RGBA() (uint32, uint32, uint32, uint32)
+pkg image/color, type CMYK struct
+pkg image/color, type CMYK struct, C uint8
+pkg image/color, type CMYK struct, K uint8
+pkg image/color, type CMYK struct, M uint8
+pkg image/color, type CMYK struct, Y uint8
+pkg image/color, var CMYKModel Model
+pkg log, func Output(int, string) error
+pkg log, method (*Logger) SetOutput(io.Writer)
+pkg math/big, const Above = 1
+pkg math/big, const Above Accuracy
+pkg math/big, const AwayFromZero = 3
+pkg math/big, const AwayFromZero RoundingMode
+pkg math/big, const Below = -1
+pkg math/big, const Below Accuracy
+pkg math/big, const Exact = 0
+pkg math/big, const Exact Accuracy
+pkg math/big, const MaxExp = 2147483647
+pkg math/big, const MaxExp ideal-int
+pkg math/big, const MaxPrec = 4294967295
+pkg math/big, const MaxPrec ideal-int
+pkg math/big, const MinExp = -2147483648
+pkg math/big, const MinExp ideal-int
+pkg math/big, const ToNearestAway = 1
+pkg math/big, const ToNearestAway RoundingMode
+pkg math/big, const ToNearestEven = 0
+pkg math/big, const ToNearestEven RoundingMode
+pkg math/big, const ToNegativeInf = 4
+pkg math/big, const ToNegativeInf RoundingMode
+pkg math/big, const ToPositiveInf = 5
+pkg math/big, const ToPositiveInf RoundingMode
+pkg math/big, const ToZero = 2
+pkg math/big, const ToZero RoundingMode
+pkg math/big, func 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)
+pkg math/big, method (*Float) Abs(*Float) *Float
+pkg math/big, method (*Float) Acc() Accuracy
+pkg math/big, method (*Float) Add(*Float, *Float) *Float
+pkg math/big, method (*Float) Append([]uint8, uint8, int) []uint8
+pkg math/big, method (*Float) Cmp(*Float) int
+pkg math/big, method (*Float) Copy(*Float) *Float
+pkg math/big, method (*Float) Float32() (float32, Accuracy)
+pkg math/big, method (*Float) Float64() (float64, Accuracy)
+pkg math/big, method (*Float) Format(uint8, int) string
+pkg math/big, method (*Float) Int(*Int) (*Int, Accuracy)
+pkg math/big, method (*Float) Int64() (int64, Accuracy)
+pkg math/big, method (*Float) IsInf() bool
+pkg math/big, method (*Float) IsInt() bool
+pkg math/big, method (*Float) MantExp(*Float) int
+pkg math/big, method (*Float) MinPrec() uint
+pkg math/big, method (*Float) Mode() RoundingMode
+pkg math/big, method (*Float) Mul(*Float, *Float) *Float
+pkg math/big, method (*Float) Neg(*Float) *Float
+pkg math/big, method (*Float) Parse(string, int) (*Float, int, error)
+pkg math/big, method (*Float) Prec() uint
+pkg math/big, method (*Float) Quo(*Float, *Float) *Float
+pkg math/big, method (*Float) Rat(*Rat) (*Rat, Accuracy)
+pkg math/big, method (*Float) Scan(io.ByteScanner, int) (*Float, int, error)
+pkg math/big, method (*Float) Set(*Float) *Float
+pkg math/big, method (*Float) SetFloat64(float64) *Float
+pkg math/big, method (*Float) SetInf(bool) *Float
+pkg math/big, method (*Float) SetInt(*Int) *Float
+pkg math/big, method (*Float) SetInt64(int64) *Float
+pkg math/big, method (*Float) SetMantExp(*Float, int) *Float
+pkg math/big, method (*Float) SetMode(RoundingMode) *Float
+pkg math/big, method (*Float) SetPrec(uint) *Float
+pkg math/big, method (*Float) SetRat(*Rat) *Float
+pkg math/big, method (*Float) SetString(string) (*Float, bool)
+pkg math/big, method (*Float) SetUint64(uint64) *Float
+pkg math/big, method (*Float) Sign() int
+pkg math/big, method (*Float) Signbit() bool
+pkg math/big, method (*Float) String() string
+pkg math/big, method (*Float) Sub(*Float, *Float) *Float
+pkg math/big, method (*Float) Uint64() (uint64, Accuracy)
+pkg math/big, method (Accuracy) String() string
+pkg math/big, method (ErrNaN) Error() string
+pkg math/big, method (RoundingMode) String() string
+pkg math/big, type Accuracy int8
+pkg math/big, type ErrNaN struct
+pkg math/big, type Float struct
+pkg math/big, type RoundingMode uint8
+pkg mime, func ExtensionsByType(string) ([]string, error)
+pkg mime/quotedprintable, func NewReader(io.Reader) io.Reader
+pkg mime/quotedprintable, func NewWriter(io.Writer) *Writer
+pkg mime/quotedprintable, method (*Writer) Close() error
+pkg mime/quotedprintable, method (*Writer) Write([]uint8) (int, error)
+pkg mime/quotedprintable, type Writer struct
+pkg mime/quotedprintable, type Writer struct, Binary bool
+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/signal, func Ignore(...os.Signal)
+pkg os/signal, func Reset(...os.Signal)
+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, method (*Reader) Size() int64
+pkg syscall (darwin-386), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-386), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-386), type SysProcAttr struct, Pgid int
+pkg syscall (darwin-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (darwin-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (darwin-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-386), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-386), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-386), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-arm), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-arm), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-arm), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-arm-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-arm-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-arm-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (linux-386), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-386), type SysProcAttr struct, Pgid int
+pkg syscall (linux-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (linux-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (linux-arm), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-arm), type SysProcAttr struct, Pgid int
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-386), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-386), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-386), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-arm), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-arm), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-arm), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-arm-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-arm-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-arm-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-386), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-386), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-386), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg text/template, method (*Template) DefinedTemplates() string
+pkg text/template, method (*Template) Option(...string) *Template
+pkg time, method (Time) AppendFormat([]uint8, string) []uint8
diff --git a/doc/articles/go_command.html b/doc/articles/go_command.html
index 2978628..cc1d86a 100644
--- a/doc/articles/go_command.html
+++ b/doc/articles/go_command.html
@@ -250,11 +250,16 @@
 <h2>Limitations</h2>
 
 <p>As mentioned above, the go command is not a general-purpose build
-tool. In particular, it does not have any facility for generating Go
-source files during a build.  Instead, if you want to use a tool like
-yacc or the protocol buffer compiler, you will need to write a
+tool.
+In particular, it does not have any facility for generating Go
+source files <em>during</em> a build, although it does provide
+<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go</code>
+<code>generate</code></a>,
+which can automate the creation of Go files <em>before</em>
+the build, such as by running <code>yacc</code>.
+For more advanced build setups, you may need to write a
 makefile (or a configuration file for the build tool of your choice)
-to generate the Go files and then check those generated source files
+to run whatever tool creates the Go files and then check those generated source files
 into your repository. This is more work for you, the package author,
 but it is significantly less work for your users, who can use
 "<code>go get</code>" without needing to obtain and build
diff --git a/doc/go1.5.txt b/doc/go1.5.txt
index 88e6dbc..b0602f9 100644
--- a/doc/go1.5.txt
+++ b/doc/go1.5.txt
@@ -10,7 +10,13 @@
 
 New Ports:
 darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127)
-linux/arm64
+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
 
 Removed Ports:
 dragonfly/386 (https://golang.org/cl/7543)
@@ -19,37 +25,72 @@
 
 archive/zip: add (*Writer).SetOffset method (https://golang.org/cl/7445)
 bufio: add Reader.Discard (https://golang.org/cl/2260)
+bytes: add Buffer.Cap (https://golang.org/cl/8342)
+bytes, strings: add Reader.Size (https://golang.org/cl/3199)
+bytes, strings: add LastIndexByte (https://golang.org/cl/9500)
 crypto/cipher: clarify what will happen if len(src) != len(dst) for the Stream interface. (https://golang.org/cl/1754)
 crypto/elliptic: add Name field to CurveParams struct (https://golang.org/cl/2133)
+crypto/elliptic: Unmarshaling points now automatically checks that the point is on the curve (https://golang.org/cl/2421)
 crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/1791)
+crypto/tls: including Certificate Transparency SCTs in the handshake is now supported (https://golang.org/cl/8988)
+crypto/tls: session ticket keys can now be rotated at runtime (https://golang.org/cl/9072)
+crypto/tls: servers will now always call GetCertificate to pick a certificate for a connection when Certificates is empty (https://golang.org/cl/8792)
 crypto/x509: wildcards are now only accepted as the first label (https://golang.org/cl/5691)
+crypto/x509: unknown critical extensions now cause errors in Verify, not when parsing (https://golang.org/cl/9390)
+database/sql: add Stats (https://golang.org/cl/7950)
 encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
-flag: new nicer format for PrintDefaults (https://go-review.googlesource.com/7330)
+flag: new nicer format for PrintDefaults (https://golang.org/cl/7330)
+fmt: empty slices now print nothing with %x (bug fix) (https://golang.org/cl/8864)
+fmt: reflect.Value now prints what it holds (https://golang.org/cl/8731)
 go/ast: add Implicit field to ast.EmptyStmt; changed meaning of ast.EmptyStmt.Semicolon position (https://golang.org/cl/5720)
+go/build: reserved GOARCHes for common architectures (https://golang.org/cl/9644)
+io: add CopyBuffer, Copy with user-provided buffer (https://golang.org/cl/8730)
 log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023)
+log: add LUTC flag (https://golang.org/cl/8761)
 math/big: add arbitrary precision Floats (many cl's)
+math/big: add Jacobi and Int.ModSqrt (https://golang.org/cl/1886)
 mime: add ExtensionByType (https://golang.org/cl/7444)
+mime/quotedprintable: new package (https://golang.org/cl/5940 + others)
+net: add Source field to OpError (https://go-review.googlesource.com/9231)
+net: fix inconsistent errors (https://golang.org/cl/9236)
 net/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/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)
+reflect: add ArrayOf (https://golang.org/cl/4111)
+reflect: add FuncOf (https://golang.org/cl/1996)
 runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020)
 runtime, syscall: use get_random_bytes syscall for NaCl (Go 1.5 now requires NaCl SDK pepper-39 or above) (https://golang.org/cl/1755)
 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)
 testing/quick: support generation of arrays (https://golang.org/cl/3865)
+text/template: add Options method (https://golang.org/cl/8462)
+text/template: huge integers are now parse errors (https://golang.org/cl/9651)
+time: add time.AppendFormat(https://golang.org/cl/1760)
 
 Tools:
 
 build: external linking support for windows (https://golang.org/cl/7163, 7282, 7283, 7284, 7534, 7535)
+cmd/cover: tool now lives in the standard repository (https://golang.org/cl/9560)
+cmd/gc: constant arithmetic is based on math/big (https://golang.org/cl/7830, 7851, 7857, 8426, 7858, 7912, 8171)
 cmd/go, go/build: add ${SRCDIR} variable expansion to cgo lines (https://golang.org/cl/1756)
 cmd/go: add $DOLLAR to generate's variables (https://golang.org/cl/8091)
 cmd/go: std wildcard now excludes commands in main repo (https://golang.org/cl/5550)
 cmd/go: .swig/.swigcxx files now require SWIG 3.0.6 or later
+cmd/go: add -run flag to go generate (https://golang.org/cl/9005)
+cmd/go: add $GOLINE to generate's variables (https://golang.org/cl/9007)
+cmd/go: add go doc (https://golang.org/cl/9227)
 cmd/vet: better validation of struct tags (https://golang.org/cl/2685)
 cmd/ld: no longer record build timestamp in Windows PE file header (https://golang.org/cl/3740)
+cmd/go: add -toolexec build option
+cmd/go: drop -ccflags build option
+cmd/go: add -asmflags build option
+cmd/go: add -buildmode build option
+cmd/gc: add -dynlink option (for amd64 only)
+cmd/ld: add -buildmode option
 cmd/trace: new command to view traces (https://golang.org/cl/3601)
 
 Performance:
@@ -75,6 +116,10 @@
 
 Assembler:
 
+New cmd/asm tool (now use go tool asm, not go tool 6a)
+
+Assembler now supports -dynlink option.
+
 ARM assembly syntax has had some features removed.
 
 	- mentioning SP or PC as a hardware register
diff --git a/doc/go_faq.html b/doc/go_faq.html
index bf7d8f3..9a30cdf 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1046,7 +1046,7 @@
 (This is the approach Google takes internally.)
 Store the copy under a new import path that identifies it as a local copy.
 For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg".
-Keith Rarick's <a href="https://github.com/kr/goven">goven</a> is one tool to help automate this process.
+<a href="https://godoc.org/golang.org/x/tools/cmd/gomvpkg">gomvpkg</a> is one tool to help automate this process.
 </p>
 
 <h2 id="Pointers">Pointers and Allocation</h2>
diff --git a/doc/progs/cgo1.go b/doc/progs/cgo1.go
index 805fe3c..d559e13 100644
--- a/doc/progs/cgo1.go
+++ b/doc/progs/cgo1.go
@@ -1,8 +1,7 @@
-// skip
-
 // Copyright 2012 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 rand
 
 /*
diff --git a/doc/progs/cgo2.go b/doc/progs/cgo2.go
index b9e9f7d..da07aa4 100644
--- a/doc/progs/cgo2.go
+++ b/doc/progs/cgo2.go
@@ -1,8 +1,7 @@
-// skip
-
 // Copyright 2012 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 rand2
 
 /*
diff --git a/doc/progs/cgo3.go b/doc/progs/cgo3.go
index c4f4791..d5cedf4 100644
--- a/doc/progs/cgo3.go
+++ b/doc/progs/cgo3.go
@@ -1,8 +1,7 @@
-// skip
-
 // Copyright 2012 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 print
 
 // #include <stdio.h>
diff --git a/doc/progs/cgo4.go b/doc/progs/cgo4.go
index 30b8935..dbb07e8 100644
--- a/doc/progs/cgo4.go
+++ b/doc/progs/cgo4.go
@@ -1,8 +1,7 @@
-// skip
-
 // Copyright 2012 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 print
 
 // #include <stdio.h>
diff --git a/doc/progs/defer.go b/doc/progs/defer.go
index 006a474..2e11020a 100644
--- a/doc/progs/defer.go
+++ b/doc/progs/defer.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2011 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.
diff --git a/doc/progs/defer.out b/doc/progs/defer.out
deleted file mode 100644
index 0cdf53a..0000000
--- a/doc/progs/defer.out
+++ /dev/null
@@ -1,3 +0,0 @@
-0
-3210
-2
diff --git a/doc/progs/defer2.go b/doc/progs/defer2.go
index ff7eaf9..cad66b0 100644
--- a/doc/progs/defer2.go
+++ b/doc/progs/defer2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2011 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.
diff --git a/doc/progs/defer2.out b/doc/progs/defer2.out
deleted file mode 100644
index 6110685..0000000
--- a/doc/progs/defer2.out
+++ /dev/null
@@ -1,12 +0,0 @@
-Calling g.
-Printing in g 0
-Printing in g 1
-Printing in g 2
-Printing in g 3
-Panicking!
-Defer in g 3
-Defer in g 2
-Defer in g 1
-Defer in g 0
-Recovered in f 4
-Returned normally from f.
diff --git a/doc/progs/eff_bytesize.go b/doc/progs/eff_bytesize.go
index a0c3d50..b459611 100644
--- a/doc/progs/eff_bytesize.go
+++ b/doc/progs/eff_bytesize.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/doc/progs/eff_bytesize.out b/doc/progs/eff_bytesize.out
deleted file mode 100644
index df763f3..0000000
--- a/doc/progs/eff_bytesize.out
+++ /dev/null
@@ -1 +0,0 @@
-1.00YB 9.09TB
diff --git a/doc/progs/eff_qr.go b/doc/progs/eff_qr.go
index 861131d..89de459 100644
--- a/doc/progs/eff_qr.go
+++ b/doc/progs/eff_qr.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/doc/progs/eff_sequence.go b/doc/progs/eff_sequence.go
index c9b18ba..11c885a 100644
--- a/doc/progs/eff_sequence.go
+++ b/doc/progs/eff_sequence.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
diff --git a/doc/progs/eff_sequence.out b/doc/progs/eff_sequence.out
deleted file mode 100644
index fd01a7d..0000000
--- a/doc/progs/eff_sequence.out
+++ /dev/null
@@ -1 +0,0 @@
-[-1 2 6 16 44]
diff --git a/doc/progs/eff_unused1.go b/doc/progs/eff_unused1.go
index f990a19..285d55e 100644
--- a/doc/progs/eff_unused1.go
+++ b/doc/progs/eff_unused1.go
@@ -1,5 +1,3 @@
-// skip
-
 package main
 
 import (
diff --git a/doc/progs/eff_unused2.go b/doc/progs/eff_unused2.go
index 3e6e041..92eb74e 100644
--- a/doc/progs/eff_unused2.go
+++ b/doc/progs/eff_unused2.go
@@ -1,5 +1,3 @@
-// compile
-
 package main
 
 import (
diff --git a/doc/progs/error.go b/doc/progs/error.go
index 57854c5..e776cdb 100644
--- a/doc/progs/error.go
+++ b/doc/progs/error.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2011 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.
diff --git a/doc/progs/error2.go b/doc/progs/error2.go
index aad1dc8..2b0e0c3 100644
--- a/doc/progs/error2.go
+++ b/doc/progs/error2.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2011 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.
diff --git a/doc/progs/error3.go b/doc/progs/error3.go
index 9f1b300..e4e57e0 100644
--- a/doc/progs/error3.go
+++ b/doc/progs/error3.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2011 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.
diff --git a/doc/progs/error4.go b/doc/progs/error4.go
index d40fc6e..8b2f304 100644
--- a/doc/progs/error4.go
+++ b/doc/progs/error4.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2011 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.
diff --git a/doc/progs/go1.go b/doc/progs/go1.go
index a4dc64d..50fd934 100644
--- a/doc/progs/go1.go
+++ b/doc/progs/go1.go
@@ -1,6 +1,3 @@
-// compile
-// this file will output a list of filenames in cwd, not suitable for cmpout
-
 // Copyright 2011 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.
diff --git a/doc/progs/gobs1.go b/doc/progs/gobs1.go
index d95f765..7077ca1 100644
--- a/doc/progs/gobs1.go
+++ b/doc/progs/gobs1.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2011 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.
diff --git a/doc/progs/gobs2.go b/doc/progs/gobs2.go
index acd1838..85bb41c 100644
--- a/doc/progs/gobs2.go
+++ b/doc/progs/gobs2.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2011 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.
diff --git a/doc/progs/image_draw.go b/doc/progs/image_draw.go
index 0a1f7ac..bb73c8a 100644
--- a/doc/progs/image_draw.go
+++ b/doc/progs/image_draw.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package1.go b/doc/progs/image_package1.go
index d331834..c4c401e 100644
--- a/doc/progs/image_package1.go
+++ b/doc/progs/image_package1.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package1.out b/doc/progs/image_package1.out
deleted file mode 100644
index 809b31b..0000000
--- a/doc/progs/image_package1.out
+++ /dev/null
@@ -1 +0,0 @@
-X is 2 Y is 1
diff --git a/doc/progs/image_package2.go b/doc/progs/image_package2.go
index e5b78b4..fcb5d9f 100644
--- a/doc/progs/image_package2.go
+++ b/doc/progs/image_package2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package2.out b/doc/progs/image_package2.out
deleted file mode 100644
index 616d307..0000000
--- a/doc/progs/image_package2.out
+++ /dev/null
@@ -1 +0,0 @@
-3 4 false
diff --git a/doc/progs/image_package3.go b/doc/progs/image_package3.go
index 95d72a0..13d0f08 100644
--- a/doc/progs/image_package3.go
+++ b/doc/progs/image_package3.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package3.out b/doc/progs/image_package3.out
deleted file mode 100644
index 3fe35de..0000000
--- a/doc/progs/image_package3.out
+++ /dev/null
@@ -1 +0,0 @@
-3 4 true
diff --git a/doc/progs/image_package4.go b/doc/progs/image_package4.go
index ec0e461..c46fddf 100644
--- a/doc/progs/image_package4.go
+++ b/doc/progs/image_package4.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package4.out b/doc/progs/image_package4.out
deleted file mode 100644
index cb1b777..0000000
--- a/doc/progs/image_package4.out
+++ /dev/null
@@ -1 +0,0 @@
-image.Point{X:2, Y:1}
diff --git a/doc/progs/image_package5.go b/doc/progs/image_package5.go
index b9e27d6..0bb5c76 100644
--- a/doc/progs/image_package5.go
+++ b/doc/progs/image_package5.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package5.out b/doc/progs/image_package5.out
deleted file mode 100644
index 2da80c1..0000000
--- a/doc/progs/image_package5.out
+++ /dev/null
@@ -1 +0,0 @@
-{255 0 0 255}
diff --git a/doc/progs/image_package6.go b/doc/progs/image_package6.go
index 5e6eefa..62eeecd 100644
--- a/doc/progs/image_package6.go
+++ b/doc/progs/image_package6.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/image_package6.out b/doc/progs/image_package6.out
deleted file mode 100644
index fcd13c0..0000000
--- a/doc/progs/image_package6.out
+++ /dev/null
@@ -1,2 +0,0 @@
-8 4
-true
diff --git a/doc/progs/interface.go b/doc/progs/interface.go
index 6972b72..c2925d5 100644
--- a/doc/progs/interface.go
+++ b/doc/progs/interface.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2012 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.
diff --git a/doc/progs/interface2.go b/doc/progs/interface2.go
index 85e7d51..a541d94 100644
--- a/doc/progs/interface2.go
+++ b/doc/progs/interface2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/interface2.out b/doc/progs/interface2.out
deleted file mode 100644
index 085bd01..0000000
--- a/doc/progs/interface2.out
+++ /dev/null
@@ -1 +0,0 @@
-type: float64
diff --git a/doc/progs/json1.go b/doc/progs/json1.go
index 887d7d1..9e10f47 100644
--- a/doc/progs/json1.go
+++ b/doc/progs/json1.go
@@ -1,5 +1,3 @@
-// run
-
 // Copyright 2012 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.
diff --git a/doc/progs/json2.go b/doc/progs/json2.go
index f358fea..6089ae6 100644
--- a/doc/progs/json2.go
+++ b/doc/progs/json2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // Copyright 2012 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.
diff --git a/doc/progs/json2.out b/doc/progs/json2.out
deleted file mode 100644
index 8f2dea5..0000000
--- a/doc/progs/json2.out
+++ /dev/null
@@ -1,2 +0,0 @@
-the circle's area 24.227111172875365
-the reciprocal of i is 0.3601008282319049
diff --git a/doc/progs/json3.go b/doc/progs/json3.go
index 41eb373..a04fdfa 100644
--- a/doc/progs/json3.go
+++ b/doc/progs/json3.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2012 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.
diff --git a/doc/progs/json4.go b/doc/progs/json4.go
index ee38f31..4926302 100644
--- a/doc/progs/json4.go
+++ b/doc/progs/json4.go
@@ -1,5 +1,3 @@
-// run
-
 // Copyright 2012 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.
diff --git a/doc/progs/json5.go b/doc/progs/json5.go
index 9ab972d..6d7a4ca 100644
--- a/doc/progs/json5.go
+++ b/doc/progs/json5.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2012 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.
diff --git a/doc/progs/run b/doc/progs/run
deleted file mode 100755
index 6e680b8..0000000
--- a/doc/progs/run
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-set -e
-
-goos=$(go env GOOS)
-
-defer_panic_recover="
-	defer
-	defer2
-"
-
-effective_go="
-	eff_bytesize
-	eff_qr
-	eff_sequence
-	eff_unused2
-"
-
-error_handling="
-	error
-	error2
-	error3
-	error4
-"
-
-law_of_reflection="
-	interface
-	interface2
-"
-
-c_go_cgo="
-	cgo1
-	cgo2
-	cgo3
-	cgo4
-"
-# cgo1 and cgo2 don't run on freebsd, srandom has a different signature
-if [ "$goos" == "freebsd" ]; then
-	c_go_cgo="cgo3 cgo4"
-fi
-# cgo1 and cgo2 don't run on netbsd, srandom has a different signature
-# cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly
-if [ "$goos" == "netbsd" ]; then
-	c_go_cgo=""
-fi
-# cgo3 and cgo4 don't run on openbsd, since cgo cannot handle stdout correctly
-if [ "$goos" == "openbsd" ]; then
-	c_go_cgo="cgo1 cgo2"
-fi
-if [ "$CGO_ENABLED" != 1 ]; then
-	c_go_cgo=""
-fi
-
-timeout="
-	timeout1
-	timeout2
-"
-
-gobs="
-	gobs1
-	gobs2
-"
-
-json="
-	json1
-	json2
-	json3
-	json4
-	json5
-"
-
-image_package="
-	image_package1
-	image_package2
-	image_package3
-	image_package4
-	image_package5
-	image_package6
-"
-
-all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs $json $image_package slices go1)
-
-for i in $all; do
-	go build $i.go
-done
-
-# Write to temporary file to avoid mingw bash bug.
-TMPFILE="${TMPDIR:-/tmp}/gotest3.$USER"
-
-function testit {
-	./$1 >"$TMPFILE" 2>&1 || true
-	x=$(echo $(cat "$TMPFILE")) # extra echo canonicalizes
-	if ! echo "$x" | grep "$2" > /dev/null
-	then
-		echo $1 failed: '"'$x'"' is not '"'$2'"'
-	fi
-}
-
-
-testit defer '^0 3210 2$'
-testit defer2 '^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$'
-
-testit eff_bytesize '^1.00YB 9.09TB$'
-testit eff_sequence '^\[-1 2 6 16 44\]$'
-
-testit go1 '^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$'
-
-testit interface2 "^type: float64$"
-
-testit json1 "^$"
-testit json2 "the reciprocal of i is"
-testit json3 "Age is int 6"
-testit json4 "^$"
-
-testit image_package1 "^X is 2 Y is 1$"
-testit image_package2 "^3 4 false$"
-testit image_package3 "^3 4 true$"
-testit image_package4 "^image.Point{X:2, Y:1}$"
-testit image_package5 "^{255 0 0 255}$"
-testit image_package6 "^8 4 true$"
-
-rm -f $all "$TMPFILE"
diff --git a/doc/progs/run.go b/doc/progs/run.go
new file mode 100755
index 0000000..8479a66
--- /dev/null
+++ b/doc/progs/run.go
@@ -0,0 +1,230 @@
+// 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 runs the docs tests found in this directory.
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strings"
+)
+
+const usage = `go run run.go [tests]
+
+run.go runs the docs tests in this directory.
+If no tests are provided, it runs all tests.
+Tests may be specified without their .go suffix.
+`
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintf(os.Stderr, usage)
+		flag.PrintDefaults()
+		os.Exit(2)
+	}
+
+	flag.Parse()
+	if flag.NArg() == 0 {
+		// run all tests
+		fixcgo()
+	} else {
+		// run specified tests
+		onlyTest(flag.Args()...)
+	}
+
+	tmpdir, err := ioutil.TempDir("", "go-progs")
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+
+	// ratec limits the number of tests running concurrently.
+	// None of the tests are intensive, so don't bother
+	// trying to manually adjust for slow builders.
+	ratec := make(chan bool, runtime.NumCPU())
+	errc := make(chan error, len(tests))
+
+	for _, tt := range tests {
+		tt := tt
+		ratec <- true
+		go func() {
+			errc <- test(tmpdir, tt.file, tt.want)
+			<-ratec
+		}()
+	}
+
+	var rc int
+	for range tests {
+		if err := <-errc; err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			rc = 1
+		}
+	}
+	os.Remove(tmpdir)
+	os.Exit(rc)
+}
+
+// test builds the test in the given file.
+// If want is non-empty, test also runs the test
+// and checks that the output matches the regexp want.
+func test(tmpdir, file, want string) error {
+	// Build the program.
+	prog := filepath.Join(tmpdir, file)
+	cmd := exec.Command("go", "build", "-o", prog, file+".go")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("go build %s.go failed: %v\nOutput:\n%s", file, err, out)
+	}
+	defer os.Remove(prog)
+
+	// Only run the test if we have output to check.
+	if want == "" {
+		return nil
+	}
+
+	cmd = exec.Command(prog)
+	out, err = cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("%s failed: %v\nOutput:\n%s", file, err, out)
+	}
+
+	// Canonicalize output.
+	out = bytes.TrimRight(out, "\n")
+	out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
+
+	// Check the result.
+	match, err := regexp.Match(want, out)
+	if err != nil {
+		return fmt.Errorf("failed to parse regexp %q: %v", want, err)
+	}
+	if !match {
+		return fmt.Errorf("%s.go:\n%q\ndoes not match %s", file, out, want)
+	}
+
+	return nil
+}
+
+type testcase struct {
+	file string
+	want string
+}
+
+var tests = []testcase{
+	// defer_panic_recover
+	{"defer", `^0 3210 2$`},
+	{"defer2", `^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$`},
+
+	// effective_go
+	{"eff_bytesize", `^1.00YB 9.09TB$`},
+	{"eff_qr", ""},
+	{"eff_sequence", `^\[-1 2 6 16 44\]$`},
+	{"eff_unused2", ""},
+
+	// error_handling
+	{"error", ""},
+	{"error2", ""},
+	{"error3", ""},
+	{"error4", ""},
+
+	// law_of_reflection
+	{"interface", ""},
+	{"interface2", `^type: float64$`},
+
+	// c_go_cgo
+	{"cgo1", ""},
+	{"cgo2", ""},
+	{"cgo3", ""},
+	{"cgo4", ""},
+
+	// timeout
+	{"timeout1", ""},
+	{"timeout2", ""},
+
+	// gobs
+	{"gobs1", ""},
+	{"gobs2", ""},
+
+	// json
+	{"json1", `^$`},
+	{"json2", `the reciprocal of i is`},
+	{"json3", `Age is int 6`},
+	{"json4", `^$`},
+	{"json5", ""},
+
+	// image_package
+	{"image_package1", `^X is 2 Y is 1$`},
+	{"image_package2", `^3 4 false$`},
+	{"image_package3", `^3 4 true$`},
+	{"image_package4", `^image.Point{X:2, Y:1}$`},
+	{"image_package5", `^{255 0 0 255}$`},
+	{"image_package6", `^8 4 true$`},
+
+	// other
+	{"go1", `^Christmas is a holiday: true .*go1.go already exists$`},
+	{"slices", ""},
+}
+
+func onlyTest(files ...string) {
+	var new []testcase
+NextFile:
+	for _, file := range files {
+		file = strings.TrimSuffix(file, ".go")
+		for _, tt := range tests {
+			if tt.file == file {
+				new = append(new, tt)
+				continue NextFile
+			}
+		}
+		fmt.Fprintf(os.Stderr, "test %s.go not found\n", file)
+		os.Exit(1)
+	}
+	tests = new
+}
+
+func skipTest(file string) {
+	for i, tt := range tests {
+		if tt.file == file {
+			copy(tests[i:], tests[i+1:])
+			tests = tests[:len(tests)-1]
+			return
+		}
+	}
+	panic("delete(" + file + "): not found")
+}
+
+func fixcgo() {
+	if os.Getenv("CGO_ENABLED") != "1" {
+		skipTest("cgo1")
+		skipTest("cgo2")
+		skipTest("cgo3")
+		skipTest("cgo4")
+		return
+	}
+
+	switch runtime.GOOS {
+	case "freebsd":
+		// cgo1 and cgo2 don't run on freebsd, srandom has a different signature
+		skipTest("cgo1")
+		skipTest("cgo2")
+	case "netbsd":
+		// cgo1 and cgo2 don't run on netbsd, srandom has a different signature
+		skipTest("cgo1")
+		skipTest("cgo2")
+		// cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly, see issue #10715.
+		skipTest("cgo3")
+		skipTest("cgo4")
+	case "openbsd", "solaris":
+		// cgo3 and cgo4 don't run on openbsd and solaris, since cgo cannot handle stdout correctly, see issue #10715.
+		skipTest("cgo3")
+		skipTest("cgo4")
+	}
+}
diff --git a/doc/progs/slices.go b/doc/progs/slices.go
index f9af5fe..967a3e7 100644
--- a/doc/progs/slices.go
+++ b/doc/progs/slices.go
@@ -1,5 +1,3 @@
-// compile
-
 // Copyright 2012 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.
diff --git a/doc/progs/timeout1.go b/doc/progs/timeout1.go
index fbc39ca..353ba69 100644
--- a/doc/progs/timeout1.go
+++ b/doc/progs/timeout1.go
@@ -1,8 +1,7 @@
-// compile
-
 // Copyright 2012 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 timeout
 
 import (
diff --git a/doc/progs/timeout2.go b/doc/progs/timeout2.go
index a12bc2a..b0d34ea 100644
--- a/doc/progs/timeout2.go
+++ b/doc/progs/timeout2.go
@@ -1,8 +1,7 @@
-// compile
-
 // Copyright 2012 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 query
 
 type Conn string
diff --git a/doc/progs/update.bash b/doc/progs/update.bash
deleted file mode 100755
index d4ecfbe..0000000
--- a/doc/progs/update.bash
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2012 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.
-
-set -e
-
-rm -f *.out *.rej *.orig [568].out
-
-for i in *.go; do
-	if grep -q '^// cmpout$' $i; then
-		echo $i
-		go run $i &> ${i/.go/.out}
-	fi
-done
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index 8c8ccbe..fc2023f 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -9,7 +9,6 @@
 void callGoFoo(void);
 void callGoStackCheck(void);
 void callPanic(void);
-void callCgoAllocate(void);
 int callGoReturnVal(void);
 int returnAfterGrow(void);
 int returnAfterGrowFromGo(void);
@@ -17,7 +16,6 @@
 import "C"
 
 import (
-	"os"
 	"path"
 	"runtime"
 	"strings"
@@ -211,23 +209,6 @@
 	C.callPanic()
 }
 
-func testAllocateFromC(t *testing.T) {
-	if strings.Contains(os.Getenv("GODEBUG"), "wbshadow=") {
-		// This test is writing pointers to Go heap objects from C.
-		// As such, those writes have no write barriers, and
-		// wbshadow=2 mode correctly discovers that and crashes.
-		// Disable test if any wbshadow mode is enabled.
-		// TODO(rsc): I am not sure whether the test is fundamentally
-		// incompatible with concurrent collection and should be
-		// turned off or rewritten entirely. The test is attempting to
-		// mimic some SWIG behavior, so it is important to work
-		// through what we expect before trying SWIG and C++
-		// with the concurrent collector.
-		t.Skip("test is incompatible with wbshadow=")
-	}
-	C.callCgoAllocate() // crashes or exits on failure
-}
-
 // Test that C code can return a value if it calls a Go function that
 // causes a stack copy.
 func testReturnAfterGrow(t *testing.T) {
diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c
index 28a62c6..c6ea3c5 100644
--- a/misc/cgo/test/callback_c_gc.c
+++ b/misc/cgo/test/callback_c_gc.c
@@ -23,58 +23,3 @@
 	crosscall2(_cgo_panic, &a, sizeof a);
 	*(int*)1 = 1;
 }
-
-/* Test calling cgo_allocate from C. This is what SWIG does. */
-
-typedef struct List List;
-struct List
-{
-	List *next;
-	int x;
-};
-
-void
-callCgoAllocate(void)
-{
-	int i;
-	struct { size_t n; void *ret; } a;
-	List *l, *head, **tail;
-
-	// Make sure this doesn't crash.
-	// And make sure it returns non-nil.
-	a.n = 0;
-	a.ret = 0;
-	crosscall2(_cgo_allocate, &a, sizeof a);
-	if(a.ret == 0) {
-		fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
-		exit(2);
-	}
-	
-	head = 0;
-	tail = &head;
-	for(i=0; i<100; i++) {
-		a.n = sizeof *l;
-		crosscall2(_cgo_allocate, &a, sizeof a);
-		l = a.ret;
-		l->x = i;
-		l->next = 0;
-		*tail = l;
-		tail = &l->next;
-	}
-	
-	gc();
-	
-	l = head;
-	for(i=0; i<100; i++) {
-		if(l->x != i) {
-			fprintf(stderr, "callCgoAllocate: lost memory\n");
-			exit(2);
-		}
-		l = l->next;
-	}
-	if(l != 0) {
-		fprintf(stderr, "callCgoAllocate: lost memory\n");
-		exit(2);
-	}
-}
-
diff --git a/misc/cgo/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c
index d367b7b..ff5dbbb 100644
--- a/misc/cgo/test/callback_c_gccgo.c
+++ b/misc/cgo/test/callback_c_gccgo.c
@@ -19,52 +19,3 @@
 {
 	_cgo_panic("panic from C");
 }
-
-/* Test calling cgo_allocate from C. This is what SWIG does. */
-
-typedef struct List List;
-struct List
-{
-	List *next;
-	int x;
-};
-
-void
-callCgoAllocate(void)
-{
-	int i;
-	List *l, *head, **tail;
-	
-	// Make sure this doesn't crash.
-	// And make sure it returns non-nil.
-	if(_cgo_allocate(0) == 0) {
-		fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
-		exit(2);
-	}
-
-	head = 0;
-	tail = &head;
-	for(i=0; i<100; i++) {
-		l = _cgo_allocate(sizeof *l);
-		l->x = i;
-		l->next = 0;
-		*tail = l;
-		tail = &l->next;
-	}
-	
-	gc();
-	
-	l = head;
-	for(i=0; i<100; i++) {
-		if(l->x != i) {
-			fprintf(stderr, "callCgoAllocate: lost memory\n");
-			exit(2);
-		}
-		l = l->next;
-	}
-	if(l != 0) {
-		fprintf(stderr, "callCgoAllocate: lost memory\n");
-		exit(2);
-	}
-}
-
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index 76576d7..0fea40f9 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -23,7 +23,6 @@
 func TestCallbackPanicLoop(t *testing.T)     { testCallbackPanicLoop(t) }
 func TestCallbackPanicLocked(t *testing.T)   { testCallbackPanicLocked(t) }
 func TestPanicFromC(t *testing.T)            { testPanicFromC(t) }
-func TestAllocateFromC(t *testing.T)         { testAllocateFromC(t) }
 func TestZeroArgCallback(t *testing.T)       { testZeroArgCallback(t) }
 func TestBlocking(t *testing.T)              { testBlocking(t) }
 func Test1328(t *testing.T)                  { test1328(t) }
diff --git a/misc/cgo/test/cthread_unix.c b/misc/cgo/test/cthread_unix.c
index 3f39c15..d29f2fc 100644
--- a/misc/cgo/test/cthread_unix.c
+++ b/misc/cgo/test/cthread_unix.c
@@ -2,7 +2,7 @@
 // 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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include <pthread.h>
 #include "_cgo_export.h"
diff --git a/misc/cgo/test/issue3261.go b/misc/cgo/test/issue3261.go
index 0411be8..32cb06b 100644
--- a/misc/cgo/test/issue3261.go
+++ b/misc/cgo/test/issue3261.go
@@ -13,6 +13,12 @@
 	puts("testLibgcc is disabled on ARM because 5l cannot handle thumb library.");
 	return (x < 0) ? -x : x;
 }
+#elif defined(__arm64__) && defined(__clang__)
+#include <stdio.h>
+int vabs(int x) {
+	puts("testLibgcc is disabled on ARM64 with clang due to lack of libgcc.");
+	return (x < 0) ? -x : x;
+}
 #else
 int __absvsi2(int); // dummy prototype for libgcc function
 // we shouldn't name the function abs, as gcc might use
diff --git a/misc/cgo/test/issue9400/asm_386.s b/misc/cgo/test/issue9400/asm_386.s
index b277fa1..e37a54f 100644
--- a/misc/cgo/test/issue9400/asm_386.s
+++ b/misc/cgo/test/issue9400/asm_386.s
@@ -1,3 +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.
+
+// +build !gccgo
+
 #include "textflag.h"
 
 TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0
diff --git a/misc/cgo/test/issue9400/asm_amd64x.s b/misc/cgo/test/issue9400/asm_amd64x.s
index 2c97e13..f09e95d 100644
--- a/misc/cgo/test/issue9400/asm_amd64x.s
+++ b/misc/cgo/test/issue9400/asm_amd64x.s
@@ -1,4 +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.
+
 // +build amd64 amd64p32
+// +build !gccgo
 
 #include "textflag.h"
 
diff --git a/misc/cgo/test/issue9400/asm_arm.s b/misc/cgo/test/issue9400/asm_arm.s
index d9d2abc..5c5983d 100644
--- a/misc/cgo/test/issue9400/asm_arm.s
+++ b/misc/cgo/test/issue9400/asm_arm.s
@@ -1,3 +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.
+
+// +build !gccgo
+
 #include "textflag.h"
 
 TEXT cas<>(SB),NOSPLIT,$0
diff --git a/misc/cgo/test/issue9400/asm_arm64.s b/misc/cgo/test/issue9400/asm_arm64.s
new file mode 100644
index 0000000..cba525f
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_arm64.s
@@ -0,0 +1,39 @@
+// 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.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$-8-0
+	// Save link register
+	MOVD	R30, R9
+
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADD	$(1024 * 8), RSP
+
+	// Ask signaller to setgid
+	MOVD	$·Baton(SB), R0
+	MOVD	$1, R1
+storeloop:
+	LDAXRW	(R0), R2
+	STLXRW	R1, (R0), R3
+	CBNZ	R3, storeloop
+
+	// Wait for setgid completion
+	MOVW	$0, R1
+	MOVW	$0, R2
+loop:
+	LDAXRW	(R0), R3
+	CMPW	R1, R3
+	BNE	loop
+	STLXRW	R2, (R0), R3
+	CBNZ	R3, loop
+
+	// Restore stack
+	SUB	$(1024 * 8), RSP
+
+	MOVD	R9, R30
+	RET
diff --git a/misc/cgo/test/issue9400/asm_ppc64x.s b/misc/cgo/test/issue9400/asm_ppc64x.s
index 0aaa10c..7dfe37e 100644
--- a/misc/cgo/test/issue9400/asm_ppc64x.s
+++ b/misc/cgo/test/issue9400/asm_ppc64x.s
@@ -1,4 +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.
+
 // +build ppc64 ppc64le
+// +build !gccgo
 
 #include "textflag.h"
 
diff --git a/misc/cgo/test/issue9400/gccgo.go b/misc/cgo/test/issue9400/gccgo.go
new file mode 100644
index 0000000..6b9d5fa
--- /dev/null
+++ b/misc/cgo/test/issue9400/gccgo.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build gccgo
+
+package issue9400
+
+import (
+	"runtime"
+	"sync/atomic"
+)
+
+// The test for the gc compiler resets the stack pointer so that the
+// stack gets modified.  We don't have a way to do that for gccgo
+// without writing more assembly code, which we haven't bothered to
+// do.  So this is not much of a test.
+
+func RewindAndSetgid() {
+	atomic.StoreInt32(&Baton, 1)
+	for atomic.LoadInt32(&Baton) != 0 {
+		runtime.Gosched()
+	}
+}
diff --git a/misc/cgo/testcarchive/main.c b/misc/cgo/testcarchive/main.c
new file mode 100644
index 0000000..cc3170d
--- /dev/null
+++ b/misc/cgo/testcarchive/main.c
@@ -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.
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "p.h"
+#include "libgo.h"
+
+int main(void) {
+	int32_t res;
+
+	if (!DidInitRun()) {
+		fprintf(stderr, "ERROR: buildmode=c-archive init should run\n");
+		return 2;
+	}
+
+	if (DidMainRun()) {
+		fprintf(stderr, "ERROR: buildmode=c-archive should not run main\n");
+		return 2;
+	}
+
+	res = FromPkg();
+	if (res != 1024) {
+		fprintf(stderr, "ERROR: FromPkg()=%d, want 1024\n", res);
+		return 2;
+	}
+
+	CheckArgs();
+
+	fprintf(stderr, "PASS\n");
+	return 0;
+}
diff --git a/misc/cgo/testcarchive/src/libgo/libgo.go b/misc/cgo/testcarchive/src/libgo/libgo.go
new file mode 100644
index 0000000..45958a5
--- /dev/null
+++ b/misc/cgo/testcarchive/src/libgo/libgo.go
@@ -0,0 +1,53 @@
+// 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"
+	"os"
+	"syscall"
+	"time"
+
+	_ "p"
+)
+
+import "C"
+
+var initCh = make(chan int, 1)
+var ranMain bool
+
+func init() {
+	// emulate an exceedingly slow package initialization function
+	time.Sleep(100 * time.Millisecond)
+	initCh <- 42
+}
+
+func main() { ranMain = true }
+
+//export DidInitRun
+func DidInitRun() bool {
+	select {
+	case x := <-initCh:
+		if x != 42 {
+			// Just in case initCh was not correctly made.
+			println("want init value of 42, got: ", x)
+			syscall.Exit(2)
+		}
+		return true
+	default:
+		return false
+	}
+}
+
+//export DidMainRun
+func DidMainRun() bool { return ranMain }
+
+//export CheckArgs
+func CheckArgs() {
+	if len(os.Args) != 3 || os.Args[1] != "arg1" || os.Args[2] != "arg2" {
+		fmt.Printf("CheckArgs: want [_, arg1, arg2], got: %v\n", os.Args)
+		os.Exit(2)
+	}
+}
diff --git a/misc/cgo/testcarchive/src/p/p.go b/misc/cgo/testcarchive/src/p/p.go
new file mode 100644
index 0000000..82b445c
--- /dev/null
+++ b/misc/cgo/testcarchive/src/p/p.go
@@ -0,0 +1,10 @@
+// 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 p
+
+import "C"
+
+//export FromPkg
+func FromPkg() int32 { return 1024 }
diff --git a/misc/cgo/testcarchive/test.bash b/misc/cgo/testcarchive/test.bash
new file mode 100755
index 0000000..89b761b
--- /dev/null
+++ b/misc/cgo/testcarchive/test.bash
@@ -0,0 +1,44 @@
+#!/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.
+
+set -e
+
+ccargs=
+if [ "$(go env GOOS)" == "darwin" ]; then
+	ccargs="-Wl,-no_pie"
+	# For darwin/arm.
+	# TODO(crawshaw): Can we do better?
+	ccargs="$ccargs -framework CoreFoundation -framework Foundation"
+fi
+ccargs="$ccargs -I pkg/$(go env GOOS)_$(go env GOARCH)"
+
+# TODO(crawshaw): Consider a go env for exec script name.
+bin=./testp
+exec_script=go_$(go env GOOS)_$(go env GOARCH)_exec
+if [ "$(which $exec_script)" != "" ]; then
+	bin="$exec_script ./testp"
+fi
+
+rm -rf libgo.a libgo.h testp pkg
+
+# Installing first will create the header files we want.
+
+GOPATH=$(pwd) go install -buildmode=c-archive libgo
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c pkg/$(go env GOOS)_$(go env GOARCH)/libgo.a
+$bin arg1 arg2
+rm -f libgo.a libgo.h testp
+
+# Test building libgo other than installing it.
+# Header files are now present.
+
+GOPATH=$(pwd) go build -buildmode=c-archive src/libgo/libgo.go
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
+$bin arg1 arg2
+rm -f libgo.a libgo.h testp
+
+GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
+$bin arg1 arg2
+rm -rf libgo.a libgo.h testp pkg
diff --git a/misc/cgo/testcshared/main0.c b/misc/cgo/testcshared/main0.c
new file mode 100644
index 0000000..1274b89
--- /dev/null
+++ b/misc/cgo/testcshared/main0.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 <stdint.h>
+#include <stdio.h>
+
+#include "p.h"
+#include "libgo.h"
+
+// Tests libgo.so to export the following functions.
+//   int8_t DidInitRun();
+//   int8_t DidMainRun();
+//   int32_t FromPkg();
+int main(void) {
+  int8_t ran_init = DidInitRun();
+  if (!ran_init) {
+    fprintf(stderr, "ERROR: DidInitRun returned unexpected results: %d\n",
+            ran_init);
+    return 1;
+  }
+  int8_t ran_main = DidMainRun();
+  if (ran_main) {
+    fprintf(stderr, "ERROR: DidMainRun returned unexpected results: %d\n",
+            ran_main);
+    return 1;
+  }
+  int32_t from_pkg = FromPkg();
+  if (from_pkg != 1024) {
+    fprintf(stderr, "ERROR: FromPkg=%d, want %d\n", from_pkg, 1024);
+    return 1;
+  }
+  // test.bash looks for "PASS" to ensure this program has reached the end. 
+  printf("PASS\n");
+  return 0;
+}
diff --git a/misc/cgo/testcshared/main1.c b/misc/cgo/testcshared/main1.c
new file mode 100644
index 0000000..420dd1e
--- /dev/null
+++ b/misc/cgo/testcshared/main1.c
@@ -0,0 +1,69 @@
+// 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 <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+int check_int8(void* handle, const char* fname, int8_t want) {
+  int8_t (*fn)();
+  fn = (int8_t (*)())dlsym(handle, fname);
+  if (!fn) {
+    fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror());
+    return 1;
+  }
+  signed char ret = fn();
+  if (ret != want) {
+    fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want);
+    return 1;
+  }
+  return 0;
+}
+
+int check_int32(void* handle, const char* fname, int32_t want) {
+  int32_t (*fn)();
+  fn = (int32_t (*)())dlsym(handle, fname);
+  if (!fn) {
+    fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror());
+    return 1;
+  }
+  int32_t ret = fn();
+  if (ret != want) {
+    fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want);
+    return 1;
+  }
+  return 0;
+}
+
+// Tests libgo.so to export the following functions.
+//   int8_t DidInitRun() // returns true
+//   int8_t DidMainRun() // returns true
+//   int32_t FromPkg() // returns 1024
+int main(int argc, char** argv) {
+  void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+  if (!handle) {
+    fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+		    dlerror());
+    return 2;
+  }
+
+  int ret = 0;
+  ret = check_int8(handle, "DidInitRun", 1);
+  if (ret != 0) {
+    return ret;
+  }
+
+  ret = check_int8(handle, "DidMainRun", 0);
+  if (ret != 0) {
+    return ret;
+  }
+
+  ret = check_int32(handle, "FromPkg", 1024);
+  if (ret != 0) {
+   return ret;
+  }
+  // test.bash looks for "PASS" to ensure this program has reached the end. 
+  printf("PASS\n");
+  return 0;
+}
diff --git a/misc/cgo/testcshared/main2.c b/misc/cgo/testcshared/main2.c
new file mode 100644
index 0000000..4023383
--- /dev/null
+++ b/misc/cgo/testcshared/main2.c
@@ -0,0 +1,56 @@
+// 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define fd (10)
+
+// Tests libgo2.so, which does not export any functions.
+// Read a string from the file descriptor and print it.
+int main(void) {
+  int i;
+  ssize_t n;
+  char buf[20];
+  struct timespec ts;
+
+  // The descriptor will be initialized in a thread, so we have to
+  // give a chance to get opened.
+  for (i = 0; i < 100; i++) {
+    n = read(fd, buf, sizeof buf);
+    if (n >= 0)
+      break;
+    if (errno != EBADF) {
+      fprintf(stderr, "BUG: read: %s\n", strerror(errno));
+      return 2;
+    }
+
+    // An EBADF error means that the shared library has not opened the
+    // descriptor yet.
+    ts.tv_sec = 0;
+    ts.tv_nsec = 1000000;
+    nanosleep(&ts, NULL);
+  }
+
+  if (n < 0) {
+    fprintf(stderr, "BUG: failed to read any data from pipe\n");
+    return 2;
+  }
+
+  if (n == 0) {
+    fprintf(stderr, "BUG: unexpected EOF\n");
+    return 2;
+  }
+
+  if (n == sizeof buf) {
+    n--;
+  }
+  buf[n] = '\0';
+  printf("%s\n", buf);
+  return 0;
+}
diff --git a/misc/cgo/testcshared/main3.c b/misc/cgo/testcshared/main3.c
new file mode 100644
index 0000000..49cc055
--- /dev/null
+++ b/misc/cgo/testcshared/main3.c
@@ -0,0 +1,29 @@
+// 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 <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+// Tests "main.main" is exported on android/arm,
+// which golang.org/x/mobile/app depends on.
+int main(int argc, char** argv) {
+  void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+  if (!handle) {
+    fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+            dlerror());
+    return 2;
+  }
+
+  uintptr_t main_fn = (uintptr_t)dlsym(handle, "main.main");
+  if (!main_fn) {
+    fprintf(stderr, "ERROR: missing main.main: %s\n", dlerror());
+    return 2;
+  }
+
+  // TODO(hyangah): check that main.main can run.
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/misc/cgo/testcshared/src/libgo/libgo.go b/misc/cgo/testcshared/src/libgo/libgo.go
new file mode 100644
index 0000000..8a4bf79
--- /dev/null
+++ b/misc/cgo/testcshared/src/libgo/libgo.go
@@ -0,0 +1,46 @@
+// 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 (
+	_ "p"
+	"syscall"
+	"time"
+)
+
+import "C"
+
+var initCh = make(chan int, 1)
+var ranMain bool
+
+func init() {
+	// emulate an exceedingly slow package initialization function
+	time.Sleep(100 * time.Millisecond)
+	initCh <- 42
+}
+
+func main() {
+	ranMain = true
+}
+
+//export DidInitRun
+func DidInitRun() bool {
+	select {
+	case x := <-initCh:
+		if x != 42 {
+			// Just in case initCh was not correctly made.
+			println("want init value of 42, got: ", x)
+			syscall.Exit(2)
+		}
+		return true
+	default:
+		return false
+	}
+}
+
+//export DidMainRun
+func DidMainRun() bool {
+	return ranMain
+}
diff --git a/misc/cgo/testcshared/src/libgo2/libgo2.go b/misc/cgo/testcshared/src/libgo2/libgo2.go
new file mode 100644
index 0000000..6096860
--- /dev/null
+++ b/misc/cgo/testcshared/src/libgo2/libgo2.go
@@ -0,0 +1,52 @@
+// 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 netbsd openbsd solaris
+
+package main
+
+// Test a shared library created by -buildmode=c-shared that does not
+// export anything.
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+)
+
+// To test this we want to communicate between the main program and
+// the shared library without using any exported symbols.  The init
+// function creates a pipe and Dups the read end to a known number
+// that the C code can also use.
+
+const (
+	fd = 10
+)
+
+func init() {
+	var p [2]int
+	if e := syscall.Pipe(p[0:]); e != nil {
+		fmt.Fprintf(os.Stderr, "pipe: %v\n", e)
+		os.Exit(2)
+	}
+
+	if e := syscall.Dup2(p[0], fd); e != nil {
+		fmt.Fprintf(os.Stderr, "dup2: %v\n", e)
+		os.Exit(2)
+	}
+
+	const str = "PASS"
+	if n, e := syscall.Write(p[1], []byte(str)); e != nil || n != len(str) {
+		fmt.Fprintf(os.Stderr, "write: %d %v\n", n, e)
+		os.Exit(2)
+	}
+
+	if e := syscall.Close(p[1]); e != nil {
+		fmt.Fprintf(os.Stderr, "close: %v\n", e)
+		os.Exit(2)
+	}
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcshared/src/p/p.go b/misc/cgo/testcshared/src/p/p.go
new file mode 100644
index 0000000..82b445c
--- /dev/null
+++ b/misc/cgo/testcshared/src/p/p.go
@@ -0,0 +1,10 @@
+// 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 p
+
+import "C"
+
+//export FromPkg
+func FromPkg() int32 { return 1024 }
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
new file mode 100755
index 0000000..9862a37
--- /dev/null
+++ b/misc/cgo/testcshared/test.bash
@@ -0,0 +1,114 @@
+#!/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.
+
+# For testing Android, this script requires adb to push and run compiled
+# binaries on a target device.
+
+set -e
+
+if [ ! -f src/libgo/libgo.go ]; then
+	cwd=$(pwd)
+	echo 'misc/cgo/testcshared/test.bash is running in $cwd' 1>&2
+	exit 1
+fi
+
+goos=$(go env GOOS)
+
+# Temporary directory on the android device.
+androidpath=/data/local/tmp/testcshared-$$
+
+function cleanup() {
+	rm -rf libgo.so libgo2.so libgo.h testp testp2 testp3 pkg
+
+	rm -rf $(go env GOROOT)/pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared
+
+	if [ "$(go env GOOS)" == "android" ]; then
+		adb shell rm -rf $androidpath
+	fi
+}
+trap cleanup EXIT
+
+if [ "$goos" == "android" ]; then
+	adb shell mkdir -p "$androidpath"
+fi
+
+function run() {
+	case "$goos" in
+	"android")
+		local args=$@
+		for ((i=0; i < ${#args}; i++)); do
+			args[$i]=${args[$i]//.\//${androidpath}\/}
+			args[$i]=${args[$i]//=./=${androidpath}}
+		done
+		output=$(adb shell ${args} | tr -d '\r')
+		case $output in
+			*PASS) echo "PASS";; 
+			*) echo "$output";;
+		esac
+		;;
+	*)
+		echo $(env $@)
+		;;
+	esac
+}
+
+function binpush() {
+	bin=${1}
+	if [ "$goos" == "android" ]; then
+		adb push "$bin"  "${androidpath}/${bin}" 2>/dev/null
+	fi
+}
+
+rm -rf pkg
+
+suffix="-installsuffix testcshared"
+
+# Create the header files.
+GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo
+
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.so src/libgo/libgo.go
+binpush libgo.so
+
+# test0: exported symbols in shared lib are accessible.
+# TODO(iant): using _shared here shouldn't really be necessary.
+$(go env CC) $(go env GOGCCFLAGS) -I pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared -o testp main0.c libgo.so
+binpush testp
+output=$(run LD_LIBRARY_PATH=. ./testp)
+if [ "$output" != "PASS" ]; then
+	echo "FAIL test0 got ${output}"
+	exit 1
+fi
+
+# test1: .so can be dynamically loaded and exported symbols are accessible.
+$(go env CC) $(go env GOGCCFLAGS) -o testp main1.c -ldl
+binpush testp
+output=$(run ./testp ./libgo.so)
+if [ "$output" != "PASS" ]; then
+	echo "FAIL test1 got ${output}"
+	exit 1
+fi
+
+# test2: tests libgo2.so which does not export any functions.
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.so src/libgo2/libgo2.go
+binpush libgo2.so
+$(go env CC) $(go env GOGCCFLAGS) -o testp2 main2.c -Wl,--no-as-needed libgo2.so
+binpush testp2
+output=$(run LD_LIBRARY_PATH=. ./testp2)
+if [ "$output" != "PASS" ]; then
+	echo "FAIL test2 got ${output}"
+	exit 1
+fi
+
+# test3: tests main.main is exported on android.
+if [ "$goos" == "android" ]; then
+	$(go env CC) $(go env GOGCCFLAGS) -o testp3 main3.c -ldl
+	binpush testp3
+	output=$(run ./testp ./libgo.so)
+	if [ "$output" != "PASS" ]; then
+		echo "FAIL test3 got ${output}"
+		exit 1
+	fi
+fi
+echo "ok"
diff --git a/misc/cgo/testshared/src/dep/dep.go b/misc/cgo/testshared/src/dep/dep.go
new file mode 100644
index 0000000..fb112cd
--- /dev/null
+++ b/misc/cgo/testshared/src/dep/dep.go
@@ -0,0 +1,7 @@
+package dep
+
+var V int = 1
+
+func F() int {
+	return V
+}
diff --git a/misc/cgo/testshared/src/exe/exe.go b/misc/cgo/testshared/src/exe/exe.go
new file mode 100644
index 0000000..34fd144
--- /dev/null
+++ b/misc/cgo/testshared/src/exe/exe.go
@@ -0,0 +1,7 @@
+package main
+
+import "dep"
+
+func main() {
+	dep.V = dep.F() + 1
+}
diff --git a/misc/cgo/testshared/src/trivial/trivial.go b/misc/cgo/testshared/src/trivial/trivial.go
new file mode 100644
index 0000000..da29a2c
--- /dev/null
+++ b/misc/cgo/testshared/src/trivial/trivial.go
@@ -0,0 +1,4 @@
+package main
+
+func main() {
+}
diff --git a/misc/cgo/testshared/test.bash b/misc/cgo/testshared/test.bash
new file mode 100755
index 0000000..21004ad
--- /dev/null
+++ b/misc/cgo/testshared/test.bash
@@ -0,0 +1,110 @@
+#!/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/cgo/testsigfwd/main.go b/misc/cgo/testsigfwd/main.go
new file mode 100644
index 0000000..6641c9d
--- /dev/null
+++ b/misc/cgo/testsigfwd/main.go
@@ -0,0 +1,58 @@
+// 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"
+
+/*
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+static void sigsegv() {
+	*p = 1;
+	fprintf(stderr, "ERROR: C SIGSEGV not thrown on caught?.\n");
+	exit(2);
+}
+
+static void sighandler(int signum) {
+	if (signum == SIGSEGV) {
+		exit(0);  // success
+	}
+}
+
+static void __attribute__ ((constructor)) sigsetup(void) {
+	struct sigaction act;
+	act.sa_handler = &sighandler;
+	sigaction(SIGSEGV, &act, 0);
+}
+*/
+import "C"
+
+var p *byte
+
+func f() (ret bool) {
+	defer func() {
+		if recover() == nil {
+			fmt.Errorf("ERROR: couldn't raise SIGSEGV in Go.")
+			C.exit(2)
+		}
+		ret = true
+	}()
+	*p = 1
+	return false
+}
+
+func main() {
+	// Test that the signal originating in Go is handled (and recovered) by Go.
+	if !f() {
+		fmt.Errorf("couldn't recover from SIGSEGV in Go.")
+		C.exit(2)
+	}
+
+	// Test that the signal originating in C is handled by C.
+	C.sigsegv()
+}
diff --git a/misc/cgo/testso/cgoso.go b/misc/cgo/testso/cgoso.go
index ba62183..29814fa 100644
--- a/misc/cgo/testso/cgoso.go
+++ b/misc/cgo/testso/cgoso.go
@@ -11,6 +11,7 @@
 #cgo dragonfly LDFLAGS: -L. -l cgosotest
 #cgo freebsd LDFLAGS: -L. -l cgosotest
 #cgo openbsd LDFLAGS: -L. -l cgosotest
+#cgo solaris LDFLAGS: -L. -lcgosotest
 #cgo netbsd LDFLAGS: -L. libcgosotest.so
 #cgo darwin LDFLAGS: -L. libcgosotest.dylib
 #cgo windows LDFLAGS: -L. libcgosotest.dll
diff --git a/misc/cgo/testso/cgoso_unix.go b/misc/cgo/testso/cgoso_unix.go
index 7d5444c..49cdeaa 100644
--- a/misc/cgo/testso/cgoso_unix.go
+++ b/misc/cgo/testso/cgoso_unix.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.
 
-// +build dragonfly freebsd linux netbsd
+// +build dragonfly freebsd linux netbsd solaris
 
 package cgosotest
 
diff --git a/misc/ios/clangwrap.sh b/misc/ios/clangwrap.sh
index 228f483..9cad49f 100755
--- a/misc/ios/clangwrap.sh
+++ b/misc/ios/clangwrap.sh
@@ -7,4 +7,14 @@
 export IPHONEOS_DEPLOYMENT_TARGET=5.1
 # cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
 CLANG=`xcrun --sdk $SDK --find clang`
-exec $CLANG -arch armv7 -isysroot $SDK_PATH "$@"
+
+if [ "$GOARCH" == "arm" ]; then
+	CLANGARCH="armv7"
+elif [ "$GOARCH" == "arm64" ]; then
+	CLANGARCH="arm64"
+else
+	echo "unknown GOARCH=$GOARCH" >&2
+	exit 1
+fi
+
+exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH "$@"
diff --git a/misc/ios/detect.go b/misc/ios/detect.go
new file mode 100644
index 0000000..54493e0
--- /dev/null
+++ b/misc/ios/detect.go
@@ -0,0 +1,132 @@
+// 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 ignore
+
+// detect attempts to autodetect the correct
+// values of the environment variables
+// used by go_darwin_arm_exec.
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"strings"
+)
+
+func main() {
+	devID := detectDevID()
+	fmt.Printf("export GOIOS_DEV_ID=%s\n", devID)
+
+	udid := detectUDID()
+	mp := detectMobileProvisionFile(udid)
+
+	f, err := ioutil.TempFile("", "go_ios_detect_")
+	check(err)
+	fname := f.Name()
+	defer os.Remove(fname)
+
+	out := combinedOutput(parseMobileProvision(mp))
+	_, err = f.Write(out)
+	check(err)
+	check(f.Close())
+
+	appID, err := plistExtract(fname, "ApplicationIdentifierPrefix:0")
+	check(err)
+	fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
+
+	teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
+	check(err)
+	fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
+}
+
+func detectDevID() string {
+	cmd := exec.Command("security", "find-identity", "-p", "codesigning", "-v")
+	lines := getLines(cmd)
+
+	for _, line := range lines {
+		if !bytes.Contains(line, []byte("iPhone Developer")) {
+			continue
+		}
+		fields := bytes.Fields(line)
+		return string(fields[1])
+	}
+	fail("no code signing identity found")
+	panic("unreachable")
+}
+
+var udidPrefix = []byte("UniqueDeviceID: ")
+
+func detectUDID() []byte {
+	cmd := exec.Command("ideviceinfo")
+	lines := getLines(cmd)
+	for _, line := range lines {
+		if bytes.HasPrefix(line, udidPrefix) {
+			return bytes.TrimPrefix(line, udidPrefix)
+		}
+	}
+	fail("udid not found; is the device connected?")
+	panic("unreachable")
+}
+
+func detectMobileProvisionFile(udid []byte) string {
+	cmd := exec.Command("mdfind", "-name", ".mobileprovision")
+	lines := getLines(cmd)
+
+	for _, line := range lines {
+		if len(line) == 0 {
+			continue
+		}
+		xmlLines := getLines(parseMobileProvision(string(line)))
+		for _, xmlLine := range xmlLines {
+			if bytes.Contains(xmlLine, udid) {
+				return string(line)
+			}
+		}
+	}
+	fail("did not find mobile provision matching device udid %s", udid)
+	panic("ureachable")
+}
+
+func parseMobileProvision(fname string) *exec.Cmd {
+	return exec.Command("security", "cms", "-D", "-i", string(fname))
+}
+
+func plistExtract(fname string, path string) ([]byte, error) {
+	out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
+	if err != nil {
+		return nil, err
+	}
+	return bytes.TrimSpace(out), nil
+}
+
+func getLines(cmd *exec.Cmd) [][]byte {
+	out := combinedOutput(cmd)
+	return bytes.Split(out, []byte("\n"))
+}
+
+func combinedOutput(cmd *exec.Cmd) []byte {
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		fmt.Println(strings.Join(cmd.Args, "\n"))
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+	return out
+}
+
+func check(err error) {
+	if err != nil {
+		fail(err.Error())
+	}
+}
+
+func fail(msg string, v ...interface{}) {
+	fmt.Fprintf(os.Stderr, msg, v...)
+	fmt.Fprintln(os.Stderr)
+	os.Exit(1)
+}
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go
index 4495f52..402de3a 100644
--- a/misc/ios/go_darwin_arm_exec.go
+++ b/misc/ios/go_darwin_arm_exec.go
@@ -5,6 +5,18 @@
 // This program can be used as go_darwin_arm_exec by the Go tool.
 // It executes binaries on an iOS device using the XCode toolchain
 // and the ios-deploy program: https://github.com/phonegap/ios-deploy
+//
+// This script supports an extra flag, -lldb, that pauses execution
+// just before the main program begins and allows the user to control
+// the remote lldb session. This flag is appended to the end of the
+// script's arguments and is not passed through to the underlying
+// binary.
+//
+// This script requires that three environment variables be set:
+// 	GOIOS_DEV_ID: The codesigning developer id or certificate identifier
+// 	GOIOS_APP_ID: The provisioning app id prefix. Must support wildcard app ids.
+// 	GOIOS_TEAM_ID: The team id that owns the app id prefix.
+// $GOROOT/misc/ios contains a script, detect.go, that attempts to autodetect these.
 package main
 
 import (
@@ -13,6 +25,7 @@
 	"flag"
 	"fmt"
 	"go/build"
+	"io"
 	"io/ioutil"
 	"log"
 	"os"
@@ -30,6 +43,12 @@
 
 var tmpdir string
 
+var (
+	devID  string
+	appID  string
+	teamID string
+)
+
 func main() {
 	log.SetFlags(0)
 	log.SetPrefix("go_darwin_arm_exec: ")
@@ -40,6 +59,10 @@
 		log.Fatal("usage: go_darwin_arm_exec a.out")
 	}
 
+	devID = getenv("GOIOS_DEV_ID")
+	appID = getenv("GOIOS_APP_ID")
+	teamID = getenv("GOIOS_TEAM_ID")
+
 	var err error
 	tmpdir, err = ioutil.TempDir("", "go_darwin_arm_exec_")
 	if err != nil {
@@ -70,6 +93,14 @@
 	}
 }
 
+func getenv(envvar string) string {
+	s := os.Getenv(envvar)
+	if s == "" {
+		log.Fatalf("%s not set\nrun $GOROOT/misc/ios/detect.go to attempt to autodetect", s)
+	}
+	return s
+}
+
 func run(bin string, args []string) (err error) {
 	appdir := filepath.Join(tmpdir, "gotest.app")
 	os.RemoveAll(appdir)
@@ -82,7 +113,7 @@
 	}
 
 	entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
-	if err := ioutil.WriteFile(entitlementsPath, []byte(entitlementsPlist), 0744); err != nil {
+	if err := ioutil.WriteFile(entitlementsPath, []byte(entitlementsPlist()), 0744); err != nil {
 		return err
 	}
 	if err := ioutil.WriteFile(filepath.Join(appdir, "Info.plist"), []byte(infoPlist), 0744); err != nil {
@@ -100,7 +131,7 @@
 	cmd := exec.Command(
 		"codesign",
 		"-f",
-		"-s", "E8BMC3FE2Z", // certificate associated with golang.org
+		"-s", devID,
 		"--entitlements", entitlementsPath,
 		appdir,
 	)
@@ -139,6 +170,9 @@
 
 	exec.Command("killall", "ios-deploy").Run()
 
+	var opts options
+	opts, args = parseArgs(args)
+
 	// ios-deploy invokes lldb to give us a shell session with the app.
 	cmd = exec.Command(
 		// lldb tries to be clever with terminals.
@@ -165,8 +199,14 @@
 		return err
 	}
 	w := new(bufWriter)
-	cmd.Stdout = w
-	cmd.Stderr = w // everything of interest is on stderr
+	if opts.lldb {
+		mw := io.MultiWriter(w, os.Stderr)
+		cmd.Stdout = mw
+		cmd.Stderr = mw
+	} else {
+		cmd.Stdout = w
+		cmd.Stderr = w // everything of interest is on stderr
+	}
 	cmd.Stdin = lldbr
 
 	if err := cmd.Start(); err != nil {
@@ -177,9 +217,9 @@
 	// of moving parts in an iOS test harness (notably lldb) that can
 	// swallow useful stdio or cause its own ruckus.
 	var timedout chan struct{}
-	if t := parseTimeout(args); t > 1*time.Second {
+	if opts.timeout > 1*time.Second {
 		timedout = make(chan struct{})
-		time.AfterFunc(t-1*time.Second, func() {
+		time.AfterFunc(opts.timeout-1*time.Second, func() {
 			close(timedout)
 		})
 	}
@@ -217,7 +257,7 @@
 	}
 
 	// Wait for installation and connection.
-	if err := waitFor("ios-deploy before run", "(lldb)     connect\r\nProcess 0 connected\r\n", 0); err != nil {
+	if err := waitFor("ios-deploy before run", "(lldb)", 0); err != nil {
 		// Retry if we see a rare and longstanding ios-deploy bug.
 		// https://github.com/phonegap/ios-deploy/issues/11
 		//	Assertion failed: (AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL) == 0)
@@ -232,6 +272,14 @@
 	do(`process handle SIGSEGV --stop false --pass true --notify false`) // does not work
 	do(`process handle SIGBUS  --stop false --pass true --notify false`) // does not work
 
+	if opts.lldb {
+		_, err := io.Copy(lldb, os.Stdin)
+		if err != io.EOF {
+			return err
+		}
+		return nil
+	}
+
 	do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
 
 	fmt.Fprintln(lldb, `run`)
@@ -257,25 +305,13 @@
 	}
 
 	// Move the current working directory into the faux gopath.
-	do(`breakpoint delete 1`)
-	do(`expr char* $mem = (char*)malloc(512)`)
-	do(`expr $mem = (char*)getwd($mem, 512)`)
-	do(`expr $mem = (char*)strcat($mem, "/` + pkgpath + `")`)
-	do(`call (void)chdir($mem)`)
-
-	// Watch for SIGSEGV. Ideally lldb would never break on SIGSEGV.
-	// http://golang.org/issue/10043
-	go func() {
-		<-w.find("stop reason = EXC_BAD_ACCESS", 0)
-		// cannot use do here, as the defer/recover is not available
-		// on this goroutine.
-		fmt.Fprintln(lldb, `bt`)
-		waitFor("finish backtrace", "(lldb)", 0)
-		w.printBuf()
-		if p := cmd.Process; p != nil {
-			p.Kill()
-		}
-	}()
+	if pkgpath != "src" {
+		do(`breakpoint delete 1`)
+		do(`expr char* $mem = (char*)malloc(512)`)
+		do(`expr $mem = (char*)getwd($mem, 512)`)
+		do(`expr $mem = (char*)strcat($mem, "/` + pkgpath + `")`)
+		do(`call (void)chdir($mem)`)
+	}
 
 	// Run the tests.
 	w.trimSuffix("(lldb) ")
@@ -289,6 +325,13 @@
 			p.Kill()
 		}
 		return errors.New("timeout running tests")
+	case <-w.find("\nPASS", 0):
+		passed := w.isPass()
+		w.printBuf()
+		if passed {
+			return nil
+		}
+		return errors.New("test failure")
 	case err := <-exited:
 		// The returned lldb error code is usually non-zero.
 		// We check for test success by scanning for the final
@@ -321,6 +364,12 @@
 	n = len(in)
 	in = bytes.TrimSuffix(in, w.suffix)
 
+	if debug {
+		inTxt := strings.Replace(string(in), "\n", "\\n", -1)
+		findTxt := strings.Replace(string(w.findTxt), "\n", "\\n", -1)
+		fmt.Printf("debug --> %s <-- debug (findTxt='%s')\n", inTxt, findTxt)
+	}
+
 	w.buf = append(w.buf, in...)
 
 	if len(w.findTxt) > 0 {
@@ -354,9 +403,6 @@
 func (w *bufWriter) clearTo(i int) {
 	w.mu.Lock()
 	defer w.mu.Unlock()
-	if debug {
-		fmt.Fprintf(os.Stderr, "--- go_darwin_arm_exec clear ---\n%s\n--- go_darwin_arm_exec clear ---\n", w.buf[:i])
-	}
 	w.buf = w.buf[i:]
 }
 
@@ -408,20 +454,29 @@
 	return bytes.Contains(w.buf, []byte("\nPASS\n")) || bytes.Contains(w.buf, []byte("\nPASS\r"))
 }
 
-func parseTimeout(testArgs []string) (timeout time.Duration) {
-	var args []string
-	for _, arg := range testArgs {
-		if strings.Contains(arg, "test.timeout") {
-			args = append(args, arg)
+type options struct {
+	timeout time.Duration
+	lldb    bool
+}
+
+func parseArgs(binArgs []string) (opts options, remainingArgs []string) {
+	var flagArgs []string
+	for _, arg := range binArgs {
+		if strings.Contains(arg, "-test.timeout") {
+			flagArgs = append(flagArgs, arg)
 		}
+		if strings.Contains(arg, "-lldb") {
+			flagArgs = append(flagArgs, arg)
+			continue
+		}
+		remainingArgs = append(remainingArgs, arg)
 	}
 	f := flag.NewFlagSet("", flag.ContinueOnError)
-	f.DurationVar(&timeout, "test.timeout", 0, "")
-	f.Parse(args)
-	if debug {
-		log.Printf("parseTimeout of %s, got %s", args, timeout)
-	}
-	return timeout
+	f.DurationVar(&opts.timeout, "test.timeout", 0, "")
+	f.BoolVar(&opts.lldb, "lldb", false, "")
+	f.Parse(flagArgs)
+	return opts, remainingArgs
+
 }
 
 func copyLocalDir(dst, src string) error {
@@ -557,39 +612,45 @@
 </plist>
 `
 
-const devID = `YE84DJ86AZ`
-
-const entitlementsPlist = `<?xml version="1.0" encoding="UTF-8"?>
+func entitlementsPlist() string {
+	return `<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 	<key>keychain-access-groups</key>
-	<array><string>` + devID + `.golang.gotest</string></array>
+	<array><string>` + appID + `.golang.gotest</string></array>
 	<key>get-task-allow</key>
 	<true/>
 	<key>application-identifier</key>
-	<string>` + devID + `.golang.gotest</string>
+	<string>` + appID + `.golang.gotest</string>
 	<key>com.apple.developer.team-identifier</key>
-	<string>` + devID + `</string>
+	<string>` + teamID + `</string>
 </dict>
-</plist>`
+</plist>
+`
+}
 
 const resourceRules = `<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-        <key>rules</key>
-        <dict>
-                <key>.*</key><true/>
-		<key>Info.plist</key> 
+	<key>rules</key>
+	<dict>
+		<key>.*</key>
+		<true/>
+		<key>Info.plist</key>
 		<dict>
-			<key>omit</key> <true/>
-			<key>weight</key> <real>10</real>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<integer>10</integer>
 		</dict>
 		<key>ResourceRules.plist</key>
 		<dict>
-			<key>omit</key> <true/>
-			<key>weight</key> <real>100</real>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<integer>100</integer>
 		</dict>
 	</dict>
 </dict>
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index b2e866c..1c013c1 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -10,6 +10,9 @@
 go	src=..
 	src
 		cmd
+			api
+				testdata
+					+
 			asm
 				internal
 					asm
diff --git a/src/androidtest.bash b/src/androidtest.bash
index ee97e30..aad1f7e 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -44,9 +44,11 @@
 export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$
 FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot
 mkdir -p $FAKE_GOROOT
+mkdir -p $FAKE_GOROOT/pkg
 cp -a "${GOROOT}/src" "${FAKE_GOROOT}/"
 cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
 cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
+cp -a "${GOROOT}/pkg/android_$GOARCH" "${FAKE_GOROOT}/pkg/"
 echo '# Syncing test files to android device'
 time adb sync data &> /dev/null
 echo ''
diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go
index dafb2ca..9dbc01a 100644
--- a/src/archive/tar/writer.go
+++ b/src/archive/tar/writer.go
@@ -355,7 +355,7 @@
 // hdr.Size bytes are written after WriteHeader.
 func (tw *Writer) Write(b []byte) (n int, err error) {
 	if tw.closed {
-		err = ErrWriteTooLong
+		err = ErrWriteAfterClose
 		return
 	}
 	overwrite := false
diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go
index 5e42e32..650899a 100644
--- a/src/archive/tar/writer_test.go
+++ b/src/archive/tar/writer_test.go
@@ -489,3 +489,20 @@
 		}
 	}
 }
+
+func TestWriteAfterClose(t *testing.T) {
+	var buffer bytes.Buffer
+	tw := NewWriter(&buffer)
+
+	hdr := &Header{
+		Name: "small.txt",
+		Size: 5,
+	}
+	if err := tw.WriteHeader(hdr); err != nil {
+		t.Fatalf("Failed to write header: %s", err)
+	}
+	tw.Close()
+	if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
+		t.Fatalf("Write: got %v; want ErrWriteAfterClose", err)
+	}
+}
diff --git a/src/buildall.bash b/src/buildall.bash
new file mode 100755
index 0000000..a07529e
--- /dev/null
+++ b/src/buildall.bash
@@ -0,0 +1,70 @@
+#!/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.
+
+# Usage: buildall.sh [-e] [pattern]
+#
+# buildall.bash builds the standard library for all Go-supported
+# architectures. It is used by the "all-compile" trybot builder,
+# as a smoke test to quickly flag portability issues.
+#
+# Options:
+#   -e: stop at first failure
+
+if [ ! -f run.bash ]; then
+	echo 'buildall.bash must be run from $GOROOT/src' 1>&2
+	exit 1
+fi
+
+sete=false
+if [ "$1" = "-e" ]; then
+    sete=true
+    shift
+fi
+
+if [ "$sete" = true ]; then
+    set -e
+fi
+
+pattern="$1"
+if [ "$pattern" = "" ]; then
+    pattern=.
+fi
+
+# put linux, nacl first in the target list to get all the architectures up front.
+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
+GOROOT="$(cd .. && pwd)"
+
+failed=false
+for target in $targets
+do
+    echo ""
+    echo "### Building $target"
+    export GOOS=$(echo $target | sed 's/-.*//')
+    export GOARCH=$(echo $target | sed 's/.*-//')
+    unset GO386 GOARM
+    if [ "$GOARCH" = "arm5" ]; then
+        export GOARCH=arm
+        export GOARM=5
+    fi
+    if [ "$GOARCH" = "387" ]; then
+        export GOARCH=386
+        export GO386=387
+    fi
+    if ! "$GOROOT/bin/go" build -a std cmd; then
+        failed=true
+        if $sete; then
+            exit 1
+        fi
+    fi
+done
+
+if [ "$failed" = "true" ]; then
+    echo "" 1>&2
+    echo "Build(s) failed." 1>&2
+    exit 1
+fi
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index 46ca1d5..4db9386 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -56,6 +56,10 @@
 // b.Len() == len(b.Bytes()).
 func (b *Buffer) Len() int { return len(b.buf) - b.off }
 
+// Cap returns the capacity of the buffer's underlying byte slice, that is, the
+// total space allocated for the buffer's data.
+func (b *Buffer) Cap() int { return cap(b.buf) }
+
 // Truncate discards all but the first n unread bytes from the buffer.
 // It panics if n is negative or greater than the length of the buffer.
 func (b *Buffer) Truncate(n int) {
diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go
index 75145b0..7de17ae 100644
--- a/src/bytes/buffer_test.go
+++ b/src/bytes/buffer_test.go
@@ -231,6 +231,23 @@
 	empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
 }
 
+func TestCapWithPreallocatedSlice(t *testing.T) {
+	buf := NewBuffer(make([]byte, 10))
+	n := buf.Cap()
+	if n != 10 {
+		t.Errorf("expected 10, got %d", n)
+	}
+}
+
+func TestCapWithSliceAndWrittenData(t *testing.T) {
+	buf := NewBuffer(make([]byte, 0, 10))
+	buf.Write([]byte("test"))
+	n := buf.Cap()
+	if n != 10 {
+		t.Errorf("expected 10, got %d", n)
+	}
+}
+
 func TestNil(t *testing.T) {
 	var b *Buffer
 	if b.String() != "<nil>" {
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index 60de451..b868240 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -138,6 +138,16 @@
 	return -1
 }
 
+// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
+func LastIndexByte(s []byte, c byte) int {
+	for i := len(s) - 1; i >= 0; i-- {
+		if s[i] == c {
+			return i
+		}
+	}
+	return -1
+}
+
 // IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
 // It returns the byte index of the first occurrence in s of the given rune.
 // It returns -1 if rune is not present in s.
diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go
index 980c41d..6245e48 100644
--- a/src/bytes/bytes_test.go
+++ b/src/bytes/bytes_test.go
@@ -265,6 +265,23 @@
 	}
 }
 
+func TestLastIndexByte(t *testing.T) {
+	testCases := []BinOpTest{
+		{"", "q", -1},
+		{"abcdef", "q", -1},
+		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle
+		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte
+		{"zabcdefabcdef", "z", 0},                 // first byte
+		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii
+	}
+	for _, test := range testCases {
+		actual := LastIndexByte([]byte(test.a), test.b[0])
+		if actual != test.i {
+			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i)
+		}
+	}
+}
+
 // test a larger buffer with different sizes and alignments
 func TestIndexByteBig(t *testing.T) {
 	var n = 1024
diff --git a/src/bytes/export_test.go b/src/bytes/export_test.go
index 3b915d5..f61523e 100644
--- a/src/bytes/export_test.go
+++ b/src/bytes/export_test.go
@@ -7,7 +7,3 @@
 // Export func for testing
 var IndexBytePortable = indexBytePortable
 var EqualPortable = equalPortable
-
-func (b *Buffer) Cap() int {
-	return cap(b.buf)
-}
diff --git a/src/bytes/reader.go b/src/bytes/reader.go
index d2d40fa..b89d154 100644
--- a/src/bytes/reader.go
+++ b/src/bytes/reader.go
@@ -29,6 +29,12 @@
 	return int(int64(len(r.s)) - r.i)
 }
 
+// Size returns the original length of the underlying byte slice.
+// Size is the number of bytes available for reading via ReadAt.
+// The returned value is always the same and is not affected by calls
+// to any other method.
+func (r *Reader) Size() int64 { return int64(len(r.s)) }
+
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go
index d3dce53..b929a28 100644
--- a/src/bytes/reader_test.go
+++ b/src/bytes/reader_test.go
@@ -244,3 +244,15 @@
 		t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut)
 	}
 }
+
+// tests that Len is affected by reads, but Size is not.
+func TestReaderLenSize(t *testing.T) {
+	r := NewReader([]byte("abc"))
+	io.CopyN(ioutil.Discard, r, 1)
+	if r.Len() != 2 {
+		t.Errorf("Len = %d; want 2", r.Len())
+	}
+	if r.Size() != 3 {
+		t.Errorf("Size = %d; want 3", r.Size())
+	}
+}
diff --git a/src/cmd/5g/cgen.go b/src/cmd/5g/cgen.go
index 07ced87..2e92239 100644
--- a/src/cmd/5g/cgen.go
+++ b/src/cmd/5g/cgen.go
@@ -75,7 +75,7 @@
 	gc.Regfree(&n1)
 }
 
-func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
 	// smaller operations for less aligned types.
@@ -85,7 +85,7 @@
 	var op int
 	switch align {
 	default:
-		gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0))
+		gc.Fatal("sgen: invalid alignment %d for %v", align, n.Type)
 
 	case 1:
 		op = arm.AMOVB
@@ -98,7 +98,7 @@
 	}
 
 	if w%int64(align) != 0 {
-		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0))
+		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
 	}
 	c := int32(w / int64(align))
 
@@ -116,13 +116,13 @@
 	if op == arm.AMOVW && !gc.Nacl && dir > 0 && c >= 4 && c <= 128 {
 		var r0 gc.Node
 		r0.Op = gc.OREGISTER
-		r0.Val.U.Reg = arm.REG_R0
+		r0.Reg = arm.REG_R0
 		var r1 gc.Node
 		r1.Op = gc.OREGISTER
-		r1.Val.U.Reg = arm.REG_R0 + 1
+		r1.Reg = arm.REG_R0 + 1
 		var r2 gc.Node
 		r2.Op = gc.OREGISTER
-		r2.Val.U.Reg = arm.REG_R0 + 2
+		r2.Reg = arm.REG_R0 + 2
 
 		var src gc.Node
 		gc.Regalloc(&src, gc.Types[gc.Tptr], &r1)
diff --git a/src/cmd/5g/cgen64.go b/src/cmd/5g/cgen64.go
index 05f2e1e..699e555 100644
--- a/src/cmd/5g/cgen64.go
+++ b/src/cmd/5g/cgen64.go
@@ -24,7 +24,7 @@
 
 	l := n.Left
 	var t1 gc.Node
-	if l.Addable == 0 {
+	if !l.Addable {
 		gc.Tempname(&t1, l.Type)
 		gc.Cgen(l, &t1)
 		l = &t1
@@ -108,7 +108,7 @@
 	// setup for binary operators
 	r := n.Right
 
-	if r != nil && r.Addable == 0 {
+	if r != nil && !r.Addable {
 		var t2 gc.Node
 		gc.Tempname(&t2, r.Type)
 		gc.Cgen(r, &t2)
@@ -129,7 +129,7 @@
 	// Do op.  Leave result in ah:al.
 	switch n.Op {
 	default:
-		gc.Fatal("cgen64: not implemented: %v\n", gc.Nconv(n, 0))
+		gc.Fatal("cgen64: not implemented: %v\n", n)
 
 		// TODO: Constants
 	case gc.OADD:
@@ -188,11 +188,11 @@
 		p1 := gins(arm.AMULLU, nil, nil)
 
 		p1.From.Type = obj.TYPE_REG
-		p1.From.Reg = bl.Val.U.Reg
-		p1.Reg = cl.Val.U.Reg
+		p1.From.Reg = bl.Reg
+		p1.Reg = cl.Reg
 		p1.To.Type = obj.TYPE_REGREG
-		p1.To.Reg = ah.Val.U.Reg
-		p1.To.Offset = int64(al.Val.U.Reg)
+		p1.To.Reg = ah.Reg
+		p1.To.Offset = int64(al.Reg)
 
 		//print("%P\n", p1);
 
@@ -200,11 +200,11 @@
 		p1 = gins(arm.AMULA, nil, nil)
 
 		p1.From.Type = obj.TYPE_REG
-		p1.From.Reg = bl.Val.U.Reg
-		p1.Reg = ch.Val.U.Reg
+		p1.From.Reg = bl.Reg
+		p1.Reg = ch.Reg
 		p1.To.Type = obj.TYPE_REGREG2
-		p1.To.Reg = ah.Val.U.Reg
-		p1.To.Offset = int64(ah.Val.U.Reg)
+		p1.To.Reg = ah.Reg
+		p1.To.Offset = int64(ah.Reg)
 
 		//print("%P\n", p1);
 
@@ -212,11 +212,11 @@
 		p1 = gins(arm.AMULA, nil, nil)
 
 		p1.From.Type = obj.TYPE_REG
-		p1.From.Reg = bh.Val.U.Reg
-		p1.Reg = cl.Val.U.Reg
+		p1.From.Reg = bh.Reg
+		p1.Reg = cl.Reg
 		p1.To.Type = obj.TYPE_REGREG2
-		p1.To.Reg = ah.Val.U.Reg
-		p1.To.Offset = int64(ah.Val.U.Reg)
+		p1.To.Reg = ah.Reg
+		p1.To.Offset = int64(ah.Reg)
 
 		//print("%P\n", p1);
 
@@ -793,7 +793,7 @@
 	var br *obj.Prog
 	switch op {
 	default:
-		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t)
 
 		// cmp hi
 	// bne L
diff --git a/src/cmd/5g/galign.go b/src/cmd/5g/galign.go
index 1b349e1..3c8ba519 100644
--- a/src/cmd/5g/galign.go
+++ b/src/cmd/5g/galign.go
@@ -23,7 +23,7 @@
 
 /*
  * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
+ * int, uint, and uintptr
  */
 var typedefs = []gc.Typedef{
 	gc.Typedef{"int", gc.TINT, gc.TINT32},
@@ -35,7 +35,6 @@
 	gc.Widthptr = 4
 	gc.Widthint = 4
 	gc.Widthreg = 4
-
 }
 
 func main() {
@@ -64,6 +63,7 @@
 	gc.Thearch.Defframe = defframe
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
+	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
@@ -76,7 +76,7 @@
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
-	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Blockcopy = blockcopy
 	gc.Thearch.Sudoaddable = sudoaddable
 	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go
index 753c6e0..0cf0d92 100644
--- a/src/cmd/5g/ggen.go
+++ b/src/cmd/5g/ggen.go
@@ -155,14 +155,14 @@
 		}
 
 		// n2 * n1 -> (n1 n2)
-		p.Reg = n1.Val.U.Reg
+		p.Reg = n1.Reg
 
 		p.To.Type = obj.TYPE_REGREG
-		p.To.Reg = n1.Val.U.Reg
-		p.To.Offset = int64(n2.Val.U.Reg)
+		p.To.Reg = n1.Reg
+		p.To.Offset = int64(n2.Reg)
 
 	default:
-		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
+		gc.Fatal("cgen_hmul %v", t)
 	}
 
 	gc.Cgen(&n1, res)
@@ -177,7 +177,7 @@
  */
 func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	if nl.Type.Width > 4 {
-		gc.Fatal("cgen_shift %v", gc.Tconv(nl.Type, 0))
+		gc.Fatal("cgen_shift %v", nl.Type)
 	}
 
 	w := int(nl.Type.Width * 8)
@@ -349,10 +349,10 @@
 	var r0 gc.Node
 	r0.Op = gc.OREGISTER
 
-	r0.Val.U.Reg = arm.REG_R0
+	r0.Reg = arm.REG_R0
 	var r1 gc.Node
 	r1.Op = gc.OREGISTER
-	r1.Val.U.Reg = arm.REG_R1
+	r1.Reg = arm.REG_R1
 	var dst gc.Node
 	gc.Regalloc(&dst, gc.Types[gc.Tptr], &r1)
 	gc.Agen(nl, &dst)
@@ -494,3 +494,10 @@
 	}
 	return false
 }
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, arm.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go
index 0d22f74..57d511e 100644
--- a/src/cmd/5g/gsubr.go
+++ b/src/cmd/5g/gsubr.go
@@ -37,11 +37,6 @@
 	"fmt"
 )
 
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 5l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-var unmappedzero int = 4096
-
 var resvd = []int{
 	arm.REG_R9,  // formerly reserved for m; might be okay to reuse now; not sure about NaCl
 	arm.REG_R10, // reserved for g
@@ -71,7 +66,7 @@
  */
 func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 	if !gc.Is64(n.Type) {
-		gc.Fatal("split64 %v", gc.Tconv(n.Type, 0))
+		gc.Fatal("split64 %v", n.Type)
 	}
 
 	if nsclean >= len(sclean) {
@@ -140,7 +135,7 @@
 
 func gmove(f *gc.Node, t *gc.Node) {
 	if gc.Debug['M'] != 0 {
-		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		fmt.Printf("gmove %v -> %v\n", f, t)
 	}
 
 	ft := gc.Simsimtype(f.Type)
@@ -209,7 +204,7 @@
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
 		// should not happen
-		gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		gc.Fatal("gmove %v -> %v", f, t)
 		return
 
 		/*
@@ -404,7 +399,7 @@
 		gmove(f, &r1)
 		p1 := gins(arm.AMOVW, &r1, &r2)
 		p1.From.Type = obj.TYPE_SHIFT
-		p1.From.Offset = 2<<5 | 31<<7 | int64(r1.Val.U.Reg)&15 // r1->31
+		p1.From.Offset = 2<<5 | 31<<7 | int64(r1.Reg)&15 // r1->31
 		p1.From.Reg = 0
 
 		//print("gmove: %P\n", p1);
@@ -628,7 +623,7 @@
 
 	switch f.Op {
 	case gc.OREGISTER:
-		if f.Val.U.Reg != t.Val.U.Reg {
+		if f.Reg != t.Reg {
 			break
 		}
 		return true
@@ -746,7 +741,7 @@
 
 	p := gins(as, nil, rhs)
 	p.From.Type = obj.TYPE_SHIFT
-	p.From.Offset = int64(stype) | int64(sval)<<7 | int64(lhs.Val.U.Reg)&15
+	p.From.Offset = int64(stype) | int64(sval)<<7 | int64(lhs.Reg)&15
 	return p
 }
 
@@ -755,7 +750,7 @@
 func gregshift(as int, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *obj.Prog {
 	p := gins(as, nil, rhs)
 	p.From.Type = obj.TYPE_SHIFT
-	p.From.Offset = int64(stype) | (int64(reg.Val.U.Reg)&15)<<8 | 1<<4 | int64(lhs.Val.U.Reg)&15
+	p.From.Offset = int64(stype) | (int64(reg.Reg)&15)<<8 | 1<<4 | int64(lhs.Reg)&15
 	return p
 }
 
@@ -770,7 +765,7 @@
 	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatal("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0), gc.Tconv(gc.Types[t.Etype], 0), gc.Tconv(gc.Types[gc.Simtype[t.Etype]], 0))
+		gc.Fatal("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]])
 
 		/*	case CASE(OADDR, TPTR32):
 				a = ALEAL;
@@ -1055,6 +1050,9 @@
 
 	case gc.ODIV<<16 | gc.TFLOAT64:
 		a = arm.ADIVD
+
+	case gc.OSQRT<<16 | gc.TFLOAT64:
+		a = arm.ASQRTD
 	}
 
 	return a
@@ -1087,7 +1085,7 @@
 	var oary [10]int64
 	var nn *gc.Node
 	o := gc.Dotoffset(n, oary[:], &nn)
-	if nn != nil && nn.Addable != 0 && o == 1 && oary[0] >= 0 {
+	if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
 		*n1 = *nn
 		n1.Type = n.Type
 		n1.Xoffset += oary[0]
@@ -1166,7 +1164,7 @@
 			return false
 		}
 
-		if nn.Addable != 0 && o == 1 && oary[0] >= 0 {
+		if nn.Addable && o == 1 && oary[0] >= 0 {
 			// directly addressable set of DOTs
 			n1 := *nn
 
diff --git a/src/cmd/5g/peep.go b/src/cmd/5g/peep.go
index 5305e4b..b76719d 100644
--- a/src/cmd/5g/peep.go
+++ b/src/cmd/5g/peep.go
@@ -1101,6 +1101,7 @@
 		return 0
 
 	case obj.ANOP, /* read,, write */
+		arm.ASQRTD,
 		arm.AMOVW,
 		arm.AMOVF,
 		arm.AMOVD,
@@ -1507,102 +1508,22 @@
 	scond     int
 	notscond  int
 }{
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABEQ, arm.ABNE, 0x0, 0x1},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABNE, arm.ABEQ, 0x1, 0x0},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABCS, arm.ABCC, 0x2, 0x3},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABHS, arm.ABLO, 0x2, 0x3},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABCC, arm.ABCS, 0x3, 0x2},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABLO, arm.ABHS, 0x3, 0x2},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABMI, arm.ABPL, 0x4, 0x5},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABPL, arm.ABMI, 0x5, 0x4},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABVS, arm.ABVC, 0x6, 0x7},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABVC, arm.ABVS, 0x7, 0x6},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABHI, arm.ABLS, 0x8, 0x9},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABLS, arm.ABHI, 0x9, 0x8},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABGE, arm.ABLT, 0xA, 0xB},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABLT, arm.ABGE, 0xB, 0xA},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABGT, arm.ABLE, 0xC, 0xD},
-	struct {
-		opcode    int
-		notopcode int
-		scond     int
-		notscond  int
-	}{arm.ABLE, arm.ABGT, 0xD, 0xC},
+	{arm.ABEQ, arm.ABNE, 0x0, 0x1},
+	{arm.ABNE, arm.ABEQ, 0x1, 0x0},
+	{arm.ABCS, arm.ABCC, 0x2, 0x3},
+	{arm.ABHS, arm.ABLO, 0x2, 0x3},
+	{arm.ABCC, arm.ABCS, 0x3, 0x2},
+	{arm.ABLO, arm.ABHS, 0x3, 0x2},
+	{arm.ABMI, arm.ABPL, 0x4, 0x5},
+	{arm.ABPL, arm.ABMI, 0x5, 0x4},
+	{arm.ABVS, arm.ABVC, 0x6, 0x7},
+	{arm.ABVC, arm.ABVS, 0x7, 0x6},
+	{arm.ABHI, arm.ABLS, 0x8, 0x9},
+	{arm.ABLS, arm.ABHI, 0x9, 0x8},
+	{arm.ABGE, arm.ABLT, 0xA, 0xB},
+	{arm.ABLT, arm.ABGE, 0xB, 0xA},
+	{arm.ABGT, arm.ABLE, 0xC, 0xD},
+	{arm.ABLE, arm.ABGT, 0xD, 0xC},
 }
 
 type Joininfo struct {
diff --git a/src/cmd/5g/prog.go b/src/cmd/5g/prog.go
index bfb703e..c472cdf 100644
--- a/src/cmd/5g/prog.go
+++ b/src/cmd/5g/prog.go
@@ -70,16 +70,17 @@
 	arm.ATST:    {gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
 
 	// Floating point.
-	arm.AADDD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.AADDF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ACMPD: {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ACMPF: {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ADIVD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ADIVF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.AMULD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.AMULF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ASUBD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ASUBF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AADDD:  {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AADDF:  {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ACMPD:  {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ACMPF:  {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ADIVD:  {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ADIVF:  {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AMULD:  {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AMULF:  {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ASUBD:  {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ASUBF:  {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ASQRTD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
 
 	// Conversions.
 	arm.AMOVWD: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
diff --git a/src/cmd/5g/util.go b/src/cmd/5g/util.go
deleted file mode 100644
index bb5eedb..0000000
--- a/src/cmd/5g/util.go
+++ /dev/null
@@ -1,12 +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 main
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/5l/asm.go b/src/cmd/5l/asm.go
index 525764e..85ea684 100644
--- a/src/cmd/5l/asm.go
+++ b/src/cmd/5l/asm.go
@@ -82,9 +82,9 @@
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_ARM_PLT32:
-		r.Type = ld.R_CALLARM
+		r.Type = obj.R_CALLARM
 
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(ld.Ctxt, targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
@@ -93,50 +93,48 @@
 		return
 
 	case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
-		ld.Diag("R_ARM_THM_CALL, are you using -marm?")
-
-		ld.Errorexit()
+		ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
 		return
 
 	case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			addgotsyminternal(ld.Ctxt, targ)
 		} else {
 			addgotsym(ld.Ctxt, targ)
 		}
 
-		r.Type = ld.R_CONST // write r->add during relocsym
+		r.Type = obj.R_CONST // write r->add during relocsym
 		r.Sym = nil
 		r.Add += int64(targ.Got)
 		return
 
 	case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			addgotsyminternal(ld.Ctxt, targ)
 		} else {
 			addgotsym(ld.Ctxt, targ)
 		}
 
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
 		r.Add += int64(targ.Got) + 4
 		return
 
 	case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
-		r.Type = ld.R_GOTOFF
+		r.Type = obj.R_GOTOFF
 
 		return
 
 	case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 
 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
 		r.Add += 4
 		return
 
 	case 256 + ld.R_ARM_CALL:
-		r.Type = ld.R_CALLARM
-		if targ.Type == ld.SDYNIMPORT {
+		r.Type = obj.R_CALLARM
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(ld.Ctxt, targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
@@ -145,16 +143,16 @@
 		return
 
 	case 256 + ld.R_ARM_REL32: // R_ARM_REL32
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 
 		r.Add += 4
 		return
 
 	case 256 + ld.R_ARM_ABS32:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = ld.R_ADDR
+		r.Type = obj.R_ADDR
 		return
 
 		// we can just ignore this, because we are targeting ARM V5+ anyway
@@ -169,8 +167,8 @@
 
 	case 256 + ld.R_ARM_PC24,
 		256 + ld.R_ARM_JUMP24:
-		r.Type = ld.R_CALLARM
-		if targ.Type == ld.SDYNIMPORT {
+		r.Type = obj.R_CALLARM
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(ld.Ctxt, targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
@@ -180,19 +178,19 @@
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != ld.SDYNIMPORT {
+	if targ.Type != obj.SDYNIMPORT {
 		return
 	}
 
 	switch r.Type {
-	case ld.R_CALLARM:
+	case obj.R_CALLARM:
 		addpltsym(ld.Ctxt, targ)
 		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 		r.Add = int64(targ.Plt)
 		return
 
-	case ld.R_ADDR:
-		if s.Type != ld.SDATA {
+	case obj.R_ADDR:
+		if s.Type != obj.SDATA {
 			break
 		}
 		if ld.Iself {
@@ -200,7 +198,7 @@
 			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
-			r.Type = ld.R_CONST                                                                // write r->add during relocsym
+			r.Type = obj.R_CONST                                                               // write r->add during relocsym
 			r.Sym = nil
 			return
 		}
@@ -218,21 +216,21 @@
 	default:
 		return -1
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case ld.R_PCREL:
+	case obj.R_PCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case ld.R_CALLARM:
+	case obj.R_CALLARM:
 		if r.Siz == 4 {
 			if r.Add&0xff000000 == 0xeb000000 { // BL
 				ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
@@ -243,9 +241,9 @@
 			return -1
 		}
 
-	case ld.R_TLS:
+	case obj.R_TLS:
 		if r.Siz == 4 {
-			if ld.Flag_shared != 0 {
+			if ld.Buildmode == ld.BuildmodeCShared {
 				ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
 			} else {
 				ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
@@ -290,7 +288,7 @@
 
 	rs := r.Xsym
 
-	if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_CALLARM {
+	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM {
 		if rs.Dynid < 0 {
 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -310,10 +308,10 @@
 	default:
 		return -1
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
 
-	case ld.R_CALLARM:
+	case obj.R_CALLARM:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_ARM_RELOC_BR24 << 28
 	}
@@ -343,7 +341,7 @@
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 	if ld.Linkmode == ld.LinkExternal {
 		switch r.Type {
-		case ld.R_CALLARM:
+		case obj.R_CALLARM:
 			r.Done = 0
 
 			// set up addend for eventual relocation via outer symbol.
@@ -359,7 +357,7 @@
 				rs = rs.Outer
 			}
 
-			if rs.Type != ld.SHOSTOBJ && rs.Sect == nil {
+			if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
 				ld.Diag("missing section for %s", rs.Name)
 			}
 			r.Xsym = rs
@@ -369,7 +367,7 @@
 			// the section load address.
 			// we need to compensate that by removing the instruction's address
 			// from addend.
-			if ld.HEADTYPE == ld.Hdarwin {
+			if ld.HEADTYPE == obj.Hdarwin {
 				r.Xadd -= ld.Symaddr(s) + int64(r.Off)
 			}
 
@@ -381,34 +379,34 @@
 	}
 
 	switch r.Type {
-	case ld.R_CONST:
+	case obj.R_CONST:
 		*val = r.Add
 		return 0
 
-	case ld.R_GOTOFF:
+	case obj.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
 		return 0
 
 		// The following three arch specific relocations are only for generation of
 	// Linux/ARM ELF's PLT entry (3 assembler instruction)
-	case ld.R_PLT0: // add ip, pc, #0xXX00000
+	case obj.R_PLT0: // add ip, pc, #0xXX00000
 		if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
 			ld.Diag(".got.plt should be placed after .plt section.")
 		}
 		*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
 		return 0
 
-	case ld.R_PLT1: // add ip, ip, #0xYY000
+	case obj.R_PLT1: // add ip, ip, #0xYY000
 		*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
 
 		return 0
 
-	case ld.R_PLT2: // ldr pc, [ip, #0xZZZ]!
+	case obj.R_PLT2: // ldr pc, [ip, #0xZZZ]!
 		*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
 
 		return 0
 
-	case ld.R_CALLARM: // bl XXXXXX or b YYYYYY
+	case obj.R_CALLARM: // bl XXXXXX or b YYYYYY
 		*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4))))
 
 		return 0
@@ -463,9 +461,9 @@
 		// .plt entry, this depends on the .got entry
 		s.Plt = int32(plt.Size)
 
-		addpltreloc(ctxt, plt, got, s, ld.R_PLT0) // add lr, pc, #0xXX00000
-		addpltreloc(ctxt, plt, got, s, ld.R_PLT1) // add lr, lr, #0xYY000
-		addpltreloc(ctxt, plt, got, s, ld.R_PLT2) // ldr pc, [lr, #0xZZZ]!
+		addpltreloc(ctxt, plt, got, s, obj.R_PLT0) // add lr, pc, #0xXX00000
+		addpltreloc(ctxt, plt, got, s, obj.R_PLT1) // add lr, lr, #0xYY000
+		addpltreloc(ctxt, plt, got, s, obj.R_PLT2) // ldr pc, [lr, #0xZZZ]!
 
 		// rel
 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
@@ -528,7 +526,7 @@
 		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
 
 		/* value */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint32(ctxt, d, 0)
 		} else {
 			ld.Addaddr(ctxt, d, s)
@@ -540,7 +538,7 @@
 		/* type */
 		t := ld.STB_GLOBAL << 4
 
-		if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&ld.SMASK == ld.STEXT {
+		if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&obj.SMASK == obj.STEXT {
 			t |= ld.STT_FUNC
 		} else {
 			t |= ld.STT_OBJECT
@@ -549,7 +547,7 @@
 		ld.Adduint8(ctxt, d, 0)
 
 		/* shndx */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
 		} else {
 			ld.Adduint16(ctxt, d, 1)
@@ -570,7 +568,7 @@
 			ld.Addstring(s, "")
 		}
 		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Machoadddynlib(lib)
 	} else {
 		ld.Diag("adddynlib: unsupported binary format")
@@ -581,7 +579,7 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
@@ -599,7 +597,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
@@ -608,13 +606,13 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
 	machlink := uint32(0)
-	if ld.HEADTYPE == ld.Hdarwin {
+	if ld.HEADTYPE == obj.Hdarwin {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
@@ -641,7 +639,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 		switch ld.HEADTYPE {
 		default:
 			if ld.Iself {
@@ -649,10 +647,10 @@
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case ld.Hdarwin:
+		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))
 		}
 
@@ -677,7 +675,7 @@
 				}
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			ld.Asmplan9sym()
 			ld.Cflush()
 
@@ -691,7 +689,7 @@
 				ld.Cflush()
 			}
 
-		case ld.Hdarwin:
+		case obj.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc()
 			}
@@ -702,11 +700,11 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 	ld.Cseek(0)
 	switch ld.HEADTYPE {
 	default:
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.Thearch.Lput(0x647)                      /* magic */
 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
@@ -716,14 +714,14 @@
 		ld.Thearch.Lput(0)
 		ld.Thearch.Lput(uint32(ld.Lcsize))
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hnacl:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
 		ld.Asmbelf(int64(symo))
 
-	case ld.Hdarwin:
+	case obj.Hdarwin:
 		ld.Asmbmacho()
 	}
 
diff --git a/src/cmd/5l/obj.go b/src/cmd/5l/obj.go
index 075f15f..fa74908 100644
--- a/src/cmd/5l/obj.go
+++ b/src/cmd/5l/obj.go
@@ -96,20 +96,18 @@
 			log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
 		}
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnacl,
-		ld.Hdarwin:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnacl,
+		obj.Hdarwin:
 		break
 	}
 
 	switch ld.HEADTYPE {
 	default:
-		ld.Diag("unknown -H option")
-		ld.Errorexit()
-		fallthrough
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
 
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if ld.INITTEXT == -1 {
@@ -122,10 +120,10 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hlinux, /* arm elf */
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd:
+	case obj.Hlinux, /* arm elf */
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd:
 		ld.Debug['d'] = 0
 		// with dynamic linking
 		ld.Elfinit()
@@ -140,7 +138,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hnacl:
+	case obj.Hnacl:
 		ld.Elfinit()
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
@@ -154,7 +152,7 @@
 			ld.INITRND = 0x10000
 		}
 
-	case ld.Hdarwin: /* apple MACH */
+	case obj.Hdarwin: /* apple MACH */
 		ld.Debug['w'] = 1 // disable DWARF generataion
 		ld.Machoinit()
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
@@ -176,6 +174,6 @@
 	// embed goarm to runtime.goarm
 	s := ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
 
-	s.Type = ld.SRODATA
+	s.Type = obj.SRODATA
 	ld.Adduint8(ld.Ctxt, s, uint8(ld.Ctxt.Goarm))
 }
diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go
index 41ed363..23e2d1b 100644
--- a/src/cmd/6g/cgen.go
+++ b/src/cmd/6g/cgen.go
@@ -10,7 +10,7 @@
 	"cmd/internal/obj/x86"
 )
 
-func stackcopy(n, ns *gc.Node, osrc, odst, w int64) {
+func blockcopy(n, ns *gc.Node, osrc, odst, w int64) {
 	var noddi gc.Node
 	gc.Nodreg(&noddi, gc.Types[gc.Tptr], x86.REG_DI)
 	var nodsi gc.Node
@@ -32,10 +32,10 @@
 		gc.Agenr(n, &nodr, &nodsi)
 	}
 
-	if nodl.Val.U.Reg != x86.REG_DI {
+	if nodl.Reg != x86.REG_DI {
 		gmove(&nodl, &noddi)
 	}
-	if nodr.Val.U.Reg != x86.REG_SI {
+	if nodr.Reg != x86.REG_SI {
 		gmove(&nodr, &nodsi)
 	}
 	gc.Regfree(&nodl)
diff --git a/src/cmd/6g/galign.go b/src/cmd/6g/galign.go
index a73ddc6..0ca8753 100644
--- a/src/cmd/6g/galign.go
+++ b/src/cmd/6g/galign.go
@@ -10,11 +10,11 @@
 	"cmd/internal/obj/x86"
 )
 
-var thechar int = '6'
-
-var thestring string = "amd64"
-
-var thelinkarch *obj.LinkArch = &x86.Linkamd64
+var (
+	thechar     int           = '6'
+	thestring   string        = "amd64"
+	thelinkarch *obj.LinkArch = &x86.Linkamd64
+)
 
 func linkarchinit() {
 	if obj.Getgoarch() == "amd64p32" {
@@ -27,17 +27,16 @@
 
 var MAXWIDTH int64 = 1 << 50
 
-var addptr int = x86.AADDQ
-
-var movptr int = x86.AMOVQ
-
-var leaptr int = x86.ALEAQ
-
-var cmpptr int = x86.ACMPQ
+var (
+	addptr int = x86.AADDQ
+	movptr int = x86.AMOVQ
+	leaptr int = x86.ALEAQ
+	cmpptr int = x86.ACMPQ
+)
 
 /*
  * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
+ * int, uint, and uintptr
  */
 var typedefs = []gc.Typedef{
 	gc.Typedef{"int", gc.TINT, gc.TINT64},
@@ -61,6 +60,9 @@
 		typedefs[2].Sameas = gc.TUINT32
 	}
 
+	if gc.Ctxt.Flag_dynlink {
+		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, x86.REG_R15)
+	}
 }
 
 func main() {
@@ -96,7 +98,9 @@
 	gc.Thearch.Dodiv = dodiv
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
+	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
+	gc.Thearch.Ginsboolval = ginsboolval
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
@@ -107,7 +111,7 @@
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
-	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Blockcopy = blockcopy
 	gc.Thearch.Sudoaddable = sudoaddable
 	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
diff --git a/src/cmd/6g/gg.go b/src/cmd/6g/gg.go
deleted file mode 100644
index 2deed5d..0000000
--- a/src/cmd/6g/gg.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "cmd/internal/obj/x86"
-import "cmd/internal/gc"
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-var reg [x86.MAXREG]uint8
-
-var panicdiv *gc.Node
-
-/*
- * cgen.c
- */
-
-/*
- * list.c
- */
diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go
index e609d0e..6e5e6bc 100644
--- a/src/cmd/6g/ggen.go
+++ b/src/cmd/6g/ggen.go
@@ -62,6 +62,55 @@
 	zerorange(p, int64(frame), lo, hi, &ax)
 }
 
+// DUFFZERO consists of repeated blocks of 4 MOVs + ADD,
+// with 4 STOSQs at the very end.
+// The trailing STOSQs prevent the need for a DI preadjustment
+// for small numbers of words to clear.
+// See runtime/mkduff.go.
+const (
+	dzBlocks    = 31 // number of MOV/ADD blocks
+	dzBlockLen  = 4  // number of clears per block
+	dzBlockSize = 19 // size of instructions in a single block
+	dzMovSize   = 4  // size of single MOV instruction w/ offset
+	dzAddSize   = 4  // size of single ADD instruction
+	dzDIStep    = 8  // number of bytes cleared by each MOV instruction
+
+	dzTailLen  = 4 // number of final STOSQ instructions
+	dzTailSize = 2 // size of single STOSQ instruction
+
+	dzSize = dzBlocks*dzBlockSize + dzTailLen*dzTailSize // total size of DUFFZERO routine
+)
+
+// duffzeroDI returns the pre-adjustment to DI for a call to DUFFZERO.
+// q is the number of words to zero.
+func dzDI(q int64) int64 {
+	if q < dzTailLen {
+		return 0
+	}
+	q -= dzTailLen
+	if q%dzBlockLen == 0 {
+		return 0
+	}
+	return -dzDIStep * (dzBlockLen - q%dzBlockLen)
+}
+
+// dzOff returns the offset for a jump into DUFFZERO.
+// q is the number of words to zero.
+func dzOff(q int64) int64 {
+	off := int64(dzSize)
+	if q < dzTailLen {
+		return off - q*dzTailSize
+	}
+	off -= dzTailLen * dzTailSize
+	q -= dzTailLen
+	blocks, steps := q/dzBlockLen, q%dzBlockLen
+	off -= dzBlockSize * blocks
+	if steps > 0 {
+		off -= dzAddSize + dzMovSize*steps
+	}
+	return off
+}
+
 func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog {
 	cnt := hi - lo
 	if cnt == 0 {
@@ -87,8 +136,9 @@
 			p = appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i)
 		}
 	} else if !gc.Nacl && (cnt <= int64(128*gc.Widthreg)) {
-		p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
-		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 2*(128-cnt/int64(gc.Widthreg)))
+		q := cnt / int64(gc.Widthreg)
+		p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo+dzDI(q), obj.TYPE_REG, x86.REG_DI, 0)
+		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(q))
 		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
 	} else {
 		p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
@@ -116,6 +166,8 @@
 	return q
 }
 
+var panicdiv *gc.Node
+
 /*
  * generate division.
  * generates one of:
@@ -274,7 +326,7 @@
 func restx(x *gc.Node, oldx *gc.Node) {
 	if oldx.Op != 0 {
 		x.Type = gc.Types[gc.TINT64]
-		reg[x.Val.U.Reg] = uint8(oldx.Ostk)
+		reg[x.Reg] = uint8(oldx.Ostk)
 		gmove(oldx, x)
 		gc.Regfree(oldx)
 	}
@@ -469,9 +521,9 @@
 		t = gc.Types[gc.TINT64]
 	}
 	var n1 gc.Node
-	gc.Nodreg(&n1, t, int(n1b.Val.U.Reg))
+	gc.Nodreg(&n1, t, int(n1b.Reg))
 	var n2 gc.Node
-	gc.Nodreg(&n2, t, int(n2b.Val.U.Reg))
+	gc.Nodreg(&n2, t, int(n2b.Reg))
 	a := optoas(op, t)
 	gins(a, &n2, &n1)
 
@@ -562,12 +614,13 @@
 		gins(x86.AREP, nil, nil)   // repeat
 		gins(x86.ASTOSQ, nil, nil) // STOQ AL,*(DI)+
 	} else {
+		if di := dzDI(q); di != 0 {
+			gconreg(addptr, di, x86.REG_DI)
+		}
 		p := gins(obj.ADUFFZERO, nil, nil)
 		p.To.Type = obj.TYPE_ADDR
 		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
-
-		// 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
-		p.To.Offset = 2 * (128 - q)
+		p.To.Offset = dzOff(q)
 	}
 
 	z := ax
@@ -671,3 +724,20 @@
 	}
 	return false
 }
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Regalloc(&n1, res.Type, res)
+	mov := optoas(gc.OAS, gc.Types[gc.Tptr])
+	p := gins(mov, nil, &n1)
+	p.From.Type = obj.TYPE_REG
+	p.From.Reg = x86.REG_TLS
+	p = gins(mov, nil, &n1)
+	p.From = p.To
+	p.From.Type = obj.TYPE_MEM
+	p.From.Index = x86.REG_TLS
+	p.From.Scale = 1
+	gmove(&n1, res)
+	gc.Regfree(&n1)
+}
diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go
index b2290af..53d0f03 100644
--- a/src/cmd/6g/gsubr.go
+++ b/src/cmd/6g/gsubr.go
@@ -37,11 +37,6 @@
 	"fmt"
 )
 
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 6l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-var unmappedzero int64 = 4096
-
 var resvd = []int{
 	x86.REG_DI, // for movstring
 	x86.REG_SI, // for movstring
@@ -104,6 +99,10 @@
 	gins(as, &n1, n2)
 }
 
+func ginsboolval(a int, n *gc.Node) {
+	gins(jmptoset(a), nil, n)
+}
+
 /*
  * set up nodes representing 2^63
  */
@@ -531,7 +530,7 @@
 
 	switch f.Op {
 	case gc.OREGISTER:
-		if f.Val.U.Reg != t.Val.U.Reg {
+		if f.Reg != t.Reg {
 			break
 		}
 		return true
@@ -590,7 +589,7 @@
 
 	case x86.ALEAQ:
 		if f != nil && gc.Isconst(f, gc.CTNIL) {
-			gc.Fatal("gins LEAQ nil %v", gc.Tconv(f.Type, 0))
+			gc.Fatal("gins LEAQ nil %v", f.Type)
 		}
 	}
 
@@ -650,7 +649,7 @@
 	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t)
 
 	case gc.OADDR<<16 | gc.TPTR32:
 		a = x86.ALEAL
@@ -703,6 +702,21 @@
 		gc.OPS<<16 | gc.TFLOAT64:
 		a = x86.AJPS
 
+	case gc.OPC<<16 | gc.TBOOL,
+		gc.OPC<<16 | gc.TINT8,
+		gc.OPC<<16 | gc.TUINT8,
+		gc.OPC<<16 | gc.TINT16,
+		gc.OPC<<16 | gc.TUINT16,
+		gc.OPC<<16 | gc.TINT32,
+		gc.OPC<<16 | gc.TUINT32,
+		gc.OPC<<16 | gc.TINT64,
+		gc.OPC<<16 | gc.TUINT64,
+		gc.OPC<<16 | gc.TPTR32,
+		gc.OPC<<16 | gc.TPTR64,
+		gc.OPC<<16 | gc.TFLOAT32,
+		gc.OPC<<16 | gc.TFLOAT64:
+		a = x86.AJPC
+
 	case gc.OLT<<16 | gc.TINT8,
 		gc.OLT<<16 | gc.TINT16,
 		gc.OLT<<16 | gc.TINT32,
@@ -907,7 +921,8 @@
 		gc.OMINUS<<16 | gc.TPTR64:
 		a = x86.ANEGQ
 
-	case gc.OAND<<16 | gc.TINT8,
+	case gc.OAND<<16 | gc.TBOOL,
+		gc.OAND<<16 | gc.TINT8,
 		gc.OAND<<16 | gc.TUINT8:
 		a = x86.AANDB
 
@@ -925,7 +940,8 @@
 		gc.OAND<<16 | gc.TPTR64:
 		a = x86.AANDQ
 
-	case gc.OOR<<16 | gc.TINT8,
+	case gc.OOR<<16 | gc.TBOOL,
+		gc.OOR<<16 | gc.TINT8,
 		gc.OOR<<16 | gc.TUINT8:
 		a = x86.AORB
 
@@ -1131,11 +1147,54 @@
 
 	case gc.ODIV<<16 | gc.TFLOAT64:
 		a = x86.ADIVSD
+
+	case gc.OSQRT<<16 | gc.TFLOAT64:
+		a = x86.ASQRTSD
 	}
 
 	return a
 }
 
+// jmptoset returns ASETxx for AJxx.
+func jmptoset(jmp int) int {
+	switch jmp {
+	case x86.AJEQ:
+		return x86.ASETEQ
+	case x86.AJNE:
+		return x86.ASETNE
+	case x86.AJLT:
+		return x86.ASETLT
+	case x86.AJCS:
+		return x86.ASETCS
+	case x86.AJLE:
+		return x86.ASETLE
+	case x86.AJLS:
+		return x86.ASETLS
+	case x86.AJGT:
+		return x86.ASETGT
+	case x86.AJHI:
+		return x86.ASETHI
+	case x86.AJGE:
+		return x86.ASETGE
+	case x86.AJCC:
+		return x86.ASETCC
+	case x86.AJMI:
+		return x86.ASETMI
+	case x86.AJOC:
+		return x86.ASETOC
+	case x86.AJOS:
+		return x86.ASETOS
+	case x86.AJPC:
+		return x86.ASETPC
+	case x86.AJPL:
+		return x86.ASETPL
+	case x86.AJPS:
+		return x86.ASETPS
+	}
+	gc.Fatal("jmptoset: no entry for %v", gc.Oconv(jmp, 0))
+	panic("unreachable")
+}
+
 const (
 	ODynam   = 1 << 0
 	OAddable = 1 << 1
@@ -1244,7 +1303,7 @@
 			return false
 		}
 
-		if nn.Addable != 0 && o == 1 && oary[0] >= 0 {
+		if nn.Addable && o == 1 && oary[0] >= 0 {
 			// directly addressable set of DOTs
 			n1 := *nn
 
diff --git a/src/cmd/6g/peep.go b/src/cmd/6g/peep.go
index 1fbf79a..cd07199 100644
--- a/src/cmd/6g/peep.go
+++ b/src/cmd/6g/peep.go
@@ -329,7 +329,7 @@
 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 			fmt.Printf("no pushback: %v\n", r0.Prog)
 			if r != nil {
-				fmt.Printf("\t%v [%d]\n", r.Prog, gc.Uniqs(r) != nil)
+				fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
 			}
 		}
 
diff --git a/src/cmd/6g/prog.go b/src/cmd/6g/prog.go
index 0644800..5f60474 100644
--- a/src/cmd/6g/prog.go
+++ b/src/cmd/6g/prog.go
@@ -196,6 +196,22 @@
 	x86.ASBBL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
 	x86.ASBBQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
 	x86.ASBBW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASETCC:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETCS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETEQ:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETGE:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETGT:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETHI:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETLE:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETLS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETLT:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETMI:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETNE:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETOC:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETOS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETPC:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETPL:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETPS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
 	x86.ASHLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
 	x86.ASHLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
 	x86.ASHLQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
@@ -204,6 +220,7 @@
 	x86.ASHRL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
 	x86.ASHRQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
 	x86.ASHRW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASQRTSD:   {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
 	x86.ASTOSB:    {gc.OK, AX | DI, DI, 0},
 	x86.ASTOSL:    {gc.OK, AX | DI, DI, 0},
 	x86.ASTOSQ:    {gc.OK, AX | DI, DI, 0},
@@ -276,4 +293,16 @@
 	if p.To.Index != x86.REG_NONE {
 		info.Regindex |= RtoB(int(p.To.Index))
 	}
+	if gc.Ctxt.Flag_dynlink {
+		// When -dynlink is passed, many operations on external names (and
+		// also calling duffzero/duffcopy) use R15 as a scratch register.
+		if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+			return
+		}
+		if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || (p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local) || (p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local) {
+			info.Reguse |= R15
+			info.Regset |= R15
+			return
+		}
+	}
 }
diff --git a/src/cmd/6g/reg.go b/src/cmd/6g/reg.go
index dd06bc5..cab07b5 100644
--- a/src/cmd/6g/reg.go
+++ b/src/cmd/6g/reg.go
@@ -40,6 +40,8 @@
 	NREGVAR = 32
 )
 
+var reg [x86.MAXREG]uint8
+
 var regname = []string{
 	".AX",
 	".CX",
@@ -100,12 +102,13 @@
 
 // For ProgInfo.
 const (
-	AX = 1 << (x86.REG_AX - x86.REG_AX)
-	BX = 1 << (x86.REG_BX - x86.REG_AX)
-	CX = 1 << (x86.REG_CX - x86.REG_AX)
-	DX = 1 << (x86.REG_DX - x86.REG_AX)
-	DI = 1 << (x86.REG_DI - x86.REG_AX)
-	SI = 1 << (x86.REG_SI - x86.REG_AX)
+	AX  = 1 << (x86.REG_AX - x86.REG_AX)
+	BX  = 1 << (x86.REG_BX - x86.REG_AX)
+	CX  = 1 << (x86.REG_CX - x86.REG_AX)
+	DX  = 1 << (x86.REG_DX - x86.REG_AX)
+	DI  = 1 << (x86.REG_DI - x86.REG_AX)
+	SI  = 1 << (x86.REG_SI - x86.REG_AX)
+	R15 = 1 << (x86.REG_R15 - x86.REG_AX)
 )
 
 func RtoB(r int) uint64 {
@@ -123,7 +126,6 @@
 		// BP is part of the calling convention if framepointer_enabled.
 		b &^= (1 << (x86.REG_BP - x86.REG_AX))
 	}
-
 	if b == 0 {
 		return 0
 	}
diff --git a/src/cmd/6g/util.go b/src/cmd/6g/util.go
deleted file mode 100644
index bb5eedb..0000000
--- a/src/cmd/6g/util.go
+++ /dev/null
@@ -1,12 +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 main
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go
index 1df166f..a025ce6 100644
--- a/src/cmd/6l/asm.go
+++ b/src/cmd/6l/asm.go
@@ -33,6 +33,7 @@
 import (
 	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"debug/elf"
 	"fmt"
 	"log"
 )
@@ -61,7 +62,61 @@
 	return 0
 }
 
+func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
+	s.Reachable = true
+	i := s.Size
+	s.Size += 4
+	ld.Symgrow(ctxt, s, s.Size)
+	r := ld.Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Type = obj.R_CALL
+	r.Siz = 4
+	return i + int64(r.Siz)
+}
+
 func gentext() {
+	if !ld.DynlinkingGo() {
+		return
+	}
+	addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+	if addmoduledata.Type == obj.STEXT {
+		// we're linking a module containing the runtime -> no need for
+		// an init function
+		return
+	}
+	addmoduledata.Reachable = true
+	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+	initfunc.Type = obj.STEXT
+	initfunc.Local = true
+	initfunc.Reachable = true
+	o := func(op ...uint8) {
+		for _, op1 := range op {
+			ld.Adduint8(ld.Ctxt, initfunc, op1)
+		}
+	}
+	// 0000000000000000 <local.dso_init>:
+	//    0:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 7 <local.dso_init+0x7>
+	// 			3: R_X86_64_PC32	runtime.firstmoduledata-0x4
+	o(0x48, 0x8d, 0x3d)
+	ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "runtime.firstmoduledata", 0), 0)
+	//    7:	e8 00 00 00 00       	callq  c <local.dso_init+0xc>
+	// 			8: R_X86_64_PLT32	runtime.addmoduledata-0x4
+	o(0xe8)
+	Addcall(ld.Ctxt, initfunc, addmoduledata)
+	//    c:	c3                   	retq
+	o(0xc3)
+	if ld.Ctxt.Etextp != nil {
+		ld.Ctxt.Etextp.Next = initfunc
+	} else {
+		ld.Ctxt.Textp = initfunc
+	}
+	ld.Ctxt.Etextp = initfunc
+	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+	initarray_entry.Reachable = true
+	initarray_entry.Local = true
+	initarray_entry.Type = obj.SINITARR
+	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
 }
 
 func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
@@ -83,20 +138,20 @@
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_X86_64_PC32:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
 		}
-		if targ.Type == 0 || targ.Type == ld.SXREF {
+		if targ.Type == 0 || targ.Type == obj.SXREF {
 			ld.Diag("unknown symbol %s in pcrel", targ.Name)
 		}
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Add += 4
 		return
 
 	case 256 + ld.R_X86_64_PLT32:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Add += 4
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add += int64(targ.Plt)
@@ -105,13 +160,13 @@
 		return
 
 	case 256 + ld.R_X86_64_GOTPCREL:
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			// have symbol
 			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
 				// turn MOVQ of GOT entry into LEAQ of symbol itself
 				s.P[r.Off-2] = 0x8d
 
-				r.Type = ld.R_PCREL
+				r.Type = obj.R_PCREL
 				r.Add += 4
 				return
 			}
@@ -121,17 +176,17 @@
 		// TODO: just needs relocation, no need to put in .dynsym
 		addgotsym(targ)
 
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
 		r.Add += 4
 		r.Add += int64(targ.Got)
 		return
 
 	case 256 + ld.R_X86_64_64:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = ld.R_ADDR
+		r.Type = obj.R_ADDR
 		return
 
 	// Handle relocations found in Mach-O object files.
@@ -139,19 +194,19 @@
 		512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
 		512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
 		// TODO: What is the difference between all these?
-		r.Type = ld.R_ADDR
+		r.Type = obj.R_ADDR
 
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
 		}
 		return
 
 	case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add = int64(targ.Plt)
-			r.Type = ld.R_PCREL
+			r.Type = obj.R_PCREL
 			return
 		}
 		fallthrough
@@ -162,15 +217,15 @@
 		512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
 		512 + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
 		512 + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
 		}
 		return
 
 	case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			// have symbol
 			// turn MOVQ of GOT entry into LEAQ of symbol itself
 			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
@@ -179,32 +234,32 @@
 			}
 
 			s.P[r.Off-2] = 0x8d
-			r.Type = ld.R_PCREL
+			r.Type = obj.R_PCREL
 			return
 		}
 		fallthrough
 
 		// fall through
 	case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
 		}
 		addgotsym(targ)
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
 		r.Add += int64(targ.Got)
 		return
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != ld.SDYNIMPORT {
+	if targ.Type != obj.SDYNIMPORT {
 		return
 	}
 
 	switch r.Type {
-	case ld.R_CALL,
-		ld.R_PCREL:
-		if ld.HEADTYPE == ld.Hwindows {
+	case obj.R_CALL,
+		obj.R_PCREL:
+		if ld.HEADTYPE == obj.Hwindows {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return
 		} else {
@@ -215,8 +270,14 @@
 			return
 		}
 
-	case ld.R_ADDR:
-		if s.Type == ld.STEXT && ld.Iself {
+	case obj.R_ADDR:
+		if s.Type == obj.STEXT && ld.Iself {
+			if ld.HEADTYPE == obj.Hsolaris {
+				addpltsym(targ)
+				r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+				r.Add += int64(targ.Plt)
+				return
+			}
 			// The code is asking for the address of an external
 			// function.  We provide it with the address of the
 			// correspondent GOT symbol.
@@ -227,7 +288,7 @@
 			return
 		}
 
-		if s.Type != ld.SDATA {
+		if s.Type != obj.SDATA {
 			break
 		}
 		if ld.Iself {
@@ -244,7 +305,7 @@
 			return
 		}
 
-		if ld.HEADTYPE == ld.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
 			// Mach-O relocations are a royal pain to lay out.
 			// They use a compact stateful bytecode representation
 			// that is too much bother to deal with.
@@ -258,7 +319,7 @@
 			adddynsym(ld.Ctxt, targ)
 
 			got := ld.Linklookup(ld.Ctxt, ".got", 0)
-			s.Type = got.Type | ld.SSUB
+			s.Type = got.Type | obj.SSUB
 			s.Outer = got
 			s.Sub = got.Sub
 			got.Sub = s
@@ -269,7 +330,7 @@
 			return
 		}
 
-		if ld.HEADTYPE == ld.Hwindows {
+		if ld.HEADTYPE == obj.Hwindows {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return
 		}
@@ -287,7 +348,7 @@
 	default:
 		return -1
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
 		} else if r.Siz == 8 {
@@ -296,24 +357,28 @@
 			return -1
 		}
 
-	case ld.R_TLS_LE:
+	case obj.R_TLS_LE:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
 		} else {
 			return -1
 		}
 
-	case ld.R_TLS_IE:
+	case obj.R_TLS_IE:
 		if r.Siz == 4 {
 			ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
 		} else {
 			return -1
 		}
 
-	case ld.R_CALL:
+	case obj.R_CALL:
 		if r.Siz == 4 {
-			if r.Xsym.Type == ld.SDYNIMPORT {
-				ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+			if r.Xsym.Type == obj.SDYNIMPORT {
+				if ld.DynlinkingGo() {
+					ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
+				} else {
+					ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+				}
 			} else {
 				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
 			}
@@ -321,20 +386,20 @@
 			return -1
 		}
 
-	case ld.R_PCREL:
+	case obj.R_PCREL:
 		if r.Siz == 4 {
-			ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+			if r.Xsym.Type == obj.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
+				ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
+			} else {
+				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+			}
 		} else {
 			return -1
 		}
 
-	case ld.R_TLS:
+	case obj.R_GOTPCREL:
 		if r.Siz == 4 {
-			if ld.Flag_shared != 0 {
-				ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
-			} else {
-				ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
-			}
+			ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
 		} else {
 			return -1
 		}
@@ -349,7 +414,7 @@
 
 	rs := r.Xsym
 
-	if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_PCREL {
+	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_PCREL {
 		if rs.Dynid < 0 {
 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -369,15 +434,15 @@
 	default:
 		return -1
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
 
-	case ld.R_CALL:
+	case obj.R_CALL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
 
 		// NOTE: Only works with 'external' relocation. Forced above.
-	case ld.R_PCREL:
+	case obj.R_PCREL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
 	}
@@ -421,15 +486,15 @@
 	default:
 		return false
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		if r.Siz == 8 {
 			v = ld.IMAGE_REL_AMD64_ADDR64
 		} else {
 			v = ld.IMAGE_REL_AMD64_ADDR32
 		}
 
-	case ld.R_CALL,
-		ld.R_PCREL:
+	case obj.R_CALL,
+		obj.R_PCREL:
 		v = ld.IMAGE_REL_AMD64_REL32
 	}
 
@@ -515,7 +580,7 @@
 		ld.Adduint64(ld.Ctxt, rela, 0)
 
 		s.Plt = int32(plt.Size - 16)
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		// To do lazy symbol lookup right, we're supposed
 		// to tell the dynamic loader which library each
 		// symbol comes from and format the link info
@@ -557,7 +622,7 @@
 		ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
 		ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
 		ld.Adduint64(ld.Ctxt, rela, 0)
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
 	} else {
 		ld.Diag("addgotsym: unsupported binary format")
@@ -581,7 +646,7 @@
 		/* type */
 		t := ld.STB_GLOBAL << 4
 
-		if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
+		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
 			t |= ld.STT_FUNC
 		} else {
 			t |= ld.STT_OBJECT
@@ -592,14 +657,14 @@
 		ld.Adduint8(ctxt, d, 0)
 
 		/* section where symbol is defined */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
 		} else {
 			ld.Adduint16(ctxt, d, 1)
 		}
 
 		/* value */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint64(ctxt, d, 0)
 		} else {
 			ld.Addaddr(ctxt, d, s)
@@ -611,9 +676,9 @@
 		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 == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
-	} else if ld.HEADTYPE == ld.Hwindows {
+	} else if ld.HEADTYPE == obj.Hwindows {
 	} else // already taken care of
 	{
 		ld.Diag("adddynsym: unsupported binary format")
@@ -631,7 +696,7 @@
 			ld.Addstring(s, "")
 		}
 		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Machoadddynlib(lib)
 	} else {
 		ld.Diag("adddynlib: unsupported binary format")
@@ -642,12 +707,12 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
@@ -665,7 +730,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
@@ -674,13 +739,13 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
 	machlink := int64(0)
-	if ld.HEADTYPE == ld.Hdarwin {
+	if ld.HEADTYPE == obj.Hdarwin {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
@@ -700,23 +765,23 @@
 		ld.Diag("unknown header type %d", ld.HEADTYPE)
 		fallthrough
 
-	case ld.Hplan9,
-		ld.Helf:
+	case obj.Hplan9,
+		obj.Helf:
 		break
 
-	case ld.Hdarwin:
+	case obj.Hdarwin:
 		ld.Debug['8'] = 1 /* 64-bit addresses */
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hdragonfly,
-		ld.Hsolaris:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hdragonfly,
+		obj.Hsolaris:
 		ld.Debug['8'] = 1 /* 64-bit addresses */
 
-	case ld.Hnacl,
-		ld.Hwindows:
+	case obj.Hnacl,
+		obj.Hwindows:
 		break
 	}
 
@@ -728,28 +793,28 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 		switch ld.HEADTYPE {
 		default:
-		case ld.Hplan9,
-			ld.Helf:
+		case obj.Hplan9,
+			obj.Helf:
 			ld.Debug['s'] = 1
 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case ld.Hdarwin:
+		case obj.Hdarwin:
 			symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
 
-		case ld.Hlinux,
-			ld.Hfreebsd,
-			ld.Hnetbsd,
-			ld.Hopenbsd,
-			ld.Hdragonfly,
-			ld.Hsolaris,
-			ld.Hnacl:
+		case obj.Hlinux,
+			obj.Hfreebsd,
+			obj.Hnetbsd,
+			obj.Hopenbsd,
+			obj.Hdragonfly,
+			obj.Hsolaris,
+			obj.Hnacl:
 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 			symo = ld.Rnd(symo, int64(ld.INITRND))
 
-		case ld.Hwindows:
+		case obj.Hwindows:
 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 			symo = ld.Rnd(symo, ld.PEFILEALIGN)
 		}
@@ -774,7 +839,7 @@
 				}
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			ld.Asmplan9sym()
 			ld.Cflush()
 
@@ -788,14 +853,14 @@
 				ld.Cflush()
 			}
 
-		case ld.Hwindows:
+		case obj.Hwindows:
 			if ld.Debug['v'] != 0 {
 				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 			}
 
 			ld.Dwarfemitdebugsections()
 
-		case ld.Hdarwin:
+		case obj.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc()
 			}
@@ -805,11 +870,11 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 	ld.Cseek(0)
 	switch ld.HEADTYPE {
 	default:
-	case ld.Hplan9: /* plan9 */
+	case obj.Hplan9: /* plan9 */
 		magic := int32(4*26*26 + 7)
 
 		magic |= 0x00008000                  /* fat header */
@@ -824,19 +889,19 @@
 		ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
 		ld.Vputb(uint64(vl))        /* va of entry */
 
-	case ld.Hdarwin:
+	case obj.Hdarwin:
 		ld.Asmbmacho()
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hdragonfly,
-		ld.Hsolaris,
-		ld.Hnacl:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hdragonfly,
+		obj.Hsolaris,
+		obj.Hnacl:
 		ld.Asmbelf(symo)
 
-	case ld.Hwindows:
+	case obj.Hwindows:
 		ld.Asmbpe()
 	}
 
diff --git a/src/cmd/6l/obj.go b/src/cmd/6l/obj.go
index f7165ab..9e6dc60 100644
--- a/src/cmd/6l/obj.go
+++ b/src/cmd/6l/obj.go
@@ -91,7 +91,7 @@
 		ld.Linkmode = ld.LinkInternal
 	}
 
-	if ld.Flag_shared != 0 {
+	if ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
 		ld.Linkmode = ld.LinkExternal
 	}
 
@@ -104,25 +104,23 @@
 			log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
 		}
 
-	case ld.Hdarwin,
-		ld.Hdragonfly,
-		ld.Hfreebsd,
-		ld.Hlinux,
-		ld.Hnacl,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hsolaris,
-		ld.Hwindows:
+	case obj.Hdarwin,
+		obj.Hdragonfly,
+		obj.Hfreebsd,
+		obj.Hlinux,
+		obj.Hnacl,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hsolaris,
+		obj.Hwindows:
 		break
 	}
 
 	switch ld.HEADTYPE {
 	default:
-		ld.Diag("unknown -H option")
-		ld.Errorexit()
-		fallthrough
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
 
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.HEADR = 32 + 8
 
 		if ld.INITTEXT == -1 {
@@ -135,7 +133,7 @@
 			ld.INITRND = 0x200000
 		}
 
-	case ld.Helf: /* elf32 executable */
+	case obj.Helf: /* elf32 executable */
 		ld.HEADR = int32(ld.Rnd(52+3*32, 16))
 
 		if ld.INITTEXT == -1 {
@@ -148,7 +146,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hdarwin: /* apple MACH */
+	case obj.Hdarwin: /* apple MACH */
 		ld.Machoinit()
 
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
@@ -162,15 +160,23 @@
 			ld.INITDAT = 0
 		}
 
-	case ld.Hlinux, /* elf64 executable */
-		ld.Hfreebsd,   /* freebsd */
-		ld.Hnetbsd,    /* netbsd */
-		ld.Hopenbsd,   /* openbsd */
-		ld.Hdragonfly, /* dragonfly */
-		ld.Hsolaris:   /* solaris */
+	case obj.Hlinux, /* elf64 executable */
+		obj.Hfreebsd,   /* freebsd */
+		obj.Hnetbsd,    /* netbsd */
+		obj.Hopenbsd,   /* openbsd */
+		obj.Hdragonfly, /* dragonfly */
+		obj.Hsolaris:   /* solaris */
 		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)
 		}
@@ -181,7 +187,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hnacl:
+	case obj.Hnacl:
 		ld.Elfinit()
 		ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway
 		ld.HEADR = 0x10000
@@ -196,7 +202,7 @@
 			ld.INITRND = 0x10000
 		}
 
-	case ld.Hwindows: /* PE executable */
+	case obj.Hwindows: /* PE executable */
 		ld.Peinit()
 
 		ld.HEADR = ld.PEFILEHEADR
diff --git a/src/cmd/7g/cgen.go b/src/cmd/7g/cgen.go
index 8d6dce4..6f268b4 100644
--- a/src/cmd/7g/cgen.go
+++ b/src/cmd/7g/cgen.go
@@ -10,7 +10,7 @@
 	"cmd/internal/obj/arm64"
 )
 
-func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
 	// smaller operations for less aligned types.
@@ -20,7 +20,7 @@
 	var op int
 	switch align {
 	default:
-		gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0))
+		gc.Fatal("sgen: invalid alignment %d for %v", align, n.Type)
 
 	case 1:
 		op = arm64.AMOVB
@@ -36,7 +36,7 @@
 	}
 
 	if w%int64(align) != 0 {
-		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0))
+		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
 	}
 	c := int32(w / int64(align))
 
diff --git a/src/cmd/7g/galign.go b/src/cmd/7g/galign.go
index 1c50c21..34b4ab6 100644
--- a/src/cmd/7g/galign.go
+++ b/src/cmd/7g/galign.go
@@ -23,7 +23,7 @@
 
 /*
  * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
+ * int, uint, and uintptr
  */
 var typedefs = []gc.Typedef{
 	gc.Typedef{"int", gc.TINT, gc.TINT64},
@@ -49,6 +49,7 @@
 	gc.Thearch.REGRETURN = arm64.REG_R0
 	gc.Thearch.REGMIN = arm64.REG_R0
 	gc.Thearch.REGMAX = arm64.REG_R31
+	gc.Thearch.REGZERO = arm64.REGZERO
 	gc.Thearch.FREGMIN = arm64.REG_F0
 	gc.Thearch.FREGMAX = arm64.REG_F31
 	gc.Thearch.MAXWIDTH = MAXWIDTH
@@ -62,6 +63,7 @@
 	gc.Thearch.Dodiv = dodiv
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
+	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
@@ -73,7 +75,7 @@
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
-	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Blockcopy = blockcopy
 	gc.Thearch.Sudoaddable = sudoaddable
 	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
diff --git a/src/cmd/7g/gg.go b/src/cmd/7g/gg.go
deleted file mode 100644
index a267482..0000000
--- a/src/cmd/7g/gg.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "cmd/internal/obj/arm64"
-import "cmd/internal/gc"
-
-// 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.
-
-var reg [arm64.NREG + arm64.NFREG]uint8
-
-var panicdiv *gc.Node
-
-/*
- * cgen.c
- */
-
-/*
- * list.c
- */
-
-/*
- * reg.c
- */
diff --git a/src/cmd/7g/ggen.go b/src/cmd/7g/ggen.go
index 0fc5854..b824a3a 100644
--- a/src/cmd/7g/ggen.go
+++ b/src/cmd/7g/ggen.go
@@ -62,6 +62,8 @@
 	zerorange(p, int64(frame), lo, hi)
 }
 
+var darwin = obj.Getgoos() == "darwin"
+
 func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 	cnt := hi - lo
 	if cnt == 0 {
@@ -71,7 +73,7 @@
 		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
 			p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+frame+lo+i)
 		}
-	} else if cnt <= int64(128*gc.Widthptr) {
+	} else if cnt <= int64(128*gc.Widthptr) && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
 		p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
 		p = appendpp(p, arm64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGRT1, 0)
 		p.Reg = arm64.REGRT1
@@ -122,6 +124,8 @@
 	gins(arm64.AHINT, &con, nil)
 }
 
+var panicdiv *gc.Node
+
 /*
  * generate division.
  * generates one of:
@@ -230,7 +234,7 @@
 		// TODO(minux): add gins3?
 		p1.Reg = p1.To.Reg
 
-		p1.To.Reg = tm.Val.U.Reg
+		p1.To.Reg = tm.Reg
 		gins(optoas(gc.OMUL, t), &tr, &tm)
 		gc.Regfree(&tr)
 		gins(optoas(gc.OSUB, t), &tm, &tl)
@@ -288,7 +292,7 @@
 		}
 
 	default:
-		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
+		gc.Fatal("cgen_hmul %v", t)
 	}
 
 	gc.Cgen(&n1, res)
@@ -394,15 +398,15 @@
 func clearfat(nl *gc.Node) {
 	/* clear a fat object */
 	if gc.Debug['g'] != 0 {
-		fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width)
+		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
 	}
 
 	w := uint64(uint64(nl.Type.Width))
 
 	// Avoid taking the address for simple enough types.
-	//if gc.Componentgen(nil, nl) {
-	//	return
-	//}
+	if gc.Componentgen(nil, nl) {
+		return
+	}
 
 	c := uint64(w % 8) // bytes
 	q := uint64(w / 8) // dwords
@@ -443,7 +447,7 @@
 
 		// The loop leaves R16 on the last zeroed dword
 		boff = 8
-	} else if q >= 4 {
+	} else if q >= 4 && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
 		p := gins(arm64.ASUB, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
@@ -481,7 +485,6 @@
 // Expand CHECKNIL pseudo-op into actual nil pointer check.
 func expandchecks(firstp *obj.Prog) {
 	var p1 *obj.Prog
-	var p2 *obj.Prog
 
 	for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
 		if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
@@ -498,37 +501,32 @@
 		}
 
 		// check is
-		//	CMP arg, ZR
-		//	BNE 2(PC) [likely]
+		//	CBNZ arg, 2(PC)
 		//	MOVD ZR, 0(arg)
 		p1 = gc.Ctxt.NewProg()
-
-		p2 = gc.Ctxt.NewProg()
 		gc.Clearp(p1)
-		gc.Clearp(p2)
-		p1.Link = p2
-		p2.Link = p.Link
+		p1.Link = p.Link
 		p.Link = p1
 		p1.Lineno = p.Lineno
-		p2.Lineno = p.Lineno
 		p1.Pc = 9999
-		p2.Pc = 9999
-		p.As = arm64.ACMP
-		p.Reg = arm64.REGZERO
-		p1.As = arm64.ABNE
 
-		//p1->from.type = TYPE_CONST;
-		//p1->from.offset = 1; // likely
-		p1.To.Type = obj.TYPE_BRANCH
-
-		p1.To.Val = p2.Link
+		p.As = arm64.ACBNZ
+		p.To.Type = obj.TYPE_BRANCH
+		p.To.Val = p1.Link
 
 		// crash by write to memory address 0.
-		p2.As = arm64.AMOVD
-		p2.From.Type = obj.TYPE_REG
-		p2.From.Reg = arm64.REGZERO
-		p2.To.Type = obj.TYPE_MEM
-		p2.To.Reg = p.From.Reg
-		p2.To.Offset = 0
+		p1.As = arm64.AMOVD
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = arm64.REGZERO
+		p1.To.Type = obj.TYPE_MEM
+		p1.To.Reg = p.From.Reg
+		p1.To.Offset = 0
 	}
 }
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, arm64.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/7g/gsubr.go b/src/cmd/7g/gsubr.go
index 2d2bdb7..a34a4306 100644
--- a/src/cmd/7g/gsubr.go
+++ b/src/cmd/7g/gsubr.go
@@ -37,11 +37,6 @@
 	"fmt"
 )
 
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 6l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-var unmappedzero int64 = 4096
-
 var resvd = []int{
 	arm64.REGTMP,
 	arm64.REGG,
@@ -452,7 +447,7 @@
 	case gc.CTINT, gc.CTRUNE:
 		return gc.Mpgetfix(n.Val.U.Xval), true
 	case gc.CTBOOL:
-		return int64(n.Val.U.Bval), true
+		return int64(obj.Bool2int(n.Val.U.Bval)), true
 	}
 	return
 }
@@ -548,25 +543,6 @@
 	return p
 }
 
-func fixlargeoffset(n *gc.Node) {
-	if n == nil {
-		return
-	}
-	if n.Op != gc.OINDREG {
-		return
-	}
-	if -4096 <= n.Xoffset && n.Xoffset < 4096 {
-		return
-	}
-	a := gc.Node(*n)
-	a.Op = gc.OREGISTER
-	a.Type = gc.Types[gc.Tptr]
-	a.Xoffset = 0
-	gc.Cgen_checknil(&a)
-	ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a)
-	n.Xoffset = 0
-}
-
 /*
  * insert n into reg slot of p
  */
@@ -607,7 +583,7 @@
 	a := int(obj.AXXX)
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+		gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
 
 	case gc.OEQ<<16 | gc.TBOOL,
 		gc.OEQ<<16 | gc.TINT8,
@@ -938,6 +914,9 @@
 
 	case gc.ODIV<<16 | gc.TFLOAT64:
 		a = arm64.AFDIVD
+
+	case gc.OSQRT<<16 | gc.TFLOAT64:
+		a = arm64.AFSQRTD
 	}
 
 	return a
diff --git a/src/cmd/7g/peep.go b/src/cmd/7g/peep.go
index 7faef1a..49bc69b 100644
--- a/src/cmd/7g/peep.go
+++ b/src/cmd/7g/peep.go
@@ -40,7 +40,142 @@
 var gactive uint32
 
 func peep(firstp *obj.Prog) {
-	// TODO(aram)
+	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	var p *obj.Prog
+	var r *gc.Flow
+	var t int
+loop1:
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		gc.Dumpit("loop1", g.Start, 0)
+	}
+
+	t = 0
+	for r = g.Start; r != nil; r = r.Link {
+		p = r.Prog
+
+		// TODO(minux) Handle smaller moves. arm and amd64
+		// distinguish between moves that *must* sign/zero
+		// extend and moves that don't care so they
+		// can eliminate moves that don't care without
+		// breaking moves that do care. This might let us
+		// simplify or remove the next peep loop, too.
+		if p.As == arm64.AMOVD || p.As == arm64.AFMOVD {
+			if regtyp(&p.To) {
+				// Try to eliminate reg->reg moves
+				if regtyp(&p.From) {
+					if p.From.Type == p.To.Type {
+						if copyprop(r) {
+							excise(r)
+							t++
+						} else if subprop(r) && copyprop(r) {
+							excise(r)
+							t++
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if t != 0 {
+		goto loop1
+	}
+
+	/*
+	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
+	 */
+	var p1 *obj.Prog
+	var r1 *gc.Flow
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		default:
+			continue
+
+		case arm64.AMOVH,
+			arm64.AMOVHU,
+			arm64.AMOVB,
+			arm64.AMOVBU,
+			arm64.AMOVW,
+			arm64.AMOVWU:
+			if p.To.Type != obj.TYPE_REG {
+				continue
+			}
+		}
+
+		r1 = r.Link
+		if r1 == nil {
+			continue
+		}
+		p1 = r1.Prog
+		if p1.As != p.As {
+			continue
+		}
+		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
+			continue
+		}
+		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
+			continue
+		}
+		excise(r1)
+	}
+
+	if gc.Debug['D'] > 1 {
+		goto ret /* allow following code improvement to be suppressed */
+	}
+
+	// MOVD $c, R'; ADD R', R (R' unused) -> ADD $c, R
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		default:
+			continue
+
+		case arm64.AMOVD:
+			if p.To.Type != obj.TYPE_REG {
+				continue
+			}
+			if p.From.Type != obj.TYPE_CONST {
+				continue
+			}
+			if p.From.Offset < 0 || 4096 <= p.From.Offset {
+				continue
+			}
+		}
+		r1 = r.Link
+		if r1 == nil {
+			continue
+		}
+		p1 = r1.Prog
+		if p1.As != arm64.AADD && p1.As != arm64.ASUB { // TODO(aram): also logical after we have bimm.
+			continue
+		}
+		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
+			continue
+		}
+		if p1.To.Type != obj.TYPE_REG {
+			continue
+		}
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("encoding $%d directly into %v in:\n%v\n%v\n", p.From.Offset, obj.Aconv(int(p1.As)), p, p1)
+		}
+		p1.From.Type = obj.TYPE_CONST
+		p1.From = p.From
+		excise(r)
+	}
+
+	/* TODO(minux):
+	 * look for OP x,y,R; CMP R, $0 -> OP.S x,y,R
+	 * when OP can set condition codes correctly
+	 */
+
+ret:
+	gc.Flowend(g)
 }
 
 func excise(r *gc.Flow) {
@@ -57,6 +192,599 @@
 	return a.Type == obj.TYPE_REG && arm64.REG_R0 <= a.Reg && a.Reg <= arm64.REG_F31 && a.Reg != arm64.REGZERO
 }
 
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R1
+ *	ADD	b, R1	/ no use of R2
+ *	MOV	R1, R2
+ * would be converted to
+ *	MOV	a, R2
+ *	ADD	b, R2
+ *	MOV	R2, R1
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ *
+ * r0 (the argument, not the register) is the MOV at the end of the
+ * above sequences. This returns 1 if it modified any instructions.
+ */
+func subprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	if !regtyp(v1) {
+		return false
+	}
+	v2 := (*obj.Addr)(&p.To)
+	if !regtyp(v2) {
+		return false
+	}
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+		if gc.Uniqs(r) == nil {
+			break
+		}
+		p = r.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+		if p.Info.Flags&gc.Call != 0 {
+			return false
+		}
+
+		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
+			if p.To.Type == v1.Type {
+				if p.To.Reg == v1.Reg {
+					copysub(&p.To, v1, v2, 1)
+					if gc.Debug['P'] != 0 {
+						fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
+						if p.From.Type == v2.Type {
+							fmt.Printf(" excise")
+						}
+						fmt.Printf("\n")
+					}
+
+					for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+						p = r.Prog
+						copysub(&p.From, v1, v2, 1)
+						copysub1(p, v1, v2, 1)
+						copysub(&p.To, v1, v2, 1)
+						if gc.Debug['P'] != 0 {
+							fmt.Printf("%v\n", r.Prog)
+						}
+					}
+
+					t := int(int(v1.Reg))
+					v1.Reg = v2.Reg
+					v2.Reg = int16(t)
+					if gc.Debug['P'] != 0 {
+						fmt.Printf("%v last\n", r.Prog)
+					}
+					return true
+				}
+			}
+		}
+
+		if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
+			break
+		}
+		if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+			break
+		}
+	}
+
+	return false
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail (v1->v2 move must remain)
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success (caller can remove v1->v2 move)
+ */
+func copyprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	v2 := (*obj.Addr)(&p.To)
+	if copyas(v1, v2) {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
+		}
+		return true
+	}
+
+	gactive++
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
+	}
+	return copy1(v1, v2, r0.S1, 0)
+}
+
+// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
+// all uses were rewritten.
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("act set; return 1\n")
+		}
+		return true
+	}
+
+	r.Active = int32(gactive)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("copy1 replace %v with %v f=%d\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
+	}
+	var t int
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if f == 0 && gc.Uniqp(r) == nil {
+			// Multiple predecessors; conservatively
+			// assume v1 was set on other path
+			f = 1
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; f=%d", f)
+			}
+		}
+
+		t = copyu(p, v2, nil)
+		switch t {
+		case 2: /* rar, can't split */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
+			}
+			return false
+
+		case 3: /* set */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
+			}
+			return true
+
+		case 1, /* used, substitute */
+			4: /* use and set */
+			if f != 0 {
+				if gc.Debug['P'] == 0 {
+					return false
+				}
+				if t == 4 {
+					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				} else {
+					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				}
+				return false
+			}
+
+			if copyu(p, v2, v1) != 0 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; sub fail; return 0\n")
+				}
+				return false
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
+			}
+			if t == 4 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
+				}
+				return true
+			}
+		}
+
+		if f == 0 {
+			t = copyu(p, v1, nil)
+			if f == 0 && (t == 2 || t == 3 || t == 4) {
+				f = 1
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+				}
+			}
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			if !copy1(v1, v2, r.S2, f) {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+// If s==nil, copyu returns the set/use of v in p; otherwise, it
+// modifies p to replace reads of v with reads of s and returns 0 for
+// success or non-zero for failure.
+//
+// If s==nil, copy returns one of the following values:
+//	1 if v only used
+//	2 if v is set and used in one address (read-alter-rewrite;
+//	  can't substitute)
+//	3 if v is only set
+//	4 if v is set in one address and used in another (so addresses
+//	  can be rewritten independently)
+//	0 otherwise (not touched)
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
+	if p.From3.Type != obj.TYPE_NONE {
+		// 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 {
+		// 7g never generates a to2
+		fmt.Printf("copyu: to2 (%v) not implemented\n", gc.Ctxt.Dconv(&p.To2))
+	}
+
+	switch p.As {
+	default:
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		return 2
+
+	case obj.ANOP, /* read p->from, write p->to */
+		arm64.ANEG,
+		arm64.AFNEGD,
+		arm64.AFNEGS,
+		arm64.AFSQRTD,
+		arm64.AFCVTZSD,
+		arm64.AFCVTZSS,
+		arm64.AFCVTZSDW,
+		arm64.AFCVTZSSW,
+		arm64.AFCVTZUD,
+		arm64.AFCVTZUS,
+		arm64.AFCVTZUDW,
+		arm64.AFCVTZUSW,
+		arm64.AFCVTSD,
+		arm64.AFCVTDS,
+		arm64.ASCVTFD,
+		arm64.ASCVTFS,
+		arm64.ASCVTFWD,
+		arm64.ASCVTFWS,
+		arm64.AUCVTFD,
+		arm64.AUCVTFS,
+		arm64.AUCVTFWD,
+		arm64.AUCVTFWS,
+		arm64.AMOVB,
+		arm64.AMOVBU,
+		arm64.AMOVH,
+		arm64.AMOVHU,
+		arm64.AMOVW,
+		arm64.AMOVWU,
+		arm64.AMOVD,
+		arm64.AFMOVS,
+		arm64.AFMOVD:
+		if p.Scond == 0 {
+			if s != nil {
+				if copysub(&p.From, v, s, 1) != 0 {
+					return 1
+				}
+
+				// Update only indirect uses of v in p->to
+				if !copyas(&p.To, v) {
+					if copysub(&p.To, v, s, 1) != 0 {
+						return 1
+					}
+				}
+				return 0
+			}
+
+			if copyas(&p.To, v) {
+				// Fix up implicit from
+				if p.From.Type == obj.TYPE_NONE {
+					p.From = p.To
+				}
+				if copyau(&p.From, v) {
+					return 4
+				}
+				return 3
+			}
+
+			if copyau(&p.From, v) {
+				return 1
+			}
+			if copyau(&p.To, v) {
+				// p->to only indirectly uses v
+				return 1
+			}
+
+			return 0
+		}
+
+		/* rar p->from, write p->to or read p->from, rar p->to */
+		if p.From.Type == obj.TYPE_MEM {
+			if copyas(&p.From, v) {
+				// No s!=nil check; need to fail
+				// anyway in that case
+				return 2
+			}
+
+			if s != nil {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyas(&p.To, v) {
+				return 3
+			}
+		} else if p.To.Type == obj.TYPE_MEM {
+			if copyas(&p.To, v) {
+				return 2
+			}
+			if s != nil {
+				if copysub(&p.From, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyau(&p.From, v) {
+				return 1
+			}
+		} else {
+			fmt.Printf("copyu: bad %v\n", p)
+		}
+
+		return 0
+
+	case arm64.AADD, /* read p->from, read p->reg, write p->to */
+		arm64.ASUB,
+		arm64.AAND,
+		arm64.AORR,
+		arm64.AEOR,
+		arm64.AMUL,
+		arm64.ASMULL,
+		arm64.AUMULL,
+		arm64.ASMULH,
+		arm64.AUMULH,
+		arm64.ASDIV,
+		arm64.AUDIV,
+		arm64.ALSL,
+		arm64.ALSR,
+		arm64.AASR,
+		arm64.AFADDD,
+		arm64.AFADDS,
+		arm64.AFSUBD,
+		arm64.AFSUBS,
+		arm64.AFMULD,
+		arm64.AFMULS,
+		arm64.AFDIVD,
+		arm64.AFDIVS:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			if copysub1(p, v, s, 1) != 0 {
+				return 1
+			}
+
+			// Update only indirect uses of v in p->to
+			if !copyas(&p.To, v) {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+			}
+			return 0
+		}
+
+		if copyas(&p.To, v) {
+			if p.Reg == 0 {
+				// Fix up implicit reg (e.g., ADD
+				// R3,R4 -> ADD R3,R4,R4) so we can
+				// update reg and to separately.
+				p.Reg = p.To.Reg
+			}
+
+			if copyau(&p.From, v) {
+				return 4
+			}
+			if copyau1(p, v) {
+				return 4
+			}
+			return 3
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case arm64.ABEQ,
+		arm64.ABNE,
+		arm64.ABGE,
+		arm64.ABLT,
+		arm64.ABGT,
+		arm64.ABLE,
+		arm64.ABLO,
+		arm64.ABLS,
+		arm64.ABHI,
+		arm64.ABHS:
+		return 0
+
+	case obj.ACHECKNIL, /* read p->from */
+		arm64.ACMP, /* read p->from, read p->reg */
+		arm64.AFCMPD,
+		arm64.AFCMPS:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			return copysub1(p, v, s, 1)
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		return 0
+
+	case arm64.AB: /* read p->to */
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case obj.ARET: /* funny */
+		if s != nil {
+			return 0
+		}
+
+		// All registers die at this point, so claim
+		// everything is set (and not used).
+		return 3
+
+	case arm64.ABL: /* funny */
+		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
+			return 2
+		}
+
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 4
+		}
+		return 3
+
+	// R31 is zero, used by DUFFZERO, cannot be substituted.
+	// R16 is ptr to memory, used and set, cannot be substituted.
+	case obj.ADUFFZERO:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == 31 {
+				return 1
+			}
+			if v.Reg == 16 {
+				return 2
+			}
+		}
+
+		return 0
+
+	// R16, R17 are ptr to src, dst, used and set, cannot be substituted.
+	// R27 is scratch, set by DUFFCOPY, cannot be substituted.
+	case obj.ADUFFCOPY:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == 16 || v.Reg == 17 {
+				return 2
+			}
+			if v.Reg == 27 {
+				return 3
+			}
+		}
+
+		return 0
+
+	case arm64.AHINT,
+		obj.ATEXT,
+		obj.APCDATA,
+		obj.AFUNCDATA,
+		obj.AVARDEF,
+		obj.AVARKILL:
+		return 0
+	}
+}
+
+// copyas returns 1 if a and v address the same register.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means this operation
+// writes the register in v.
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+	if regtyp(v) {
+		if a.Type == v.Type {
+			if a.Reg == v.Reg {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// copyau returns 1 if a either directly or indirectly addresses the
+// same register as v.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means the operation
+// either reads or writes the register in v (if !copyas(a, v), then
+// the operation reads the register in v).
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+	if copyas(a, v) {
+		return true
+	}
+	if v.Type == obj.TYPE_REG {
+		if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
+			if v.Reg == a.Reg {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// copyau1 returns 1 if p->reg references the same register as v and v
+// is a direct reference.
+func copyau1(p *obj.Prog, v *obj.Addr) bool {
+	if regtyp(v) && v.Reg != 0 {
+		if p.Reg == v.Reg {
+			return true
+		}
+	}
+	return false
+}
+
+// copysub replaces v with s in a if f!=0 or indicates it if could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on arm64).
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau(a, v) {
+			a.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
+// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on arm64).
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau1(p1, v) {
+			p1.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
 func sameaddr(a *obj.Addr, v *obj.Addr) bool {
 	if a.Type != v.Type {
 		return false
diff --git a/src/cmd/7g/prog.go b/src/cmd/7g/prog.go
index 4afb29b..023f302 100644
--- a/src/cmd/7g/prog.go
+++ b/src/cmd/7g/prog.go
@@ -57,21 +57,22 @@
 	arm64.ALSL:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
 	arm64.ALSR:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
 	arm64.AASR:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.ACMP:   {gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm64.ACMP:   {gc.SizeQ | gc.LeftRead | gc.RegRead, 0, 0, 0},
 
 	// Floating point.
-	arm64.AFADDD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFADDS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFSUBD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFSUBS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFNEGD: {gc.SizeD | gc.LeftRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFNEGS: {gc.SizeF | gc.LeftRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFMULD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFMULS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFDIVD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFDIVS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm64.AFCMPD: {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm64.AFCMPS: {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm64.AFADDD:  {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFADDS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFSUBD:  {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFSUBS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFNEGD:  {gc.SizeD | gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFNEGS:  {gc.SizeF | gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFSQRTD: {gc.SizeD | gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFMULD:  {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFMULS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFDIVD:  {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFDIVS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFCMPD:  {gc.SizeD | gc.LeftRead | gc.RegRead, 0, 0, 0},
+	arm64.AFCMPS:  {gc.SizeF | gc.LeftRead | gc.RegRead, 0, 0, 0},
 
 	// float -> integer
 	arm64.AFCVTZSD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
@@ -121,6 +122,8 @@
 	arm64.ABLS:    {gc.Cjmp, 0, 0, 0},
 	arm64.ABHI:    {gc.Cjmp, 0, 0, 0},
 	arm64.ABHS:    {gc.Cjmp, 0, 0, 0},
+	arm64.ACBZ:    {gc.Cjmp, 0, 0, 0},
+	arm64.ACBNZ:   {gc.Cjmp, 0, 0, 0},
 	obj.ARET:      {gc.Break, 0, 0, 0},
 	obj.ADUFFZERO: {gc.Call, 0, 0, 0},
 	obj.ADUFFCOPY: {gc.Call, 0, 0, 0},
diff --git a/src/cmd/7g/reg.go b/src/cmd/7g/reg.go
index c8035f5..0e5ac73 100644
--- a/src/cmd/7g/reg.go
+++ b/src/cmd/7g/reg.go
@@ -39,6 +39,8 @@
 	NREGVAR = 64 /* 32 general + 32 floating */
 )
 
+var reg [arm64.NREG + arm64.NFREG]uint8
+
 var regname = []string{
 	".R0",
 	".R1",
@@ -115,6 +117,11 @@
 	// Exclude registers with fixed functions
 	regbits := uint64(RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REGPR))
 
+	// Exclude R26 - R31.
+	for r := arm64.REGMAX + 1; r <= arm64.REGZERO; r++ {
+		regbits |= RtoB(r)
+	}
+
 	// Also exclude floating point registers with fixed constants
 	regbits |= RtoB(arm64.REG_F27) | RtoB(arm64.REG_F28) | RtoB(arm64.REG_F29) | RtoB(arm64.REG_F30) | RtoB(arm64.REG_F31)
 
diff --git a/src/cmd/7g/util.go b/src/cmd/7g/util.go
deleted file mode 100644
index bb5eedb..0000000
--- a/src/cmd/7g/util.go
+++ /dev/null
@@ -1,12 +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 main
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/7l/asm.go b/src/cmd/7l/asm.go
index d597ace..a17899d 100644
--- a/src/cmd/7l/asm.go
+++ b/src/cmd/7l/asm.go
@@ -33,6 +33,7 @@
 import (
 	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"encoding/binary"
 	"fmt"
 	"log"
 )
@@ -66,8 +67,40 @@
 }
 
 func elfreloc1(r *ld.Reloc, sectoff int64) int {
-	// TODO(minux)
-	return -1
+	ld.Thearch.Vput(uint64(sectoff))
+
+	elfsym := r.Xsym.Elfsym
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		switch r.Siz {
+		case 4:
+			ld.Thearch.Vput(ld.R_AARCH64_ABS32 | uint64(elfsym)<<32)
+		case 8:
+			ld.Thearch.Vput(ld.R_AARCH64_ABS64 | uint64(elfsym)<<32)
+		default:
+			return -1
+		}
+
+	case obj.R_ADDRARM64:
+		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
+		ld.Thearch.Vput(ld.R_AARCH64_ADR_PREL_PG_HI21 | uint64(elfsym)<<32)
+		ld.Thearch.Vput(uint64(r.Xadd))
+		ld.Thearch.Vput(uint64(sectoff + 4))
+		ld.Thearch.Vput(ld.R_AARCH64_ADD_ABS_LO12_NC | uint64(elfsym)<<32)
+
+	case obj.R_CALLARM64:
+		if r.Siz != 4 {
+			return -1
+		}
+		ld.Thearch.Vput(ld.R_AARCH64_CALL26 | uint64(elfsym)<<32)
+
+	}
+	ld.Thearch.Vput(uint64(r.Xadd))
+
+	return 0
 }
 
 func elfsetupplt() {
@@ -76,25 +109,178 @@
 }
 
 func machoreloc1(r *ld.Reloc, sectoff int64) int {
-	return -1
+	var v uint32
+
+	rs := r.Xsym
+
+	// ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
+	// see cmd/internal/ld/data.go for details. The workarond is that don't use !extern
+	// UNSIGNED relocation at all.
+	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM64 || r.Type == obj.R_ADDRARM64 || r.Type == obj.R_ADDR {
+		if rs.Dynid < 0 {
+			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+			return -1
+		}
+
+		v = uint32(rs.Dynid)
+		v |= 1 << 27 // external relocation
+	} else {
+		v = uint32((rs.Sect.(*ld.Section)).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)
+			return -1
+		}
+	}
+
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
+
+	case obj.R_CALLARM64:
+		if r.Xadd != 0 {
+			ld.Diag("ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
+		}
+
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
+
+	case obj.R_ADDRARM64:
+		r.Siz = 4
+		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
+		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
+		if r.Xadd != 0 {
+			ld.Thearch.Lput(uint32(sectoff + 4))
+			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+		}
+		ld.Thearch.Lput(uint32(sectoff + 4))
+		ld.Thearch.Lput(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
+		if r.Xadd != 0 {
+			ld.Thearch.Lput(uint32(sectoff))
+			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+		}
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
+	}
+
+	switch r.Siz {
+	default:
+		return -1
+
+	case 1:
+		v |= 0 << 25
+
+	case 2:
+		v |= 1 << 25
+
+	case 4:
+		v |= 2 << 25
+
+	case 8:
+		v |= 3 << 25
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(v)
+	return 0
 }
 
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 	if ld.Linkmode == ld.LinkExternal {
-		// TODO(minux): translate R_CALLARM64 into standard ELF relocation.
-		return -1
+		switch r.Type {
+		default:
+			return -1
+
+		case obj.R_ADDRARM64:
+			r.Done = 0
+
+			// set up addend for eventual relocation via outer symbol.
+			rs := r.Sym
+			r.Xadd = r.Add
+			for rs.Outer != nil {
+				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
+				rs = rs.Outer
+			}
+
+			if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
+				ld.Diag("missing section for %s", rs.Name)
+			}
+			r.Xsym = rs
+
+			// the first instruction is always at the lower address, this is endian neutral;
+			// but note that o0 and o1 should still use the target endian.
+			o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
+			o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])
+
+			// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
+			// will make the linking fail because it thinks the code is not PIC even though
+			// the BR26 relocation should be fully resolved at link time.
+			// That is the reason why the next if block is disabled. When the bug in ld64
+			// is fixed, we can enable this block and also enable duff's device in cmd/7g.
+			if false && ld.HEADTYPE == obj.Hdarwin {
+				// Mach-O wants the addend to be encoded in the instruction
+				// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
+				// can only encode 24-bit of signed addend, but the instructions
+				// supports 33-bit of signed addend, so we always encode the
+				// addend in place.
+				o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5)
+				o1 |= uint32(r.Xadd&0xfff) << 10
+				r.Xadd = 0
+			}
+
+			// when laid out, the instruction order must always be o1, o2.
+			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+				*val = int64(o0)<<32 | int64(o1)
+			} else {
+				*val = int64(o1)<<32 | int64(o0)
+			}
+
+			return 0
+
+		case obj.R_CALLARM64:
+			r.Done = 0
+			r.Xsym = r.Sym
+			*val = int64(0xfc000000 & uint32(r.Add))
+			r.Xadd = int64((uint32(r.Add) &^ 0xfc000000) * 4)
+			r.Add = 0
+			return 0
+		}
 	}
 
 	switch r.Type {
-	case ld.R_CONST:
+	case obj.R_CONST:
 		*val = r.Add
 		return 0
 
-	case ld.R_GOTOFF:
+	case obj.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
 		return 0
 
-	case ld.R_CALLARM64:
+	case obj.R_ADDRARM64:
+		t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
+		if t >= 1<<32 || t < -1<<32 {
+			ld.Diag("program too large, address relocation distance = %d", t)
+		}
+
+		// the first instruction is always at the lower address, this is endian neutral;
+		// but note that o0 and o1 should still use the target endian.
+		o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
+		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])
+
+		o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
+		o1 |= uint32(t&0xfff) << 10
+
+		// when laid out, the instruction order must always be o1, o2.
+		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+			*val = int64(o0)<<32 | int64(o1)
+		} else {
+			*val = int64(o1)<<32 | int64(o0)
+		}
+		return 0
+
+	case obj.R_CALLARM64:
 		*val = int64((0xfc000000 & uint32(r.Add)) | uint32((ld.Symaddr(r.Sym)+r.Add*4-(s.Value+int64(r.Off)))/4))
 		return 0
 	}
@@ -108,7 +294,7 @@
 }
 
 func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	log.Fatalf("adddynsym not implemented")
+	// TODO(minux): implement when needed.
 }
 
 func adddynlib(lib string) {
@@ -122,6 +308,8 @@
 			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")
 	}
@@ -131,7 +319,7 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
@@ -149,7 +337,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
@@ -158,11 +346,29 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
+	machlink := uint32(0)
+	if ld.HEADTYPE == obj.Hdarwin {
+		if ld.Debug['v'] != 0 {
+			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))
+
+			ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+			ld.Dwarfemitdebugsections()
+			ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+		}
+
+		machlink = uint32(ld.Domacholink())
+	}
+
 	/* output symbol table */
 	ld.Symsize = 0
 
@@ -173,7 +379,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 		switch ld.HEADTYPE {
 		default:
 			if ld.Iself {
@@ -181,8 +387,11 @@
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			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))
 		}
 
 		ld.Cseek(int64(symo))
@@ -206,7 +415,7 @@
 				}
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			ld.Asmplan9sym()
 			ld.Cflush()
 
@@ -219,6 +428,11 @@
 
 				ld.Cflush()
 			}
+
+		case obj.Hdarwin:
+			if ld.Linkmode == ld.LinkExternal {
+				ld.Machoemitreloc()
+			}
 		}
 	}
 
@@ -226,11 +440,11 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 	ld.Cseek(0)
 	switch ld.HEADTYPE {
 	default:
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.Thearch.Lput(0x647)                      /* magic */
 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
@@ -240,12 +454,15 @@
 		ld.Thearch.Lput(0)
 		ld.Thearch.Lput(uint32(ld.Lcsize))
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hnacl:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
 		ld.Asmbelf(int64(symo))
+
+	case obj.Hdarwin:
+		ld.Asmbmacho()
 	}
 
 	ld.Cflush()
diff --git a/src/cmd/7l/obj.go b/src/cmd/7l/obj.go
index 3fa70f2..f8ac7d3 100644
--- a/src/cmd/7l/obj.go
+++ b/src/cmd/7l/obj.go
@@ -88,6 +88,11 @@
 		ld.Linkmode = ld.LinkInternal
 	}
 
+	// Darwin/arm64 only supports external linking
+	if ld.HEADTYPE == obj.Hdarwin {
+		ld.Linkmode = ld.LinkExternal
+	}
+
 	switch ld.HEADTYPE {
 	default:
 		if ld.Linkmode == ld.LinkAuto {
@@ -96,15 +101,15 @@
 		if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
 			log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
 		}
+	case obj.Hlinux, obj.Hdarwin:
+		break
 	}
 
 	switch ld.HEADTYPE {
 	default:
-		ld.Diag("unknown -H option")
-		ld.Errorexit()
-		fallthrough
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
 
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if ld.INITTEXT == -1 {
@@ -117,8 +122,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hlinux: /* ppc64 elf */
-		ld.Debug['d'] = 1 // TODO(aram): dynamic linking is not supported yet.
+	case obj.Hlinux: /* arm64 elf */
 		ld.Elfinit()
 		ld.HEADR = ld.ELFRESERVE
 		if ld.INITTEXT == -1 {
@@ -131,7 +135,21 @@
 			ld.INITRND = 0x10000
 		}
 
-	case ld.Hnacl:
+	case obj.Hdarwin: /* apple MACH */
+		ld.Debug['w'] = 1 // disable DWARF generation
+		ld.Machoinit()
+		ld.HEADR = ld.INITIAL_MACHO_HEADR
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4096 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.Hnacl:
 		ld.Elfinit()
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go
index 5546aba3..dfbdafe 100644
--- a/src/cmd/8g/cgen.go
+++ b/src/cmd/8g/cgen.go
@@ -17,7 +17,7 @@
  */
 func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
 	if !gc.Is64(n.Type) {
-		if n.Addable != 0 {
+		if n.Addable {
 			// nothing to do.
 			*res = *n
 		} else {
@@ -48,7 +48,7 @@
 	return gc.Gbranch(x86.AJNE, nil, +1)
 }
 
-func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	var dst gc.Node
 	gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
 	var src gc.Node
@@ -58,13 +58,13 @@
 	gc.Tempname(&tsrc, gc.Types[gc.Tptr])
 	var tdst gc.Node
 	gc.Tempname(&tdst, gc.Types[gc.Tptr])
-	if n.Addable == 0 {
+	if !n.Addable {
 		gc.Agen(n, &tsrc)
 	}
-	if res.Addable == 0 {
+	if !res.Addable {
 		gc.Agen(res, &tdst)
 	}
-	if n.Addable != 0 {
+	if n.Addable {
 		gc.Agen(n, &src)
 	} else {
 		gmove(&tsrc, &src)
@@ -74,7 +74,7 @@
 		gc.Gvardef(res)
 	}
 
-	if res.Addable != 0 {
+	if res.Addable {
 		gc.Agen(res, &dst)
 	} else {
 		gmove(&tdst, &dst)
diff --git a/src/cmd/8g/cgen64.go b/src/cmd/8g/cgen64.go
index ee04bdb..a682e2f 100644
--- a/src/cmd/8g/cgen64.go
+++ b/src/cmd/8g/cgen64.go
@@ -63,14 +63,14 @@
 
 	l := n.Left
 	r := n.Right
-	if l.Addable == 0 {
+	if !l.Addable {
 		var t1 gc.Node
 		gc.Tempname(&t1, l.Type)
 		gc.Cgen(l, &t1)
 		l = &t1
 	}
 
-	if r != nil && r.Addable == 0 {
+	if r != nil && !r.Addable {
 		var t2 gc.Node
 		gc.Tempname(&t2, r.Type)
 		gc.Cgen(r, &t2)
@@ -532,7 +532,7 @@
 	var br *obj.Prog
 	switch op {
 	default:
-		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t)
 
 		// cmp hi
 	// jne L
diff --git a/src/cmd/8g/galign.go b/src/cmd/8g/galign.go
index e92802d..e96b628 100644
--- a/src/cmd/8g/galign.go
+++ b/src/cmd/8g/galign.go
@@ -8,6 +8,8 @@
 	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
+	"fmt"
+	"os"
 )
 
 var thechar int = '8'
@@ -23,7 +25,7 @@
 
 /*
  * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
+ * int, uint, and uintptr
  */
 var typedefs = []gc.Typedef{
 	gc.Typedef{"int", gc.TINT, gc.TINT32},
@@ -35,7 +37,6 @@
 	gc.Widthptr = 4
 	gc.Widthint = 4
 	gc.Widthreg = 4
-
 }
 
 func main() {
@@ -54,11 +55,13 @@
 	case "387":
 		gc.Thearch.FREGMIN = x86.REG_F0
 		gc.Thearch.FREGMAX = x86.REG_F7
+		gc.Thearch.Use387 = true
 	case "sse2":
 		gc.Thearch.FREGMIN = x86.REG_X0
 		gc.Thearch.FREGMAX = x86.REG_X7
 	default:
-		gc.Fatal("unsupported setting GO386=%s", v)
+		fmt.Fprintf(os.Stderr, "unsupported setting GO386=%s\n", v)
+		gc.Exit(1)
 	}
 	gc.Thearch.MAXWIDTH = MAXWIDTH
 	gc.Thearch.ReservedRegs = resvd
@@ -76,6 +79,7 @@
 	gc.Thearch.Dodiv = cgen_div
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
+	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
@@ -88,7 +92,7 @@
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
-	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Blockcopy = blockcopy
 	gc.Thearch.Sudoaddable = sudoaddable
 	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
diff --git a/src/cmd/8g/gg.go b/src/cmd/8g/gg.go
deleted file mode 100644
index bfbd12e..0000000
--- a/src/cmd/8g/gg.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "cmd/internal/obj/x86"
-import "cmd/internal/gc"
-
-// TODO(rsc):
-//	assume CLD?
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// foptoas flags
-const (
-	Frev  = 1 << 0
-	Fpop  = 1 << 1
-	Fpop2 = 1 << 2
-)
-
-var reg [x86.MAXREG]uint8
-
-var panicdiv *gc.Node
-
-/*
- * cgen.c
- */
-
-/*
- * list.c
- */
diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go
index 949156e..5902552 100644
--- a/src/cmd/8g/ggen.go
+++ b/src/cmd/8g/ggen.go
@@ -189,6 +189,8 @@
 	}
 }
 
+var panicdiv *gc.Node
+
 /*
  * generate division.
  * caller must set:
@@ -348,7 +350,7 @@
  */
 func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	if gc.Is64(nl.Type) {
-		gc.Fatal("cgen_div %v", gc.Tconv(nl.Type, 0))
+		gc.Fatal("cgen_div %v", nl.Type)
 	}
 
 	var t *gc.Type
@@ -375,7 +377,7 @@
  */
 func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	if nl.Type.Width > 4 {
-		gc.Fatal("cgen_shift %v", gc.Tconv(nl.Type, 0))
+		gc.Fatal("cgen_shift %v", nl.Type)
 	}
 
 	w := int(nl.Type.Width * 8)
@@ -617,10 +619,10 @@
 		return
 	}
 
-	if gc.Use_sse {
-		cgen_floatsse(n, res)
-	} else {
+	if gc.Thearch.Use387 {
 		cgen_float387(n, res)
+	} else {
+		cgen_floatsse(n, res)
 	}
 }
 
@@ -637,7 +639,7 @@
 		// binary
 		if nl.Ullman >= nr.Ullman {
 			gc.Cgen(nl, &f0)
-			if nr.Addable != 0 {
+			if nr.Addable {
 				gins(foptoas(int(n.Op), n.Type, 0), nr, &f0)
 			} else {
 				gc.Cgen(nr, &f0)
@@ -645,7 +647,7 @@
 			}
 		} else {
 			gc.Cgen(nr, &f0)
-			if nl.Addable != 0 {
+			if nl.Addable {
 				gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0)
 			} else {
 				gc.Cgen(nl, &f0)
@@ -738,42 +740,74 @@
 	return
 }
 
-func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) {
+func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
 	nl := n.Left
 	nr := n.Right
 	a := int(n.Op)
-	if true_ == 0 {
+	if !wantTrue {
 		// brcom is not valid on floats when NaN is involved.
 		p1 := gc.Gbranch(obj.AJMP, nil, 0)
-
 		p2 := gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p1, gc.Pc)
 
 		// No need to avoid re-genning ninit.
-		bgen_float(n, 1, -likely, p2)
+		bgen_float(n, true, -likely, p2)
 
 		gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
 		gc.Patch(p2, gc.Pc)
 		return
 	}
 
-	var tmp gc.Node
-	var et int
-	var n2 gc.Node
-	var ax gc.Node
-	if gc.Use_sse {
-		if nl.Addable == 0 {
-			var n1 gc.Node
-			gc.Tempname(&n1, nl.Type)
-			gc.Cgen(nl, &n1)
-			nl = &n1
+	if gc.Thearch.Use387 {
+		a = gc.Brrev(a) // because the args are stacked
+		if a == gc.OGE || a == gc.OGT {
+			// only < and <= work right with NaN; reverse if needed
+			nl, nr = nr, nl
+			a = gc.Brrev(a)
 		}
 
-		if nr.Addable == 0 {
-			var tmp gc.Node
-			gc.Tempname(&tmp, nr.Type)
-			gc.Cgen(nr, &tmp)
-			nr = &tmp
+		var ax, n2, tmp gc.Node
+		gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
+		gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
+		gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
+		if gc.Simsimtype(nr.Type) == gc.TFLOAT64 {
+			if nl.Ullman > nr.Ullman {
+				gc.Cgen(nl, &tmp)
+				gc.Cgen(nr, &tmp)
+				gins(x86.AFXCHD, &tmp, &n2)
+			} else {
+				gc.Cgen(nr, &tmp)
+				gc.Cgen(nl, &tmp)
+			}
+
+			gins(x86.AFUCOMIP, &tmp, &n2)
+			gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
+		} else {
+			// TODO(rsc): The moves back and forth to memory
+			// here are for truncating the value to 32 bits.
+			// This handles 32-bit comparison but presumably
+			// all the other ops have the same problem.
+			// We need to figure out what the right general
+			// solution is, besides telling people to use float64.
+			var t1 gc.Node
+			gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
+
+			var t2 gc.Node
+			gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
+			gc.Cgen(nr, &t1)
+			gc.Cgen(nl, &t2)
+			gmove(&t2, &tmp)
+			gins(x86.AFCOMFP, &t1, &tmp)
+			gins(x86.AFSTSW, nil, &ax)
+			gins(x86.ASAHF, nil, nil)
+		}
+	} else {
+		// Not 387
+		if !nl.Addable {
+			nl = gc.CgenTemp(nl)
+		}
+		if !nr.Addable {
+			nr = gc.CgenTemp(nr)
 		}
 
 		var n2 gc.Node
@@ -790,10 +824,7 @@
 
 		if a == gc.OGE || a == gc.OGT {
 			// only < and <= work right with NaN; reverse if needed
-			r := nr
-
-			nr = nl
-			nl = r
+			nl, nr = nr, nl
 			a = gc.Brrev(a)
 		}
 
@@ -802,75 +833,21 @@
 			gc.Regfree(nl)
 		}
 		gc.Regfree(nr)
-		goto ret
-	} else {
-		goto x87
 	}
 
-x87:
-	a = gc.Brrev(a) // because the args are stacked
-	if a == gc.OGE || a == gc.OGT {
-		// only < and <= work right with NaN; reverse if needed
-		r := nr
-
-		nr = nl
-		nl = r
-		a = gc.Brrev(a)
-	}
-
-	gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
-	gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
-	gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
-	et = gc.Simsimtype(nr.Type)
-	if et == gc.TFLOAT64 {
-		if nl.Ullman > nr.Ullman {
-			gc.Cgen(nl, &tmp)
-			gc.Cgen(nr, &tmp)
-			gins(x86.AFXCHD, &tmp, &n2)
-		} else {
-			gc.Cgen(nr, &tmp)
-			gc.Cgen(nl, &tmp)
-		}
-
-		gins(x86.AFUCOMIP, &tmp, &n2)
-		gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
-	} else {
-		// TODO(rsc): The moves back and forth to memory
-		// here are for truncating the value to 32 bits.
-		// This handles 32-bit comparison but presumably
-		// all the other ops have the same problem.
-		// We need to figure out what the right general
-		// solution is, besides telling people to use float64.
-		var t1 gc.Node
-		gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
-
-		var t2 gc.Node
-		gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
-		gc.Cgen(nr, &t1)
-		gc.Cgen(nl, &t2)
-		gmove(&t2, &tmp)
-		gins(x86.AFCOMFP, &t1, &tmp)
-		gins(x86.AFSTSW, nil, &ax)
-		gins(x86.ASAHF, nil, nil)
-	}
-
-	goto ret
-
-ret:
-	if a == gc.OEQ {
+	switch a {
+	case gc.OEQ:
 		// neither NE nor P
 		p1 := gc.Gbranch(x86.AJNE, nil, -likely)
-
 		p2 := gc.Gbranch(x86.AJPS, nil, -likely)
 		gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
 		gc.Patch(p1, gc.Pc)
 		gc.Patch(p2, gc.Pc)
-	} else if a == gc.ONE {
+	case gc.ONE:
 		// either NE or P
 		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
-
 		gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
-	} else {
+	default:
 		gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to)
 	}
 }
@@ -944,3 +921,20 @@
 	}
 	return false
 }
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Regalloc(&n1, res.Type, res)
+	mov := optoas(gc.OAS, gc.Types[gc.Tptr])
+	p := gins(mov, nil, &n1)
+	p.From.Type = obj.TYPE_REG
+	p.From.Reg = x86.REG_TLS
+	p = gins(mov, nil, &n1)
+	p.From = p.To
+	p.From.Type = obj.TYPE_MEM
+	p.From.Index = x86.REG_TLS
+	p.From.Scale = 1
+	gmove(&n1, res)
+	gc.Regfree(&n1)
+}
diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go
index 7ca4dac..34ddfe0 100644
--- a/src/cmd/8g/gsubr.go
+++ b/src/cmd/8g/gsubr.go
@@ -42,6 +42,13 @@
 // At the same time, can raise StackBig in ../../runtime/stack.h.
 var unmappedzero uint32 = 4096
 
+// foptoas flags
+const (
+	Frev  = 1 << 0
+	Fpop  = 1 << 1
+	Fpop2 = 1 << 2
+)
+
 /*
  * return Axxx for Oxxx on type t.
  */
@@ -53,7 +60,7 @@
 	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t)
 
 	case gc.OADDR<<16 | gc.TPTR32:
 		a = x86.ALEAL
@@ -402,10 +409,10 @@
 	a := obj.AXXX
 	et := int(gc.Simtype[t.Etype])
 
-	if gc.Use_sse {
+	if !gc.Thearch.Use387 {
 		switch uint32(op)<<16 | uint32(et) {
 		default:
-			gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+			gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), t)
 
 		case gc.OCMP<<16 | gc.TFLOAT32:
 			a = x86.AUCOMISS
@@ -538,7 +545,7 @@
 		return x86.AFCHS
 	}
 
-	gc.Fatal("foptoas %v %v %#x", gc.Oconv(int(op), 0), gc.Tconv(t, 0), flg)
+	gc.Fatal("foptoas %v %v %#x", gc.Oconv(int(op), 0), t, flg)
 	return 0
 }
 
@@ -608,7 +615,7 @@
  */
 func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 	if !gc.Is64(n.Type) {
-		gc.Fatal("split64 %v", gc.Tconv(n.Type, 0))
+		gc.Fatal("split64 %v", n.Type)
 	}
 
 	if nsclean >= len(sclean) {
@@ -715,7 +722,7 @@
 
 func gmove(f *gc.Node, t *gc.Node) {
 	if gc.Debug['M'] != 0 {
-		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		fmt.Printf("gmove %v -> %v\n", f, t)
 	}
 
 	ft := gc.Simsimtype(f.Type)
@@ -758,7 +765,7 @@
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
 		// should not happen
-		gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		gc.Fatal("gmove %v -> %v", f, t)
 		return
 
 		/*
@@ -1036,10 +1043,10 @@
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		if gc.Use_sse {
-			floatmove_sse(f, t)
-		} else {
+		if gc.Thearch.Use387 {
 			floatmove_387(f, t)
+		} else {
+			floatmove_sse(f, t)
 		}
 		return
 
@@ -1322,7 +1329,7 @@
 		gmove(f, &t1)
 		switch tt {
 		default:
-			gc.Fatal("gmove %v", gc.Nconv(t, 0))
+			gc.Fatal("gmove %v", t)
 
 		case gc.TINT8:
 			gins(x86.ACMPL, &t1, ncon(-0x80&(1<<32-1)))
@@ -1421,7 +1428,7 @@
 			goto hard
 		}
 		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
-			if f.Val.U.Reg != x86.REG_F0 || t.Val.U.Reg != x86.REG_F0 {
+			if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
 				goto fatal
 			}
 			return
@@ -1432,8 +1439,8 @@
 			a = x86.AFMOVD
 		}
 		if gc.Ismem(t) {
-			if f.Op != gc.OREGISTER || f.Val.U.Reg != x86.REG_F0 {
-				gc.Fatal("gmove %v", gc.Nconv(f, 0))
+			if f.Op != gc.OREGISTER || f.Reg != x86.REG_F0 {
+				gc.Fatal("gmove %v", f)
 			}
 			a = x86.AFMOVFP
 			if ft == gc.TFLOAT64 {
@@ -1446,7 +1453,7 @@
 			goto hard
 		}
 		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
-			if f.Val.U.Reg != x86.REG_F0 || t.Val.U.Reg != x86.REG_F0 {
+			if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
 				goto fatal
 			}
 			return
@@ -1517,7 +1524,7 @@
 	switch uint32(ft)<<16 | uint32(tt) {
 	// should not happen
 	default:
-		gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		gc.Fatal("gmove %v -> %v", f, t)
 
 		return
 
@@ -1638,7 +1645,7 @@
 
 	switch f.Op {
 	case gc.OREGISTER:
-		if f.Val.U.Reg != t.Val.U.Reg {
+		if f.Reg != t.Reg {
 			break
 		}
 		return true
@@ -1658,7 +1665,7 @@
 	if as == x86.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL {
 		gc.Fatal("gins CVTSD2SS const")
 	}
-	if as == x86.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Val.U.Reg == x86.REG_F0 {
+	if as == x86.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Reg == x86.REG_F0 {
 		gc.Fatal("gins MOVSD into F0")
 	}
 
@@ -1681,7 +1688,7 @@
 
 	case x86.ALEAL:
 		if f != nil && gc.Isconst(f, gc.CTNIL) {
-			gc.Fatal("gins LEAL nil %v", gc.Tconv(f.Type, 0))
+			gc.Fatal("gins LEAL nil %v", f.Type)
 		}
 	}
 
@@ -1732,7 +1739,7 @@
 	var oary [10]int64
 	var nn *gc.Node
 	o := gc.Dotoffset(n, oary[:], &nn)
-	if nn != nil && nn.Addable != 0 && o == 1 && oary[0] >= 0 {
+	if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
 		*n1 = *nn
 		n1.Type = n.Type
 		n1.Xoffset += oary[0]
diff --git a/src/cmd/8g/reg.go b/src/cmd/8g/reg.go
index 9f2cb60..50b5b97 100644
--- a/src/cmd/8g/reg.go
+++ b/src/cmd/8g/reg.go
@@ -37,6 +37,8 @@
 	NREGVAR = 16 /* 8 integer + 8 floating */
 )
 
+var reg [x86.MAXREG]uint8
+
 var regname = []string{
 	".ax",
 	".cx",
diff --git a/src/cmd/8g/util.go b/src/cmd/8g/util.go
deleted file mode 100644
index bb5eedb..0000000
--- a/src/cmd/8g/util.go
+++ /dev/null
@@ -1,12 +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 main
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/8l/asm.go b/src/cmd/8l/asm.go
index 49ff080..7231379 100644
--- a/src/cmd/8l/asm.go
+++ b/src/cmd/8l/asm.go
@@ -75,20 +75,20 @@
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_386_PC32:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
 		}
-		if targ.Type == 0 || targ.Type == ld.SXREF {
+		if targ.Type == 0 || targ.Type == obj.SXREF {
 			ld.Diag("unknown symbol %s in pcrel", targ.Name)
 		}
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Add += 4
 		return
 
 	case 256 + ld.R_386_PLT32:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Add += 4
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(ld.Ctxt, targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add += int64(targ.Plt)
@@ -97,13 +97,13 @@
 		return
 
 	case 256 + ld.R_386_GOT32:
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			// have symbol
 			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
 				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
 				s.P[r.Off-2] = 0x8d
 
-				r.Type = ld.R_GOTOFF
+				r.Type = obj.R_GOTOFF
 				return
 			}
 
@@ -113,7 +113,7 @@
 				s.P[r.Off-2] = 0x36
 
 				s.P[r.Off-1] = 0x68
-				r.Type = ld.R_ADDR
+				r.Type = obj.R_ADDR
 				return
 			}
 
@@ -122,49 +122,49 @@
 		}
 
 		addgotsym(ld.Ctxt, targ)
-		r.Type = ld.R_CONST // write r->add during relocsym
+		r.Type = obj.R_CONST // write r->add during relocsym
 		r.Sym = nil
 		r.Add += int64(targ.Got)
 		return
 
 	case 256 + ld.R_386_GOTOFF:
-		r.Type = ld.R_GOTOFF
+		r.Type = obj.R_GOTOFF
 		return
 
 	case 256 + ld.R_386_GOTPC:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
 		r.Add += 4
 		return
 
 	case 256 + ld.R_386_32:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
 		}
-		r.Type = ld.R_ADDR
+		r.Type = obj.R_ADDR
 		return
 
 	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
-		r.Type = ld.R_ADDR
-		if targ.Type == ld.SDYNIMPORT {
+		r.Type = obj.R_ADDR
+		if targ.Type == obj.SDYNIMPORT {
 			ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
 		}
 		return
 
 	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			addpltsym(ld.Ctxt, targ)
 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 			r.Add = int64(targ.Plt)
-			r.Type = ld.R_PCREL
+			r.Type = obj.R_PCREL
 			return
 		}
 
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		return
 
 	case 512 + ld.MACHO_FAKE_GOTPCREL:
-		if targ.Type != ld.SDYNIMPORT {
+		if targ.Type != obj.SDYNIMPORT {
 			// have symbol
 			// turn MOVL of GOT entry into LEAL of symbol itself
 			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
@@ -173,32 +173,32 @@
 			}
 
 			s.P[r.Off-2] = 0x8d
-			r.Type = ld.R_PCREL
+			r.Type = obj.R_PCREL
 			return
 		}
 
 		addgotsym(ld.Ctxt, targ)
 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
 		r.Add += int64(targ.Got)
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		return
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != ld.SDYNIMPORT {
+	if targ.Type != obj.SDYNIMPORT {
 		return
 	}
 
 	switch r.Type {
-	case ld.R_CALL,
-		ld.R_PCREL:
+	case obj.R_CALL,
+		obj.R_PCREL:
 		addpltsym(ld.Ctxt, targ)
 		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 		r.Add = int64(targ.Plt)
 		return
 
-	case ld.R_ADDR:
-		if s.Type != ld.SDATA {
+	case obj.R_ADDR:
+		if s.Type != obj.SDATA {
 			break
 		}
 		if ld.Iself {
@@ -206,12 +206,12 @@
 			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))
-			r.Type = ld.R_CONST // write r->add during relocsym
+			r.Type = obj.R_CONST // write r->add during relocsym
 			r.Sym = nil
 			return
 		}
 
-		if ld.HEADTYPE == ld.Hdarwin && s.Size == PtrSize && r.Off == 0 {
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 {
 			// Mach-O relocations are a royal pain to lay out.
 			// They use a compact stateful bytecode representation
 			// that is too much bother to deal with.
@@ -225,7 +225,7 @@
 			adddynsym(ld.Ctxt, targ)
 
 			got := ld.Linklookup(ld.Ctxt, ".got", 0)
-			s.Type = got.Type | ld.SSUB
+			s.Type = got.Type | obj.SSUB
 			s.Outer = got
 			s.Sub = got.Sub
 			got.Sub = s
@@ -236,7 +236,7 @@
 			return
 		}
 
-		if ld.HEADTYPE == ld.Hwindows && s.Size == PtrSize {
+		if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return
 		}
@@ -254,23 +254,22 @@
 	default:
 		return -1
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case ld.R_CALL,
-		ld.R_PCREL:
+	case obj.R_CALL,
+		obj.R_PCREL:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
 		} else {
 			return -1
 		}
 
-	case ld.R_TLS_LE,
-		ld.R_TLS_IE:
+	case obj.R_TLS_LE:
 		if r.Siz == 4 {
 			ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
 		} else {
@@ -286,7 +285,7 @@
 
 	rs := r.Xsym
 
-	if rs.Type == ld.SHOSTOBJ {
+	if rs.Type == obj.SHOSTOBJ {
 		if rs.Dynid < 0 {
 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
 			return -1
@@ -306,11 +305,11 @@
 	default:
 		return -1
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
 
-	case ld.R_CALL,
-		ld.R_PCREL:
+	case obj.R_CALL,
+		obj.R_PCREL:
 		v |= 1 << 24 // pc-relative bit
 		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
 	}
@@ -354,11 +353,11 @@
 	default:
 		return false
 
-	case ld.R_ADDR:
+	case obj.R_ADDR:
 		v = ld.IMAGE_REL_I386_DIR32
 
-	case ld.R_CALL,
-		ld.R_PCREL:
+	case obj.R_CALL,
+		obj.R_PCREL:
 		v = ld.IMAGE_REL_I386_REL32
 	}
 
@@ -372,11 +371,11 @@
 		return -1
 	}
 	switch r.Type {
-	case ld.R_CONST:
+	case obj.R_CONST:
 		*val = r.Add
 		return 0
 
-	case ld.R_GOTOFF:
+	case obj.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
 		return 0
 	}
@@ -456,7 +455,7 @@
 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
 
 		s.Plt = int32(plt.Size - 16)
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		// Same laziness as in 6l.
 
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -490,7 +489,7 @@
 		rel := ld.Linklookup(ctxt, ".rel", 0)
 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
 	} else {
 		ld.Diag("addgotsym: unsupported binary format")
@@ -514,7 +513,7 @@
 		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
 
 		/* value */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint32(ctxt, d, 0)
 		} else {
 			ld.Addaddr(ctxt, d, s)
@@ -526,7 +525,7 @@
 		/* type */
 		t := ld.STB_GLOBAL << 4
 
-		if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
+		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
 			t |= ld.STT_FUNC
 		} else {
 			t |= ld.STT_OBJECT
@@ -535,14 +534,14 @@
 		ld.Adduint8(ctxt, d, 0)
 
 		/* shndx */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
 		} else {
 			ld.Adduint16(ctxt, d, 1)
 		}
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
-	} else if ld.HEADTYPE == ld.Hwindows {
+	} else if ld.HEADTYPE == obj.Hwindows {
 	} else // already taken care of
 	{
 		ld.Diag("adddynsym: unsupported binary format")
@@ -560,9 +559,9 @@
 			ld.Addstring(s, "")
 		}
 		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == ld.Hdarwin {
+	} else if ld.HEADTYPE == obj.Hdarwin {
 		ld.Machoadddynlib(lib)
-	} else if ld.HEADTYPE != ld.Hwindows {
+	} else if ld.HEADTYPE != obj.Hwindows {
 		ld.Diag("adddynlib: unsupported binary format")
 	}
 }
@@ -571,7 +570,7 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
@@ -589,7 +588,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
@@ -598,13 +597,13 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
 	machlink := uint32(0)
-	if ld.HEADTYPE == ld.Hdarwin {
+	if ld.HEADTYPE == obj.Hdarwin {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
@@ -628,7 +627,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 		switch ld.HEADTYPE {
 		default:
 			if ld.Iself {
@@ -636,13 +635,13 @@
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
-		case ld.Hdarwin:
+		case obj.Hdarwin:
 			symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
 
-		case ld.Hwindows:
+		case obj.Hwindows:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 			symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
 		}
@@ -668,7 +667,7 @@
 				}
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			ld.Asmplan9sym()
 			ld.Cflush()
 
@@ -682,13 +681,13 @@
 				ld.Cflush()
 			}
 
-		case ld.Hwindows:
+		case obj.Hwindows:
 			if ld.Debug['v'] != 0 {
 				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 			}
 			ld.Dwarfemitdebugsections()
 
-		case ld.Hdarwin:
+		case obj.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc()
 			}
@@ -698,11 +697,11 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 	ld.Cseek(0)
 	switch ld.HEADTYPE {
 	default:
-	case ld.Hplan9: /* plan9 */
+	case obj.Hplan9: /* plan9 */
 		magic := int32(4*11*11 + 7)
 
 		ld.Lputb(uint32(magic))              /* magic */
@@ -714,17 +713,17 @@
 		ld.Lputb(uint32(ld.Spsize))       /* sp offsets */
 		ld.Lputb(uint32(ld.Lcsize))       /* line offsets */
 
-	case ld.Hdarwin:
+	case obj.Hdarwin:
 		ld.Asmbmacho()
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hnacl:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
 		ld.Asmbelf(int64(symo))
 
-	case ld.Hwindows:
+	case obj.Hwindows:
 		ld.Asmbpe()
 	}
 
diff --git a/src/cmd/8l/obj.go b/src/cmd/8l/obj.go
index 938a777..7b490ae 100644
--- a/src/cmd/8l/obj.go
+++ b/src/cmd/8l/obj.go
@@ -96,22 +96,20 @@
 			log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
 		}
 
-	case ld.Hdarwin,
-		ld.Hfreebsd,
-		ld.Hlinux,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hwindows:
+	case obj.Hdarwin,
+		obj.Hfreebsd,
+		obj.Hlinux,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hwindows:
 		break
 	}
 
 	switch ld.HEADTYPE {
 	default:
-		ld.Diag("unknown -H option")
-		ld.Errorexit()
-		fallthrough
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
 
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if ld.INITTEXT == -1 {
@@ -124,7 +122,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hdarwin: /* apple MACH */
+	case obj.Hdarwin: /* apple MACH */
 		ld.Machoinit()
 
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
@@ -138,10 +136,10 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hlinux, /* elf32 executable */
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd:
+	case obj.Hlinux, /* elf32 executable */
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd:
 		ld.Elfinit()
 
 		ld.HEADR = ld.ELFRESERVE
@@ -155,7 +153,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hnacl:
+	case obj.Hnacl:
 		ld.Elfinit()
 		ld.HEADR = 0x10000
 		ld.Funcalign = 32
@@ -169,7 +167,7 @@
 			ld.INITRND = 0x10000
 		}
 
-	case ld.Hwindows: /* PE executable */
+	case obj.Hwindows: /* PE executable */
 		ld.Peinit()
 
 		ld.HEADR = ld.PEFILEHEADR
diff --git a/src/cmd/9g/cgen.go b/src/cmd/9g/cgen.go
index 0f7fc07..5d24a6f 100644
--- a/src/cmd/9g/cgen.go
+++ b/src/cmd/9g/cgen.go
@@ -10,7 +10,7 @@
 	"cmd/internal/obj/ppc64"
 )
 
-func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
 	// smaller operations for less aligned types.
@@ -20,7 +20,7 @@
 	var op int
 	switch align {
 	default:
-		gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0))
+		gc.Fatal("sgen: invalid alignment %d for %v", align, n.Type)
 
 	case 1:
 		op = ppc64.AMOVBU
@@ -36,7 +36,7 @@
 	}
 
 	if w%int64(align) != 0 {
-		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0))
+		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
 	}
 	c := int32(w / int64(align))
 
diff --git a/src/cmd/9g/galign.go b/src/cmd/9g/galign.go
index b9e6c32..a2f4a0e 100644
--- a/src/cmd/9g/galign.go
+++ b/src/cmd/9g/galign.go
@@ -31,7 +31,7 @@
 
 /*
  * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
+ * int, uint, and uintptr
  */
 var typedefs = []gc.Typedef{
 	gc.Typedef{"int", gc.TINT, gc.TINT64},
@@ -43,7 +43,6 @@
 	gc.Widthptr = 8
 	gc.Widthint = 8
 	gc.Widthreg = 8
-
 }
 
 func main() {
@@ -71,6 +70,7 @@
 	gc.Thearch.Dodiv = dodiv
 	gc.Thearch.Excise = excise
 	gc.Thearch.Expandchecks = expandchecks
+	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
@@ -82,7 +82,7 @@
 	gc.Thearch.Sameaddr = sameaddr
 	gc.Thearch.Smallindir = smallindir
 	gc.Thearch.Stackaddr = stackaddr
-	gc.Thearch.Stackcopy = stackcopy
+	gc.Thearch.Blockcopy = blockcopy
 	gc.Thearch.Sudoaddable = sudoaddable
 	gc.Thearch.Sudoclean = sudoclean
 	gc.Thearch.Excludedregs = excludedregs
diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go
index a009186..28ebd9c 100644
--- a/src/cmd/9g/ggen.go
+++ b/src/cmd/9g/ggen.go
@@ -230,7 +230,7 @@
 		// TODO(minux): add gins3?
 		p1.Reg = p1.To.Reg
 
-		p1.To.Reg = tm.Val.U.Reg
+		p1.To.Reg = tm.Reg
 		gins(optoas(gc.OMUL, t), &tr, &tm)
 		gc.Regfree(&tr)
 		gins(optoas(gc.OSUB, t), &tm, &tl)
@@ -288,7 +288,7 @@
 		}
 
 	default:
-		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
+		gc.Fatal("cgen_hmul %v", t)
 	}
 
 	gc.Cgen(&n1, res)
@@ -394,7 +394,7 @@
 func clearfat(nl *gc.Node) {
 	/* clear a fat object */
 	if gc.Debug['g'] != 0 {
-		fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width)
+		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
 	}
 
 	w := uint64(uint64(nl.Type.Width))
@@ -549,3 +549,10 @@
 		p2.To.Offset = 0
 	}
 }
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, ppc64.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go
index 5a6fd29..8223fe7 100644
--- a/src/cmd/9g/gsubr.go
+++ b/src/cmd/9g/gsubr.go
@@ -37,11 +37,6 @@
 	"fmt"
 )
 
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 6l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-var unmappedzero int64 = 4096
-
 var resvd = []int{
 	ppc64.REGZERO,
 	ppc64.REGSP, // reserved for SP
@@ -531,7 +526,7 @@
 	case gc.CTINT, gc.CTRUNE:
 		return gc.Mpgetfix(n.Val.U.Xval), true
 	case gc.CTBOOL:
-		return int64(n.Val.U.Bval), true
+		return int64(obj.Bool2int(n.Val.U.Bval)), true
 	}
 	return
 }
@@ -643,31 +638,6 @@
 	return p
 }
 
-func fixlargeoffset(n *gc.Node) {
-	if n == nil {
-		return
-	}
-	if n.Op != gc.OINDREG {
-		return
-	}
-	if n.Val.U.Reg == ppc64.REGSP { // stack offset cannot be large
-		return
-	}
-	if n.Xoffset != int64(int32(n.Xoffset)) {
-		// TODO(minux): offset too large, move into R31 and add to R31 instead.
-		// this is used only in test/fixedbugs/issue6036.go.
-		gc.Fatal("offset too large: %v", gc.Nconv(n, 0))
-
-		a := gc.Node(*n)
-		a.Op = gc.OREGISTER
-		a.Type = gc.Types[gc.Tptr]
-		a.Xoffset = 0
-		gc.Cgen_checknil(&a)
-		ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a)
-		n.Xoffset = 0
-	}
-}
-
 /*
  * return Axxx for Oxxx on type t.
  */
@@ -679,7 +649,7 @@
 	a := int(obj.AXXX)
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+		gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
 
 	case gc.OEQ<<16 | gc.TBOOL,
 		gc.OEQ<<16 | gc.TINT8,
@@ -966,11 +936,10 @@
 		gc.OMUL<<16 | gc.TUINT32,
 		gc.OMUL<<16 | gc.TPTR32,
 		// don't use word multiply, the high 32-bit are undefined.
-		// fallthrough
 		gc.OMUL<<16 | gc.TUINT64,
 		gc.OMUL<<16 | gc.TPTR64:
-		a = ppc64.AMULLD
 		// for 64-bit multiplies, signedness doesn't matter.
+		a = ppc64.AMULLD
 
 	case gc.OMUL<<16 | gc.TFLOAT32:
 		a = ppc64.AFMULS
diff --git a/src/cmd/9g/peep.go b/src/cmd/9g/peep.go
index 6992968..94c9b15 100644
--- a/src/cmd/9g/peep.go
+++ b/src/cmd/9g/peep.go
@@ -481,7 +481,7 @@
 	v2 := (*obj.Addr)(&p.To)
 	if copyas(v1, v2) {
 		if gc.Debug['P'] != 0 {
-			fmt.Printf("eliminating self-move\n", r0.Prog)
+			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
 		}
 		return true
 	}
diff --git a/src/cmd/9g/util.go b/src/cmd/9g/util.go
deleted file mode 100644
index bb5eedb..0000000
--- a/src/cmd/9g/util.go
+++ /dev/null
@@ -1,12 +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 main
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/9l/asm.go b/src/cmd/9l/asm.go
index a32b39c..257f23e 100644
--- a/src/cmd/9l/asm.go
+++ b/src/cmd/9l/asm.go
@@ -118,7 +118,7 @@
 	for s = *pprevtextp; s != nil; pprevtextp, s = &s.Next, s.Next {
 		for i = range s.R {
 			r = &s.R[i]
-			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
+			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT {
 				continue
 			}
 
@@ -168,7 +168,7 @@
 
 	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
 
-	stub.Type = ld.STEXT
+	stub.Type = obj.STEXT
 
 	// Save TOC pointer in TOC save slot
 	ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
@@ -183,7 +183,7 @@
 	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 		r.Off += int32(r.Siz)
 	}
-	r.Type = ld.R_POWER_TOC
+	r.Type = obj.R_POWER_TOC
 	r.Variant = ld.RV_POWER_HA
 	ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
 	r = ld.Addrel(stub)
@@ -194,7 +194,7 @@
 	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 		r.Off += int32(r.Siz)
 	}
-	r.Type = ld.R_POWER_TOC
+	r.Type = obj.R_POWER_TOC
 	r.Variant = ld.RV_POWER_LO
 	ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
 
@@ -220,7 +220,7 @@
 
 		// Handle relocations found in ELF object files.
 	case 256 + ld.R_PPC64_REL24:
-		r.Type = ld.R_CALLPOWER
+		r.Type = obj.R_CALLPOWER
 
 		// This is a local call, so the caller isn't setting
 		// up r12 and r2 is the same for the caller and
@@ -229,7 +229,7 @@
 		// to use r12 to compute r2.)
 		r.Add += int64(r.Sym.Localentry) * 4
 
-		if targ.Type == ld.SDYNIMPORT {
+		if targ.Type == obj.SDYNIMPORT {
 			// Should have been handled in elfsetupplt
 			ld.Diag("unexpected R_PPC64_REL24 for dyn import")
 		}
@@ -237,8 +237,8 @@
 		return
 
 	case 256 + ld.R_PPC64_ADDR64:
-		r.Type = ld.R_ADDR
-		if targ.Type == ld.SDYNIMPORT {
+		r.Type = obj.R_ADDR
+		if targ.Type == obj.SDYNIMPORT {
 			// These happen in .toc sections
 			adddynsym(ld.Ctxt, targ)
 
@@ -252,56 +252,56 @@
 		return
 
 	case 256 + ld.R_PPC64_TOC16:
-		r.Type = ld.R_POWER_TOC
+		r.Type = obj.R_POWER_TOC
 		r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
 		return
 
 	case 256 + ld.R_PPC64_TOC16_LO:
-		r.Type = ld.R_POWER_TOC
+		r.Type = obj.R_POWER_TOC
 		r.Variant = ld.RV_POWER_LO
 		return
 
 	case 256 + ld.R_PPC64_TOC16_HA:
-		r.Type = ld.R_POWER_TOC
+		r.Type = obj.R_POWER_TOC
 		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
 		return
 
 	case 256 + ld.R_PPC64_TOC16_HI:
-		r.Type = ld.R_POWER_TOC
+		r.Type = obj.R_POWER_TOC
 		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
 		return
 
 	case 256 + ld.R_PPC64_TOC16_DS:
-		r.Type = ld.R_POWER_TOC
+		r.Type = obj.R_POWER_TOC
 		r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
 		return
 
 	case 256 + ld.R_PPC64_TOC16_LO_DS:
-		r.Type = ld.R_POWER_TOC
+		r.Type = obj.R_POWER_TOC
 		r.Variant = ld.RV_POWER_DS
 		return
 
 	case 256 + ld.R_PPC64_REL16_LO:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Variant = ld.RV_POWER_LO
 		r.Add += 2 // Compensate for relocation size of 2
 		return
 
 	case 256 + ld.R_PPC64_REL16_HI:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
 		r.Add += 2
 		return
 
 	case 256 + ld.R_PPC64_REL16_HA:
-		r.Type = ld.R_PCREL
+		r.Type = obj.R_PCREL
 		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
 		r.Add += 2
 		return
 	}
 
 	// Handle references to ELF symbols from our own object files.
-	if targ.Type != ld.SDYNIMPORT {
+	if targ.Type != obj.SDYNIMPORT {
 		return
 	}
 
@@ -357,15 +357,15 @@
 	}
 
 	switch r.Type {
-	case ld.R_CONST:
+	case obj.R_CONST:
 		*val = r.Add
 		return 0
 
-	case ld.R_GOTOFF:
+	case obj.R_GOTOFF:
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
 		return 0
 
-	case ld.R_ADDRPOWER:
+	case obj.R_ADDRPOWER:
 		// r->add is two ppc64 instructions holding an immediate 32-bit constant.
 		// We want to add r->sym's address to that constant.
 		// The encoding of the immediate x<<16 + y,
@@ -393,7 +393,7 @@
 		}
 		return 0
 
-	case ld.R_CALLPOWER:
+	case obj.R_CALLPOWER:
 		// Bits 6 through 29 = (S + A - P) >> 2
 		var o1 uint32
 		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
@@ -415,7 +415,7 @@
 		*val = int64(o1&0xfc000003 | uint32(t)&^0xfc000003)
 		return 0
 
-	case ld.R_POWER_TOC: // S + A - .TOC.
+	case obj.R_POWER_TOC: // S + A - .TOC.
 		*val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
 
 		return 0
@@ -539,7 +539,7 @@
 		r.Sym = glink
 		r.Off = int32(glink.Size)
 		r.Siz = 4
-		r.Type = ld.R_CALLPOWER
+		r.Type = obj.R_CALLPOWER
 		ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
 
 		// In the ppc64 ABI, the dynamic linker is responsible
@@ -594,7 +594,7 @@
 	r.Off = int32(glink.Size)
 	r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
 	r.Siz = 8
-	r.Type = ld.R_ADDRPOWER
+	r.Type = obj.R_ADDRPOWER
 
 	// addis r11,0,.plt@ha; addi r11,r11,.plt@l
 	r.Add = 0x3d600000<<32 | 0x396b0000
@@ -639,7 +639,7 @@
 		/* type */
 		t := ld.STB_GLOBAL << 4
 
-		if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
+		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
 			t |= ld.STT_FUNC
 		} else {
 			t |= ld.STT_OBJECT
@@ -650,14 +650,14 @@
 		ld.Adduint8(ctxt, d, 0)
 
 		/* section where symbol is defined */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
 		} else {
 			ld.Adduint16(ctxt, d, 1)
 		}
 
 		/* value */
-		if s.Type == ld.SDYNIMPORT {
+		if s.Type == obj.SDYNIMPORT {
 			ld.Adduint64(ctxt, d, 0)
 		} else {
 			ld.Addaddr(ctxt, d, s)
@@ -690,7 +690,7 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	if ld.Iself {
 		ld.Asmbelfsetup()
@@ -708,7 +708,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 
 		ld.Cseek(int64(ld.Segrodata.Fileoff))
 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
@@ -717,7 +717,7 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -732,7 +732,7 @@
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
 		}
-		ld.Bflush(&ld.Bso)
+		ld.Bso.Flush()
 		switch ld.HEADTYPE {
 		default:
 			if ld.Iself {
@@ -740,7 +740,7 @@
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 		}
 
@@ -765,7 +765,7 @@
 				}
 			}
 
-		case ld.Hplan9:
+		case obj.Hplan9:
 			ld.Asmplan9sym()
 			ld.Cflush()
 
@@ -785,11 +785,11 @@
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
-	ld.Bflush(&ld.Bso)
+	ld.Bso.Flush()
 	ld.Cseek(0)
 	switch ld.HEADTYPE {
 	default:
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.Thearch.Lput(0x647)                      /* magic */
 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
@@ -799,11 +799,11 @@
 		ld.Thearch.Lput(0)
 		ld.Thearch.Lput(uint32(ld.Lcsize))
 
-	case ld.Hlinux,
-		ld.Hfreebsd,
-		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hnacl:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
 		ld.Asmbelf(int64(symo))
 	}
 
diff --git a/src/cmd/9l/obj.go b/src/cmd/9l/obj.go
index 29b384a..46a9239 100644
--- a/src/cmd/9l/obj.go
+++ b/src/cmd/9l/obj.go
@@ -111,11 +111,9 @@
 
 	switch ld.HEADTYPE {
 	default:
-		ld.Diag("unknown -H option")
-		ld.Errorexit()
-		fallthrough
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
 
-	case ld.Hplan9: /* plan 9 */
+	case obj.Hplan9: /* plan 9 */
 		ld.HEADR = 32
 
 		if ld.INITTEXT == -1 {
@@ -128,7 +126,7 @@
 			ld.INITRND = 4096
 		}
 
-	case ld.Hlinux: /* ppc64 elf */
+	case obj.Hlinux: /* ppc64 elf */
 		if ld.Thestring == "ppc64" {
 			ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
 		}
@@ -144,7 +142,7 @@
 			ld.INITRND = 0x10000
 		}
 
-	case ld.Hnacl:
+	case obj.Hnacl:
 		ld.Elfinit()
 		ld.HEADR = 0x10000
 		ld.Funcalign = 16
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
index 8fd9995..c83a883 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -96,8 +96,9 @@
 	case "nacl", "android":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 85988e3..01b6def 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build api_tool
-
 // Binary api computes the exported API of a set of Go packages.
 package main
 
@@ -16,6 +14,7 @@
 	"go/build"
 	"go/parser"
 	"go/token"
+	"go/types"
 	"io"
 	"io/ioutil"
 	"log"
@@ -26,8 +25,6 @@
 	"runtime"
 	"sort"
 	"strings"
-
-	"code.google.com/p/go.tools/go/types"
 )
 
 // Flags
@@ -155,7 +152,8 @@
 					// w.Import(name) will return nil
 					continue
 				}
-				w.export(w.Import(name))
+				pkg, _ := w.Import(name)
+				w.export(pkg)
 			}
 		}
 
@@ -205,7 +203,8 @@
 	}
 	optional := fileFeatures(*nextFile)
 	exception := fileFeatures(*exceptFile)
-	fail = !compareAPI(bw, features, required, optional, exception)
+	fail = !compareAPI(bw, features, required, optional, exception,
+		*allowNew && strings.Contains(runtime.Version(), "devel"))
 }
 
 // export emits the exported package features.
@@ -241,7 +240,7 @@
 	return spaceParensRx.ReplaceAllString(f, "")
 }
 
-func compareAPI(w io.Writer, features, required, optional, exception []string) (ok bool) {
+func compareAPI(w io.Writer, features, required, optional, exception []string, allowAdd bool) (ok bool) {
 	ok = true
 
 	optionalSet := set(optional)
@@ -283,7 +282,7 @@
 				delete(optionalSet, newFeature)
 			} else {
 				fmt.Fprintf(w, "+%s\n", newFeature)
-				if !*allowNew || !strings.Contains(runtime.Version(), "devel") {
+				if !allowAdd {
 					ok = false // we're in lock-down mode for next release
 				}
 			}
@@ -419,13 +418,13 @@
 // for a package that is in the process of being imported.
 var importing types.Package
 
-func (w *Walker) Import(name string) (pkg *types.Package) {
-	pkg = w.imported[name]
+func (w *Walker) Import(name string) (*types.Package, error) {
+	pkg := w.imported[name]
 	if pkg != nil {
 		if pkg == &importing {
 			log.Fatalf("cycle importing package %q", name)
 		}
-		return pkg
+		return pkg, nil
 	}
 	w.imported[name] = &importing
 
@@ -449,7 +448,7 @@
 			key = tagKey(dir, context, tags)
 			if pkg := pkgCache[key]; pkg != nil {
 				w.imported[name] = pkg
-				return pkg
+				return pkg, nil
 			}
 		}
 	}
@@ -457,7 +456,7 @@
 	info, err := context.ImportDir(dir, 0)
 	if err != nil {
 		if _, nogo := err.(*build.NoGoError); nogo {
-			return
+			return nil, nil
 		}
 		log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err)
 	}
@@ -486,11 +485,7 @@
 	conf := types.Config{
 		IgnoreFuncBodies: true,
 		FakeImportC:      true,
-		Import: func(imports map[string]*types.Package, name string) (*types.Package, error) {
-			pkg := w.Import(name)
-			imports[name] = pkg
-			return pkg, nil
-		},
+		Importer:         w,
 	}
 	pkg, err = conf.Check(name, fset, files, nil)
 	if err != nil {
@@ -506,7 +501,7 @@
 	}
 
 	w.imported[name] = pkg
-	return
+	return pkg, nil
 }
 
 // pushScope enters a new scope (walking a package, type, node, etc)
@@ -608,12 +603,14 @@
 	case *types.Chan:
 		var s string
 		switch typ.Dir() {
-		case ast.SEND:
+		case types.SendOnly:
 			s = "chan<- "
-		case ast.RECV:
+		case types.RecvOnly:
 			s = "<-chan "
-		default:
+		case types.SendRecv:
 			s = "chan "
+		default:
+			panic("unreachable")
 		}
 		buf.WriteString(s)
 		w.writeType(buf, typ.Elem())
@@ -633,7 +630,7 @@
 }
 
 func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
-	w.writeParams(buf, sig.Params(), sig.IsVariadic())
+	w.writeParams(buf, sig.Params(), sig.Variadic())
 	switch res := sig.Results(); res.Len() {
 	case 0:
 		// nothing to do
@@ -705,10 +702,10 @@
 
 	// emit methods with value receiver
 	var methodNames map[string]bool
-	vset := typ.MethodSet()
+	vset := types.NewMethodSet(typ)
 	for i, n := 0, vset.Len(); i < n; i++ {
 		m := vset.At(i)
-		if m.Obj().IsExported() {
+		if m.Obj().Exported() {
 			w.emitMethod(m)
 			if methodNames == nil {
 				methodNames = make(map[string]bool)
@@ -720,10 +717,10 @@
 	// emit methods with pointer receiver; exclude
 	// methods that we have emitted already
 	// (the method set of *T includes the methods of T)
-	pset := types.NewPointer(typ).MethodSet()
+	pset := types.NewMethodSet(types.NewPointer(typ))
 	for i, n := 0, pset.Len(); i < n; i++ {
 		m := pset.At(i)
-		if m.Obj().IsExported() && !methodNames[m.Obj().Name()] {
+		if m.Obj().Exported() && !methodNames[m.Obj().Name()] {
 			w.emitMethod(m)
 		}
 	}
@@ -736,7 +733,7 @@
 
 	for i := 0; i < typ.NumFields(); i++ {
 		f := typ.Field(i)
-		if !f.IsExported() {
+		if !f.Exported() {
 			continue
 		}
 		typ := f.Type()
@@ -753,10 +750,10 @@
 
 	var methodNames []string
 	complete := true
-	mset := typ.MethodSet()
+	mset := types.NewMethodSet(typ)
 	for i, n := 0, mset.Len(); i < n; i++ {
 		m := mset.At(i).Obj().(*types.Func)
-		if !m.IsExported() {
+		if !m.Exported() {
 			complete = false
 			continue
 		}
@@ -807,7 +804,7 @@
 		if p, _ := recv.(*types.Pointer); p != nil {
 			base = p.Elem()
 		}
-		if obj := base.(*types.Named).Obj(); !obj.IsExported() {
+		if obj := base.(*types.Named).Obj(); !obj.Exported() {
 			log.Fatalf("exported method with unexported receiver base type: %s", m)
 		}
 	}
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
index f4fb7d3..6184e14 100644
--- a/src/cmd/api/goapi_test.go
+++ b/src/cmd/api/goapi_test.go
@@ -1,5 +1,3 @@
-// +build api_tool
-
 // Copyright 2011 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.
@@ -38,9 +36,11 @@
 			continue
 		}
 
-		goldenFile := filepath.Join("testdata", "src", fi.Name(), "golden.txt")
+		// TODO(gri) remove extra pkg directory eventually
+		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
 		w := NewWalker(nil, "testdata/src/pkg")
-		w.export(w.Import(fi.Name()))
+		pkg, _ := w.Import(fi.Name())
+		w.export(pkg)
 
 		if *updateGolden {
 			os.Remove(goldenFile)
@@ -132,7 +132,7 @@
 	}
 	for _, tt := range tests {
 		buf := new(bytes.Buffer)
-		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception)
+		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
 		if gotok != tt.ok {
 			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
 		}
@@ -179,7 +179,8 @@
 			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
 			for _, name := range pkgNames {
 				if name != "unsafe" && !strings.HasPrefix(name, "cmd/") {
-					w.export(w.Import(name))
+					pkg, _ := w.Import(name)
+					w.export(pkg)
 				}
 			}
 			w.Features()
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index b814e86..3a92d70 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -4,32 +4,18 @@
 
 // +build ignore
 
-// The run program is invoked via "go run" from src/run.bash or
-// src/run.bat conditionally builds and runs the cmd/api tool.
-//
-// TODO(bradfitz): the "conditional" condition is always true.
-// We should only do this if the user has the hg codereview extension
-// enabled and verifies that the go.tools subrepo is checked out with
-// a suitably recently version. In prep for the cmd/api rewrite.
+// The run program is invoked via the dist tool.
+// To invoke manually: go tool dist test -run api --no-rebuild
 package main
 
 import (
 	"fmt"
 	"log"
-	"net/http"
 	"os"
 	"os/exec"
-	"os/user"
 	"path/filepath"
-	"runtime"
-	"strings"
 )
 
-// goToolsVersion is the git revision of the x/tools subrepo we need
-// to build cmd/api.  This only needs to be updated whenever a go/types
-// bug fix is needed by the cmd/api tool.
-const goToolsVersion = "875ff2496f865e" // aka hg 6698ca2900e2
-
 var goroot string
 
 func main() {
@@ -38,22 +24,8 @@
 	if goroot == "" {
 		log.Fatal("No $GOROOT set.")
 	}
-	_, err := exec.LookPath("git")
-	if err != nil {
-		fmt.Println("Skipping cmd/api checks; git not available")
-		return
-	}
 
-	gopath := prepGoPath()
-
-	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
-	cmd.Env = append(filterOut(os.Environ(), "GOARCH", "GOPATH"), "GOPATH="+gopath)
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
-	}
-
-	out, err = exec.Command("go", "tool", "api",
+	out, err := exec.Command("go", "tool", "api",
 		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4"),
 		"-next", file("next"),
 		"-except", file("except")).CombinedOutput()
@@ -63,22 +35,6 @@
 	fmt.Print(string(out))
 }
 
-// filterOut returns a copy of the src environment without environment
-// variables from remove.
-// TODO: delete when issue 6201 is fixed.
-func filterOut(src []string, remove ...string) (out []string) {
-S:
-	for _, s := range src {
-		for _, r := range remove {
-			if strings.HasPrefix(s, r) && strings.HasPrefix(s, r+"=") {
-				continue S
-			}
-		}
-		out = append(out, s)
-	}
-	return
-}
-
 // file expands s to $GOROOT/api/s.txt.
 // If there are more than 1, they're comma-separated.
 func file(s ...string) string {
@@ -87,119 +43,3 @@
 	}
 	return filepath.Join(goroot, "api", s[0]+".txt")
 }
-
-// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
-// It tries to re-use a go.tools checkout from a previous run if possible,
-// else it hg clones it.
-func prepGoPath() string {
-	// Use a builder-specific temp directory name, so builders running
-	// two copies don't trample on each other: https://golang.org/issue/9407
-	// We don't use io.TempDir or a PID or timestamp here because we do
-	// want this to be stable between runs, to minimize "git clone" calls
-	// in the common case.
-	var tempBase = fmt.Sprintf("go.tools.TMP.%s.%s", runtime.GOOS, runtime.GOARCH)
-
-	username := ""
-	u, err := user.Current()
-	if err == nil {
-		username = u.Username
-	} else {
-		username = os.Getenv("USER")
-		if username == "" {
-			username = "nobody"
-		}
-	}
-
-	// The GOPATH we'll return
-	gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username)+"-"+cleanUsername(strings.Fields(runtime.Version())[0]), goToolsVersion)
-
-	// cloneDir is where we run "git clone".
-	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")
-
-	// The dir we clone into. We only atomically rename it to finalDir on
-	// clone success.
-	tmpDir := filepath.Join(cloneDir, tempBase)
-
-	// finalDir is where the checkout will live once it's complete.
-	finalDir := filepath.Join(cloneDir, "go.tools")
-
-	if goToolsCheckoutGood(finalDir) {
-		return gopath
-	}
-	os.RemoveAll(finalDir) // in case it's there but corrupt
-	os.RemoveAll(tmpDir)   // in case of aborted hg clone before
-
-	if err := os.MkdirAll(cloneDir, 0700); err != nil {
-		log.Fatal(err)
-	}
-	cmd := exec.Command("git", "clone", "https://go.googlesource.com/tools", tempBase)
-	cmd.Dir = cloneDir
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		if _, err := http.Head("http://ip.appspot.com/"); err != nil {
-			log.Printf("# Skipping API check; network appears to be unavailable")
-			os.Exit(0)
-		}
-		log.Fatalf("Error running git clone on x/tools: %v\n%s", err, out)
-	}
-	cmd = exec.Command("git", "reset", "--hard", goToolsVersion)
-	cmd.Dir = tmpDir
-	out, err = cmd.CombinedOutput()
-	if err != nil {
-		log.Fatalf("Error updating x/tools in %v to %v: %v, %s", tmpDir, goToolsVersion, err, out)
-	}
-
-	if err := os.Rename(tmpDir, finalDir); err != nil {
-		if os.IsExist(err) {
-			// A different builder beat us into putting this repo into
-			// its final place. But that's fine; if it's there, it's
-			// the right version and we can use it.
-			//
-			// This happens on the Go project's Windows builders
-			// especially, where we have two builders (386 and amd64)
-			// running at the same time, trying to compete for moving
-			// it into place.
-			os.RemoveAll(tmpDir)
-		} else {
-			log.Fatal(err)
-		}
-	}
-	return gopath
-}
-
-func cleanUsername(n string) string {
-	b := make([]rune, len(n))
-	for i, r := range n {
-		if r == '\\' || r == '/' || r == ':' {
-			b[i] = '_'
-		} else {
-			b[i] = r
-		}
-	}
-	return string(b)
-}
-
-func goToolsCheckoutGood(dir string) bool {
-	if _, err := os.Stat(dir); err != nil {
-		return false
-	}
-
-	cmd := exec.Command("git", "rev-parse", "HEAD")
-	cmd.Dir = dir
-	out, err := cmd.Output()
-	if err != nil {
-		return false
-	}
-	id := strings.TrimSpace(string(out))
-	if !strings.HasPrefix(id, goToolsVersion) {
-		return false
-	}
-
-	cmd = exec.Command("git", "status", "--porcelain")
-	cmd.Dir = dir
-	out, err = cmd.Output()
-	if err != nil || strings.TrimSpace(string(out)) != "" {
-		return false
-	}
-	return true
-}
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index 1f176dd..9f2d347 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -103,35 +103,51 @@
 		}
 	}
 	// Annoying aliases.
-	instructions["JA"] = x86.AJHI
-	instructions["JAE"] = x86.AJCC
-	instructions["JB"] = x86.AJCS
-	instructions["JBE"] = x86.AJLS
-	instructions["JC"] = x86.AJCS
-	instructions["JE"] = x86.AJEQ
-	instructions["JG"] = x86.AJGT
-	instructions["JHS"] = x86.AJCC
-	instructions["JL"] = x86.AJLT
-	instructions["JLO"] = x86.AJCS
-	instructions["JNA"] = x86.AJLS
-	instructions["JNAE"] = x86.AJCS
-	instructions["JNB"] = x86.AJCC
-	instructions["JNBE"] = x86.AJHI
-	instructions["JNC"] = x86.AJCC
-	instructions["JNG"] = x86.AJLE
-	instructions["JNGE"] = x86.AJLT
-	instructions["JNL"] = x86.AJGE
-	instructions["JNLE"] = x86.AJGT
-	instructions["JNO"] = x86.AJOC
-	instructions["JNP"] = x86.AJPC
-	instructions["JNS"] = x86.AJPL
-	instructions["JNZ"] = x86.AJNE
-	instructions["JO"] = x86.AJOS
-	instructions["JP"] = x86.AJPS
-	instructions["JPE"] = x86.AJPS
-	instructions["JPO"] = x86.AJPC
-	instructions["JS"] = x86.AJMI
-	instructions["JZ"] = x86.AJEQ
+	instructions["JA"] = x86.AJHI   /* alternate */
+	instructions["JAE"] = x86.AJCC  /* alternate */
+	instructions["JB"] = x86.AJCS   /* alternate */
+	instructions["JBE"] = x86.AJLS  /* alternate */
+	instructions["JC"] = x86.AJCS   /* alternate */
+	instructions["JCC"] = x86.AJCC  /* carry clear (CF = 0) */
+	instructions["JCS"] = x86.AJCS  /* carry set (CF = 1) */
+	instructions["JE"] = x86.AJEQ   /* alternate */
+	instructions["JEQ"] = x86.AJEQ  /* equal (ZF = 1) */
+	instructions["JG"] = x86.AJGT   /* alternate */
+	instructions["JGE"] = x86.AJGE  /* greater than or equal (signed) (SF = OF) */
+	instructions["JGT"] = x86.AJGT  /* greater than (signed) (ZF = 0 && SF = OF) */
+	instructions["JHI"] = x86.AJHI  /* higher (unsigned) (CF = 0 && ZF = 0) */
+	instructions["JHS"] = x86.AJCC  /* alternate */
+	instructions["JL"] = x86.AJLT   /* alternate */
+	instructions["JLE"] = x86.AJLE  /* less than or equal (signed) (ZF = 1 || SF != OF) */
+	instructions["JLO"] = x86.AJCS  /* alternate */
+	instructions["JLS"] = x86.AJLS  /* lower or same (unsigned) (CF = 1 || ZF = 1) */
+	instructions["JLT"] = x86.AJLT  /* less than (signed) (SF != OF) */
+	instructions["JMI"] = x86.AJMI  /* negative (minus) (SF = 1) */
+	instructions["JNA"] = x86.AJLS  /* alternate */
+	instructions["JNAE"] = x86.AJCS /* alternate */
+	instructions["JNB"] = x86.AJCC  /* alternate */
+	instructions["JNBE"] = x86.AJHI /* alternate */
+	instructions["JNC"] = x86.AJCC  /* alternate */
+	instructions["JNE"] = x86.AJNE  /* not equal (ZF = 0) */
+	instructions["JNG"] = x86.AJLE  /* alternate */
+	instructions["JNGE"] = x86.AJLT /* alternate */
+	instructions["JNL"] = x86.AJGE  /* alternate */
+	instructions["JNLE"] = x86.AJGT /* alternate */
+	instructions["JNO"] = x86.AJOC  /* alternate */
+	instructions["JNP"] = x86.AJPC  /* alternate */
+	instructions["JNS"] = x86.AJPL  /* alternate */
+	instructions["JNZ"] = x86.AJNE  /* alternate */
+	instructions["JO"] = x86.AJOS   /* alternate */
+	instructions["JOC"] = x86.AJOC  /* overflow clear (OF = 0) */
+	instructions["JOS"] = x86.AJOS  /* overflow set (OF = 1) */
+	instructions["JP"] = x86.AJPS   /* alternate */
+	instructions["JPC"] = x86.AJPC  /* parity clear (PF = 0) */
+	instructions["JPE"] = x86.AJPS  /* alternate */
+	instructions["JPL"] = x86.AJPL  /* non-negative (plus) (SF = 0) */
+	instructions["JPO"] = x86.AJPC  /* alternate */
+	instructions["JPS"] = x86.AJPS  /* parity set (PF = 1) */
+	instructions["JS"] = x86.AJMI   /* alternate */
+	instructions["JZ"] = x86.AJEQ   /* alternate */
 	instructions["MASKMOVDQU"] = x86.AMASKMOVOU
 	instructions["MOVD"] = x86.AMOVQ
 	instructions["MOVDQ2Q"] = x86.AMOVQ
diff --git a/src/cmd/asm/internal/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go
index db2adff..5916e24 100644
--- a/src/cmd/asm/internal/arch/ppc64.go
+++ b/src/cmd/asm/internal/arch/ppc64.go
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file encapsulates some of the odd characteristics of the ARM
-// instruction set, to minimize its interaction with the core of the
-// assembler.
+// This file encapsulates some of the odd characteristics of the
+// 64-bit PowerPC (PPC64) instruction set, to minimize its interaction
+// with the core of the assembler.
 
 package arch
 
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 811853b..725c635 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -545,6 +545,13 @@
 			prog.Reg = r1
 			break
 		}
+		if p.arch.Thechar == '7' {
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.From3 = a[2]
+			prog.To = a[3]
+			break
+		}
 		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
 			// 2nd operand must always be a register.
 			// TODO: Do we need to guard this with the instruction type?
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index 58c3238..abe4e4e 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -33,7 +33,7 @@
 	var ok bool
 	testOut = new(bytes.Buffer) // The assembler writes -S output to this buffer.
 	ctxt.Bso = obj.Binitw(os.Stdout)
-	defer obj.Bflush(ctxt.Bso)
+	defer ctxt.Bso.Flush()
 	ctxt.Diag = log.Fatalf
 	obj.Binitw(ioutil.Discard)
 	pList.Firstpc, ok = parser.Parse()
@@ -78,6 +78,10 @@
 	testEndToEnd(t, "arm")
 }
 
+func TestARM64EndToEnd(t *testing.T) {
+	testEndToEnd(t, "arm64")
+}
+
 func TestAMD64EndToEnd(t *testing.T) {
 	testEndToEnd(t, "amd64")
 }
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index 1b10a3a..b9154a9 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -287,6 +287,7 @@
 	{"retlo+12(FP)", "retlo+12(FP)"},
 	{"runtime·_sfloat2(SB)", "runtime._sfloat2(SB)"},
 	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
+	{"(R1, R3)", "(R1, R3)"},
 }
 
 var ppc64OperandTests = []operandTest{
@@ -424,4 +425,5 @@
 	{"$runtime·badsystemstack(SB)", "$runtime.badsystemstack(SB)"},
 	{"ZR", "ZR"},
 	{"(ZR)", "(ZR)"},
+	{"(R29, RSP)", "(R29, RSP)"},
 }
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 81d7ccc..6b67451 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -461,7 +461,7 @@
 		char := p.arch.Thechar
 		switch p.next().ScanToken {
 		case ',':
-			if char != '5' {
+			if char != '5' && char != '7' {
 				p.errorf("illegal register pair syntax")
 				return
 			}
@@ -629,15 +629,17 @@
 	a.Reg = r1
 	if r2 != 0 {
 		// TODO: Consistency in the encoding would be nice here.
-		if p.arch.Thechar == '5' {
-			// Special form for ARM: destination register pair (R1, R2).
+		if p.arch.Thechar == '5' || p.arch.Thechar == '7' {
+			// Special form
+			// ARM: destination register pair (R1, R2).
+			// ARM64: register pair (R1, R2) for LDP/STP.
 			if prefix != 0 || scale != 0 {
 				p.errorf("illegal address mode for register pair")
 				return
 			}
 			a.Type = obj.TYPE_REGREG
 			a.Offset = int64(r2)
-			// Nothing may follow; this is always a pure destination.
+			// Nothing may follow
 			return
 		}
 		if p.arch.Thechar == '9' {
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.out b/src/cmd/asm/internal/asm/testdata/arm64.out
new file mode 100644
index 0000000..ceead88
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm64.out
@@ -0,0 +1,51 @@
+5 00001 (testdata/arm64.s:5)	TEXT	foo(SB), 7, $-8
+16 00002 (testdata/arm64.s:16)	ADDW	$1, R2, R3
+17 00003 (testdata/arm64.s:17)	ADDW	R1, R2, R3
+18 00004 (testdata/arm64.s:18)	ADDW	R1, ZR, R3
+19 00005 (testdata/arm64.s:19)	ADD	$1, R2, R3
+20 00006 (testdata/arm64.s:20)	ADD	R1, R2, R3
+21 00007 (testdata/arm64.s:21)	ADD	R1, ZR, R3
+22 00008 (testdata/arm64.s:22)	ADD	$1, R2, R3
+32 00009 (testdata/arm64.s:32)	ADDW	$1, R2
+33 00010 (testdata/arm64.s:33)	ADDW	R1, R2
+34 00011 (testdata/arm64.s:34)	ADD	$1, R2
+35 00012 (testdata/arm64.s:35)	ADD	R1, R2
+44 00013 (testdata/arm64.s:44)	CLSW	R1, R2
+45 00014 (testdata/arm64.s:45)	CLS	R1, R2
+54 00015 (testdata/arm64.s:54)	MOVW	R1, R2
+55 00016 (testdata/arm64.s:55)	MOVW	ZR, R1
+56 00017 (testdata/arm64.s:56)	MOVW	R1, ZR
+57 00018 (testdata/arm64.s:57)	MOVW	$1, ZR
+58 00019 (testdata/arm64.s:58)	MOVW	$1, R1
+59 00020 (testdata/arm64.s:59)	MOVW	ZR, (R1)
+60 00021 (testdata/arm64.s:60)	MOVD	R1, R2
+61 00022 (testdata/arm64.s:61)	MOVD	ZR, R1
+62 00023 (testdata/arm64.s:62)	MOVD	$1, ZR
+63 00024 (testdata/arm64.s:63)	MOVD	$1, R1
+64 00025 (testdata/arm64.s:64)	MOVD	ZR, (R1)
+73 00026 (testdata/arm64.s:73)	MOVK	$1, R1
+82 00027 (testdata/arm64.s:82)	CALL	28(PC)
+88 00028 (testdata/arm64.s:88)	CALL	(R2)
+89 00029 (testdata/arm64.s:89)	CALL	foo(SB)
+90 00030 (testdata/arm64.s:90)	CALL	bar<>(SB)
+98 00031 (testdata/arm64.s:98)	BEQ	32(PC)
+106 00032 (testdata/arm64.s:106)	SVC
+115 00033 (testdata/arm64.s:115)	CMP	$3, R2
+116 00034 (testdata/arm64.s:116)	CMP	R1, R2
+126 00035 (testdata/arm64.s:126)	CBZ	R1
+135 00036 (testdata/arm64.s:135)	CSET	GT, R1
+143 00037 (testdata/arm64.s:143)	CSEL	LT, R1, R2, ZR
+144 00038 (testdata/arm64.s:144)	CSINC	GT, R1, ZR, R3
+145 00039 (testdata/arm64.s:145)	CSNEG	MI, R1, R2, R3
+146 00040 (testdata/arm64.s:146)	CSINV	0, R1, R2, R3
+152 00041 (testdata/arm64.s:152)	CSEL	LT, R1, R2
+160 00042 (testdata/arm64.s:160)	CCMN	MI, ZR, R1, $4
+169 00043 (testdata/arm64.s:169)	FADDD	$(0.5), F1
+170 00044 (testdata/arm64.s:170)	FADDD	F1, F2
+176 00045 (testdata/arm64.s:176)	FADDD	$(0.69999999999999996), F1, F2
+177 00046 (testdata/arm64.s:177)	FADDD	F1, F2, F3
+229 00047 (testdata/arm64.s:229)	DMB	$1
+238 00048 (testdata/arm64.s:238)	LDAXRW	(R0), R2
+239 00049 (testdata/arm64.s:239)	STLXRW	R1, (R0), R3
+247 00050 (testdata/arm64.s:247)	RET
+255 00051 (testdata/arm64.s:255)	END
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
new file mode 100644
index 0000000..1e344b5
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -0,0 +1,255 @@
+// This input was created by taking the instruction productions in
+// the old assembler's (7a's) grammar and hand-writing complete
+// instructions for each rule, to guarantee we cover the same space.
+
+TEXT	foo(SB), 7, $-8
+
+//
+// ADD
+//
+//	LTYPE1 imsr ',' spreg ',' reg
+//	{
+//		outcode($1, &$2, $4, &$6);
+//	}
+// imsr comes from the old 7a, we only support immediates and registers
+// at the moment, no shifted registers.
+	ADDW	$1, R2, R3
+	ADDW	R1, R2, R3
+	ADDW	R1, ZR, R3
+	ADD	$1, R2, R3
+	ADD	R1, R2, R3
+	ADD	R1, ZR, R3
+	ADD	$1, R2, R3
+
+//	LTYPE1 imsr ',' spreg ','
+//	{
+//		outcode($1, &$2, $4, &nullgen);
+//	}
+//	LTYPE1 imsr ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	ADDW	$1, R2
+	ADDW	R1, R2
+	ADD	$1, R2
+	ADD	R1, R2
+
+//
+// CLS
+//
+//	LTYPE2 imsr ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	CLSW	R1, R2
+	CLS	R1, R2
+
+//
+// MOV
+//
+//	LTYPE3 addr ',' addr
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	MOVW	R1, R2
+	MOVW	ZR, R1
+	MOVW	R1, ZR
+	MOVW	$1, ZR
+	MOVW	$1, R1
+	MOVW	ZR, (R1)
+	MOVD	R1, R2
+	MOVD	ZR, R1
+	MOVD	$1, ZR
+	MOVD	$1, R1
+	MOVD	ZR, (R1)
+
+//
+// MOVK
+//
+//		LMOVK imm ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	MOVK	$1, R1
+
+//
+// B/BL
+//
+//		LTYPE4 comma rel
+//	{
+//		outcode($1, &nullgen, NREG, &$3);
+//	}
+	BL	1(PC)
+
+//		LTYPE4 comma nireg
+//	{
+//		outcode($1, &nullgen, NREG, &$3);
+//	}
+	BL	(R2)
+	BL	foo(SB)
+	BL	bar<>(SB)
+//
+// BEQ
+//
+//		LTYPE5 comma rel
+//	{
+//		outcode($1, &nullgen, NREG, &$3);
+//	}
+	BEQ	1(PC)
+//
+// SVC
+//
+//		LTYPE6
+//	{
+//		outcode($1, &nullgen, NREG, &nullgen);
+//	}
+	SVC
+
+//
+// CMP
+//
+//		LTYPE7 imsr ',' spreg comma
+//	{
+//		outcode($1, &$2, $4, &nullgen);
+//	}
+	CMP	$3, R2
+	CMP	R1, R2
+
+//
+// CBZ
+//
+//		LTYPE8 reg ',' rel
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+again:
+	CBZ	R1, again
+
+//
+// CSET
+//
+//		LTYPER cond ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	CSET	GT, R1
+//
+// CSEL/CSINC/CSNEG/CSINV
+//
+//		LTYPES cond ',' reg ',' reg ',' reg
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+	CSEL	LT, R1, R2, ZR
+	CSINC	GT, R1, ZR, R3
+	CSNEG	MI, R1, R2, R3
+	CSINV	CS, R1, R2, R3
+
+//		LTYPES cond ',' reg ',' reg
+//	{
+//		outcode($1, &$2, $4.reg, &$6);
+//	}
+	CSEL	LT, R1, R2
+//
+// CCMN
+//
+//		LTYPEU cond ',' imsr ',' reg ',' imm comma
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+	CCMN	MI, ZR, R1, $4
+
+//
+// FADDD
+//
+//		LTYPEK frcon ',' freg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	FADDD	$0.5, F1
+	FADDD	F1, F2
+
+//		LTYPEK frcon ',' freg ',' freg
+//	{
+//		outcode($1, &$2, $4.reg, &$6);
+//	}
+	FADDD	$0.7, F1, F2
+	FADDD	F1, F2, F3
+
+//
+// FCMP
+//
+//		LTYPEL frcon ',' freg comma
+//	{
+//		outcode($1, &$2, $4.reg, &nullgen);
+//	}
+//	FCMP	$0.2, F1
+//	FCMP	F1, F2
+
+//
+// FCCMP
+//
+//		LTYPEF cond ',' freg ',' freg ',' imm comma
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+//	FCCMP	LT, F1, F2, $1
+
+//
+// FMULA
+//
+//		LTYPE9 freg ',' freg ',' freg ',' freg comma
+//	{
+//		outgcode($1, &$2, $4.reg, &$6, &$8);
+//	}
+//	FMULA	F1, F2, F3, F4
+
+//
+// FCSEL
+//
+//		LFCSEL cond ',' freg ',' freg ',' freg
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+//
+// MADD Rn,Rm,Ra,Rd
+//
+//		LTYPEM reg ',' reg ',' sreg ',' reg
+//	{
+//		outgcode($1, &$2, $6, &$4, &$8);
+//	}
+//	MADD	R1, R2, R3, R4
+
+// DMB, HINT
+//
+//		LDMB imm
+//	{
+//		outcode($1, &$2, NREG, &nullgen);
+//	}
+	DMB	$1
+
+//
+// STXR
+//
+//		LSTXR reg ',' addr ',' reg
+//	{
+//		outtcode($1, &$2, &$4, &$6);
+//	}
+	LDAXRW	(R0), R2
+	STLXRW	R1, (R0), R3
+
+// RET
+//
+//		LTYPEA comma
+//	{
+//		outcode($1, &nullgen, NREG, &nullgen);
+//	}
+	RET
+
+// END
+//
+//	LTYPEE comma
+//	{
+//		outcode($1, &nullgen, NREG, &nullgen);
+//	}
+	END
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index 0fa997f..c74f269 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -19,6 +19,7 @@
 	PrintOut   = flag.Bool("S", false, "print assembly and machine code")
 	TrimPath   = flag.String("trimpath", "", "remove prefix from recorded source file paths")
 	Shared     = flag.Bool("shared", false, "generate code that can be linked into a shared library")
+	Dynlink    = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
 )
 
 var (
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index e8b10ce..32bdee6 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -40,12 +40,13 @@
 	if *flags.PrintOut {
 		ctxt.Debugasm = 1
 	}
-	ctxt.Trimpath = *flags.TrimPath
-	if *flags.Shared {
+	ctxt.LineHist.TrimPathPrefix = *flags.TrimPath
+	ctxt.Flag_dynlink = *flags.Dynlink
+	if *flags.Shared || *flags.Dynlink {
 		ctxt.Flag_shared = 1
 	}
 	ctxt.Bso = obj.Binitw(os.Stdout)
-	defer obj.Bflush(ctxt.Bso)
+	defer ctxt.Bso.Flush()
 	ctxt.Diag = log.Fatalf
 	output := obj.Binitw(fd)
 	fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
@@ -57,9 +58,10 @@
 	var ok bool
 	pList.Firstpc, ok = parser.Parse()
 	if !ok {
-		log.Fatalf("asm: assembly of %s failed", flag.Arg(0))
+		log.Printf("asm: assembly of %s failed", flag.Arg(0))
+		os.Remove(*flags.OutputFile)
 		os.Exit(1)
 	}
 	obj.Writeobjdirect(ctxt, output)
-	obj.Bflush(output)
+	output.Flush()
 }
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 10e2278..8bbd1cc 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -235,9 +235,17 @@
 			error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
 		}
 
+		doc := ""
+		for _, c1 := range n.Doc.List {
+			if c1 != c {
+				doc += c1.Text + "\n"
+			}
+		}
+
 		f.ExpFunc = append(f.ExpFunc, &ExpFunc{
 			Func:    n,
 			ExpName: name,
+			Doc:     doc,
 		})
 		break
 	}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index dca0ff3..1a2595b 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -239,6 +239,13 @@
 		syscall package when bootstrapping a new target.
 	-objdir directory
 		Put all generated files in directory.
+	-importpath string
+		The import path for the Go package. Optional; used for
+		nicer comments in the generated files.
+	-exportheader file
+		If there are any exported functions, write the
+		generated export declarations to file.
+		C code can #include this to see the declarations.
 	-gccgo
 		Generate output for the gccgo compiler rather than the
 		gc compiler.
@@ -428,6 +435,7 @@
 	void
 	_cgo_be59f0f25121_Cfunc_puts(void *v)
 	{
+		_cgo_wait_runtime_init_done();
 		struct {
 			char* p0;
 			int r;
@@ -436,7 +444,8 @@
 		a->r = puts((void*)a->p0);
 	}
 
-It extracts the arguments from the pointer to _Cfunc_puts's argument
+It waits for Go runtime to be initialized (required for shared libraries),
+extracts the arguments from the pointer to _Cfunc_puts's argument
 frame, invokes the system C function (in this case, puts), stores the
 result in the frame, and returns.
 
@@ -455,6 +464,7 @@
 
 	int main() { return 0; }
 	void crosscall2(void(*fn)(void*, int), void *a, int c) { }
+	void _cgo_wait_runtime_init_done() { }
 	void _cgo_allocate(void *a, int c) { }
 	void _cgo_panic(void *a, int c) { }
 
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 3ec753f5..694c88c 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -199,6 +199,10 @@
 			val = strings.TrimSpace(line[tabIndex:])
 		}
 
+		if key == "__clang__" {
+			p.GccIsClang = true
+		}
+
 		if n := f.Name[key]; n != nil {
 			if *debugDefine {
 				fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
@@ -762,7 +766,7 @@
 		"-c",          // do not link
 		"-xc",         // input language is C
 	)
-	if strings.Contains(c[0], "clang") {
+	if p.GccIsClang {
 		c = append(c,
 			"-ferror-limit=0",
 			// Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 41abb2c..3b9ccae 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -33,6 +33,7 @@
 	PtrSize     int64
 	IntSize     int64
 	GccOptions  []string
+	GccIsClang  bool
 	CgoFlags    map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
 	Written     map[string]bool
 	Name        map[string]*Name // accumulated Name from Files
@@ -98,6 +99,7 @@
 type ExpFunc struct {
 	Func    *ast.FuncDecl
 	ExpName string // name to use from C
+	Doc     string
 }
 
 // A TypeRepr contains the string representation of a type.
@@ -160,11 +162,14 @@
 var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimport output")
 var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
 
-// These flags are for bootstrapping a new Go implementation,
+// This flag is for bootstrapping a new Go implementation,
 // to generate Go types that match the data layout and
 // constant values used in the host's C libraries and system calls.
 var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
+
 var objDir = flag.String("objdir", "", "object directory")
+var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
+var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
 
 var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
 var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 346ae94..30f828c 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -52,11 +52,13 @@
 	fmt.Fprintf(fm, "int main() { return 0; }\n")
 	if *importRuntimeCgo {
 		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n")
 		fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
 	} else {
 		// If we're not importing runtime/cgo, we *are* runtime/cgo,
-		// which provides crosscall2.  We just need a prototype.
+		// which provides these functions.  We just need a prototype.
 		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
+		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n")
 	}
 	fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
 	fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
@@ -164,10 +166,33 @@
 		}
 	}
 
+	fgcc := creat(*objDir + "_cgo_export.c")
+	fgcch := creat(*objDir + "_cgo_export.h")
 	if *gccgo {
-		p.writeGccgoExports(fgo2, fm)
+		p.writeGccgoExports(fgo2, fm, fgcc, fgcch)
 	} else {
-		p.writeExports(fgo2, fm)
+		p.writeExports(fgo2, fm, fgcc, fgcch)
+	}
+	if err := fgcc.Close(); err != nil {
+		fatalf("%s", err)
+	}
+	if err := fgcch.Close(); err != nil {
+		fatalf("%s", err)
+	}
+
+	if *exportHeader != "" && len(p.ExpFunc) > 0 {
+		fexp := creat(*exportHeader)
+		fgcch, err := os.Open(*objDir + "_cgo_export.h")
+		if err != nil {
+			fatalf("%s", err)
+		}
+		_, err = io.Copy(fexp, fgcch)
+		if err != nil {
+			fatalf("%s", err)
+		}
+		if err = fexp.Close(); err != nil {
+			fatalf("%s", err)
+		}
 	}
 
 	init := gccgoInit.String()
@@ -624,7 +649,7 @@
 // and http://golang.org/issue/5603.
 func (p *Package) packedAttribute() string {
 	s := "__attribute__((__packed__"
-	if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
+	if !p.GccIsClang && (goarch == "amd64" || goarch == "386") {
 		s += ", __gcc_struct__"
 	}
 	return s + "))"
@@ -632,18 +657,14 @@
 
 // Write out the various stubs we need to support functions exported
 // from Go so that they are callable from C.
-func (p *Package) writeExports(fgo2, fm io.Writer) {
-	fgcc := creat(*objDir + "_cgo_export.c")
-	fgcch := creat(*objDir + "_cgo_export.h")
-
-	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n/*  This file is arch-specific.  */\n")
-	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
-	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
+func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
+	p.writeExportHeader(fgcch)
 
 	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
-	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
 
-	fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")
+	fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int), void *, int);\n")
+	fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\n\n")
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
@@ -734,11 +755,16 @@
 				s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
 			})
 		s += ")"
+
+		if len(exp.Doc) > 0 {
+			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+		}
 		fmt.Fprintf(fgcch, "\nextern %s;\n", s)
 
 		fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
 		fmt.Fprintf(fgcc, "\n%s\n", s)
 		fmt.Fprintf(fgcc, "{\n")
+		fmt.Fprintf(fgcc, "\t_cgo_wait_runtime_init_done();\n")
 		fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
 		if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
 			fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
@@ -823,19 +849,16 @@
 }
 
 // Write out the C header allowing C code to call exported gccgo functions.
-func (p *Package) writeGccgoExports(fgo2, fm io.Writer) {
-	fgcc := creat(*objDir + "_cgo_export.c")
-	fgcch := creat(*objDir + "_cgo_export.h")
-
+func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 	gccgoSymbolPrefix := p.gccgoSymbolPrefix()
 
-	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
-	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
-	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
+	p.writeExportHeader(fgcch)
 
 	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
 	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
 
+	fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
+
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
 		fntype := fn.Type
@@ -855,6 +878,7 @@
 				})
 		default:
 			// Declare a result struct.
+			fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
 			fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
 			forFieldList(fntype.Results,
 				func(i int, atype ast.Expr) {
@@ -884,6 +908,10 @@
 		fmt.Fprintf(cdeclBuf, ")")
 		cParams := cdeclBuf.String()
 
+		if len(exp.Doc) > 0 {
+			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+		}
+
 		// We need to use a name that will be exported by the
 		// Go code; otherwise gccgo will make it static and we
 		// will not be able to link against it from the C
@@ -904,6 +932,8 @@
 
 		fmt.Fprint(fgcc, "\n")
 		fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
+		fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
+		fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
 		fmt.Fprint(fgcc, "\t")
 		if resultCount > 0 {
 			fmt.Fprint(fgcc, "return ")
@@ -981,6 +1011,22 @@
 	}
 }
 
+// writeExportHeader writes out the start of the _cgo_export.h file.
+func (p *Package) writeExportHeader(fgcch io.Writer) {
+	fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
+	pkg := *importPath
+	if pkg == "" {
+		pkg = p.PackagePath
+	}
+	fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
+
+	fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments.  */\n\n")
+	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+	fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments.  */\n\n")
+
+	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
+}
+
 // Return the package prefix when using gccgo.
 func (p *Package) gccgoSymbolPrefix() string {
 	if !*gccgo {
@@ -1294,6 +1340,11 @@
 }
 
 const gccExportHeaderProlog = `
+/* Start of boilerplate cgo prologue.  */
+
+#ifndef GO_CGO_PROLOGUE_H
+#define GO_CGO_PROLOGUE_H
+
 typedef signed char GoInt8;
 typedef unsigned char GoUint8;
 typedef short GoInt16;
@@ -1319,4 +1370,24 @@
 typedef void *GoChan;
 typedef struct { void *t; void *v; } GoInterface;
 typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
+
+#endif
+
+/* End of boilerplate cgo prologue.  */
+`
+
+// gccgoExportFileProlog is written to the _cgo_export.c file when
+// using gccgo.
+// We use weak declarations, and test the addresses, so that this code
+// works with older versions of gccgo.
+const gccgoExportFileProlog = `
+extern _Bool runtime_iscgo __attribute__ ((weak));
+
+static void GoInit(void) __attribute__ ((constructor));
+static void GoInit(void) {
+	if(&runtime_iscgo)
+		runtime_iscgo = 1;
+}
+
+extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
 `
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
new file mode 100644
index 0000000..31ec434
--- /dev/null
+++ b/src/cmd/cover/cover.go
@@ -0,0 +1,722 @@
+// Copyright 2013 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 (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/printer"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+const usageMessage = "" +
+	`Usage of 'go tool cover':
+Given a coverage profile produced by 'go test':
+	go test -coverprofile=c.out
+
+Open a web browser displaying annotated source code:
+	go tool cover -html=c.out
+
+Write out an HTML file instead of launching a web browser:
+	go tool cover -html=c.out -o coverage.html
+
+Display coverage percentages to stdout for each function:
+	go tool cover -func=c.out
+
+Finally, to generate modified source code with coverage annotations
+(what go test -cover does):
+	go tool cover -mode=set -var=CoverageVariableName program.go
+`
+
+func usage() {
+	fmt.Fprintln(os.Stderr, usageMessage)
+	fmt.Fprintln(os.Stderr, "Flags:")
+	flag.PrintDefaults()
+	fmt.Fprintln(os.Stderr, "\n  Only one of -html, -func, or -mode may be set.")
+	os.Exit(2)
+}
+
+var (
+	mode    = flag.String("mode", "", "coverage mode: set, count, atomic")
+	varVar  = flag.String("var", "GoCover", "name of coverage variable to generate")
+	output  = flag.String("o", "", "file for output; default: stdout")
+	htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
+	funcOut = flag.String("func", "", "output coverage profile information for each function")
+)
+
+var profile string // The profile to read; the value of -html or -func
+
+var counterStmt func(*File, ast.Expr) ast.Stmt
+
+const (
+	atomicPackagePath = "sync/atomic"
+	atomicPackageName = "_cover_atomic_"
+)
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	// Usage information when no arguments.
+	if flag.NFlag() == 0 && flag.NArg() == 0 {
+		flag.Usage()
+	}
+
+	err := parseFlags()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`)
+		os.Exit(2)
+	}
+
+	// Generate coverage-annotated source.
+	if *mode != "" {
+		annotate(flag.Arg(0))
+		return
+	}
+
+	// Output HTML or function coverage information.
+	if *htmlOut != "" {
+		err = htmlOutput(profile, *output)
+	} else {
+		err = funcOutput(profile, *output)
+	}
+
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "cover: %v\n", err)
+		os.Exit(2)
+	}
+}
+
+// parseFlags sets the profile and counterStmt globals and performs validations.
+func parseFlags() error {
+	profile = *htmlOut
+	if *funcOut != "" {
+		if profile != "" {
+			return fmt.Errorf("too many options")
+		}
+		profile = *funcOut
+	}
+
+	// Must either display a profile or rewrite Go source.
+	if (profile == "") == (*mode == "") {
+		return fmt.Errorf("too many options")
+	}
+
+	if *mode != "" {
+		switch *mode {
+		case "set":
+			counterStmt = setCounterStmt
+		case "count":
+			counterStmt = incCounterStmt
+		case "atomic":
+			counterStmt = atomicCounterStmt
+		default:
+			return fmt.Errorf("unknown -mode %v", *mode)
+		}
+
+		if flag.NArg() == 0 {
+			return fmt.Errorf("missing source file")
+		} else if flag.NArg() == 1 {
+			return nil
+		}
+	} else if flag.NArg() == 0 {
+		return nil
+	}
+	return fmt.Errorf("too many arguments")
+}
+
+// Block represents the information about a basic block to be recorded in the analysis.
+// Note: Our definition of basic block is based on control structures; we don't break
+// apart && and ||. We could but it doesn't seem important enough to bother.
+type Block struct {
+	startByte token.Pos
+	endByte   token.Pos
+	numStmt   int
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The basic parse tree walker is a method of this type.
+type File struct {
+	fset      *token.FileSet
+	name      string // Name of file.
+	astFile   *ast.File
+	blocks    []Block
+	atomicPkg string // Package name for "sync/atomic" in this file.
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+	switch n := node.(type) {
+	case *ast.BlockStmt:
+		// If it's a switch or select, the body is a list of case clauses; don't tag the block itself.
+		if len(n.List) > 0 {
+			switch n.List[0].(type) {
+			case *ast.CaseClause: // switch
+				for _, n := range n.List {
+					clause := n.(*ast.CaseClause)
+					clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+				}
+				return f
+			case *ast.CommClause: // select
+				for _, n := range n.List {
+					clause := n.(*ast.CommClause)
+					clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+				}
+				return f
+			}
+		}
+		n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
+	case *ast.IfStmt:
+		ast.Walk(f, n.Body)
+		if n.Else == nil {
+			return nil
+		}
+		// The elses are special, because if we have
+		//	if x {
+		//	} else if y {
+		//	}
+		// we want to cover the "if y". To do this, we need a place to drop the counter,
+		// so we add a hidden block:
+		//	if x {
+		//	} else {
+		//		if y {
+		//		}
+		//	}
+		switch stmt := n.Else.(type) {
+		case *ast.IfStmt:
+			block := &ast.BlockStmt{
+				Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
+				List:   []ast.Stmt{stmt},
+				Rbrace: stmt.End(),
+			}
+			n.Else = block
+		case *ast.BlockStmt:
+			stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
+		default:
+			panic("unexpected node type in if")
+		}
+		ast.Walk(f, n.Else)
+		return nil
+	case *ast.SelectStmt:
+		// Don't annotate an empty select - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	case *ast.SwitchStmt:
+		// Don't annotate an empty switch - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	case *ast.TypeSwitchStmt:
+		// Don't annotate an empty type switch - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	}
+	return f
+}
+
+// unquote returns the unquoted string.
+func unquote(s string) string {
+	t, err := strconv.Unquote(s)
+	if err != nil {
+		log.Fatalf("cover: improperly quoted string %q\n", s)
+	}
+	return t
+}
+
+// addImport adds an import for the specified path, if one does not already exist, and returns
+// the local package name.
+func (f *File) addImport(path string) string {
+	// Does the package already import it?
+	for _, s := range f.astFile.Imports {
+		if unquote(s.Path.Value) == path {
+			if s.Name != nil {
+				return s.Name.Name
+			}
+			return filepath.Base(path)
+		}
+	}
+	newImport := &ast.ImportSpec{
+		Name: ast.NewIdent(atomicPackageName),
+		Path: &ast.BasicLit{
+			Kind:  token.STRING,
+			Value: fmt.Sprintf("%q", path),
+		},
+	}
+	impDecl := &ast.GenDecl{
+		Tok: token.IMPORT,
+		Specs: []ast.Spec{
+			newImport,
+		},
+	}
+	// Make the new import the first Decl in the file.
+	astFile := f.astFile
+	astFile.Decls = append(astFile.Decls, nil)
+	copy(astFile.Decls[1:], astFile.Decls[0:])
+	astFile.Decls[0] = impDecl
+	astFile.Imports = append(astFile.Imports, newImport)
+
+	// Now refer to the package, just in case it ends up unused.
+	// That is, append to the end of the file the declaration
+	//	var _ = _cover_atomic_.AddUint32
+	reference := &ast.GenDecl{
+		Tok: token.VAR,
+		Specs: []ast.Spec{
+			&ast.ValueSpec{
+				Names: []*ast.Ident{
+					ast.NewIdent("_"),
+				},
+				Values: []ast.Expr{
+					&ast.SelectorExpr{
+						X:   ast.NewIdent(atomicPackageName),
+						Sel: ast.NewIdent("AddUint32"),
+					},
+				},
+			},
+		},
+	}
+	astFile.Decls = append(astFile.Decls, reference)
+	return atomicPackageName
+}
+
+var slashslash = []byte("//")
+
+// initialComments returns the prefix of content containing only
+// whitespace and line comments.  Any +build directives must appear
+// within this region.  This approach is more reliable than using
+// go/printer to print a modified AST containing comments.
+//
+func initialComments(content []byte) []byte {
+	// Derived from go/build.Context.shouldBuild.
+	end := 0
+	p := content
+	for len(p) > 0 {
+		line := p
+		if i := bytes.IndexByte(line, '\n'); i >= 0 {
+			line, p = line[:i], p[i+1:]
+		} else {
+			p = p[len(p):]
+		}
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 { // Blank line.
+			end = len(content) - len(p)
+			continue
+		}
+		if !bytes.HasPrefix(line, slashslash) { // Not comment line.
+			break
+		}
+	}
+	return content[:end]
+}
+
+func annotate(name string) {
+	fset := token.NewFileSet()
+	content, err := ioutil.ReadFile(name)
+	if err != nil {
+		log.Fatalf("cover: %s: %s", name, err)
+	}
+	parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments)
+	if err != nil {
+		log.Fatalf("cover: %s: %s", name, err)
+	}
+	parsedFile.Comments = trimComments(parsedFile, fset)
+
+	file := &File{
+		fset:    fset,
+		name:    name,
+		astFile: parsedFile,
+	}
+	if *mode == "atomic" {
+		file.atomicPkg = file.addImport(atomicPackagePath)
+	}
+	ast.Walk(file, file.astFile)
+	fd := os.Stdout
+	if *output != "" {
+		var err error
+		fd, err = os.Create(*output)
+		if err != nil {
+			log.Fatalf("cover: %s", err)
+		}
+	}
+	fd.Write(initialComments(content)) // Retain '// +build' directives.
+	file.print(fd)
+	// After printing the source tree, add some declarations for the counters etc.
+	// We could do this by adding to the tree, but it's easier just to print the text.
+	file.addVariables(fd)
+}
+
+// trimComments drops all but the //go: comments, some of which are semantically important.
+// We drop all others because they can appear in places that cause our counters
+// to appear in syntactically incorrect places. //go: appears at the beginning of
+// the line and is syntactically safe.
+func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
+	var comments []*ast.CommentGroup
+	for _, group := range file.Comments {
+		var list []*ast.Comment
+		for _, comment := range group.List {
+			if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 {
+				list = append(list, comment)
+			}
+		}
+		if list != nil {
+			comments = append(comments, &ast.CommentGroup{list})
+		}
+	}
+	return comments
+}
+
+func (f *File) print(w io.Writer) {
+	printer.Fprint(w, f.fset, f.astFile)
+}
+
+// intLiteral returns an ast.BasicLit representing the integer value.
+func (f *File) intLiteral(i int) *ast.BasicLit {
+	node := &ast.BasicLit{
+		Kind:  token.INT,
+		Value: fmt.Sprint(i),
+	}
+	return node
+}
+
+// index returns an ast.BasicLit representing the number of counters present.
+func (f *File) index() *ast.BasicLit {
+	return f.intLiteral(len(f.blocks))
+}
+
+// setCounterStmt returns the expression: __count[23] = 1.
+func setCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.AssignStmt{
+		Lhs: []ast.Expr{counter},
+		Tok: token.ASSIGN,
+		Rhs: []ast.Expr{f.intLiteral(1)},
+	}
+}
+
+// incCounterStmt returns the expression: __count[23]++.
+func incCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.IncDecStmt{
+		X:   counter,
+		Tok: token.INC,
+	}
+}
+
+// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1)
+func atomicCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.ExprStmt{
+		X: &ast.CallExpr{
+			Fun: &ast.SelectorExpr{
+				X:   ast.NewIdent(f.atomicPkg),
+				Sel: ast.NewIdent("AddUint32"),
+			},
+			Args: []ast.Expr{&ast.UnaryExpr{
+				Op: token.AND,
+				X:  counter,
+			},
+				f.intLiteral(1),
+			},
+		},
+	}
+}
+
+// newCounter creates a new counter expression of the appropriate form.
+func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt {
+	counter := &ast.IndexExpr{
+		X: &ast.SelectorExpr{
+			X:   ast.NewIdent(*varVar),
+			Sel: ast.NewIdent("Count"),
+		},
+		Index: f.index(),
+	}
+	stmt := counterStmt(f, counter)
+	f.blocks = append(f.blocks, Block{start, end, numStmt})
+	return stmt
+}
+
+// addCounters takes a list of statements and adds counters to the beginning of
+// each basic block at the top level of that list. For instance, given
+//
+//	S1
+//	if cond {
+//		S2
+// 	}
+//	S3
+//
+// counters will be added before S1 and before S3. The block containing S2
+// will be visited in a separate call.
+// TODO: Nested simple blocks get unnecessary (but correct) counters
+func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt {
+	// Special case: make sure we add a counter to an empty block. Can't do this below
+	// or we will add a counter to an empty statement list after, say, a return statement.
+	if len(list) == 0 {
+		return []ast.Stmt{f.newCounter(pos, blockEnd, 0)}
+	}
+	// We have a block (statement list), but it may have several basic blocks due to the
+	// appearance of statements that affect the flow of control.
+	var newList []ast.Stmt
+	for {
+		// Find first statement that affects flow of control (break, continue, if, etc.).
+		// It will be the last statement of this basic block.
+		var last int
+		end := blockEnd
+		for last = 0; last < len(list); last++ {
+			end = f.statementBoundary(list[last])
+			if f.endsBasicSourceBlock(list[last]) {
+				extendToClosingBrace = false // Block is broken up now.
+				last++
+				break
+			}
+		}
+		if extendToClosingBrace {
+			end = blockEnd
+		}
+		if pos != end { // Can have no source to cover if e.g. blocks abut.
+			newList = append(newList, f.newCounter(pos, end, last))
+		}
+		newList = append(newList, list[0:last]...)
+		list = list[last:]
+		if len(list) == 0 {
+			break
+		}
+		pos = list[0].Pos()
+	}
+	return newList
+}
+
+// hasFuncLiteral reports the existence and position of the first func literal
+// in the node, if any. If a func literal appears, it usually marks the termination
+// of a basic block because the function body is itself a block.
+// Therefore we draw a line at the start of the body of the first function literal we find.
+// TODO: what if there's more than one? Probably doesn't matter much.
+func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
+	if n == nil {
+		return false, 0
+	}
+	var literal funcLitFinder
+	ast.Walk(&literal, n)
+	return literal.found(), token.Pos(literal)
+}
+
+// statementBoundary finds the location in s that terminates the current basic
+// block in the source.
+func (f *File) statementBoundary(s ast.Stmt) token.Pos {
+	// Control flow statements are easy.
+	switch s := s.(type) {
+	case *ast.BlockStmt:
+		// Treat blocks like basic blocks to avoid overlapping counters.
+		return s.Lbrace
+	case *ast.IfStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Cond)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.ForStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Cond)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Post)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.LabeledStmt:
+		return f.statementBoundary(s.Stmt)
+	case *ast.RangeStmt:
+		found, pos := hasFuncLiteral(s.X)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.SwitchStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Tag)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.SelectStmt:
+		return s.Body.Lbrace
+	case *ast.TypeSwitchStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	}
+	// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
+	// If it does, that's tricky because we want to exclude the body of the function from this block.
+	// Draw a line at the start of the body of the first function literal we find.
+	// TODO: what if there's more than one? Probably doesn't matter much.
+	found, pos := hasFuncLiteral(s)
+	if found {
+		return pos
+	}
+	return s.End()
+}
+
+// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc.,
+// or if it's just problematic, for instance contains a function literal, which will complicate
+// accounting due to the block-within-an expression.
+func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
+	switch s := s.(type) {
+	case *ast.BlockStmt:
+		// Treat blocks like basic blocks to avoid overlapping counters.
+		return true
+	case *ast.BranchStmt:
+		return true
+	case *ast.ForStmt:
+		return true
+	case *ast.IfStmt:
+		return true
+	case *ast.LabeledStmt:
+		return f.endsBasicSourceBlock(s.Stmt)
+	case *ast.RangeStmt:
+		return true
+	case *ast.SwitchStmt:
+		return true
+	case *ast.SelectStmt:
+		return true
+	case *ast.TypeSwitchStmt:
+		return true
+	case *ast.ExprStmt:
+		// Calls to panic change the flow.
+		// We really should verify that "panic" is the predefined function,
+		// but without type checking we can't and the likelihood of it being
+		// an actual problem is vanishingly small.
+		if call, ok := s.X.(*ast.CallExpr); ok {
+			if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 {
+				return true
+			}
+		}
+	}
+	found, _ := hasFuncLiteral(s)
+	return found
+}
+
+// funcLitFinder implements the ast.Visitor pattern to find the location of any
+// function literal in a subtree.
+type funcLitFinder token.Pos
+
+func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) {
+	if f.found() {
+		return nil // Prune search.
+	}
+	switch n := node.(type) {
+	case *ast.FuncLit:
+		*f = funcLitFinder(n.Body.Lbrace)
+		return nil // Prune search.
+	}
+	return f
+}
+
+func (f *funcLitFinder) found() bool {
+	return token.Pos(*f) != token.NoPos
+}
+
+// Sort interface for []block1; used for self-check in addVariables.
+
+type block1 struct {
+	Block
+	index int
+}
+
+type blockSlice []block1
+
+func (b blockSlice) Len() int           { return len(b) }
+func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte }
+func (b blockSlice) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
+
+// offset translates a token position into a 0-indexed byte offset.
+func (f *File) offset(pos token.Pos) int {
+	return f.fset.Position(pos).Offset
+}
+
+// addVariables adds to the end of the file the declarations to set up the counter and position variables.
+func (f *File) addVariables(w io.Writer) {
+	// Self-check: Verify that the instrumented basic blocks are disjoint.
+	t := make([]block1, len(f.blocks))
+	for i := range f.blocks {
+		t[i].Block = f.blocks[i]
+		t[i].index = i
+	}
+	sort.Sort(blockSlice(t))
+	for i := 1; i < len(t); i++ {
+		if t[i-1].endByte > t[i].startByte {
+			fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index)
+			// Note: error message is in byte positions, not token positions.
+			fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n",
+				f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte),
+				f.name, f.offset(t[i].startByte), f.offset(t[i].endByte))
+		}
+	}
+
+	// Declare the coverage struct as a package-level variable.
+	fmt.Fprintf(w, "\nvar %s = struct {\n", *varVar)
+	fmt.Fprintf(w, "\tCount     [%d]uint32\n", len(f.blocks))
+	fmt.Fprintf(w, "\tPos       [3 * %d]uint32\n", len(f.blocks))
+	fmt.Fprintf(w, "\tNumStmt   [%d]uint16\n", len(f.blocks))
+	fmt.Fprintf(w, "} {\n")
+
+	// Initialize the position array field.
+	fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks))
+
+	// A nice long list of positions. Each position is encoded as follows to reduce size:
+	// - 32-bit starting line number
+	// - 32-bit ending line number
+	// - (16 bit ending column number << 16) | (16-bit starting column number).
+	for i, block := range f.blocks {
+		start := f.fset.Position(block.startByte)
+		end := f.fset.Position(block.endByte)
+		fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
+	}
+
+	// Close the position array.
+	fmt.Fprintf(w, "\t},\n")
+
+	// Initialize the position array field.
+	fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks))
+
+	// A nice long list of statements-per-block, so we can give a conventional
+	// valuation of "percent covered". To save space, it's a 16-bit number, so we
+	// clamp it if it overflows - won't matter in practice.
+	for i, block := range f.blocks {
+		n := block.numStmt
+		if n > 1<<16-1 {
+			n = 1<<16 - 1
+		}
+		fmt.Fprintf(w, "\t\t%d, // %d\n", n, i)
+	}
+
+	// Close the statements-per-block array.
+	fmt.Fprintf(w, "\t},\n")
+
+	// Close the struct initialization.
+	fmt.Fprintf(w, "}\n")
+}
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
new file mode 100644
index 0000000..e5cfccf
--- /dev/null
+++ b/src/cmd/cover/cover_test.go
@@ -0,0 +1,97 @@
+// Copyright 2013 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_test
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"testing"
+)
+
+const (
+	// Data directory, also the package directory for the test.
+	testdata = "testdata"
+
+	// Binaries we compile.
+	testcover = "./testcover.exe"
+)
+
+var (
+	// Files we use.
+	testMain    = filepath.Join(testdata, "main.go")
+	testTest    = filepath.Join(testdata, "test.go")
+	coverInput  = filepath.Join(testdata, "test_line.go")
+	coverOutput = filepath.Join(testdata, "test_cover.go")
+)
+
+var debug = false // Keeps the rewritten files around if set.
+
+// Run this shell script, but do it in Go so it can be run by "go test".
+//
+//	replace the word LINE with the line number < testdata/test.go > testdata/test_line.go
+// 	go build -o ./testcover
+// 	./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
+//	go run ./testdata/main.go ./testdata/test.go
+//
+func TestCover(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl":
+		t.Skipf("skipping; %v/%v no support for forking", runtime.GOOS, runtime.GOARCH)
+	case "darwin", "android":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping; %v/%v no support for forking", runtime.GOOS, runtime.GOARCH)
+		}
+	}
+	// Read in the test file (testTest) and write it, with LINEs specified, to coverInput.
+	file, err := ioutil.ReadFile(testTest)
+	if err != nil {
+		t.Fatal(err)
+	}
+	lines := bytes.Split(file, []byte("\n"))
+	for i, line := range lines {
+		lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
+	}
+	err = ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666)
+
+	// defer removal of test_line.go
+	if !debug {
+		defer os.Remove(coverInput)
+	}
+
+	// go build -o testcover
+	cmd := exec.Command("go", "build", "-o", testcover)
+	run(cmd, t)
+
+	// defer removal of testcover
+	defer os.Remove(testcover)
+
+	// ./testcover -mode=count -var=coverTest -o ./testdata/test_cover.go testdata/test_line.go
+	cmd = exec.Command(testcover, "-mode=count", "-var=coverTest", "-o", coverOutput, coverInput)
+	run(cmd, t)
+
+	// defer removal of ./testdata/test_cover.go
+	if !debug {
+		defer os.Remove(coverOutput)
+	}
+
+	// go run ./testdata/main.go ./testdata/test.go
+	cmd = exec.Command("go", "run", testMain, coverOutput)
+	run(cmd, t)
+}
+
+func run(c *exec.Cmd, t *testing.T) {
+	c.Stdout = os.Stdout
+	c.Stderr = os.Stderr
+	err := c.Run()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/src/cmd/cover/doc.go b/src/cmd/cover/doc.go
new file mode 100644
index 0000000..636d7e0
--- /dev/null
+++ b/src/cmd/cover/doc.go
@@ -0,0 +1,21 @@
+// Copyright 2013 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.
+
+/*
+Cover is a program for analyzing the coverage profiles generated by
+'go test -coverprofile=cover.out'.
+
+Cover is also used by 'go test -cover' to rewrite the source code with
+annotations to track which parts of each function are executed.
+It operates on one Go source file at a time, computing approximate
+basic block information by studying the source. It is thus more portable
+than binary-rewriting coverage tools, but also a little less capable.
+For instance, it does not probe inside && and || expressions, and can
+be mildly confused by single statements with multiple function literals.
+
+For usage information, please see:
+	go help testflag
+	go tool cover -help
+*/
+package main
diff --git a/src/cmd/cover/func.go b/src/cmd/cover/func.go
new file mode 100644
index 0000000..66ec242
--- /dev/null
+++ b/src/cmd/cover/func.go
@@ -0,0 +1,164 @@
+// Copyright 2013 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.
+
+// This file implements the visitor that computes the (line, column)-(line-column) range for each function.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"os"
+	"path/filepath"
+	"text/tabwriter"
+)
+
+// funcOutput takes two file names as arguments, a coverage profile to read as input and an output
+// file to write ("" means to write to standard output). The function reads the profile and produces
+// as output the coverage data broken down by function, like this:
+//
+//	fmt/format.go:30:	init			100.0%
+//	fmt/format.go:57:	clearflags		100.0%
+//	...
+//	fmt/scan.go:1046:	doScan			100.0%
+//	fmt/scan.go:1075:	advance			96.2%
+//	fmt/scan.go:1119:	doScanf			96.8%
+//	total:		(statements)			91.9%
+
+func funcOutput(profile, outputFile string) error {
+	profiles, err := ParseProfiles(profile)
+	if err != nil {
+		return err
+	}
+
+	var out *bufio.Writer
+	if outputFile == "" {
+		out = bufio.NewWriter(os.Stdout)
+	} else {
+		fd, err := os.Create(outputFile)
+		if err != nil {
+			return err
+		}
+		defer fd.Close()
+		out = bufio.NewWriter(fd)
+	}
+	defer out.Flush()
+
+	tabber := tabwriter.NewWriter(out, 1, 8, 1, '\t', 0)
+	defer tabber.Flush()
+
+	var total, covered int64
+	for _, profile := range profiles {
+		fn := profile.FileName
+		file, err := findFile(fn)
+		if err != nil {
+			return err
+		}
+		funcs, err := findFuncs(file)
+		if err != nil {
+			return err
+		}
+		// Now match up functions and profile blocks.
+		for _, f := range funcs {
+			c, t := f.coverage(profile)
+			fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t))
+			total += t
+			covered += c
+		}
+	}
+	fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total))
+
+	return nil
+}
+
+// findFuncs parses the file and returns a slice of FuncExtent descriptors.
+func findFuncs(name string) ([]*FuncExtent, error) {
+	fset := token.NewFileSet()
+	parsedFile, err := parser.ParseFile(fset, name, nil, 0)
+	if err != nil {
+		return nil, err
+	}
+	visitor := &FuncVisitor{
+		fset:    fset,
+		name:    name,
+		astFile: parsedFile,
+	}
+	ast.Walk(visitor, visitor.astFile)
+	return visitor.funcs, nil
+}
+
+// FuncExtent describes a function's extent in the source by file and position.
+type FuncExtent struct {
+	name      string
+	startLine int
+	startCol  int
+	endLine   int
+	endCol    int
+}
+
+// FuncVisitor implements the visitor that builds the function position list for a file.
+type FuncVisitor struct {
+	fset    *token.FileSet
+	name    string // Name of file.
+	astFile *ast.File
+	funcs   []*FuncExtent
+}
+
+// Visit implements the ast.Visitor interface.
+func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor {
+	switch n := node.(type) {
+	case *ast.FuncDecl:
+		start := v.fset.Position(n.Pos())
+		end := v.fset.Position(n.End())
+		fe := &FuncExtent{
+			name:      n.Name.Name,
+			startLine: start.Line,
+			startCol:  start.Column,
+			endLine:   end.Line,
+			endCol:    end.Column,
+		}
+		v.funcs = append(v.funcs, fe)
+	}
+	return v
+}
+
+// coverage returns the fraction of the statements in the function that were covered, as a numerator and denominator.
+func (f *FuncExtent) coverage(profile *Profile) (num, den int64) {
+	// We could avoid making this n^2 overall by doing a single scan and annotating the functions,
+	// but the sizes of the data structures is never very large and the scan is almost instantaneous.
+	var covered, total int64
+	// The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block.
+	for _, b := range profile.Blocks {
+		if b.StartLine > f.endLine || (b.StartLine == f.endLine && b.StartCol >= f.endCol) {
+			// Past the end of the function.
+			break
+		}
+		if b.EndLine < f.startLine || (b.EndLine == f.startLine && b.EndCol <= f.startCol) {
+			// Before the beginning of the function
+			continue
+		}
+		total += int64(b.NumStmt)
+		if b.Count > 0 {
+			covered += int64(b.NumStmt)
+		}
+	}
+	if total == 0 {
+		total = 1 // Avoid zero denominator.
+	}
+	return covered, total
+}
+
+// findFile finds the location of the named file in GOROOT, GOPATH etc.
+func findFile(file string) (string, error) {
+	dir, file := filepath.Split(file)
+	pkg, err := build.Import(dir, ".", build.FindOnly)
+	if err != nil {
+		return "", fmt.Errorf("can't find %q: %v", file, err)
+	}
+	return filepath.Join(pkg.Dir, file), nil
+}
diff --git a/src/cmd/cover/html.go b/src/cmd/cover/html.go
new file mode 100644
index 0000000..bb0a495
--- /dev/null
+++ b/src/cmd/cover/html.go
@@ -0,0 +1,279 @@
+// Copyright 2013 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 (
+	"bufio"
+	"bytes"
+	"fmt"
+	"html/template"
+	"io"
+	"io/ioutil"
+	"math"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+)
+
+// htmlOutput reads the profile data from profile and generates an HTML
+// coverage report, writing it to outfile. If outfile is empty,
+// it writes the report to a temporary file and opens it in a web browser.
+func htmlOutput(profile, outfile string) error {
+	profiles, err := ParseProfiles(profile)
+	if err != nil {
+		return err
+	}
+
+	var d templateData
+
+	for _, profile := range profiles {
+		fn := profile.FileName
+		if profile.Mode == "set" {
+			d.Set = true
+		}
+		file, err := findFile(fn)
+		if err != nil {
+			return err
+		}
+		src, err := ioutil.ReadFile(file)
+		if err != nil {
+			return fmt.Errorf("can't read %q: %v", fn, err)
+		}
+		var buf bytes.Buffer
+		err = htmlGen(&buf, src, profile.Boundaries(src))
+		if err != nil {
+			return err
+		}
+		d.Files = append(d.Files, &templateFile{
+			Name:     fn,
+			Body:     template.HTML(buf.String()),
+			Coverage: percentCovered(profile),
+		})
+	}
+
+	var out *os.File
+	if outfile == "" {
+		var dir string
+		dir, err = ioutil.TempDir("", "cover")
+		if err != nil {
+			return err
+		}
+		out, err = os.Create(filepath.Join(dir, "coverage.html"))
+	} else {
+		out, err = os.Create(outfile)
+	}
+	err = htmlTemplate.Execute(out, d)
+	if err == nil {
+		err = out.Close()
+	}
+	if err != nil {
+		return err
+	}
+
+	if outfile == "" {
+		if !startBrowser("file://" + out.Name()) {
+			fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name())
+		}
+	}
+
+	return nil
+}
+
+// percentCovered returns, as a percentage, the fraction of the statements in
+// the profile covered by the test run.
+// In effect, it reports the coverage of a given source file.
+func percentCovered(p *Profile) float64 {
+	var total, covered int64
+	for _, b := range p.Blocks {
+		total += int64(b.NumStmt)
+		if b.Count > 0 {
+			covered += int64(b.NumStmt)
+		}
+	}
+	if total == 0 {
+		return 0
+	}
+	return float64(covered) / float64(total) * 100
+}
+
+// htmlGen generates an HTML coverage report with the provided filename,
+// source code, and tokens, and writes it to the given Writer.
+func htmlGen(w io.Writer, src []byte, boundaries []Boundary) error {
+	dst := bufio.NewWriter(w)
+	for i := range src {
+		for len(boundaries) > 0 && boundaries[0].Offset == i {
+			b := boundaries[0]
+			if b.Start {
+				n := 0
+				if b.Count > 0 {
+					n = int(math.Floor(b.Norm*9)) + 1
+				}
+				fmt.Fprintf(dst, `<span class="cov%v" title="%v">`, n, b.Count)
+			} else {
+				dst.WriteString("</span>")
+			}
+			boundaries = boundaries[1:]
+		}
+		switch b := src[i]; b {
+		case '>':
+			dst.WriteString("&gt;")
+		case '<':
+			dst.WriteString("&lt;")
+		case '&':
+			dst.WriteString("&amp;")
+		case '\t':
+			dst.WriteString("        ")
+		default:
+			dst.WriteByte(b)
+		}
+	}
+	return dst.Flush()
+}
+
+// startBrowser tries to open the URL in a browser
+// and reports whether it succeeds.
+func startBrowser(url string) bool {
+	// try to start the browser
+	var args []string
+	switch runtime.GOOS {
+	case "darwin":
+		args = []string{"open"}
+	case "windows":
+		args = []string{"cmd", "/c", "start"}
+	default:
+		args = []string{"xdg-open"}
+	}
+	cmd := exec.Command(args[0], append(args[1:], url)...)
+	return cmd.Start() == nil
+}
+
+// rgb returns an rgb value for the specified coverage value
+// between 0 (no coverage) and 10 (max coverage).
+func rgb(n int) string {
+	if n == 0 {
+		return "rgb(192, 0, 0)" // Red
+	}
+	// Gradient from gray to green.
+	r := 128 - 12*(n-1)
+	g := 128 + 12*(n-1)
+	b := 128 + 3*(n-1)
+	return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b)
+}
+
+// colors generates the CSS rules for coverage colors.
+func colors() template.CSS {
+	var buf bytes.Buffer
+	for i := 0; i < 11; i++ {
+		fmt.Fprintf(&buf, ".cov%v { color: %v }\n", i, rgb(i))
+	}
+	return template.CSS(buf.String())
+}
+
+var htmlTemplate = template.Must(template.New("html").Funcs(template.FuncMap{
+	"colors": colors,
+}).Parse(tmplHTML))
+
+type templateData struct {
+	Files []*templateFile
+	Set   bool
+}
+
+type templateFile struct {
+	Name     string
+	Body     template.HTML
+	Coverage float64
+}
+
+const tmplHTML = `
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+		<style>
+			body {
+				background: black;
+				color: rgb(80, 80, 80);
+			}
+			body, pre, #legend span {
+				font-family: Menlo, monospace;
+				font-weight: bold;
+			}
+			#topbar {
+				background: black;
+				position: fixed;
+				top: 0; left: 0; right: 0;
+				height: 42px;
+				border-bottom: 1px solid rgb(80, 80, 80);
+			}
+			#content {
+				margin-top: 50px;
+			}
+			#nav, #legend {
+				float: left;
+				margin-left: 10px;
+			}
+			#legend {
+				margin-top: 12px;
+			}
+			#nav {
+				margin-top: 10px;
+			}
+			#legend span {
+				margin: 0 5px;
+			}
+			{{colors}}
+		</style>
+	</head>
+	<body>
+		<div id="topbar">
+			<div id="nav">
+				<select id="files">
+				{{range $i, $f := .Files}}
+				<option value="file{{$i}}">{{$f.Name}} ({{printf "%.1f" $f.Coverage}}%)</option>
+				{{end}}
+				</select>
+			</div>
+			<div id="legend">
+				<span>not tracked</span>
+			{{if .Set}}
+				<span class="cov0">not covered</span>
+				<span class="cov8">covered</span>
+			{{else}}
+				<span class="cov0">no coverage</span>
+				<span class="cov1">low coverage</span>
+				<span class="cov2">*</span>
+				<span class="cov3">*</span>
+				<span class="cov4">*</span>
+				<span class="cov5">*</span>
+				<span class="cov6">*</span>
+				<span class="cov7">*</span>
+				<span class="cov8">*</span>
+				<span class="cov9">*</span>
+				<span class="cov10">high coverage</span>
+			{{end}}
+			</div>
+		</div>
+		<div id="content">
+		{{range $i, $f := .Files}}
+		<pre class="file" id="file{{$i}}" {{if $i}}style="display: none"{{end}}>{{$f.Body}}</pre>
+		{{end}}
+		</div>
+	</body>
+	<script>
+	(function() {
+		var files = document.getElementById('files');
+		var visible = document.getElementById('file0');
+		files.addEventListener('change', onChange, false);
+		function onChange() {
+			visible.style.display = 'none';
+			visible = document.getElementById(files.value);
+			visible.style.display = 'block';
+			window.scrollTo(0, 0);
+		}
+	})();
+	</script>
+</html>
+`
diff --git a/src/cmd/cover/profile.go b/src/cmd/cover/profile.go
new file mode 100644
index 0000000..a03b5d5
--- /dev/null
+++ b/src/cmd/cover/profile.go
@@ -0,0 +1,192 @@
+// Copyright 2013 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.
+
+// This file provides support for parsing coverage profiles
+// generated by "go test -coverprofile=cover.out".
+// It is a copy of golang.org/x/tools/cover/profile.go.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"math"
+	"os"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// Profile represents the profiling data for a specific file.
+type Profile struct {
+	FileName string
+	Mode     string
+	Blocks   []ProfileBlock
+}
+
+// ProfileBlock represents a single block of profiling data.
+type ProfileBlock struct {
+	StartLine, StartCol int
+	EndLine, EndCol     int
+	NumStmt, Count      int
+}
+
+type byFileName []*Profile
+
+func (p byFileName) Len() int           { return len(p) }
+func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName }
+func (p byFileName) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// ParseProfiles parses profile data in the specified file and returns a
+// Profile for each source file described therein.
+func ParseProfiles(fileName string) ([]*Profile, error) {
+	pf, err := os.Open(fileName)
+	if err != nil {
+		return nil, err
+	}
+	defer pf.Close()
+
+	files := make(map[string]*Profile)
+	buf := bufio.NewReader(pf)
+	// First line is "mode: foo", where foo is "set", "count", or "atomic".
+	// Rest of file is in the format
+	//	encoding/base64/base64.go:34.44,37.40 3 1
+	// where the fields are: name.go:line.column,line.column numberOfStatements count
+	s := bufio.NewScanner(buf)
+	mode := ""
+	for s.Scan() {
+		line := s.Text()
+		if mode == "" {
+			const p = "mode: "
+			if !strings.HasPrefix(line, p) || line == p {
+				return nil, fmt.Errorf("bad mode line: %v", line)
+			}
+			mode = line[len(p):]
+			continue
+		}
+		m := lineRe.FindStringSubmatch(line)
+		if m == nil {
+			return nil, fmt.Errorf("line %q doesn't match expected format: %v", m, lineRe)
+		}
+		fn := m[1]
+		p := files[fn]
+		if p == nil {
+			p = &Profile{
+				FileName: fn,
+				Mode:     mode,
+			}
+			files[fn] = p
+		}
+		p.Blocks = append(p.Blocks, ProfileBlock{
+			StartLine: toInt(m[2]),
+			StartCol:  toInt(m[3]),
+			EndLine:   toInt(m[4]),
+			EndCol:    toInt(m[5]),
+			NumStmt:   toInt(m[6]),
+			Count:     toInt(m[7]),
+		})
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+	for _, p := range files {
+		sort.Sort(blocksByStart(p.Blocks))
+	}
+	// Generate a sorted slice.
+	profiles := make([]*Profile, 0, len(files))
+	for _, profile := range files {
+		profiles = append(profiles, profile)
+	}
+	sort.Sort(byFileName(profiles))
+	return profiles, nil
+}
+
+type blocksByStart []ProfileBlock
+
+func (b blocksByStart) Len() int      { return len(b) }
+func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b blocksByStart) Less(i, j int) bool {
+	bi, bj := b[i], b[j]
+	return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol
+}
+
+var lineRe = regexp.MustCompile(`^(.+):([0-9]+).([0-9]+),([0-9]+).([0-9]+) ([0-9]+) ([0-9]+)$`)
+
+func toInt(s string) int {
+	i, err := strconv.Atoi(s)
+	if err != nil {
+		panic(err)
+	}
+	return i
+}
+
+// Boundary represents the position in a source file of the beginning or end of a
+// block as reported by the coverage profile. In HTML mode, it will correspond to
+// the opening or closing of a <span> tag and will be used to colorize the source
+type Boundary struct {
+	Offset int     // Location as a byte offset in the source file.
+	Start  bool    // Is this the start of a block?
+	Count  int     // Event count from the cover profile.
+	Norm   float64 // Count normalized to [0..1].
+}
+
+// Boundaries returns a Profile as a set of Boundary objects within the provided src.
+func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) {
+	// Find maximum count.
+	max := 0
+	for _, b := range p.Blocks {
+		if b.Count > max {
+			max = b.Count
+		}
+	}
+	// Divisor for normalization.
+	divisor := math.Log(float64(max))
+
+	// boundary returns a Boundary, populating the Norm field with a normalized Count.
+	boundary := func(offset int, start bool, count int) Boundary {
+		b := Boundary{Offset: offset, Start: start, Count: count}
+		if !start || count == 0 {
+			return b
+		}
+		if max <= 1 {
+			b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS.
+		} else if count > 0 {
+			b.Norm = math.Log(float64(count)) / divisor
+		}
+		return b
+	}
+
+	line, col := 1, 2 // TODO: Why is this 2?
+	for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); {
+		b := p.Blocks[bi]
+		if b.StartLine == line && b.StartCol == col {
+			boundaries = append(boundaries, boundary(si, true, b.Count))
+		}
+		if b.EndLine == line && b.EndCol == col || line > b.EndLine {
+			boundaries = append(boundaries, boundary(si, false, 0))
+			bi++
+			continue // Don't advance through src; maybe the next block starts here.
+		}
+		if src[si] == '\n' {
+			line++
+			col = 0
+		}
+		col++
+		si++
+	}
+	sort.Sort(boundariesByPos(boundaries))
+	return
+}
+
+type boundariesByPos []Boundary
+
+func (b boundariesByPos) Len() int      { return len(b) }
+func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b boundariesByPos) Less(i, j int) bool {
+	if b[i].Offset == b[j].Offset {
+		return !b[i].Start && b[j].Start
+	}
+	return b[i].Offset < b[j].Offset
+}
diff --git a/src/cmd/cover/testdata/main.go b/src/cmd/cover/testdata/main.go
new file mode 100644
index 0000000..6ed39c4
--- /dev/null
+++ b/src/cmd/cover/testdata/main.go
@@ -0,0 +1,112 @@
+// Copyright 2013 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 runner for coverage test. This file is not coverage-annotated; test.go is.
+// It knows the coverage counter is called "coverTest".
+
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func main() {
+	testAll()
+	verify()
+}
+
+type block struct {
+	count uint32
+	line  uint32
+}
+
+var counters = make(map[block]bool)
+
+// check records the location and expected value for a counter.
+func check(line, count uint32) {
+	b := block{
+		count,
+		line,
+	}
+	counters[b] = true
+}
+
+// checkVal is a version of check that returns its extra argument,
+// so it can be used in conditionals.
+func checkVal(line, count uint32, val int) int {
+	b := block{
+		count,
+		line,
+	}
+	counters[b] = true
+	return val
+}
+
+var PASS = true
+
+// verify checks the expected counts against the actual. It runs after the test has completed.
+func verify() {
+	for b := range counters {
+		got, index := count(b.line)
+		if b.count == anything && got != 0 {
+			got = anything
+		}
+		if got != b.count {
+			fmt.Fprintf(os.Stderr, "test_go:%d expected count %d got %d [counter %d]\n", b.line, b.count, got, index)
+			PASS = false
+		}
+	}
+	verifyPanic()
+	if !PASS {
+		fmt.Fprintf(os.Stderr, "FAIL\n")
+		os.Exit(2)
+	}
+}
+
+// verifyPanic is a special check for the known counter that should be
+// after the panic call in testPanic.
+func verifyPanic() {
+	if coverTest.Count[panicIndex-1] != 1 {
+		// Sanity check for test before panic.
+		fmt.Fprintf(os.Stderr, "bad before panic")
+		PASS = false
+	}
+	if coverTest.Count[panicIndex] != 0 {
+		fmt.Fprintf(os.Stderr, "bad at panic: %d should be 0\n", coverTest.Count[panicIndex])
+		PASS = false
+	}
+	if coverTest.Count[panicIndex+1] != 1 {
+		fmt.Fprintf(os.Stderr, "bad after panic")
+		PASS = false
+	}
+}
+
+// count returns the count and index for the counter at the specified line.
+func count(line uint32) (uint32, int) {
+	// Linear search is fine. Choose perfect fit over approximate.
+	// We can have a closing brace for a range on the same line as a condition for an "else if"
+	// and we don't want that brace to steal the count for the condition on the "if".
+	// Therefore we test for a perfect (lo==line && hi==line) match, but if we can't
+	// find that we take the first imperfect match.
+	index := -1
+	indexLo := uint32(1e9)
+	for i := range coverTest.Count {
+		lo, hi := coverTest.Pos[3*i], coverTest.Pos[3*i+1]
+		if lo == line && line == hi {
+			return coverTest.Count[i], i
+		}
+		// Choose the earliest match (the counters are in unpredictable order).
+		if lo <= line && line <= hi && indexLo > lo {
+			index = i
+			indexLo = lo
+		}
+	}
+	if index == -1 {
+		fmt.Fprintln(os.Stderr, "cover_test: no counter for line", line)
+		PASS = false
+		return 0, 0
+	}
+	return coverTest.Count[index], index
+}
diff --git a/src/cmd/cover/testdata/test.go b/src/cmd/cover/testdata/test.go
new file mode 100644
index 0000000..9013950
--- /dev/null
+++ b/src/cmd/cover/testdata/test.go
@@ -0,0 +1,218 @@
+// Copyright 2013 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.
+
+// This program is processed by the cover command, and then testAll is called.
+// The test driver in main.go can then compare the coverage statistics with expectation.
+
+// The word LINE is replaced by the line number in this file. When the file is executed,
+// the coverage processing has changed the line numbers, so we can't use runtime.Caller.
+
+package main
+
+const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
+
+func testAll() {
+	testSimple()
+	testBlockRun()
+	testIf()
+	testFor()
+	testRange()
+	testSwitch()
+	testTypeSwitch()
+	testSelect1()
+	testSelect2()
+	testPanic()
+	testEmptySwitches()
+}
+
+// The indexes of the counters in testPanic are known to main.go
+const panicIndex = 3
+
+// This test appears first because the index of its counters is known to main.go
+func testPanic() {
+	defer func() {
+		recover()
+	}()
+	check(LINE, 1)
+	panic("should not get next line")
+	check(LINE, 0) // this is GoCover.Count[panicIndex]
+	// The next counter is in testSimple and it will be non-zero.
+	// If the panic above does not trigger a counter, the test will fail
+	// because GoCover.Count[panicIndex] will be the one in testSimple.
+}
+
+func testSimple() {
+	check(LINE, 1)
+}
+
+func testIf() {
+	if true {
+		check(LINE, 1)
+	} else {
+		check(LINE, 0)
+	}
+	if false {
+		check(LINE, 0)
+	} else {
+		check(LINE, 1)
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 2 {
+			check(LINE, 3)
+		}
+		if checkVal(LINE, 3, i) <= 1 {
+			check(LINE, 2)
+		}
+		if checkVal(LINE, 3, i) <= 0 {
+			check(LINE, 1)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 1 {
+			check(LINE, 2)
+		} else {
+			check(LINE, 1)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 0 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 2, i) <= 1 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 1, i) <= 2 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 0, i) <= 3 {
+			check(LINE, 0)
+		}
+	}
+	if func(a, b int) bool { return a < b }(3, 4) {
+		check(LINE, 1)
+	}
+}
+
+func testFor() {
+	for i := 0; i < 10; func() { i++; check(LINE, 10) }() {
+		check(LINE, 10)
+	}
+}
+
+func testRange() {
+	for _, f := range []func(){
+		func() { check(LINE, 1) },
+	} {
+		f()
+		check(LINE, 1)
+	}
+}
+
+func testBlockRun() {
+	check(LINE, 1)
+	{
+		check(LINE, 1)
+	}
+	{
+		check(LINE, 1)
+	}
+	check(LINE, 1)
+	{
+		check(LINE, 1)
+	}
+	{
+		check(LINE, 1)
+	}
+	check(LINE, 1)
+}
+
+func testSwitch() {
+	for i := 0; i < 5; func() { i++; check(LINE, 5) }() {
+		switch i {
+		case 0:
+			check(LINE, 1)
+		case 1:
+			check(LINE, 1)
+		case 2:
+			check(LINE, 1)
+		default:
+			check(LINE, 2)
+		}
+	}
+}
+
+func testTypeSwitch() {
+	var x = []interface{}{1, 2.0, "hi"}
+	for _, v := range x {
+		switch func() { check(LINE, 3) }(); v.(type) {
+		case int:
+			check(LINE, 1)
+		case float64:
+			check(LINE, 1)
+		case string:
+			check(LINE, 1)
+		case complex128:
+			check(LINE, 0)
+		default:
+			check(LINE, 0)
+		}
+	}
+}
+
+func testSelect1() {
+	c := make(chan int)
+	go func() {
+		for i := 0; i < 1000; i++ {
+			c <- i
+		}
+	}()
+	for {
+		select {
+		case <-c:
+			check(LINE, anything)
+		case <-c:
+			check(LINE, anything)
+		default:
+			check(LINE, 1)
+			return
+		}
+	}
+}
+
+func testSelect2() {
+	c1 := make(chan int, 1000)
+	c2 := make(chan int, 1000)
+	for i := 0; i < 1000; i++ {
+		c1 <- i
+		c2 <- i
+	}
+	for {
+		select {
+		case <-c1:
+			check(LINE, 1000)
+		case <-c2:
+			check(LINE, 1000)
+		default:
+			check(LINE, 1)
+			return
+		}
+	}
+}
+
+// Empty control statements created syntax errors. This function
+// is here just to be sure that those are handled correctly now.
+func testEmptySwitches() {
+	check(LINE, 1)
+	switch 3 {
+	}
+	check(LINE, 1)
+	switch i := (interface{})(3).(int); i {
+	}
+	check(LINE, 1)
+	c := make(chan int)
+	go func() {
+		check(LINE, 1)
+		c <- 1
+		select {}
+	}()
+	<-c
+	check(LINE, 1)
+}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index ba624aa..64b2399 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -775,17 +775,6 @@
 		return false
 	}
 
-	// cmd/go/doc.go has a giant /* */ comment before
-	// it gets to the important detail that it is not part of
-	// package main.  We don't parse those comments,
-	// so special case that file.
-	if strings.HasSuffix(file, "cmd/go/doc.go") || strings.HasSuffix(file, "cmd\\go\\doc.go") {
-		return false
-	}
-	if strings.HasSuffix(file, "cmd/cgo/doc.go") || strings.HasSuffix(file, "cmd\\cgo\\doc.go") {
-		return false
-	}
-
 	// Check file contents for // +build lines.
 	for _, p := range splitlines(readfile(file)) {
 		p = strings.TrimSpace(p)
@@ -859,6 +848,7 @@
 	"errors",
 	"sync/atomic",
 	"sync",
+	"internal/singleflight",
 	"io",
 	"unicode",
 	"unicode/utf8",
@@ -872,6 +862,7 @@
 	"container/heap",
 	"encoding/base64",
 	"syscall",
+	"internal/syscall/windows/registry",
 	"time",
 	"internal/syscall/windows",
 	"os",
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index 73f4d8e..70aafe9 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -7,6 +7,7 @@
 import (
 	"fmt"
 	"os"
+	"strings"
 )
 
 /*
@@ -18,6 +19,9 @@
 //	package runtime
 //	const defaultGoroot = <goroot>
 //	const theVersion = <version>
+//	const goexperiment = <goexperiment>
+//	const stackGuardMultiplier = <multiplier value>
+//	const buildVersion = <build version>
 //
 func mkzversion(dir, file string) {
 	out := fmt.Sprintf(
@@ -28,7 +32,8 @@
 			"const defaultGoroot = `%s`\n"+
 			"const theVersion = `%s`\n"+
 			"const goexperiment = `%s`\n"+
-			"var buildVersion = theVersion\n", goroot_final, findgoversion(), os.Getenv("GOEXPERIMENT"))
+			"const stackGuardMultiplier = %d\n"+
+			"var buildVersion = theVersion\n", goroot_final, findgoversion(), os.Getenv("GOEXPERIMENT"), stackGuardMultiplier())
 
 	writefile(out, file, 0)
 }
@@ -44,6 +49,7 @@
 //	const defaultGOARCH = runtime.GOARCH
 //	const defaultGO_EXTLINK_ENABLED = <goextlinkenabled>
 //	const version = <version>
+//	const stackGuardMultiplier = <multiplier value>
 //	const goexperiment = <goexperiment>
 //
 // The use of runtime.GOOS and runtime.GOARCH makes sure that
@@ -70,8 +76,21 @@
 			"const defaultGOARCH = runtime.GOARCH\n"+
 			"const defaultGO_EXTLINK_ENABLED = `%s`\n"+
 			"const version = `%s`\n"+
+			"const stackGuardMultiplier = %d\n"+
 			"const goexperiment = `%s`\n",
-		goroot_final, go386, goarm, goextlinkenabled, findgoversion(), os.Getenv("GOEXPERIMENT"))
+		goroot_final, go386, goarm, goextlinkenabled, findgoversion(), stackGuardMultiplier(), os.Getenv("GOEXPERIMENT"))
 
 	writefile(out, file, 0)
 }
+
+// stackGuardMultiplier returns a multiplier to apply to the default
+// stack guard size.  Larger multipliers are used for non-optimized
+// builds that have larger stack frames.
+func stackGuardMultiplier() int {
+	for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
+		if s == "-N" {
+			return 2
+		}
+	}
+	return 1
+}
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index daaf66c..f5037fa 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -39,6 +39,7 @@
 	"asm/internal/flags",
 	"asm/internal/lex",
 	"internal/asm",
+	"internal/gc/big",
 	"internal/gc",
 	"internal/ld",
 	"internal/obj",
diff --git a/src/cmd/dist/cpuid_386.s b/src/cmd/dist/cpuid_386.s
index 853824a..ed4fb52 100644
--- a/src/cmd/dist/cpuid_386.s
+++ b/src/cmd/dist/cpuid_386.s
@@ -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 !gccgo
+
 TEXT ·cpuid(SB),$0-8
 	MOVL ax+4(FP), AX
 	CPUID
diff --git a/src/cmd/dist/cpuid_amd64.s b/src/cmd/dist/cpuid_amd64.s
index dbb1085..b6cdfed 100644
--- a/src/cmd/dist/cpuid_amd64.s
+++ b/src/cmd/dist/cpuid_amd64.s
@@ -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 !gccgo
+
 TEXT ·cpuid(SB),$0-12
 	MOVL ax+8(FP), AX
 	CPUID
diff --git a/src/cmd/dist/cpuid_default.s b/src/cmd/dist/cpuid_default.s
index e5bfd18..165b4a9 100644
--- a/src/cmd/dist/cpuid_default.s
+++ b/src/cmd/dist/cpuid_default.s
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !386,!amd64
+// +build !386,!amd64,!gccgo
 
 #include "textflag.h"
 
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index b0ffdcf..1ed0995 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -94,10 +94,39 @@
 		}
 	}
 
+	if t.iOS() {
+		// Install the Mach exception handler used to intercept
+		// EXC_BAD_ACCESS and convert it into a Go panic. This is
+		// necessary for a Go program running under lldb (the way
+		// we run tests). It is disabled by default because iOS
+		// apps are not allowed to access the exc_server symbol.
+		cmd := exec.Command("go", "install", "-a", "-tags", "lldb", "runtime/cgo")
+		cmd.Stdout = os.Stdout
+		cmd.Stderr = os.Stderr
+		if err := cmd.Run(); err != nil {
+			log.Fatalf("building mach exception handler: %v", err)
+		}
+
+		defer func() {
+			cmd := exec.Command("go", "install", "-a", "runtime/cgo")
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			if err := cmd.Run(); err != nil {
+				log.Fatalf("reverting mach exception handler: %v", err)
+			}
+		}()
+	}
+
 	t.timeoutScale = 1
 	if t.goarch == "arm" || t.goos == "windows" {
 		t.timeoutScale = 2
 	}
+	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
+		t.timeoutScale, err = strconv.Atoi(s)
+		if err != nil {
+			log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
+		}
+	}
 
 	if t.runRxStr != "" {
 		t.runRx = regexp.MustCompile(t.runRxStr)
@@ -154,7 +183,7 @@
 	}
 	// ranGoTest and stdMatches are state closed over by the
 	// stdlib testing func below. The tests are run sequentially,
-	// so there'no need for locks.
+	// so there's no need for locks.
 	var (
 		ranGoTest  bool
 		stdMatches []string
@@ -193,28 +222,25 @@
 	}
 
 	// Runtime CPU tests.
-	for _, cpu := range []string{"1", "2", "4"} {
-		cpu := cpu
-		testName := "runtime:cpu" + cpu
-		t.tests = append(t.tests, distTest{
-			name:    testName,
-			heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
-			fn: func() error {
-				cmd := t.dirCmd(".", "go", "test", "-short", t.timeout(300), "runtime", "-cpu="+cpu)
-				// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
-				// creation of first goroutines and first garbage collections in the parallel setting.
-				cmd.Env = mergeEnvLists([]string{"GOMAXPROCS=2"}, os.Environ())
-				return cmd.Run()
-			},
-		})
-	}
+	testName := "runtime:cpu124"
+	t.tests = append(t.tests, distTest{
+		name:    testName,
+		heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
+		fn: func() error {
+			cmd := t.dirCmd("src", "go", "test", "-short", t.timeout(300), "runtime", "-cpu=1,2,4")
+			// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+			// creation of first goroutines and first garbage collections in the parallel setting.
+			cmd.Env = mergeEnvLists([]string{"GOMAXPROCS=2"}, os.Environ())
+			return cmd.Run()
+		},
+	})
 
 	// sync tests
 	t.tests = append(t.tests, distTest{
 		name:    "sync_cpu",
 		heading: "sync -cpu=10",
 		fn: func() error {
-			return t.dirCmd(".", "go", "test", "sync", "-short", t.timeout(120), "-cpu=10").Run()
+			return t.dirCmd("src", "go", "test", "sync", "-short", t.timeout(120), "-cpu=10").Run()
 		},
 	})
 
@@ -272,15 +298,27 @@
 		} else if t.hasBash() && t.goos != "android" && !iOS {
 			t.registerTest("testso", "../misc/cgo/testso", "./test.bash")
 		}
+		if t.supportedBuildmode("c-archive") {
+			t.registerTest("testcarchive", "../misc/cgo/testcarchive", "./test.bash")
+		}
+		if t.supportedBuildmode("c-shared") {
+			t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash")
+		}
+		if t.supportedBuildmode("shared") {
+			t.registerTest("testshared", "../misc/cgo/testshared", "./test.bash")
+		}
 		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" {
 			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 {
-		t.registerTest("doc_progs", "../doc/progs", "time", "./run")
+		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")
@@ -303,7 +341,7 @@
 			name:    "api",
 			heading: "API check",
 			fn: func() error {
-				return t.dirCmd(".", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go")).Run()
+				return t.dirCmd("src", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go")).Run()
 			},
 		})
 	}
@@ -335,6 +373,10 @@
 	return cmd
 }
 
+func (t *tester) iOS() bool {
+	return t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
+}
+
 func (t *tester) out(v string) {
 	if t.banner == "" {
 		return
@@ -346,6 +388,7 @@
 	pair := t.gohostos + "-" + t.goarch
 	switch pair {
 	case "android-arm",
+		"darwin-arm", "darwin-arm64",
 		"dragonfly-386", "dragonfly-amd64",
 		"freebsd-386", "freebsd-amd64", "freebsd-arm",
 		"linux-386", "linux-amd64", "linux-arm",
@@ -366,16 +409,53 @@
 	return false
 }
 
+func (t *tester) supportedBuildmode(mode string) bool {
+	pair := t.goos + "-" + t.goarch
+	switch mode {
+	case "c-archive":
+		if !t.extLink() {
+			return false
+		}
+		switch pair {
+		case "darwin-amd64", "darwin-arm", "darwin-arm64",
+			"linux-amd64", "linux-386":
+			return true
+		}
+		return false
+	case "c-shared":
+		// TODO(hyangah): add linux-386.
+		switch pair {
+		case "linux-amd64", "android-arm":
+			return true
+		}
+		return false
+	case "shared":
+		switch pair {
+		case "linux-amd64":
+			return true
+		}
+		return false
+	default:
+		log.Fatal("internal error: unknown buildmode %s", mode)
+		return false
+	}
+}
+
 func (t *tester) cgoTest() error {
 	env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
 
-	iOS := t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
-	if t.goos == "android" || iOS {
+	if t.goos == "android" || t.iOS() {
 		cmd := t.dirCmd("misc/cgo/test", "go", "test")
 		cmd.Env = env
 		return cmd.Run()
 	}
 
+	cmd := t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", "-linkmode=auto")
+	cmd.Env = env
+	if err := cmd.Run(); err != nil {
+		return err
+	}
+
 	if t.gohostos != "dragonfly" {
 		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
 		cmd := t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal")
@@ -533,18 +613,18 @@
 }
 
 func (t *tester) raceTest() error {
-	if err := t.dirCmd(".", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec").Run(); err != nil {
+	if err := t.dirCmd("src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec").Run(); err != nil {
 		return err
 	}
-	if err := t.dirCmd(".", "go", "test", "-race", "-run=Output", "runtime/race").Run(); err != nil {
+	if err := t.dirCmd("src", "go", "test", "-race", "-run=Output", "runtime/race").Run(); err != nil {
 		return err
 	}
-	if err := t.dirCmd(".", "go", "test", "-race", "-short", "flag", "os/exec").Run(); err != nil {
+	if err := t.dirCmd("src", "go", "test", "-race", "-short", "flag", "os/exec").Run(); err != nil {
 		return err
 	}
 	if t.extLink() {
 		// Test with external linking; see issue 9133.
-		if err := t.dirCmd(".", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "flag", "os/exec").Run(); err != nil {
+		if err := t.dirCmd("src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "flag", "os/exec").Run(); err != nil {
 			return err
 		}
 	}
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index 0bbdbad..cae5d69 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -480,18 +480,6 @@
 	return os.SameFile(fi1, fi2)
 }
 
-func cpuid(info *[4]uint32, ax uint32)
-
-func cansse2() bool {
-	if gohostarch != "386" && gohostarch != "amd64" {
-		return false
-	}
-
-	var info [4]uint32
-	cpuid(&info, 1)
-	return info[3]&(1<<26) != 0 // SSE2
-}
-
 func xgetgoarm() string {
 	if goos == "nacl" {
 		// NaCl guarantees VFPv3 and is always cross-compiled.
diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go
new file mode 100644
index 0000000..9f6cfd0
--- /dev/null
+++ b/src/cmd/dist/util_gc.go
@@ -0,0 +1,19 @@
+// 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 !gccgo
+
+package main
+
+func cpuid(info *[4]uint32, ax uint32)
+
+func cansse2() bool {
+	if gohostarch != "386" && gohostarch != "amd64" {
+		return false
+	}
+
+	var info [4]uint32
+	cpuid(&info, 1)
+	return info[3]&(1<<26) != 0 // SSE2
+}
diff --git a/src/cmd/dist/util_gccgo.go b/src/cmd/dist/util_gccgo.go
new file mode 100644
index 0000000..14ac70b
--- /dev/null
+++ b/src/cmd/dist/util_gccgo.go
@@ -0,0 +1,20 @@
+// 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 gccgo
+
+package main
+
+/*
+int supports_sse2() {
+#if defined(__i386__) || defined(__x86_64__)
+	return __builtin_cpu_supports("sse2");
+#else
+	return 0;
+#endif
+}
+*/
+import "C"
+
+func cansse2() bool { return C.supports_sse2() != 0 }
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
new file mode 100644
index 0000000..b3be2a9
--- /dev/null
+++ b/src/cmd/doc/main.go
@@ -0,0 +1,296 @@
+// 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.
+
+// Doc (usually run as go doc) accepts zero, one or two arguments.
+//
+// Zero arguments:
+//	go doc
+// Show the documentation for the package in the current directory.
+//
+// One argument:
+//	go doc <pkg>
+//	go doc <sym>[.<method>]
+//	go doc [<pkg>].<sym>[.<method>]
+// The first item in this list that succeeds is the one whose documentation
+// is printed. If there is a symbol but no package, the package in the current
+// directory is chosen.
+//
+// Two arguments:
+//	go doc <pkg> <sym>[.<method>]
+//
+// Show the documentation for the package, symbol, and method. The
+// first argument must be a full package path. This is similar to the
+// command-line usage for the godoc command.
+//
+// For complete documentation, run "go help doc".
+package main
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+var (
+	unexported = flag.Bool("u", false, "show unexported symbols as well as exported")
+	matchCase  = flag.Bool("c", false, "symbol matching honors case (paths not affected)")
+)
+
+// usage is a replacement usage function for the flags package.
+func usage() {
+	fmt.Fprintf(os.Stderr, "Usage of [go] doc:\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc <pkg>\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc <sym>[.<method>]\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc [<pkg>].<sym>[.<method>]\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc <pkg> <sym>[.<method>]\n")
+	fmt.Fprintf(os.Stderr, "For more information run\n")
+	fmt.Fprintf(os.Stderr, "\tgo help doc\n\n")
+	fmt.Fprintf(os.Stderr, "Flags:\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("doc: ")
+	flag.Usage = usage
+	flag.Parse()
+	buildPackage, userPath, symbol := parseArgs()
+	symbol, method := parseSymbol(symbol)
+	pkg := parsePackage(buildPackage, userPath)
+	switch {
+	case symbol == "":
+		pkg.packageDoc()
+		return
+	case method == "":
+		pkg.symbolDoc(symbol)
+	default:
+		pkg.methodDoc(symbol, method)
+	}
+}
+
+// parseArgs analyzes the arguments (if any) and returns the package
+// it represents, the part of the argument the user used to identify
+// the path (or "" if it's the current package) and the symbol
+// (possibly with a .method) within that package.
+// parseSymbol is used to analyze the symbol itself.
+func parseArgs() (*build.Package, string, string) {
+	switch flag.NArg() {
+	default:
+		usage()
+	case 0:
+		// Easy: current directory.
+		return importDir(pwd()), "", ""
+	case 1:
+		// Done below.
+	case 2:
+		// Package must be importable.
+		pkg, err := build.Import(flag.Arg(0), "", build.ImportComment)
+		if err != nil {
+			log.Fatal(err)
+		}
+		return pkg, flag.Arg(0), flag.Arg(1)
+	}
+	// Usual case: one argument.
+	arg := flag.Arg(0)
+	// If it contains slashes, it begins with a package path.
+	// First, is it a complete package path as it is? If so, we are done.
+	// This avoids confusion over package paths that have other
+	// package paths as their prefix.
+	pkg, err := build.Import(arg, "", build.ImportComment)
+	if err == nil {
+		return pkg, arg, ""
+	}
+	// Another disambiguator: If the symbol starts with an upper
+	// case letter, it can only be a symbol in the current directory.
+	// Kills the problem caused by case-insensitive file systems
+	// matching an upper case name as a package name.
+	if isUpper(arg) {
+		pkg, err := build.ImportDir(".", build.ImportComment)
+		if err == nil {
+			return pkg, "", arg
+		}
+	}
+	// If it has a slash, it must be a package path but there is a symbol.
+	// It's the last package path we care about.
+	slash := strings.LastIndex(arg, "/")
+	// There may be periods in the package path before or after the slash
+	// and between a symbol and method.
+	// Split the string at various periods to see what we find.
+	// In general there may be ambiguities but this should almost always
+	// work.
+	var period int
+	// 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:], ".")
+		symbol := ""
+		if period < 0 {
+			period = len(arg)
+		} else {
+			symbol = arg[period+1:]
+		}
+		// Have we identified a package already?
+		pkg, err := build.Import(arg[0:period], "", build.ImportComment)
+		if err == nil {
+			return pkg, arg[0:period], symbol
+		}
+		// See if we have the basename or tail of a package, as in json for encoding/json
+		// or ivy/value for robpike.io/ivy/value.
+		path := findPackage(arg[0:period])
+		if path != "" {
+			return importDir(path), arg[0:period], symbol
+		}
+	}
+	// If it has a slash, we've failed.
+	if slash >= 0 {
+		log.Fatalf("no such package %s", arg[0:period])
+	}
+	// Guess it's a symbol in the current directory.
+	return importDir(pwd()), "", arg
+}
+
+// importDir is just an error-catching wrapper for build.ImportDir.
+func importDir(dir string) *build.Package {
+	pkg, err := build.ImportDir(dir, build.ImportComment)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return pkg
+}
+
+// parseSymbol breaks str apart into a symbol and method.
+// Both may be missing or the method may be missing.
+// If present, each must be a valid Go identifier.
+func parseSymbol(str string) (symbol, method string) {
+	if str == "" {
+		return
+	}
+	elem := strings.Split(str, ".")
+	switch len(elem) {
+	case 1:
+	case 2:
+		method = elem[1]
+		isIdentifier(method)
+	default:
+		log.Printf("too many periods in symbol specification")
+		usage()
+	}
+	symbol = elem[0]
+	isIdentifier(symbol)
+	return
+}
+
+// isIdentifier checks that the name is valid Go identifier, and
+// logs and exits if it is not.
+func isIdentifier(name string) {
+	if len(name) == 0 {
+		log.Fatal("empty symbol")
+	}
+	for i, ch := range name {
+		if unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch) {
+			continue
+		}
+		log.Fatalf("invalid identifier %q", name)
+	}
+}
+
+// isExported reports whether the name is an exported identifier.
+// If the unexported flag (-u) is true, isExported returns true because
+// it means that we treat the name as if it is exported.
+func isExported(name string) bool {
+	return *unexported || isUpper(name)
+}
+
+// isUpper reports whether the name starts with an upper case letter.
+func isUpper(name string) bool {
+	ch, _ := utf8.DecodeRuneInString(name)
+	return unicode.IsUpper(ch)
+}
+
+// findPackage returns the full file name path specified by the
+// (perhaps partial) package path pkg.
+func findPackage(pkg string) string {
+	if pkg == "" {
+		return ""
+	}
+	if isUpper(pkg) {
+		return "" // Upper case symbol cannot be a package name.
+	}
+	path := pathFor(build.Default.GOROOT, pkg)
+	if path != "" {
+		return path
+	}
+	for _, root := range splitGopath() {
+		path = pathFor(root, pkg)
+		if path != "" {
+			return path
+		}
+	}
+	return ""
+}
+
+// splitGopath splits $GOPATH into a list of roots.
+func splitGopath() []string {
+	return filepath.SplitList(build.Default.GOPATH)
+}
+
+// pathsFor recursively walks the tree at root looking for possible directories for the package:
+// those whose package path is pkg or which have a proper suffix pkg.
+func pathFor(root, pkg string) (result string) {
+	root = path.Join(root, "src")
+	slashDot := string(filepath.Separator) + "."
+	// We put a slash on the pkg so can use simple string comparison below
+	// yet avoid inadvertent matches, like /foobar matching bar.
+	pkgString := filepath.Clean(string(filepath.Separator) + pkg)
+
+	// We use panic/defer to short-circuit processing at the first match.
+	// A nil panic reports that the path has been found.
+	defer func() {
+		err := recover()
+		if err != nil {
+			panic(err)
+		}
+	}()
+
+	visit := func(pathName string, f os.FileInfo, err error) error {
+		if err != nil {
+			return nil
+		}
+		// One package per directory. Ignore the files themselves.
+		if !f.IsDir() {
+			return nil
+		}
+		// No .git or other dot nonsense please.
+		if strings.Contains(pathName, slashDot) {
+			return filepath.SkipDir
+		}
+		// Is the tail of the path correct?
+		if strings.HasSuffix(pathName, pkgString) {
+			result = pathName
+			panic(nil)
+		}
+		return nil
+	}
+
+	filepath.Walk(root, visit)
+	return "" // Call to panic above sets the real value.
+}
+
+// pwd returns the current directory.
+func pwd() string {
+	wd, err := os.Getwd()
+	if err != nil {
+		log.Fatal(err)
+	}
+	return wd
+}
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
new file mode 100644
index 0000000..3a0aa7f
--- /dev/null
+++ b/src/cmd/doc/pkg.go
@@ -0,0 +1,468 @@
+// 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 (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/doc"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"log"
+	"os"
+	"unicode"
+	"unicode/utf8"
+)
+
+type Package struct {
+	name     string       // Package name, json for encoding/json.
+	userPath string       // String the user used to find this package.
+	pkg      *ast.Package // Parsed package.
+	file     *ast.File    // Merged from all files in the package
+	doc      *doc.Package
+	build    *build.Package
+	fs       *token.FileSet // Needed for printing.
+	buf      bytes.Buffer
+}
+
+// parsePackage turns the build package we found into a parsed package
+// we can then use to generate documentation.
+func parsePackage(pkg *build.Package, userPath string) *Package {
+	fs := token.NewFileSet()
+	// include tells parser.ParseDir which files to include.
+	// That means the file must be in the build package's GoFiles or CgoFiles
+	// list only (no tag-ignored files, tests, swig or other non-Go files).
+	include := func(info os.FileInfo) bool {
+		for _, name := range pkg.GoFiles {
+			if name == info.Name() {
+				return true
+			}
+		}
+		for _, name := range pkg.CgoFiles {
+			if name == info.Name() {
+				return true
+			}
+		}
+		return false
+	}
+	pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments)
+	if err != nil {
+		log.Fatal(err)
+	}
+	// Make sure they are all in one package.
+	if len(pkgs) != 1 {
+		log.Fatalf("multiple packages directory %s", pkg.Dir)
+	}
+	astPkg := pkgs[pkg.Name]
+
+	// TODO: go/doc does not include typed constants in the constants
+	// list, which is what we want. For instance, time.Sunday is of type
+	// time.Weekday, so it is defined in the type but not in the
+	// Consts list for the package. This prevents
+	//	go doc time.Sunday
+	// from finding the symbol. Work around this for now, but we
+	// should fix it in go/doc.
+	// A similar story applies to factory functions.
+	docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
+	for _, typ := range docPkg.Types {
+		docPkg.Consts = append(docPkg.Consts, typ.Consts...)
+		docPkg.Vars = append(docPkg.Vars, typ.Vars...)
+		docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
+	}
+
+	return &Package{
+		name:     pkg.Name,
+		userPath: userPath,
+		pkg:      astPkg,
+		file:     ast.MergePackageFiles(astPkg, 0),
+		doc:      docPkg,
+		build:    pkg,
+		fs:       fs,
+	}
+}
+
+func (pkg *Package) Printf(format string, args ...interface{}) {
+	fmt.Fprintf(&pkg.buf, format, args...)
+}
+
+func (pkg *Package) flush() {
+	_, err := os.Stdout.Write(pkg.buf.Bytes())
+	if err != nil {
+		log.Fatal(err)
+	}
+	pkg.buf.Reset() // Not needed, but it's a flush.
+}
+
+var newlineBytes = []byte("\n\n") // We never ask for more than 2.
+
+// newlines guarantees there are n newlines at the end of the buffer.
+func (pkg *Package) newlines(n int) {
+	for !bytes.HasSuffix(pkg.buf.Bytes(), newlineBytes[:n]) {
+		pkg.buf.WriteRune('\n')
+	}
+}
+
+// emit prints the node.
+func (pkg *Package) emit(comment string, node ast.Node) {
+	if node != nil {
+		err := format.Node(&pkg.buf, pkg.fs, node)
+		if err != nil {
+			log.Fatal(err)
+		}
+		if comment != "" {
+			pkg.newlines(1)
+			doc.ToText(&pkg.buf, comment, "    ", "\t", 80)
+		}
+		pkg.newlines(1)
+	}
+}
+
+var formatBuf bytes.Buffer // Reusable to avoid allocation.
+
+// formatNode is a helper function for printing.
+func (pkg *Package) formatNode(node ast.Node) []byte {
+	formatBuf.Reset()
+	format.Node(&formatBuf, pkg.fs, node)
+	return formatBuf.Bytes()
+}
+
+// oneLineFunc prints a function declaration as a single line.
+func (pkg *Package) oneLineFunc(decl *ast.FuncDecl) {
+	decl.Doc = nil
+	decl.Body = nil
+	pkg.emit("", decl)
+}
+
+// oneLineValueGenDecl prints a var or const declaration as a single line.
+func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) {
+	decl.Doc = nil
+	dotDotDot := ""
+	if len(decl.Specs) > 1 {
+		dotDotDot = " ..."
+	}
+	// Find the first relevant spec.
+	for i, spec := range decl.Specs {
+		valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
+		if !isExported(valueSpec.Names[0].Name) {
+			continue
+		}
+		typ := ""
+		if valueSpec.Type != nil {
+			typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
+		}
+		val := ""
+		if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
+			val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
+		}
+		pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
+		break
+	}
+}
+
+// oneLineTypeDecl prints a type declaration as a single line.
+func (pkg *Package) oneLineTypeDecl(spec *ast.TypeSpec) {
+	spec.Doc = nil
+	spec.Comment = nil
+	switch spec.Type.(type) {
+	case *ast.InterfaceType:
+		pkg.Printf("type %s interface { ... }\n", spec.Name)
+	case *ast.StructType:
+		pkg.Printf("type %s struct { ... }\n", spec.Name)
+	default:
+		pkg.Printf("type %s %s\n", spec.Name, pkg.formatNode(spec.Type))
+	}
+}
+
+// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
+func (pkg *Package) packageDoc() {
+	defer pkg.flush()
+	pkg.packageClause(false)
+
+	doc.ToText(&pkg.buf, pkg.doc.Doc, "", "\t", 80)
+	pkg.newlines(2)
+
+	pkg.valueSummary(pkg.doc.Consts)
+	pkg.valueSummary(pkg.doc.Vars)
+	pkg.funcSummary(pkg.doc.Funcs)
+	pkg.typeSummary()
+}
+
+// packageClause prints the package clause.
+// The argument boolean, if true, suppresses the output if the
+// user's argument is identical to the actual package path or
+// is empty, meaning it's the current directory.
+func (pkg *Package) packageClause(checkUserPath bool) {
+	if checkUserPath {
+		if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
+			return
+		}
+	}
+	importPath := pkg.build.ImportComment
+	if importPath == "" {
+		importPath = pkg.build.ImportPath
+	}
+	pkg.Printf("package %s // import %q\n\n", pkg.name, importPath)
+	if importPath != pkg.build.ImportPath {
+		pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
+	}
+}
+
+// valueSummary prints a one-line summary for each set of values and constants.
+func (pkg *Package) valueSummary(values []*doc.Value) {
+	for _, value := range values {
+		// Only print first item in spec, show ... to stand for the rest.
+		spec := value.Decl.Specs[0].(*ast.ValueSpec) // Must succeed.
+		exported := true
+		for _, name := range spec.Names {
+			if !isExported(name.Name) {
+				exported = false
+				break
+			}
+		}
+		if exported {
+			pkg.oneLineValueGenDecl(value.Decl)
+		}
+	}
+}
+
+// funcSummary prints a one-line summary for each function.
+func (pkg *Package) funcSummary(funcs []*doc.Func) {
+	for _, fun := range funcs {
+		decl := fun.Decl
+		// Exported functions only. The go/doc package does not include methods here.
+		if isExported(fun.Name) {
+			pkg.oneLineFunc(decl)
+		}
+	}
+}
+
+// typeSummary prints a one-line summary for each type.
+func (pkg *Package) typeSummary() {
+	for _, typ := range pkg.doc.Types {
+		for _, spec := range typ.Decl.Specs {
+			typeSpec := spec.(*ast.TypeSpec) // Must succeed.
+			if isExported(typeSpec.Name.Name) {
+				pkg.oneLineTypeDecl(typeSpec)
+			}
+		}
+	}
+}
+
+// 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 {
+		for _, name := range value.Names {
+			if match(symbol, name) {
+				values = append(values, value)
+			}
+		}
+	}
+	return
+}
+
+// findFuncs finds the doc.Funcs that describes the symbol.
+func (pkg *Package) findFuncs(symbol string) (funcs []*doc.Func) {
+	for _, fun := range pkg.doc.Funcs {
+		if match(symbol, fun.Name) {
+			funcs = append(funcs, fun)
+		}
+	}
+	return
+}
+
+// findTypes finds the doc.Types that describes the symbol.
+// If symbol is empty, it finds all exported types.
+func (pkg *Package) findTypes(symbol string) (types []*doc.Type) {
+	for _, typ := range pkg.doc.Types {
+		if symbol == "" && isExported(typ.Name) || match(symbol, typ.Name) {
+			types = append(types, typ)
+		}
+	}
+	return
+}
+
+// findTypeSpec returns the ast.TypeSpec within the declaration that defines the symbol.
+// The name must match exactly.
+func (pkg *Package) findTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec {
+	for _, spec := range decl.Specs {
+		typeSpec := spec.(*ast.TypeSpec) // Must succeed.
+		if symbol == typeSpec.Name.Name {
+			return typeSpec
+		}
+	}
+	return nil
+}
+
+// symbolDoc prints the docs for symbol. There may be multiple matches.
+// If symbol matches a type, output includes its methods factories and associated constants.
+// If there is no top-level symbol, symbolDoc looks for methods that match.
+func (pkg *Package) symbolDoc(symbol string) {
+	defer pkg.flush()
+	found := false
+	// Functions.
+	for _, fun := range pkg.findFuncs(symbol) {
+		if !found {
+			pkg.packageClause(true)
+		}
+		// Symbol is a function.
+		decl := fun.Decl
+		decl.Body = nil
+		pkg.emit(fun.Doc, decl)
+		found = true
+	}
+	// Constants and variables behave the same.
+	values := pkg.findValues(symbol, pkg.doc.Consts)
+	values = append(values, pkg.findValues(symbol, pkg.doc.Vars)...)
+	for _, value := range values {
+		if !found {
+			pkg.packageClause(true)
+		}
+		pkg.emit(value.Doc, value.Decl)
+		found = true
+	}
+	// Types.
+	for _, typ := range pkg.findTypes(symbol) {
+		if !found {
+			pkg.packageClause(true)
+		}
+		decl := typ.Decl
+		spec := pkg.findTypeSpec(decl, typ.Name)
+		trimUnexportedFields(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.
+		pkg.valueSummary(typ.Consts)
+		pkg.valueSummary(typ.Vars)
+		pkg.funcSummary(typ.Funcs)
+		pkg.funcSummary(typ.Methods)
+		found = true
+	}
+	if !found {
+		// See if there are methods.
+		if !pkg.printMethodDoc("", symbol) {
+			log.Printf("symbol %s not present in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
+		}
+	}
+}
+
+// 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) {
+	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
+	}
+	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.
+		ok := true
+		for _, name := range field.Names {
+			if !isExported(name.Name) {
+				trimmed = true
+				ok = false
+				break
+			}
+		}
+		if ok {
+			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",
+					},
+				},
+			},
+		}
+		list = append(list, unexportedField)
+		structType.Fields.List = list
+	}
+}
+
+// printMethodDoc prints the docs for matches of symbol.method.
+// If symbol is empty, it prints all methods that match the name.
+// It reports whether it found any methods.
+func (pkg *Package) printMethodDoc(symbol, method string) bool {
+	defer pkg.flush()
+	types := pkg.findTypes(symbol)
+	if types == nil {
+		if symbol == "" {
+			return false
+		}
+		log.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
+	}
+	found := false
+	for _, typ := range types {
+		for _, meth := range typ.Methods {
+			if match(method, meth.Name) {
+				decl := meth.Decl
+				decl.Body = nil
+				pkg.emit(meth.Doc, decl)
+				found = true
+			}
+		}
+	}
+	return found
+}
+
+// methodDoc prints the docs for matches of symbol.method.
+func (pkg *Package) methodDoc(symbol, method string) {
+	defer pkg.flush()
+	if !pkg.printMethodDoc(symbol, method) {
+		log.Fatalf("no method %s.%s in package %s installed in %q", symbol, method, pkg.name, pkg.build.ImportPath)
+	}
+}
+
+// match reports whether the user's symbol matches the program's.
+// A lower-case character in the user's string matches either case in the program's.
+// The program string must be exported.
+func match(user, program string) bool {
+	if !isExported(program) {
+		return false
+	}
+	if *matchCase {
+		return user == program
+	}
+	for _, u := range user {
+		p, w := utf8.DecodeRuneInString(program)
+		program = program[w:]
+		if u == p {
+			continue
+		}
+		if unicode.IsLower(u) && simpleFold(u) == simpleFold(p) {
+			continue
+		}
+		return false
+	}
+	return program == ""
+}
+
+// simpleFold returns the minimum rune equivalent to r
+// under Unicode-defined simple case folding.
+func simpleFold(r rune) rune {
+	for {
+		r1 := unicode.SimpleFold(r)
+		if r1 <= r {
+			return r1 // wrapped around, found min
+		}
+		r = r1
+	}
+}
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
new file mode 100644
index 0000000..e0d4a6c
--- /dev/null
+++ b/src/cmd/go/alldocs.go
@@ -0,0 +1,1274 @@
+// Copyright 2011 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.
+
+// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
+// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
+
+/*
+Go is a tool for managing Go source code.
+
+Usage:
+
+	go command [arguments]
+
+The commands are:
+
+	build       compile packages and dependencies
+	clean       remove object files
+	doc         show documentation for package or symbol
+	env         print Go environment information
+	fix         run go tool fix on packages
+	fmt         run gofmt on package sources
+	generate    generate Go files by processing source
+	get         download and install packages and dependencies
+	install     compile and install packages and dependencies
+	list        list packages
+	run         compile and run Go program
+	test        test packages
+	tool        run specified go tool
+	version     print Go version
+	vet         run go tool vet on packages
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+
+	c           calling between Go and C
+	buildmode   description of build modes
+	filetype    file types
+	gopath      GOPATH environment variable
+	importpath  import path syntax
+	packages    description of package lists
+	testflag    description of testing flags
+	testfunc    description of testing functions
+
+Use "go help [topic]" for more information about that topic.
+
+
+Compile packages and dependencies
+
+Usage:
+
+	go build [-o output] [-i] [build flags] [packages]
+
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+If the arguments are a list of .go files, build treats them as a list
+of source files specifying a single package.
+
+When the command line specifies a single main package,
+build writes the resulting executable to output.
+Otherwise build compiles the packages but discards the results,
+serving only as a check that the packages can be built.
+
+The -o flag specifies the output file name. If not specified, the
+output file name depends on the arguments and derives from the name
+of the package, such as p.a for package p, unless p is 'main'. If
+the package is main and file names are provided, the file name
+derives from the first file name mentioned, such as f1 for 'go build
+f1.go f2.go'; with no files provided ('go build'), the output file
+name is the base name of the containing directory.
+
+The -i flag installs the packages that are dependencies of the target.
+
+The build flags are shared by the build, clean, get, install, list, run,
+and test commands:
+
+	-a
+		force rebuilding of packages that are already up-to-date.
+		In Go releases, does not apply to the standard library.
+	-n
+		print the commands but do not run them.
+	-p n
+		the number of builds that can be run in parallel.
+		The default is the number of CPUs available, except
+		on darwin/arm which defaults to 1.
+	-race
+		enable data race detection.
+		Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
+	-v
+		print the names of packages as they are compiled.
+	-work
+		print the name of the temporary work directory and
+		do not delete it when exiting.
+	-x
+		print the commands.
+
+	-buildmode mode
+		build mode to use. See 'go help buildmode' for more.
+	-linkshared
+		link against shared libraries previously created with
+		-buildmode=shared
+	-compiler name
+		name of compiler to use, as in runtime.Compiler (gccgo or gc).
+	-gccgoflags 'arg list'
+		arguments to pass on each gccgo compiler/linker invocation.
+	-gcflags 'arg list'
+		arguments to pass on each 5g, 6g, 8g, or 9g compiler invocation.
+	-installsuffix suffix
+		a suffix to use in the name of the package installation directory,
+		in order to keep output separate from default builds.
+		If using the -race flag, the install suffix is automatically set to race
+		or, if set explicitly, has _race appended to it.  Using a -buildmode
+		option that requires non-default compile flags has a similar effect.
+	-ldflags 'flag list'
+		arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
+	-asmflags 'flag list'
+		arguments to pass on each asm assembler invocation.
+	-tags 'tag list'
+		a list of build tags to consider satisfied during the build.
+		For more information about build tags, see the description of
+		build constraints in the documentation for the go/build package.
+	-toolexec 'cmd args'
+		a program to use to invoke toolchain programs like 5a, 5g, and 5l.
+		For example, instead of running 5g, the go command will run
+		'cmd args /path/to/5g <arguments for 5g>'.
+
+The list flags accept a space-separated list of strings. To embed spaces
+in an element in the list, surround it with either single or double quotes.
+
+For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+run 'go help gopath'.  For more about calling between Go and C/C++,
+run 'go help c'.
+
+See also: go install, go get, go clean.
+
+
+Remove object files
+
+Usage:
+
+	go clean [-i] [-r] [-n] [-x] [build flags] [packages]
+
+Clean removes object files from package source directories.
+The go command builds most objects in a temporary directory,
+so go clean is mainly concerned with object files left by other
+tools or by manual invocations of go build.
+
+Specifically, clean removes the following files from each of the
+source directories corresponding to the import paths:
+
+	_obj/            old object directory, left from Makefiles
+	_test/           old test directory, left from Makefiles
+	_testmain.go     old gotest file, left from Makefiles
+	test.out         old test log, left from Makefiles
+	build.out        old test log, left from Makefiles
+	*.[568ao]        object files, left from Makefiles
+
+	DIR(.exe)        from go build
+	DIR.test(.exe)   from go test -c
+	MAINFILE(.exe)   from go build MAINFILE.go
+	*.so             from SWIG
+
+In the list, DIR represents the final path element of the
+directory, and MAINFILE is the base name of any Go source
+file in the directory that is not included when building
+the package.
+
+The -i flag causes clean to remove the corresponding installed
+archive or binary (what 'go install' would create).
+
+The -n flag causes clean to print the remove commands it would execute,
+but not run them.
+
+The -r flag causes clean to be applied recursively to all the
+dependencies of the packages named by the import paths.
+
+The -x flag causes clean to print remove commands as it executes them.
+
+For more about build flags, see 'go help build'.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Show documentation for package or symbol
+
+Usage:
+
+	go doc [-u] [-c] [package|[package.]symbol[.method]]
+
+Doc prints the documentation comments associated with the item identified by its
+arguments (a package, const, func, type, var, or method) followed by a one-line
+summary of each of the first-level items "under" that item (package-level declarations
+for a package, methods for a type, etc.).
+
+Doc accepts zero, one, or two arguments.
+
+Given no arguments, that is, when run as
+
+	go doc
+
+it prints the package documentation for the package in the current directory.
+
+When run with one argument, the argument is treated as a Go-syntax-like representation
+of the item to be documented. What the argument selects depends on what is installed
+in GOROOT and GOPATH, as well as the form of the argument, which is schematically
+one of these:
+
+	go doc <pkg>
+	go doc <sym>[.<method>]
+	go doc [<pkg>].<sym>[.<method>]
+
+The first item in this list matched by the argument is the one whose documentation
+is printed. (See the examples below.) For packages, the order of scanning is
+determined lexically, but the GOROOT tree is always scanned before GOPATH.
+
+If there is no package specified or matched, the package in the current directory
+is selected, so "go doc Foo" shows the documentation for symbol Foo in the current
+package.
+
+The package path must be either a qualified path or a proper suffix of a path. The
+go tool's usual package mechanism does not apply: package path elements like . and
+... are not implemented by go doc.
+
+When run with two arguments, the first must be a full package path (not just a
+suffix), and the second is a symbol or symbol and method; this is similar to the
+syntax accepted by godoc:
+
+	go doc <pkg> <sym>[.<method>]
+
+In all forms, when matching symbols, lower-case letters in the argument match
+either case but upper-case letters match exactly. This means that there may be
+multiple matches of a lower-case argument in a package if different symbols have
+different cases. If this occurs, documentation for all matches is printed.
+
+Examples:
+	go doc
+		Show documentation for current package.
+	go doc Foo
+		Show documentation for Foo in the current package.
+		(Foo starts with a capital letter so it cannot match a package path.)
+	go doc encoding/json
+		Show documentation for the encoding/json package.
+	go doc json
+		Shorthand for encoding/json.
+	go doc json.Number (or go doc json.number)
+		Show documentation and method summary for json.Number.
+	go doc json.Number.Int64 (or go doc json.number.int64)
+		Show documentation for json.Number's Int64 method.
+	go doc template.new
+		Show documentation for html/template's New function.
+		(html/template is lexically before text/template)
+	go doc text/template.new # One argument
+		Show documentation for text/template's New function.
+	go doc text/template new # Two arguments
+		Show documentation for text/template's New function.
+
+Flags:
+	-c
+		Respect case when matching symbols.
+	-u
+		Show documentation for unexported as well as exported
+		symbols and methods.
+
+
+Print Go environment information
+
+Usage:
+
+	go env [var ...]
+
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file).  If one or more variable
+names is given as arguments,  env prints the value of
+each named variable on its own line.
+
+
+Run go tool fix on packages
+
+Usage:
+
+	go fix [packages]
+
+Fix runs the Go fix command on the packages named by the import paths.
+
+For more about fix, see 'godoc fix'.
+For more about specifying packages, see 'go help packages'.
+
+To run fix with specific options, run 'go tool fix'.
+
+See also: go fmt, go vet.
+
+
+Run gofmt on package sources
+
+Usage:
+
+	go fmt [-n] [-x] [packages]
+
+Fmt runs the command 'gofmt -l -w' on the packages named
+by the import paths.  It prints the names of the files that are modified.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about specifying packages, see 'go help packages'.
+
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go fix, go vet.
+
+
+Generate Go files by processing source
+
+Usage:
+
+	go generate [-run regexp] [file.go... | packages]
+
+Generate runs commands described by directives within existing
+files. Those commands can run any process but the intent is to
+create or update Go source files, for instance by running yacc.
+
+Go generate is never run automatically by go build, go get, go test,
+and so on. It must be run explicitly.
+
+Go generate scans the file for directives, which are lines of
+the form,
+
+	//go:generate command argument...
+
+(note: no leading spaces and no space in "//go") where command
+is the generator to be run, corresponding to an executable file
+that can be run locally. It must either be in the shell path
+(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
+command alias, described below.
+
+Note that go generate does not parse the file, so lines that look
+like directives in comments or multiline strings will be treated
+as directives.
+
+The arguments to the directive are space-separated tokens or
+double-quoted strings passed to the generator as individual
+arguments when it is run.
+
+Quoted strings use Go syntax and are evaluated before execution; a
+quoted string appears as a single argument to the generator.
+
+Go generate sets several variables when it runs the generator:
+
+	$GOARCH
+		The execution architecture (arm, amd64, etc.)
+	$GOOS
+		The execution operating system (linux, windows, etc.)
+	$GOFILE
+		The base name of the file.
+	$GOLINE
+		The line number of the directive in the source file.
+	$GOPACKAGE
+		The name of the package of the file containing the directive.
+	$DOLLAR
+		A dollar sign.
+
+Other than variable substitution and quoted-string evaluation, no
+special processing such as "globbing" is performed on the command
+line.
+
+As a last step before running the command, any invocations of any
+environment variables with alphanumeric names, such as $GOFILE or
+$HOME, are expanded throughout the command line. The syntax for
+variable expansion is $NAME on all operating systems.  Due to the
+order of evaluation, variables are expanded even inside quoted
+strings. If the variable NAME is not set, $NAME expands to the
+empty string.
+
+A directive of the form,
+
+	//go:generate -command xxx args...
+
+specifies, for the remainder of this source file only, that the
+string xxx represents the command identified by the arguments. This
+can be used to create aliases or to handle multiword generators.
+For example,
+
+	//go:generate -command yacc go tool yacc
+
+specifies that the command "yacc" represents the generator
+"go tool yacc".
+
+Generate processes packages in the order given on the command line,
+one at a time. If the command line lists .go files, they are treated
+as a single package. Within a package, generate processes the
+source files in a package in file name order, one at a time. Within
+a source file, generate runs generators in the order they appear
+in the file, one at a time.
+
+If any generator returns an error exit status, "go generate" skips
+all further processing for that package.
+
+The generator is run in the package's source directory.
+
+Go generate accepts one specific flag:
+
+	-run=""
+		if non-empty, specifies a regular expression to select
+		directives whose full original source text (excluding
+		any trailing spaces and final newline) matches the
+		expression.
+
+It also accepts the standard build flags -v, -n, and -x.
+The -v flag prints the names of packages and files as they are
+processed.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Download and install packages and dependencies
+
+Usage:
+
+	go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+The -d flag instructs get to stop after downloading the packages; that is,
+it instructs get not to install the packages.
+
+The -f flag, valid only when -u is set, forces get -u not to verify that
+each package has been checked out from the source control repository
+implied by its import path. This can be useful if the source is a local fork
+of the original.
+
+The -fix flag instructs get to run the fix tool on the downloaded packages
+before resolving dependencies or building the code.
+
+The -t flag instructs get to also download the packages required to build
+the tests for the specified packages.
+
+The -u flag instructs get to use the network to update the named packages
+and their dependencies.  By default, get uses the network to check out
+missing packages but does not use it to look for updates to existing packages.
+
+Get also accepts build flags to control the installation. See 'go help build'.
+
+When checking out or updating a package, get looks for a branch or tag
+that matches the locally installed version of Go. The most important
+rule is that if the local installation is running version "go1", get
+searches for a branch or tag named "go1". If no such version exists it
+retrieves the most recent version of the package.
+
+For more about specifying packages, see 'go help packages'.
+
+For more about how 'go get' finds source code to
+download, see 'go help importpath'.
+
+See also: go build, go install, go clean.
+
+
+Compile and install packages and dependencies
+
+Usage:
+
+	go install [build flags] [packages]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go get, go clean.
+
+
+List packages
+
+Usage:
+
+	go list [-e] [-f format] [-json] [build flags] [packages]
+
+List lists the packages named by the import paths, one per line.
+
+The default output shows the package import path:
+
+    code.google.com/p/google-api-go-client/books/v1
+    code.google.com/p/goauth2/oauth
+    code.google.com/p/sqlite
+
+The -f flag specifies an alternate format for the list, using the
+syntax of package template.  The default output is equivalent to -f
+'{{.ImportPath}}'. The struct being passed to the template is:
+
+    type Package struct {
+        Dir           string // directory containing package sources
+        ImportPath    string // import path of package in dir
+        ImportComment string // path in import comment on package statement
+        Name          string // package name
+        Doc           string // package documentation string
+        Target        string // install path
+        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?
+        Root          string // Go root or Go path dir containing this package
+
+        // Source files
+        GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+        CgoFiles       []string // .go sources files that import "C"
+        IgnoredGoFiles []string // .go sources ignored due to build constraints
+        CFiles         []string // .c source files
+        CXXFiles       []string // .cc, .cxx and .cpp source files
+        MFiles         []string // .m source files
+        HFiles         []string // .h, .hh, .hpp and .hxx source files
+        SFiles         []string // .s source files
+        SwigFiles      []string // .swig files
+        SwigCXXFiles   []string // .swigcxx files
+        SysoFiles      []string // .syso object files to add to archive
+
+        // Cgo directives
+        CgoCFLAGS    []string // cgo: flags for C compiler
+        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
+        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
+        CgoLDFLAGS   []string // cgo: flags for linker
+        CgoPkgConfig []string // cgo: pkg-config names
+
+        // Dependency information
+        Imports []string // import paths used by this package
+        Deps    []string // all (recursively) imported dependencies
+
+        // Error information
+        Incomplete bool            // this package or a dependency has an error
+        Error      *PackageError   // error loading package
+        DepsErrors []*PackageError // errors loading dependencies
+
+        TestGoFiles  []string // _test.go files in package
+        TestImports  []string // imports from TestGoFiles
+        XTestGoFiles []string // _test.go files outside package
+        XTestImports []string // imports from XTestGoFiles
+    }
+
+The template function "join" calls strings.Join.
+
+The template function "context" returns the build context, defined as:
+
+	type Context struct {
+		GOARCH        string   // target architecture
+		GOOS          string   // target operating system
+		GOROOT        string   // Go root
+		GOPATH        string   // Go path
+		CgoEnabled    bool     // whether cgo can be used
+		UseAllFiles   bool     // use files regardless of +build lines, file names
+		Compiler      string   // compiler to assume when computing target paths
+		BuildTags     []string // build constraints to match in +build lines
+		ReleaseTags   []string // releases the current release is compatible with
+		InstallSuffix string   // suffix to use in the name of the install dir
+	}
+
+For more information about the meaning of these fields see the documentation
+for the go/build package's Context type.
+
+The -json flag causes the package data to be printed in JSON format
+instead of using the template format.
+
+The -e flag changes the handling of erroneous packages, those that
+cannot be found or are malformed.  By default, the list command
+prints an error to standard error for each erroneous package and
+omits the packages from consideration during the usual printing.
+With the -e flag, the list command never prints errors to standard
+error and instead processes the erroneous packages with the usual
+printing.  Erroneous packages will have a non-empty ImportPath and
+a non-nil Error field; other information may or may not be missing
+(zeroed).
+
+For more about build flags, see 'go help build'.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Compile and run Go program
+
+Usage:
+
+	go run [build flags] [-exec xprog] gofiles... [arguments...]
+
+Run compiles and runs the main package comprising the named Go source files.
+A Go source file is defined to be a file ending in a literal ".go" suffix.
+
+By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
+If the -exec flag is not given, GOOS or GOARCH is different from the system
+default, and a program named go_$GOOS_$GOARCH_exec can be found
+on the current search path, 'go run' invokes the binary using that program,
+for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+cross-compiled programs when a simulator or other execution method is
+available.
+
+For more about build flags, see 'go help build'.
+
+See also: go build.
+
+
+Test packages
+
+Usage:
+
+	go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
+
+'Go test' automates testing the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+	ok   archive/tar   0.011s
+	FAIL archive/zip   0.022s
+	ok   compress/gzip 0.033s
+	...
+
+followed by detailed output for each failed package.
+
+'Go test' recompiles each package along with any files with names matching
+the file pattern "*_test.go".
+Files whose names begin with "_" (including "_test.go") or "." are ignored.
+These additional files can contain test functions, benchmark functions, and
+example functions.  See 'go help testfunc' for more.
+Each listed package causes the execution of a separate test binary.
+
+Test files that declare a package with the suffix "_test" will be compiled as a
+separate package, and then linked and run with the main test binary.
+
+By default, go test needs no arguments.  It compiles and tests the package
+with source in the current directory, including tests, and runs the tests.
+
+The package is built in a temporary directory so it does not interfere with the
+non-test installation.
+
+In addition to the build flags, the flags handled by 'go test' itself are:
+
+	-c
+		Compile the test binary to pkg.test but do not run it
+		(where pkg is the last element of the package's import path).
+		The file name can be changed with the -o flag.
+
+	-exec xprog
+	    Run the test binary using xprog. The behavior is the same as
+	    in 'go run'. See 'go help run' for details.
+
+	-i
+	    Install packages that are dependencies of the test.
+	    Do not run the test.
+
+	-o file
+		Compile the test binary to the named file.
+		The test still runs (unless -c or -i is specified).
+
+
+The test binary also accepts flags that control execution of the test; these
+flags are also accessible by 'go test'.  See 'go help testflag' for details.
+
+If the test binary needs any other flags, they should be presented after the
+package names. The go tool treats as a flag the first argument that begins with
+a minus sign that it does not recognize itself; that argument and all subsequent
+arguments are passed as arguments to the test binary.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+
+
+Run specified go tool
+
+Usage:
+
+	go tool [-n] command [args...]
+
+Tool runs the go tool command identified by the arguments.
+With no arguments it prints the list of known tools.
+
+The -n flag causes tool to print the command that would be
+executed but not execute it.
+
+For more about each tool command, see 'go tool command -h'.
+
+
+Print Go version
+
+Usage:
+
+	go version
+
+Version prints the Go version, as reported by runtime.Version.
+
+
+Run go tool vet on packages
+
+Usage:
+
+	go vet [-n] [-x] [packages]
+
+Vet runs the Go vet command on the packages named by the import paths.
+
+For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
+For more about specifying packages, see 'go help packages'.
+
+To run the vet tool with specific options, run 'go tool vet'.
+
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+See also: go fmt, go fix.
+
+
+Calling between Go and C
+
+There are two different ways to call between Go and C/C++ code.
+
+The first is the cgo tool, which is part of the Go distribution.  For
+information on how to use it see the cgo documentation (godoc cmd/cgo).
+
+The second is the SWIG program, which is a general tool for
+interfacing between languages.  For information on SWIG see
+http://swig.org/.  When running go build, any file with a .swig
+extension will be passed to SWIG.  Any file with a .swigcxx extension
+will be passed to SWIG with the -c++ option.
+
+When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+compiler.  The CC or CXX environment variables may be set to determine
+the C or C++ compiler, respectively, to use.
+
+
+Description of build modes
+
+The 'go build' and 'go install' commands take a -buildmode argument which
+indicates which kind of object file is to be built. Currently supported values
+are:
+
+	-buildmode=archive
+		Build the listed non-main packages into .a files. Packages named
+		main are ignored.
+
+	-buildmode=c-archive
+		Build the listed main package, plus all packages it imports,
+		into a C archive file. The only callable symbols will be those
+		functions marked as exported. Requires exactly one main package
+		to be listed.
+
+	-buildmode=c-shared
+		Build the listed main packages, plus all packages that they
+		import, into C shared libraries. The only callable symbols will
+		be those functions marked as exported. Non-main packages are
+		ignored.
+
+	-buildmode=default
+		Listed main packages are built into executables and listed
+		non-main packages are built into .a files (the default
+		behavior).
+
+	-buildmode=shared
+		Combine all the listed non-main packages into a single shared
+		library that will be used when building with the -linkshared
+		option. Packages named main are ignored.
+
+	-buildmode=exe
+		Build the listed main packages and everything they import into
+		executables. Packages not named main are ignored.
+
+
+File types
+
+The go command examines the contents of a restricted set of files
+in each directory. It identifies which files to examine based on
+the extension of the file name. These extensions are:
+
+	.go
+		Go source files.
+	.c, .h
+		C source files.
+		If the package uses cgo, these will be compiled with the
+		OS-native compiler (typically gcc); otherwise they will be
+		compiled with the Go-specific support compiler,
+		5c, 6c, or 8c, etc. as appropriate.
+	.cc, .cpp, .cxx, .hh, .hpp, .hxx
+		C++ source files. Only useful with cgo or SWIG, and always
+		compiled with the OS-native compiler.
+	.m
+		Objective-C source files. Only useful with cgo, and always
+		compiled with the OS-native compiler.
+	.s, .S
+		Assembler source files.
+		If the package uses cgo, these will be assembled with the
+		OS-native assembler (typically gcc (sic)); otherwise they
+		will be assembled with the Go-specific support assembler,
+		5a, 6a, or 8a, etc., as appropriate.
+	.swig, .swigcxx
+		SWIG definition files.
+	.syso
+		System object files.
+
+Files of each of these types except .syso may contain build
+constraints, but the go command stops scanning for build constraints
+at the first item in the file that is not a blank line or //-style
+line comment.
+
+
+GOPATH environment variable
+
+The Go path is used to resolve import statements.
+It is implemented by and documented in the go/build package.
+
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to get, build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src/ directory holds source code.  The path below 'src'
+determines the import path or executable name.
+
+The pkg/ directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin/ directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path.  That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands.  If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
+
+Here's an example directory layout:
+
+    GOPATH=/home/user/gocode
+
+    /home/user/gocode/
+        src/
+            foo/
+                bar/               (go code in package bar)
+                    x.go
+                quux/              (go code in package main)
+                    y.go
+        bin/
+            quux                   (installed command)
+        pkg/
+            linux_amd64/
+                foo/
+                    bar.a          (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory
+in the list.
+
+
+Import path syntax
+
+An import path (see 'go help packages') denotes a package
+stored in the local file system.  In general, an import path denotes
+either a standard package (such as "unicode/utf8") or a package
+found in one of the work spaces (see 'go help gopath').
+
+Relative import paths
+
+An import path beginning with ./ or ../ is called a relative path.
+The toolchain supports relative import paths as a shortcut in two ways.
+
+First, a relative path can be used as a shorthand on the command line.
+If you are working in the directory containing the code imported as
+"unicode" and want to run the tests for "unicode/utf8", you can type
+"go test ./utf8" instead of needing to specify the full path.
+Similarly, in the reverse situation, "go test .." will test "unicode" from
+the "unicode/utf8" directory. Relative patterns are also allowed, like
+"go test ./..." to test all subdirectories. See 'go help packages' for details
+on the pattern syntax.
+
+Second, if you are compiling a Go program not in a work space,
+you can use a relative path in an import statement in that program
+to refer to nearby code also not in a work space.
+This makes it easy to experiment with small multipackage programs
+outside of the usual work spaces, but such programs cannot be
+installed with "go install" (there is no work space in which to install them),
+so they are rebuilt from scratch each time they are built.
+To avoid ambiguity, Go programs cannot use relative import paths
+within a work space.
+
+Remote import paths
+
+Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+	Bitbucket (Git, Mercurial)
+
+		import "bitbucket.org/user/project"
+		import "bitbucket.org/user/project/sub/directory"
+
+	GitHub (Git)
+
+		import "github.com/user/project"
+		import "github.com/user/project/sub/directory"
+
+	Google Code Project Hosting (Git, Mercurial, Subversion)
+
+		import "code.google.com/p/project"
+		import "code.google.com/p/project/sub/directory"
+
+		import "code.google.com/p/project.subrepository"
+		import "code.google.com/p/project.subrepository/sub/directory"
+
+	Launchpad (Bazaar)
+
+		import "launchpad.net/project"
+		import "launchpad.net/project/series"
+		import "launchpad.net/project/series/sub/directory"
+
+		import "launchpad.net/~user/project/branch"
+		import "launchpad.net/~user/project/branch/sub/directory"
+
+	IBM DevOps Services (Git)
+
+		import "hub.jazz.net/git/user/project"
+		import "hub.jazz.net/git/user/project/sub/directory"
+
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
+
+	repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository.  The supported version control systems are:
+
+	Bazaar      .bzr
+	Git         .git
+	Mercurial   .hg
+	Subversion  .svn
+
+For example,
+
+	import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+example.org/user/foo or foo.hg, and
+
+	import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at
+example.org/repo or repo.git.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading.  For example, a Git
+download tries git://, then https://, then http://.
+
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+	<meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path corresponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+	import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+	https://example.org/pkg/foo?go-get=1 (preferred)
+	http://example.org/pkg/foo?go-get=1  (fallback)
+
+If that page contains the meta tag
+
+	<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help get' for more.
+
+Import path checking
+
+When the custom import path feature described above redirects to a
+known code hosting site, each of the resulting packages has two possible
+import paths, using the custom domain or the known hosting site.
+
+A package statement is said to have an "import comment" if it is immediately
+followed (before the next newline) by a comment of one of these two forms:
+
+	package math // import "path"
+	package math /* import "path" * /
+
+The go command will refuse to install a package with an import comment
+unless it is being referred to by that import path. In this way, import comments
+let package authors make sure the custom import path is used and not a
+direct path to the underlying code hosting site.
+
+See https://golang.org/s/go14customimport for details.
+
+
+Description of package lists
+
+Many commands apply to a set of packages:
+
+	go action [packages]
+
+Usually, [packages] is a list of import paths.
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath').
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+There are three reserved names for paths that should not be used
+for packages to be built with the go tool:
+
+- "main" denotes the top-level package in a stand-alone executable.
+
+- "all" expands to all package directories found in all the GOPATH
+trees. For example, 'go list all' lists all the packages on the local
+system.
+
+- "std" is like all but expands to just the packages in the standard
+Go library.
+
+- "cmd" expands to the Go repository's commands and their
+internal libraries.
+
+An import path is a pattern if it includes one or more "..." wildcards,
+each of which can match any string, including the empty string and
+strings containing slashes.  Such a pattern expands to all package
+directories found in the GOPATH trees with names matching the
+patterns.  As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
+
+An import path can also name a package to be downloaded from
+a remote repository.  Run 'go help importpath' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you.  For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'code.google.com/p/project'.
+
+As a special case, if the package list is a list of .go files from a
+single directory, the command is applied to a single synthesized
+package made up of exactly those files, ignoring any build constraints
+in those files and ignoring any other files in the directory.
+
+Directory and file names that begin with "." or "_" are ignored
+by the go tool, as are directories named "testdata".
+
+
+Description of testing flags
+
+The 'go test' command takes both flags that apply to 'go test' itself
+and flags that apply to the resulting test binary.
+
+Several of the flags control profiling and write an execution profile
+suitable for "go tool pprof"; run "go tool pprof help" for more
+information.  The --alloc_space, --alloc_objects, and --show_bytes
+options of pprof control how the information is presented.
+
+The following flags are recognized by the 'go test' command and
+control the execution of any test:
+
+	-bench regexp
+	    Run benchmarks matching the regular expression.
+	    By default, no benchmarks run. To run all benchmarks,
+	    use '-bench .' or '-bench=.'.
+
+	-benchmem
+	    Print memory allocation statistics for benchmarks.
+
+	-benchtime t
+	    Run enough iterations of each benchmark to take t, specified
+	    as a time.Duration (for example, -benchtime 1h30s).
+	    The default is 1 second (1s).
+
+	-blockprofile block.out
+	    Write a goroutine blocking profile to the specified file
+	    when all tests are complete.
+	    Writes test binary as -c would.
+
+	-blockprofilerate n
+	    Control the detail provided in goroutine blocking profiles by
+	    calling runtime.SetBlockProfileRate with n.
+	    See 'godoc runtime SetBlockProfileRate'.
+	    The profiler aims to sample, on average, one blocking event every
+	    n nanoseconds the program spends blocked.  By default,
+	    if -test.blockprofile is set without this flag, all blocking events
+	    are recorded, equivalent to -test.blockprofilerate=1.
+
+	-cover
+	    Enable coverage analysis.
+
+	-covermode set,count,atomic
+	    Set the mode for coverage analysis for the package[s]
+	    being tested. The default is "set" unless -race is enabled,
+	    in which case it is "atomic".
+	    The values:
+		set: bool: does this statement run?
+		count: int: how many times does this statement run?
+		atomic: int: count, but correct in multithreaded tests;
+			significantly more expensive.
+	    Sets -cover.
+
+	-coverpkg pkg1,pkg2,pkg3
+	    Apply coverage analysis in each test to the given list of packages.
+	    The default is for each test to analyze only the package being tested.
+	    Packages are specified as import paths.
+	    Sets -cover.
+
+	-coverprofile cover.out
+	    Write a coverage profile to the file after all tests have passed.
+	    Sets -cover.
+
+	-cpu 1,2,4
+	    Specify a list of GOMAXPROCS values for which the tests or
+	    benchmarks should be executed.  The default is the current value
+	    of GOMAXPROCS.
+
+	-cpuprofile cpu.out
+	    Write a CPU profile to the specified file before exiting.
+	    Writes test binary as -c would.
+
+	-memprofile mem.out
+	    Write a memory profile to the file after all tests have passed.
+	    Writes test binary as -c would.
+
+	-memprofilerate n
+	    Enable more precise (and expensive) memory profiles by setting
+	    runtime.MemProfileRate.  See 'godoc runtime MemProfileRate'.
+	    To profile all memory allocations, use -test.memprofilerate=1
+	    and pass --alloc_space flag to the pprof tool.
+
+	-outputdir directory
+	    Place output files from profiling in the specified directory,
+	    by default the directory in which "go test" is running.
+
+	-parallel n
+	    Allow parallel execution of test functions that call t.Parallel.
+	    The value of this flag is the maximum number of tests to run
+	    simultaneously; by default, it is set to the value of GOMAXPROCS.
+
+	-run regexp
+	    Run only those tests and examples matching the regular
+	    expression.
+
+	-short
+	    Tell long-running tests to shorten their run time.
+	    It is off by default but set during all.bash so that installing
+	    the Go tree can run a sanity check but not spend time running
+	    exhaustive tests.
+
+	-timeout t
+	    If a test runs longer than t, panic.
+
+	-trace trace.out
+	    Write an execution trace to the specified file before exiting.
+	    Writes test binary as -c would.
+
+	-v
+	    Verbose output: log all tests as they are run. Also print all
+	    text from Log and Logf calls even if the test succeeds.
+
+The test binary, called pkg.test where pkg is the name of the
+directory containing the package sources, can be invoked directly
+after building it with 'go test -c'. When invoking the test binary
+directly, each of the standard flag names must be prefixed with 'test.',
+as in -test.run=TestMyFunc or -test.v.
+
+When running 'go test', flags not listed above are passed through
+unaltered. For instance, the command
+
+	go test -x -v -cpuprofile=prof.out -dir=testdata -update
+
+will compile the test binary and then run it as
+
+	pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+
+The test flags that generate profiles (other than for coverage) also
+leave the test binary in pkg.test for use when analyzing the profiles.
+
+Flags not recognized by 'go test' must be placed after any specified packages.
+
+
+Description of testing functions
+
+The 'go test' command expects to find test, benchmark, and example functions
+in the "*_test.go" files corresponding to the package under test.
+
+A test function is one named TestXXX (where XXX is any alphanumeric string
+not starting with a lower case letter) and should have the signature,
+
+	func TestXXX(t *testing.T) { ... }
+
+A benchmark function is one named BenchmarkXXX and should have the signature,
+
+	func BenchmarkXXX(b *testing.B) { ... }
+
+An example function is similar to a test function but, instead of using
+*testing.T to report success or failure, prints output to os.Stdout.
+That output is compared against the function's "Output:" comment, which
+must be the last comment in the function body (see example below). An
+example with no such comment, or with no text after "Output:" is compiled
+but not executed.
+
+Godoc displays the body of ExampleXXX to demonstrate the use
+of the function, constant, or variable XXX.  An example of a method M with
+receiver type T or *T is named ExampleT_M.  There may be multiple examples
+for a given function, constant, or variable, distinguished by a trailing _xxx,
+where xxx is a suffix not beginning with an upper case letter.
+
+Here is an example of an example:
+
+	func ExamplePrintln() {
+		Println("The output of\nthis example.")
+		// Output: The output of
+		// this example.
+	}
+
+The entire test file is presented as the example when it contains a single
+example function, at least one other function, type, variable, or constant
+declaration, and no test or benchmark functions.
+
+See the documentation of the testing package for more information.
+
+
+*/
+package main
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
index dc7ed5f..c6f569e 100644
--- a/src/cmd/go/bootstrap.go
+++ b/src/cmd/go/bootstrap.go
@@ -17,6 +17,14 @@
 
 var errHTTP = errors.New("no http in bootstrap go command")
 
+type httpError struct {
+	statusCode int
+}
+
+func (e *httpError) Error() string {
+	panic("unreachable")
+}
+
 func httpGET(url string) ([]byte, error) {
 	return nil, errHTTP
 }
@@ -28,3 +36,7 @@
 func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
 	panic("unreachable")
 }
+
+func readnote(a, b string, t int32) ([]byte, error) {
+	return nil, nil
+}
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 61453c7..fda126b 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -75,6 +75,11 @@
 	-x
 		print the commands.
 
+	-buildmode mode
+		build mode to use. See 'go help buildmode' for more.
+	-linkshared
+		link against shared libraries previously created with
+		-buildmode=shared
 	-compiler name
 		name of compiler to use, as in runtime.Compiler (gccgo or gc).
 	-gccgoflags 'arg list'
@@ -85,7 +90,8 @@
 		a suffix to use in the name of the package installation directory,
 		in order to keep output separate from default builds.
 		If using the -race flag, the install suffix is automatically set to race
-		or, if set explicitly, has _race appended to it.
+		or, if set explicitly, has _race appended to it.  Using a -buildmode
+		option that requires non-default compile flags has a similar effect.
 	-ldflags 'flag list'
 		arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
 	-asmflags 'flag list'
@@ -121,12 +127,15 @@
 	addBuildFlags(cmdBuild)
 	addBuildFlags(cmdInstall)
 
-	if buildContext.GOOS == "darwin" && buildContext.GOARCH == "arm" {
-		// darwin/arm cannot run multiple tests simultaneously.
-		// Parallelism is limited in go_darwin_arm_exec, but
-		// also needs to be limited here so go test std does not
-		// timeout tests that waiting to run.
-		buildP = 1
+	if buildContext.GOOS == "darwin" {
+		switch buildContext.GOARCH {
+		case "arm", "arm64":
+			// darwin/arm cannot run multiple tests simultaneously.
+			// Parallelism is limited in go_darwin_arm_exec, but
+			// also needs to be limited here so go test std does not
+			// timeout tests that waiting to run.
+			buildP = 1
+		}
 	}
 }
 
@@ -145,9 +154,12 @@
 var buildGccgoflags []string // -gccgoflags flag
 var buildRace bool           // -race flag
 var buildToolExec []string   // -toolexec flag
+var buildBuildmode string    // -buildmode flag
+var buildLinkshared bool     // -linkshared flag
 
 var buildContext = build.Default
 var buildToolchain toolchain = noToolchain{}
+var ldBuildmode string
 
 // buildCompiler implements flag.Var.
 // It implements Set by updating both
@@ -199,6 +211,8 @@
 	cmd.Flag.Var(buildCompiler{}, "compiler", "")
 	cmd.Flag.BoolVar(&buildRace, "race", false, "")
 	cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "")
+	cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "")
+	cmd.Flag.BoolVar(&buildLinkshared, "linkshared", false, "")
 }
 
 func addBuildFlagsNX(cmd *Command) {
@@ -273,8 +287,112 @@
 	return "<stringsFlag>"
 }
 
+func pkgsMain(pkgs []*Package) (res []*Package) {
+	for _, p := range pkgs {
+		if p.Name == "main" {
+			res = append(res, p)
+		}
+	}
+	return res
+}
+
+func pkgsNotMain(pkgs []*Package) (res []*Package) {
+	for _, p := range pkgs {
+		if p.Name != "main" {
+			res = append(res, p)
+		}
+	}
+	return res
+}
+
+var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
+
+func buildModeInit() {
+	_, gccgo := buildToolchain.(gccgoToolchain)
+	var codegenArg string
+	platform := goos + "/" + goarch
+	switch buildBuildmode {
+	case "archive":
+		pkgsFilter = pkgsNotMain
+	case "c-archive":
+		pkgsFilter = func(p []*Package) []*Package {
+			if len(p) != 1 || p[0].Name != "main" {
+				fatalf("-buildmode=c-archive requires exactly one main package")
+			}
+			return p
+		}
+		exeSuffix = ".a"
+		ldBuildmode = "c-archive"
+	case "c-shared":
+		pkgsFilter = pkgsMain
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/amd64":
+				codegenArg = "-shared"
+			case "linux/arm":
+				buildAsmflags = append(buildAsmflags, "-shared")
+			case "android/arm":
+			default:
+				fatalf("-buildmode=c-shared not supported on %s\n", platform)
+			}
+		}
+		ldBuildmode = "c-shared"
+	case "default":
+		ldBuildmode = "exe"
+	case "exe":
+		pkgsFilter = pkgsMain
+		ldBuildmode = "exe"
+	case "shared":
+		pkgsFilter = pkgsNotMain
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/amd64":
+			default:
+				fatalf("-buildmode=shared not supported on %s\n", platform)
+			}
+			codegenArg = "-dynlink"
+		}
+		if *buildO != "" {
+			fatalf("-buildmode=shared and -o not supported together")
+		}
+		ldBuildmode = "shared"
+	default:
+		fatalf("buildmode=%s not supported", buildBuildmode)
+	}
+	if buildLinkshared {
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			if platform != "linux/amd64" {
+				fmt.Fprintf(os.Stderr, "go %s: -linkshared is only supported on linux/amd64\n", flag.Args()[0])
+				os.Exit(2)
+			}
+			codegenArg = "-dynlink"
+			// TODO(mwhudson): remove -w when that gets fixed in linker.
+			buildLdflags = append(buildLdflags, "-linkshared", "-w")
+		}
+	}
+	if codegenArg != "" {
+		if gccgo {
+			buildGccgoflags = append(buildGccgoflags, codegenArg)
+		} else {
+			buildAsmflags = append(buildAsmflags, codegenArg)
+			buildGcflags = append(buildGcflags, codegenArg)
+		}
+		if buildContext.InstallSuffix != "" {
+			buildContext.InstallSuffix += "_"
+		}
+		buildContext.InstallSuffix += codegenArg[1:]
+	}
+}
+
 func runBuild(cmd *Command, args []string) {
 	raceInit()
+	buildModeInit()
 	var b builder
 	b.init()
 
@@ -315,13 +433,23 @@
 		p.target = "" // must build - not up to date
 		a := b.action(modeInstall, depMode, p)
 		a.target = *buildO
+		if p.local {
+			// If p.local, then b.action did not really install,
+			// so install the header file now if necessary.
+			a = b.maybeAddHeaderAction(a, false)
+		}
 		b.do(a)
 		return
 	}
 
-	a := &action{}
-	for _, p := range packages(args) {
-		a.deps = append(a.deps, b.action(modeBuild, depMode, p))
+	var a *action
+	if buildBuildmode == "shared" {
+		a = b.libaction(libname(args), pkgsFilter(packages(args)), modeBuild, depMode)
+	} else {
+		a = &action{}
+		for _, p := range pkgsFilter(packages(args)) {
+			a.deps = append(a.deps, b.action(modeBuild, depMode, p))
+		}
 	}
 	b.do(a)
 }
@@ -340,9 +468,34 @@
 	`,
 }
 
+// libname returns the filename to use for the shared library when using
+// -buildmode=shared.  The rules we use are:
+//  1) Drop any trailing "/..."s if present
+//  2) Change / to -
+//  3) Join arguments with ,
+// So std -> libstd.so
+//    a b/... -> liba,b.so
+//    gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
+func libname(args []string) string {
+	var libname string
+	for _, arg := range args {
+		arg = strings.TrimSuffix(arg, "/...")
+		arg = strings.Replace(arg, "/", "-", -1)
+		if libname == "" {
+			libname = arg
+		} else {
+			libname += "," + arg
+		}
+	}
+	// TODO(mwhudson): Needs to change for platforms that use different naming
+	// conventions...
+	return "lib" + libname + ".so"
+}
+
 func runInstall(cmd *Command, args []string) {
 	raceInit()
-	pkgs := packagesForBuild(args)
+	buildModeInit()
+	pkgs := pkgsFilter(packagesForBuild(args))
 
 	for _, p := range pkgs {
 		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
@@ -359,26 +512,31 @@
 
 	var b builder
 	b.init()
-	a := &action{}
-	var tools []*action
-	for _, p := range pkgs {
-		// If p is a tool, delay the installation until the end of the build.
-		// This avoids installing assemblers/compilers that are being executed
-		// by other steps in the build.
-		// cmd/cgo is handled specially in b.action, so that we can
-		// both build and use it in the same 'go install'.
-		action := b.action(modeInstall, modeInstall, p)
-		if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
-			a.deps = append(a.deps, action.deps...)
-			action.deps = append(action.deps, a)
-			tools = append(tools, action)
-			continue
+	var a *action
+	if buildBuildmode == "shared" {
+		a = b.libaction(libname(args), pkgs, modeInstall, modeInstall)
+	} else {
+		a = &action{}
+		var tools []*action
+		for _, p := range pkgs {
+			// If p is a tool, delay the installation until the end of the build.
+			// This avoids installing assemblers/compilers that are being executed
+			// by other steps in the build.
+			// cmd/cgo is handled specially in b.action, so that we can
+			// both build and use it in the same 'go install'.
+			action := b.action(modeInstall, modeInstall, p)
+			if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
+				a.deps = append(a.deps, action.deps...)
+				action.deps = append(action.deps, a)
+				tools = append(tools, action)
+				continue
+			}
+			a.deps = append(a.deps, action)
 		}
-		a.deps = append(a.deps, action)
-	}
-	if len(tools) > 0 {
-		a = &action{
-			deps: tools,
+		if len(tools) > 0 {
+			a = &action{
+				deps: tools,
+			}
 		}
 	}
 	b.do(a)
@@ -456,8 +614,9 @@
 
 // cacheKey is the key for the action cache.
 type cacheKey struct {
-	mode buildMode
-	p    *Package
+	mode  buildMode
+	p     *Package
+	shlib string
 }
 
 // buildMode specifies the build mode:
@@ -580,24 +739,70 @@
 	return pkg
 }
 
+func readpkglist(shlibpath string) []*Package {
+	pkglistbytes, err := readnote(shlibpath, "GO\x00\x00", 1)
+	if err != nil {
+		fatalf("readnote failed: %v", err)
+	}
+	scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
+	var pkgs []*Package
+	var stk importStack
+	for scanner.Scan() {
+		t := scanner.Text()
+		pkgs = append(pkgs, loadPackage(t, &stk))
+	}
+	return pkgs
+}
+
 // action returns the action for applying the given operation (mode) to the package.
 // depMode is the action to use when building dependencies.
+// action never looks for p in a shared library.
 func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
-	key := cacheKey{mode, p}
+	return b.action1(mode, depMode, p, false)
+}
+
+// action1 returns the action for applying the given operation (mode) to the package.
+// depMode is the action to use when building dependencies.
+// action1 will look for p in a shared library if lookshared is true.
+func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool) *action {
+	shlib := ""
+	if lookshared {
+		shlib = p.Shlib
+	}
+	key := cacheKey{mode, p, shlib}
+
 	a := b.actionCache[key]
 	if a != nil {
 		return a
 	}
+	if shlib != "" {
+		key2 := cacheKey{modeInstall, nil, shlib}
+		a = b.actionCache[key2]
+		if a != nil {
+			b.actionCache[key] = a
+			return a
+		}
+		pkgs := readpkglist(filepath.Join(p.build.PkgTargetRoot, shlib))
+		a = b.libaction(shlib, pkgs, modeInstall, depMode)
+		b.actionCache[key2] = a
+		b.actionCache[key] = a
+		return a
+	}
 
 	a = &action{p: p, pkgdir: p.build.PkgRoot}
 	if p.pkgdir != "" { // overrides p.t
 		a.pkgdir = p.pkgdir
 	}
-
 	b.actionCache[key] = a
 
 	for _, p1 := range p.imports {
-		a.deps = append(a.deps, b.action(depMode, depMode, p1))
+		ls := buildLinkshared
+		// If p1 is part of the same shared library as p, we need the action
+		// that builds p here, not the shared libary or we get action loops.
+		if p1.Shlib == p.Shlib {
+			ls = false
+		}
+		a.deps = append(a.deps, b.action1(depMode, depMode, p1, ls))
 	}
 
 	// If we are not doing a cross-build, then record the binary we'll
@@ -606,7 +811,7 @@
 	// a package is using it.  If this is a cross-build, then the cgo we
 	// are writing is not the cgo we need to use.
 	if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
-		if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" {
+		if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" {
 			var stk importStack
 			p1 := loadPackage("cmd/cgo", &stk)
 			if p1.Error != nil {
@@ -653,8 +858,10 @@
 	switch mode {
 	case modeInstall:
 		a.f = (*builder).install
-		a.deps = []*action{b.action(modeBuild, depMode, p)}
+		a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared)}
 		a.target = a.p.target
+		a = b.maybeAddHeaderAction(a, true)
+
 	case modeBuild:
 		a.f = (*builder).build
 		a.target = a.objpkg
@@ -677,6 +884,137 @@
 	return a
 }
 
+func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action {
+	a := &action{}
+	if mode == modeBuild {
+		a.f = (*builder).linkShared
+		a.target = filepath.Join(b.work, libname)
+		for _, p := range pkgs {
+			if p.target == "" {
+				continue
+			}
+			a.deps = append(a.deps, b.action(depMode, depMode, p))
+		}
+	} else if mode == modeInstall {
+		// Currently build mode shared forces external linking mode, and
+		// external linking mode forces an import of runtime/cgo. So if it
+		// was not passed on the command line and it is not present in
+		// another shared library, add it here.
+		seencgo := false
+		for _, p := range pkgs {
+			seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
+		}
+		if !seencgo {
+			var stk importStack
+			p := loadPackage("runtime/cgo", &stk)
+			if p.Error != nil {
+				fatalf("load runtime/cgo: %v", p.Error)
+			}
+			computeStale(p)
+			// If runtime/cgo is in another shared library, then that's
+			// also the shared library that contains runtime, so
+			// something will depend on it and so runtime/cgo's staleness
+			// will be checked when processing that library.
+			if p.Shlib == "" || p.Shlib == libname {
+				pkgs = append([]*Package{}, pkgs...)
+				pkgs = append(pkgs, p)
+			}
+		}
+
+		// Figure out where the library will go.
+		var libdir string
+		for _, p := range pkgs {
+			plibdir := p.build.PkgTargetRoot
+			if libdir == "" {
+				libdir = plibdir
+			} else if libdir != plibdir {
+				fatalf("multiple roots %s & %s", libdir, plibdir)
+			}
+		}
+		a.target = filepath.Join(libdir, libname)
+
+		// Now we can check whether we need to rebuild it.
+		stale := false
+		var built time.Time
+		if fi, err := os.Stat(a.target); err == nil {
+			built = fi.ModTime()
+		}
+		for _, p := range pkgs {
+			if p.target == "" {
+				continue
+			}
+			stale = stale || p.Stale
+			lstat, err := os.Stat(p.target)
+			if err != nil || lstat.ModTime().After(built) {
+				stale = true
+			}
+			a.deps = append(a.deps, b.action(depMode, depMode, p))
+		}
+
+		if stale {
+			a.f = (*builder).install
+			buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
+			a.deps = []*action{buildAction}
+			for _, p := range pkgs {
+				if p.target == "" {
+					continue
+				}
+				shlibnameaction := &action{}
+				shlibnameaction.f = (*builder).installShlibname
+				shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname"
+				a.deps = append(a.deps, shlibnameaction)
+				shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
+			}
+		}
+	} else {
+		fatalf("unregonized mode %v", mode)
+	}
+	return a
+}
+
+// In c-archive/c-shared mode, if the package for the action uses cgo,
+// add a dependency to install the generated export header file, if
+// there is one.
+// The isInstall parameter is whether a is an install action.
+func (b *builder) maybeAddHeaderAction(a *action, isInstall bool) *action {
+	switch buildBuildmode {
+	case "c-archive", "c-shared":
+	default:
+		return a
+	}
+	if !a.p.usesCgo() {
+		return a
+	}
+
+	if isInstall {
+		// For an install action, change the action function.
+		// We can't add an action after the install action,
+		// because it deletes the working directory.
+		// Adding an action before the install action is painful,
+		// because it uses deps[0] to find the source.
+		a.f = (*builder).installWithHeader
+		return a
+	}
+
+	return &action{
+		p:      a.p,
+		deps:   []*action{a},
+		f:      (*builder).installHeader,
+		pkgdir: a.pkgdir,
+		objdir: a.objdir,
+		target: a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h",
+	}
+}
+
+// Install the library and the cgo export header if there is one.
+func (b *builder) installWithHeader(a *action) error {
+	target := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h"
+	if err := b.doInstallHeader(a, a.objdir, target); err != nil {
+		return err
+	}
+	return b.install(a)
+}
+
 // actionList returns the list of actions in the dag rooted at root
 // as visited in a depth-first post-order traversal.
 func actionList(root *action) []*action {
@@ -697,6 +1035,31 @@
 	return all
 }
 
+// allArchiveActions returns a list of the archive dependencies of root.
+// This is needed because if package p depends on package q that is in libr.so, the
+// action graph looks like p->libr.so->q and so just scanning through p's
+// dependencies does not find the import dir for q.
+func allArchiveActions(root *action) []*action {
+	seen := map[*action]bool{}
+	r := []*action{}
+	var walk func(*action)
+	walk = func(a *action) {
+		if seen[a] {
+			return
+		}
+		seen[a] = true
+		if strings.HasSuffix(a.target, ".so") || a == root {
+			for _, a1 := range a.deps {
+				walk(a1)
+			}
+		} else if strings.HasSuffix(a.target, ".a") {
+			r = append(r, a)
+		}
+	}
+	walk(root)
+	return r
+}
+
 // do runs the action graph rooted at root.
 func (b *builder) do(root *action) {
 	// Build list of all actions, assigning depth-first post-order priority.
@@ -964,7 +1327,7 @@
 	}
 
 	// Prepare Go import path list.
-	inc := b.includeArgs("-I", a.deps)
+	inc := b.includeArgs("-I", allArchiveActions(a))
 
 	// Compile Go.
 	ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles)
@@ -1096,6 +1459,82 @@
 	return
 }
 
+func (b *builder) installShlibname(a *action) error {
+	a1 := a.deps[0]
+	err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0644)
+	if err != nil {
+		return err
+	}
+	if buildX {
+		b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target)
+	}
+	return nil
+}
+
+// setextld sets the appropriate linker flags for the specified compiler.
+func setextld(ldflags []string, compiler []string) []string {
+	for _, f := range ldflags {
+		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+			// don't override -extld if supplied
+			return ldflags
+		}
+	}
+	ldflags = append(ldflags, "-extld="+compiler[0])
+	if len(compiler) > 1 {
+		extldflags := false
+		add := strings.Join(compiler[1:], " ")
+		for i, f := range ldflags {
+			if f == "-extldflags" && i+1 < len(ldflags) {
+				ldflags[i+1] = add + " " + ldflags[i+1]
+				extldflags = true
+				break
+			} else if strings.HasPrefix(f, "-extldflags=") {
+				ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+				extldflags = true
+				break
+			}
+		}
+		if !extldflags {
+			ldflags = append(ldflags, "-extldflags="+add)
+		}
+	}
+	return ldflags
+}
+
+func (b *builder) linkShared(a *action) (err error) {
+	// TODO(mwhudson): obvious copy pasting from gcToolchain.ld, should make a few
+	// changes to that function and then call it. And support gccgo.
+	allactions := actionList(a)
+	importArgs := b.includeArgs("-L", allactions[:len(allactions)-1])
+	ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
+	ldflags = append(ldflags, "-buildmode=shared")
+	ldflags = append(ldflags, buildLdflags...)
+	cxx := a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0)
+	for _, a := range allactions {
+		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
+			cxx = true
+		}
+	}
+	// If the user has not specified the -extld option, then specify the
+	// appropriate linker. In case of C++ code, use the compiler named
+	// by the CXX environment variable or defaultCXX if CXX is not set.
+	// Else, use the CC environment variable and defaultCC as fallback.
+	var compiler []string
+	if cxx {
+		compiler = envList("CXX", defaultCXX)
+	} else {
+		compiler = envList("CC", defaultCC)
+	}
+	ldflags = setextld(ldflags, compiler)
+	for _, d := range a.deps {
+		if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries
+			continue
+		}
+		ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
+	}
+	return b.run(".", a.target, nil, buildToolExec, tool(archChar()+"l"), "-o", a.target, importArgs, ldflags)
+}
+
 // install is the action for installing a single package or executable.
 func (b *builder) install(a *action) (err error) {
 	defer func() {
@@ -1106,7 +1545,11 @@
 	a1 := a.deps[0]
 	perm := os.FileMode(0644)
 	if a1.link {
-		perm = 0755
+		switch buildBuildmode {
+		case "c-archive", "c-shared":
+		default:
+			perm = 0755
+		}
 	}
 
 	// make target directory
@@ -1143,6 +1586,9 @@
 	// This is the $WORK/my/package/_test directory for the
 	// package being built, so there are few of these.
 	for _, a1 := range all {
+		if a1.p == nil {
+			continue
+		}
 		if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
 			incMap[dir] = true
 			inc = append(inc, flag, dir)
@@ -1155,17 +1601,12 @@
 
 	// Finally, look in the installed package directories for each action.
 	for _, a1 := range all {
+		if a1.p == nil {
+			continue
+		}
 		if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
 			incMap[dir] = true
-			if _, ok := buildToolchain.(gccgoToolchain); ok {
-				dir = filepath.Join(dir, "gccgo_"+goos+"_"+goarch)
-			} else {
-				dir = filepath.Join(dir, goos+"_"+goarch)
-				if buildContext.InstallSuffix != "" {
-					dir += "_" + buildContext.InstallSuffix
-				}
-			}
-			inc = append(inc, flag, dir)
+			inc = append(inc, flag, a1.p.build.PkgTargetRoot)
 		}
 	}
 
@@ -1252,6 +1693,29 @@
 	return nil
 }
 
+// Install the cgo export header file, if there is one.
+func (b *builder) installHeader(a *action) error {
+	return b.doInstallHeader(a, a.objdir, a.target)
+}
+
+func (b *builder) doInstallHeader(a *action, objdir, target string) error {
+	src := objdir + "_cgo_install.h"
+	if _, err := os.Stat(src); os.IsNotExist(err) {
+		// If the file does not exist, there are no exported
+		// functions, and we do not install anything.
+		return nil
+	}
+
+	dir, _ := filepath.Split(target)
+	if dir != "" {
+		if err := b.mkdir(dir); err != nil {
+			return err
+		}
+	}
+
+	return b.moveOrCopyFile(a, target, src, 0644)
+}
+
 // cover runs, in effect,
 //	go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
 func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
@@ -1661,6 +2125,9 @@
 	}
 
 	gcargs := []string{"-p", p.ImportPath}
+	if p.Name == "main" {
+		gcargs[1] = "main"
+	}
 	if p.Standard && p.ImportPath == "runtime" {
 		// runtime compiles with a special 6g flag to emit
 		// additional reflect type data.
@@ -1857,40 +2324,14 @@
 	// appropriate linker. In case of C++ code, use the compiler named
 	// by the CXX environment variable or defaultCXX if CXX is not set.
 	// Else, use the CC environment variable and defaultCC as fallback.
-	extld := false
-	for _, f := range ldflags {
-		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
-			extld = true
-			break
-		}
+	var compiler []string
+	if cxx {
+		compiler = envList("CXX", defaultCXX)
+	} else {
+		compiler = envList("CC", defaultCC)
 	}
-	if !extld {
-		var compiler []string
-		if cxx {
-			compiler = envList("CXX", defaultCXX)
-		} else {
-			compiler = envList("CC", defaultCC)
-		}
-		ldflags = append(ldflags, "-extld="+compiler[0])
-		if len(compiler) > 1 {
-			extldflags := false
-			add := strings.Join(compiler[1:], " ")
-			for i, f := range ldflags {
-				if f == "-extldflags" && i+1 < len(ldflags) {
-					ldflags[i+1] = add + " " + ldflags[i+1]
-					extldflags = true
-					break
-				} else if strings.HasPrefix(f, "-extldflags=") {
-					ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
-					extldflags = true
-					break
-				}
-			}
-			if !extldflags {
-				ldflags = append(ldflags, "-extldflags="+add)
-			}
-		}
-	}
+	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)
 }
@@ -1946,6 +2387,7 @@
 	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}
+	defs = tools.maybePIC(defs)
 	defs = append(defs, b.gccArchArgs()...)
 	return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-I", obj, "-o", ofile, defs, sfile)
 }
@@ -2003,7 +2445,13 @@
 	afiles = append(xfiles, afiles...)
 
 	for _, a := range allactions {
-		cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
+		// Gather CgoLDFLAGS, but not from standard packages.
+		// The go tool can dig up runtime/cgo from GOROOT and
+		// think that it should use its CgoLDFLAGS, but gccgo
+		// doesn't use runtime/cgo.
+		if !a.p.Standard {
+			cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
+		}
 		if len(a.p.CgoFiles) > 0 {
 			usesCgo = true
 		}
@@ -2017,23 +2465,87 @@
 			objc = true
 		}
 	}
+
+	switch ldBuildmode {
+	case "c-archive", "c-shared":
+		ldflags = append(ldflags, "-Wl,--whole-archive")
+	}
+
 	ldflags = append(ldflags, afiles...)
+
+	switch ldBuildmode {
+	case "c-archive", "c-shared":
+		ldflags = append(ldflags, "-Wl,--no-whole-archive")
+	}
+
 	ldflags = append(ldflags, cgoldflags...)
 	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
 	ldflags = append(ldflags, p.CgoLDFLAGS...)
-	if usesCgo && goos == "linux" {
-		ldflags = append(ldflags, "-Wl,-E")
+
+	ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
+
+	var realOut string
+	switch ldBuildmode {
+	case "exe":
+		if usesCgo && goos == "linux" {
+			ldflags = append(ldflags, "-Wl,-E")
+		}
+
+	case "c-archive":
+		// Link the Go files into a single .o, and also link
+		// in -lgolibbegin.
+		//
+		// We need to use --whole-archive with -lgolibbegin
+		// because it doesn't define any symbols that will
+		// cause the contents to be pulled in; it's just
+		// initialization code.
+		//
+		// The user remains responsible for linking against
+		// -lgo -lpthread -lm in the final link.  We can't use
+		// -r to pick them up because we can't combine
+		// split-stack and non-split-stack code in a single -r
+		// link, and libgo picks up non-split-stack code from
+		// libffi.
+		ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
+
+		// We are creating an object file, so we don't want a build ID.
+		ldflags = b.disableBuildID(ldflags)
+
+		realOut = out
+		out = out + ".o"
+
+	case "c-shared":
+		ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc")
+
+	default:
+		fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
 	}
-	if cxx {
-		ldflags = append(ldflags, "-lstdc++")
+
+	switch ldBuildmode {
+	case "exe", "c-shared":
+		if cxx {
+			ldflags = append(ldflags, "-lstdc++")
+		}
+		if objc {
+			ldflags = append(ldflags, "-lobjc")
+		}
 	}
-	if objc {
-		ldflags = append(ldflags, "-lobjc")
+
+	if err := b.run(".", p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
+		return err
 	}
-	return b.run(".", p.ImportPath, nil, tools.linker(), "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
+
+	switch ldBuildmode {
+	case "c-archive":
+		if err := b.run(".", p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
+			return err
+		}
+	}
+
+	return nil
 }
 
-func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
 	inc := filepath.Join(goroot, "pkg", "include")
 	cfile = mkAbs(p.Dir, cfile)
 	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
@@ -2041,10 +2553,24 @@
 	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}
+	switch goarch {
+	case "386", "amd64":
+		defs = append(defs, "-fsplit-stack")
+	}
+	defs = tools.maybePIC(defs)
 	return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
 		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
 }
 
+// maybePIC adds -fPIC to the list of arguments if needed.
+func (tools gccgoToolchain) maybePIC(args []string) []string {
+	switch buildBuildmode {
+	case "c-shared", "shared":
+		args = append(args, "-fPIC")
+	}
+	return args
+}
+
 func gccgoPkgpath(p *Package) string {
 	if p.build.IsCommand() && !p.forceLibrary {
 		return ""
@@ -2284,12 +2810,25 @@
 	}
 
 	if _, ok := buildToolchain.(gccgoToolchain); ok {
+		switch goarch {
+		case "386", "amd64":
+			cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
+		}
 		cgoflags = append(cgoflags, "-gccgo")
 		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
 			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
 		}
 	}
-	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
+
+	switch buildBuildmode {
+	case "c-archive", "c-shared":
+		// Tell cgo that if there are any exported functions
+		// it should generate a header file that C code can
+		// #include.
+		cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
+	}
+
+	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
 		return nil, nil, err
 	}
 	outGo = append(outGo, gofiles...)
@@ -2437,19 +2976,8 @@
 	}
 	ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
 
-	// Some systems, such as Ubuntu, always add --build-id to
-	// every link, but we don't want a build ID since we are
-	// producing an object file.  On some of those system a plain
-	// -r (not -Wl,-r) will turn off --build-id, but clang 3.0
-	// doesn't support a plain -r.  I don't know how to turn off
-	// --build-id when using clang other than passing a trailing
-	// --build-id=none.  So that is what we do, but only on
-	// systems likely to support it, which is to say, systems that
-	// normally use gold or the GNU linker.
-	switch goos {
-	case "android", "dragonfly", "linux", "netbsd":
-		ldflags = append(ldflags, "-Wl,--build-id=none")
-	}
+	// We are creating an object file, so we don't want a build ID.
+	ldflags = b.disableBuildID(ldflags)
 
 	if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
 		return nil, nil, err
@@ -2645,20 +3173,42 @@
 		args = append(args, "-c++")
 	}
 
-	if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
+	out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file)
+	if err != nil {
 		if len(out) > 0 {
 			if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
 				return "", "", errors.New("must have SWIG version >= 3.0.6")
 			}
-			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
+			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error
 			return "", "", errPrintedOutput
 		}
 		return "", "", err
 	}
+	if len(out) > 0 {
+		b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
+	}
 
 	return obj + goFile, obj + gccBase + gccExt, nil
 }
 
+// disableBuildID adjusts a linker command line to avoid creating a
+// build ID when creating an object file rather than an executable or
+// shared library.  Some systems, such as Ubuntu, always add
+// --build-id to every link, but we don't want a build ID when we are
+// producing an object file.  On some of those system a plain -r (not
+// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a
+// plain -r.  I don't know how to turn off --build-id when using clang
+// other than passing a trailing --build-id=none.  So that is what we
+// do, but only on systems likely to support it, which is to say,
+// systems that normally use gold or the GNU linker.
+func (b *builder) disableBuildID(ldflags []string) []string {
+	switch goos {
+	case "android", "dragonfly", "linux", "netbsd":
+		ldflags = append(ldflags, "-Wl,--build-id=none")
+	}
+	return ldflags
+}
+
 // An actionQueue is a priority queue of actions.
 type actionQueue []*action
 
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index ba1a707..a9bda4d 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -1,1143 +1,92 @@
-// Copyright 2011 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.
 
-// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
-// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
-
-/*
-Go is a tool for managing Go source code.
-
-Usage:
-
-	go command [arguments]
-
-The commands are:
-
-	build       compile packages and dependencies
-	clean       remove object files
-	env         print Go environment information
-	fix         run go tool fix on packages
-	fmt         run gofmt on package sources
-	generate    generate Go files by processing source
-	get         download and install packages and dependencies
-	install     compile and install packages and dependencies
-	list        list packages
-	run         compile and run Go program
-	test        test packages
-	tool        run specified go tool
-	version     print Go version
-	vet         run go tool vet on packages
-
-Use "go help [command]" for more information about a command.
-
-Additional help topics:
-
-	c           calling between Go and C
-	filetype    file types
-	gopath      GOPATH environment variable
-	importpath  import path syntax
-	packages    description of package lists
-	testflag    description of testing flags
-	testfunc    description of testing functions
-
-Use "go help [topic]" for more information about that topic.
-
-
-Compile packages and dependencies
-
-Usage:
-
-	go build [-o output] [-i] [build flags] [packages]
-
-Build compiles the packages named by the import paths,
-along with their dependencies, but it does not install the results.
-
-If the arguments are a list of .go files, build treats them as a list
-of source files specifying a single package.
-
-When the command line specifies a single main package,
-build writes the resulting executable to output.
-Otherwise build compiles the packages but discards the results,
-serving only as a check that the packages can be built.
-
-The -o flag specifies the output file name. If not specified, the
-output file name depends on the arguments and derives from the name
-of the package, such as p.a for package p, unless p is 'main'. If
-the package is main and file names are provided, the file name
-derives from the first file name mentioned, such as f1 for 'go build
-f1.go f2.go'; with no files provided ('go build'), the output file
-name is the base name of the containing directory.
-
-The -i flag installs the packages that are dependencies of the target.
-
-The build flags are shared by the build, clean, get, install, list, run,
-and test commands:
-
-	-a
-		force rebuilding of packages that are already up-to-date.
-		In Go releases, does not apply to the standard library.
-	-n
-		print the commands but do not run them.
-	-p n
-		the number of builds that can be run in parallel.
-		The default is the number of CPUs available, except
-		on darwin/arm which defaults to 1.
-	-race
-		enable data race detection.
-		Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-	-v
-		print the names of packages as they are compiled.
-	-work
-		print the name of the temporary work directory and
-		do not delete it when exiting.
-	-x
-		print the commands.
-
-	-compiler name
-		name of compiler to use, as in runtime.Compiler (gccgo or gc).
-	-gccgoflags 'arg list'
-		arguments to pass on each gccgo compiler/linker invocation.
-	-gcflags 'arg list'
-		arguments to pass on each 5g, 6g, 8g, or 9g compiler invocation.
-	-installsuffix suffix
-		a suffix to use in the name of the package installation directory,
-		in order to keep output separate from default builds.
-		If using the -race flag, the install suffix is automatically set to race
-		or, if set explicitly, has _race appended to it.
-	-ldflags 'flag list'
-		arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
-	-asmflags 'flag list'
-		arguments to pass on each asm assembler invocation.
-	-tags 'tag list'
-		a list of build tags to consider satisfied during the build.
-		For more information about build tags, see the description of
-		build constraints in the documentation for the go/build package.
-	-toolexec 'cmd args'
-		a program to use to invoke toolchain programs like 5a, 5g, and 5l.
-		For example, instead of running 5g, the go command will run
-		'cmd args /path/to/5g <arguments for 5g>'.
-
-The list flags accept a space-separated list of strings. To embed spaces
-in an element in the list, surround it with either single or double quotes.
-
-For more about specifying packages, see 'go help packages'.
-For more about where packages and binaries are installed,
-run 'go help gopath'.  For more about calling between Go and C/C++,
-run 'go help c'.
-
-See also: go install, go get, go clean.
-
-
-Remove object files
-
-Usage:
-
-	go clean [-i] [-r] [-n] [-x] [build flags] [packages]
-
-Clean removes object files from package source directories.
-The go command builds most objects in a temporary directory,
-so go clean is mainly concerned with object files left by other
-tools or by manual invocations of go build.
-
-Specifically, clean removes the following files from each of the
-source directories corresponding to the import paths:
-
-	_obj/            old object directory, left from Makefiles
-	_test/           old test directory, left from Makefiles
-	_testmain.go     old gotest file, left from Makefiles
-	test.out         old test log, left from Makefiles
-	build.out        old test log, left from Makefiles
-	*.[568ao]        object files, left from Makefiles
-
-	DIR(.exe)        from go build
-	DIR.test(.exe)   from go test -c
-	MAINFILE(.exe)   from go build MAINFILE.go
-	*.so             from SWIG
-
-In the list, DIR represents the final path element of the
-directory, and MAINFILE is the base name of any Go source
-file in the directory that is not included when building
-the package.
-
-The -i flag causes clean to remove the corresponding installed
-archive or binary (what 'go install' would create).
-
-The -n flag causes clean to print the remove commands it would execute,
-but not run them.
-
-The -r flag causes clean to be applied recursively to all the
-dependencies of the packages named by the import paths.
-
-The -x flag causes clean to print remove commands as it executes them.
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Print Go environment information
-
-Usage:
-
-	go env [var ...]
-
-Env prints Go environment information.
-
-By default env prints information as a shell script
-(on Windows, a batch file).  If one or more variable
-names is given as arguments,  env prints the value of
-each named variable on its own line.
-
-
-Run go tool fix on packages
-
-Usage:
-
-	go fix [packages]
-
-Fix runs the Go fix command on the packages named by the import paths.
-
-For more about fix, see 'godoc fix'.
-For more about specifying packages, see 'go help packages'.
-
-To run fix with specific options, run 'go tool fix'.
-
-See also: go fmt, go vet.
-
-
-Run gofmt on package sources
-
-Usage:
-
-	go fmt [-n] [-x] [packages]
-
-Fmt runs the command 'gofmt -l -w' on the packages named
-by the import paths.  It prints the names of the files that are modified.
-
-For more about gofmt, see 'godoc gofmt'.
-For more about specifying packages, see 'go help packages'.
-
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-To run gofmt with specific options, run gofmt itself.
-
-See also: go fix, go vet.
-
-
-Generate Go files by processing source
-
-Usage:
-
-	go generate [-run regexp] [file.go... | packages]
-
-Generate runs commands described by directives within existing
-files. Those commands can run any process but the intent is to
-create or update Go source files, for instance by running yacc.
-
-Go generate is never run automatically by go build, go get, go test,
-and so on. It must be run explicitly.
-
-Go generate scans the file for directives, which are lines of
-the form,
-
-	//go:generate command argument...
-
-(note: no leading spaces and no space in "//go") where command
-is the generator to be run, corresponding to an executable file
-that can be run locally. It must either be in the shell path
-(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
-command alias, described below.
-
-Note that go generate does not parse the file, so lines that look
-like directives in comments or multiline strings will be treated
-as directives.
-
-The arguments to the directive are space-separated tokens or
-double-quoted strings passed to the generator as individual
-arguments when it is run.
-
-Quoted strings use Go syntax and are evaluated before execution; a
-quoted string appears as a single argument to the generator.
-
-Go generate sets several variables when it runs the generator:
-
-	$GOARCH
-		The execution architecture (arm, amd64, etc.)
-	$GOOS
-		The execution operating system (linux, windows, etc.)
-	$GOFILE
-		The base name of the file.
-	$GOPACKAGE
-		The name of the package of the file containing the directive.
-
-Other than variable substitution and quoted-string evaluation, no
-special processing such as "globbing" is performed on the command
-line.
-
-As a last step before running the command, any invocations of any
-environment variables with alphanumeric names, such as $GOFILE or
-$HOME, are expanded throughout the command line. The syntax for
-variable expansion is $NAME on all operating systems.  Due to the
-order of evaluation, variables are expanded even inside quoted
-strings. If the variable NAME is not set, $NAME expands to the
-empty string.
-
-A directive of the form,
-
-	//go:generate -command xxx args...
-
-specifies, for the remainder of this source file only, that the
-string xxx represents the command identified by the arguments. This
-can be used to create aliases or to handle multiword generators.
-For example,
-
-	//go:generate -command yacc go tool yacc
-
-specifies that the command "yacc" represents the generator
-"go tool yacc".
-
-Generate processes packages in the order given on the command line,
-one at a time. If the command line lists .go files, they are treated
-as a single package. Within a package, generate processes the
-source files in a package in file name order, one at a time. Within
-a source file, generate runs generators in the order they appear
-in the file, one at a time.
-
-If any generator returns an error exit status, "go generate" skips
-all further processing for that package.
-
-The generator is run in the package's source directory.
-
-Go generate accepts one specific flag:
-
-	-run=""
-		TODO: This flag is unimplemented.
-		if non-empty, specifies a regular expression to
-		select directives whose command matches the expression.
-
-It also accepts the standard build flags -v, -n, and -x.
-The -v flag prints the names of packages and files as they are
-processed.
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Download and install packages and dependencies
-
-Usage:
-
-	go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
-
-Get downloads and installs the packages named by the import paths,
-along with their dependencies.
-
-The -d flag instructs get to stop after downloading the packages; that is,
-it instructs get not to install the packages.
-
-The -f flag, valid only when -u is set, forces get -u not to verify that
-each package has been checked out from the source control repository
-implied by its import path. This can be useful if the source is a local fork
-of the original.
-
-The -fix flag instructs get to run the fix tool on the downloaded packages
-before resolving dependencies or building the code.
-
-The -t flag instructs get to also download the packages required to build
-the tests for the specified packages.
-
-The -u flag instructs get to use the network to update the named packages
-and their dependencies.  By default, get uses the network to check out
-missing packages but does not use it to look for updates to existing packages.
-
-Get also accepts build flags to control the installation. See 'go help build'.
-
-When checking out or updating a package, get looks for a branch or tag
-that matches the locally installed version of Go. The most important
-rule is that if the local installation is running version "go1", get
-searches for a branch or tag named "go1". If no such version exists it
-retrieves the most recent version of the package.
-
-For more about specifying packages, see 'go help packages'.
-
-For more about how 'go get' finds source code to
-download, see 'go help importpath'.
-
-See also: go build, go install, go clean.
-
-
-Compile and install packages and dependencies
-
-Usage:
-
-	go install [build flags] [packages]
-
-Install compiles and installs the packages named by the import paths,
-along with their dependencies.
-
-For more about the build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go get, go clean.
-
-
-List packages
-
-Usage:
-
-	go list [-e] [-f format] [-json] [build flags] [packages]
-
-List lists the packages named by the import paths, one per line.
-
-The default output shows the package import path:
-
-    code.google.com/p/google-api-go-client/books/v1
-    code.google.com/p/goauth2/oauth
-    code.google.com/p/sqlite
-
-The -f flag specifies an alternate format for the list, using the
-syntax of package template.  The default output is equivalent to -f
-'{{.ImportPath}}'. The struct being passed to the template is:
-
-    type Package struct {
-        Dir           string // directory containing package sources
-        ImportPath    string // import path of package in dir
-        ImportComment string // path in import comment on package statement
-        Name          string // package name
-        Doc           string // package documentation string
-        Target        string // install path
-        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?
-        Root          string // Go root or Go path dir containing this package
-
-        // Source files
-        GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
-        CgoFiles       []string // .go sources files that import "C"
-        IgnoredGoFiles []string // .go sources ignored due to build constraints
-        CFiles         []string // .c source files
-        CXXFiles       []string // .cc, .cxx and .cpp source files
-        MFiles         []string // .m source files
-        HFiles         []string // .h, .hh, .hpp and .hxx source files
-        SFiles         []string // .s source files
-        SwigFiles      []string // .swig files
-        SwigCXXFiles   []string // .swigcxx files
-        SysoFiles      []string // .syso object files to add to archive
-
-        // Cgo directives
-        CgoCFLAGS    []string // cgo: flags for C compiler
-        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
-        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
-        CgoLDFLAGS   []string // cgo: flags for linker
-        CgoPkgConfig []string // cgo: pkg-config names
-
-        // Dependency information
-        Imports []string // import paths used by this package
-        Deps    []string // all (recursively) imported dependencies
-
-        // Error information
-        Incomplete bool            // this package or a dependency has an error
-        Error      *PackageError   // error loading package
-        DepsErrors []*PackageError // errors loading dependencies
-
-        TestGoFiles  []string // _test.go files in package
-        TestImports  []string // imports from TestGoFiles
-        XTestGoFiles []string // _test.go files outside package
-        XTestImports []string // imports from XTestGoFiles
-    }
-
-The template function "join" calls strings.Join.
-
-The template function "context" returns the build context, defined as:
-
-	type Context struct {
-		GOARCH        string   // target architecture
-		GOOS          string   // target operating system
-		GOROOT        string   // Go root
-		GOPATH        string   // Go path
-		CgoEnabled    bool     // whether cgo can be used
-		UseAllFiles   bool     // use files regardless of +build lines, file names
-		Compiler      string   // compiler to assume when computing target paths
-		BuildTags     []string // build constraints to match in +build lines
-		ReleaseTags   []string // releases the current release is compatible with
-		InstallSuffix string   // suffix to use in the name of the install dir
-	}
-
-For more information about the meaning of these fields see the documentation
-for the go/build package's Context type.
-
-The -json flag causes the package data to be printed in JSON format
-instead of using the template format.
-
-The -e flag changes the handling of erroneous packages, those that
-cannot be found or are malformed.  By default, the list command
-prints an error to standard error for each erroneous package and
-omits the packages from consideration during the usual printing.
-With the -e flag, the list command never prints errors to standard
-error and instead processes the erroneous packages with the usual
-printing.  Erroneous packages will have a non-empty ImportPath and
-a non-nil Error field; other information may or may not be missing
-(zeroed).
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Compile and run Go program
-
-Usage:
-
-	go run [build flags] [-exec xprog] gofiles... [arguments...]
-
-Run compiles and runs the main package comprising the named Go source files.
-A Go source file is defined to be a file ending in a literal ".go" suffix.
-
-By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
-If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
-If the -exec flag is not given, GOOS or GOARCH is different from the system
-default, and a program named go_$GOOS_$GOARCH_exec can be found
-on the current search path, 'go run' invokes the binary using that program,
-for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
-cross-compiled programs when a simulator or other execution method is
-available.
-
-For more about build flags, see 'go help build'.
-
-See also: go build.
-
-
-Test packages
-
-Usage:
-
-	go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
-
-'Go test' automates testing the packages named by the import paths.
-It prints a summary of the test results in the format:
-
-	ok   archive/tar   0.011s
-	FAIL archive/zip   0.022s
-	ok   compress/gzip 0.033s
-	...
-
-followed by detailed output for each failed package.
-
-'Go test' recompiles each package along with any files with names matching
-the file pattern "*_test.go".
-Files whose names begin with "_" (including "_test.go") or "." are ignored.
-These additional files can contain test functions, benchmark functions, and
-example functions.  See 'go help testfunc' for more.
-Each listed package causes the execution of a separate test binary.
-
-Test files that declare a package with the suffix "_test" will be compiled as a
-separate package, and then linked and run with the main test binary.
-
-By default, go test needs no arguments.  It compiles and tests the package
-with source in the current directory, including tests, and runs the tests.
-
-The package is built in a temporary directory so it does not interfere with the
-non-test installation.
-
-In addition to the build flags, the flags handled by 'go test' itself are:
-
-	-c
-		Compile the test binary to pkg.test but do not run it
-		(where pkg is the last element of the package's import path).
-		The file name can be changed with the -o flag.
-
-	-exec xprog
-	    Run the test binary using xprog. The behavior is the same as
-	    in 'go run'. See 'go help run' for details.
-
-	-i
-	    Install packages that are dependencies of the test.
-	    Do not run the test.
-
-	-o file
-		Compile the test binary to the named file.
-		The test still runs (unless -c or -i is specified).
-
-
-The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'.  See 'go help testflag' for details.
-
-If the test binary needs any other flags, they should be presented after the
-package names. The go tool treats as a flag the first argument that begins with
-a minus sign that it does not recognize itself; that argument and all subsequent
-arguments are passed as arguments to the test binary.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-
-
-Run specified go tool
-
-Usage:
-
-	go tool [-n] command [args...]
-
-Tool runs the go tool command identified by the arguments.
-With no arguments it prints the list of known tools.
-
-The -n flag causes tool to print the command that would be
-executed but not execute it.
-
-For more about each tool command, see 'go tool command -h'.
-
-
-Print Go version
-
-Usage:
-
-	go version
-
-Version prints the Go version, as reported by runtime.Version.
-
-
-Run go tool vet on packages
-
-Usage:
-
-	go vet [-n] [-x] [packages]
-
-Vet runs the Go vet command on the packages named by the import paths.
-
-For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
-For more about specifying packages, see 'go help packages'.
-
-To run the vet tool with specific options, run 'go tool vet'.
-
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-See also: go fmt, go fix.
-
-
-Calling between Go and C
-
-There are two different ways to call between Go and C/C++ code.
-
-The first is the cgo tool, which is part of the Go distribution.  For
-information on how to use it see the cgo documentation (godoc cmd/cgo).
-
-The second is the SWIG program, which is a general tool for
-interfacing between languages.  For information on SWIG see
-http://swig.org/.  When running go build, any file with a .swig
-extension will be passed to SWIG.  Any file with a .swigcxx extension
-will be passed to SWIG with the -c++ option.
-
-When either cgo or SWIG is used, go build will pass any .c, .m, .s,
-or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
-compiler.  The CC or CXX environment variables may be set to determine
-the C or C++ compiler, respectively, to use.
-
-
-File types
-
-The go command examines the contents of a restricted set of files
-in each directory. It identifies which files to examine based on
-the extension of the file name. These extensions are:
-
-	.go
-		Go source files.
-	.c, .h
-		C source files.
-		If the package uses cgo, these will be compiled with the
-		OS-native compiler (typically gcc); otherwise they will be
-		compiled with the Go-specific support compiler,
-		5c, 6c, or 8c, etc. as appropriate.
-	.cc, .cpp, .cxx, .hh, .hpp, .hxx
-		C++ source files. Only useful with cgo or SWIG, and always
-		compiled with the OS-native compiler.
-	.m
-		Objective-C source files. Only useful with cgo, and always
-		compiled with the OS-native compiler.
-	.s, .S
-		Assembler source files.
-		If the package uses cgo, these will be assembled with the
-		OS-native assembler (typically gcc (sic)); otherwise they
-		will be assembled with the Go-specific support assembler,
-		5a, 6a, or 8a, etc., as appropriate.
-	.swig, .swigcxx
-		SWIG definition files.
-	.syso
-		System object files.
-
-Files of each of these types except .syso may contain build
-constraints, but the go command stops scanning for build constraints
-at the first item in the file that is not a blank line or //-style
-line comment.
-
-
-GOPATH environment variable
-
-The Go path is used to resolve import statements.
-It is implemented by and documented in the go/build package.
-
-The GOPATH environment variable lists places to look for Go code.
-On Unix, the value is a colon-separated string.
-On Windows, the value is a semicolon-separated string.
-On Plan 9, the value is a list.
-
-GOPATH must be set to get, build and install packages outside the
-standard Go tree.
-
-Each directory listed in GOPATH must have a prescribed structure:
-
-The src/ directory holds source code.  The path below 'src'
-determines the import path or executable name.
-
-The pkg/ directory holds installed package objects.
-As in the Go tree, each target operating system and
-architecture pair has its own subdirectory of pkg
-(pkg/GOOS_GOARCH).
-
-If DIR is a directory listed in the GOPATH, a package with
-source in DIR/src/foo/bar can be imported as "foo/bar" and
-has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
-
-The bin/ directory holds compiled commands.
-Each command is named for its source directory, but only
-the final element, not the entire path.  That is, the
-command with source in DIR/src/foo/quux is installed into
-DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
-so that you can add DIR/bin to your PATH to get at the
-installed commands.  If the GOBIN environment variable is
-set, commands are installed to the directory it names instead
-of DIR/bin.
-
-Here's an example directory layout:
-
-    GOPATH=/home/user/gocode
-
-    /home/user/gocode/
-        src/
-            foo/
-                bar/               (go code in package bar)
-                    x.go
-                quux/              (go code in package main)
-                    y.go
-        bin/
-            quux                   (installed command)
-        pkg/
-            linux_amd64/
-                foo/
-                    bar.a          (installed package object)
-
-Go searches each directory listed in GOPATH to find source code,
-but new packages are always downloaded into the first directory
-in the list.
-
-
-Import path syntax
-
-An import path (see 'go help packages') denotes a package
-stored in the local file system.  In general, an import path denotes
-either a standard package (such as "unicode/utf8") or a package
-found in one of the work spaces (see 'go help gopath').
-
-Relative import paths
-
-An import path beginning with ./ or ../ is called a relative path.
-The toolchain supports relative import paths as a shortcut in two ways.
-
-First, a relative path can be used as a shorthand on the command line.
-If you are working in the directory containing the code imported as
-"unicode" and want to run the tests for "unicode/utf8", you can type
-"go test ./utf8" instead of needing to specify the full path.
-Similarly, in the reverse situation, "go test .." will test "unicode" from
-the "unicode/utf8" directory. Relative patterns are also allowed, like
-"go test ./..." to test all subdirectories. See 'go help packages' for details
-on the pattern syntax.
-
-Second, if you are compiling a Go program not in a work space,
-you can use a relative path in an import statement in that program
-to refer to nearby code also not in a work space.
-This makes it easy to experiment with small multipackage programs
-outside of the usual work spaces, but such programs cannot be
-installed with "go install" (there is no work space in which to install them),
-so they are rebuilt from scratch each time they are built.
-To avoid ambiguity, Go programs cannot use relative import paths
-within a work space.
-
-Remote import paths
-
-Certain import paths also
-describe how to obtain the source code for the package using
-a revision control system.
-
-A few common code hosting sites have special syntax:
-
-	Bitbucket (Git, Mercurial)
-
-		import "bitbucket.org/user/project"
-		import "bitbucket.org/user/project/sub/directory"
-
-	GitHub (Git)
-
-		import "github.com/user/project"
-		import "github.com/user/project/sub/directory"
-
-	Google Code Project Hosting (Git, Mercurial, Subversion)
-
-		import "code.google.com/p/project"
-		import "code.google.com/p/project/sub/directory"
-
-		import "code.google.com/p/project.subrepository"
-		import "code.google.com/p/project.subrepository/sub/directory"
-
-	Launchpad (Bazaar)
-
-		import "launchpad.net/project"
-		import "launchpad.net/project/series"
-		import "launchpad.net/project/series/sub/directory"
-
-		import "launchpad.net/~user/project/branch"
-		import "launchpad.net/~user/project/branch/sub/directory"
-
-	IBM DevOps Services (Git)
-
-		import "hub.jazz.net/git/user/project"
-		import "hub.jazz.net/git/user/project/sub/directory"
-
-For code hosted on other servers, import paths may either be qualified
-with the version control type, or the go tool can dynamically fetch
-the import path over https/http and discover where the code resides
-from a <meta> tag in the HTML.
-
-To declare the code location, an import path of the form
-
-	repository.vcs/path
-
-specifies the given repository, with or without the .vcs suffix,
-using the named version control system, and then the path inside
-that repository.  The supported version control systems are:
-
-	Bazaar      .bzr
-	Git         .git
-	Mercurial   .hg
-	Subversion  .svn
-
-For example,
-
-	import "example.org/user/foo.hg"
-
-denotes the root directory of the Mercurial repository at
-example.org/user/foo or foo.hg, and
-
-	import "example.org/repo.git/foo/bar"
-
-denotes the foo/bar directory of the Git repository at
-example.org/repo or repo.git.
-
-When a version control system supports multiple protocols,
-each is tried in turn when downloading.  For example, a Git
-download tries git://, then https://, then http://.
-
-If the import path is not a known code hosting site and also lacks a
-version control qualifier, the go tool attempts to fetch the import
-over https/http and looks for a <meta> tag in the document's HTML
-<head>.
-
-The meta tag has the form:
-
-	<meta name="go-import" content="import-prefix vcs repo-root">
-
-The import-prefix is the import path corresponding to the repository
-root. It must be a prefix or an exact match of the package being
-fetched with "go get". If it's not an exact match, another http
-request is made at the prefix to verify the <meta> tags match.
-
-The vcs is one of "git", "hg", "svn", etc,
-
-The repo-root is the root of the version control system
-containing a scheme and not containing a .vcs qualifier.
-
-For example,
-
-	import "example.org/pkg/foo"
-
-will result in the following request(s):
-
-	https://example.org/pkg/foo?go-get=1 (preferred)
-	http://example.org/pkg/foo?go-get=1  (fallback)
-
-If that page contains the meta tag
-
-	<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
-
-the go tool will verify that https://example.org/?go-get=1 contains the
-same meta tag and then git clone https://code.org/r/p/exproj into
-GOPATH/src/example.org.
-
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
-
-The go command attempts to download the version of the
-package appropriate for the Go release being used.
-Run 'go help get' for more.
-
-Import path checking
-
-When the custom import path feature described above redirects to a
-known code hosting site, each of the resulting packages has two possible
-import paths, using the custom domain or the known hosting site.
-
-A package statement is said to have an "import comment" if it is immediately
-followed (before the next newline) by a comment of one of these two forms:
-
-	package math // import "path"
-	package math /* import "path" * /
-
-The go command will refuse to install a package with an import comment
-unless it is being referred to by that import path. In this way, import comments
-let package authors make sure the custom import path is used and not a
-direct path to the underlying code hosting site.
-
-See https://golang.org/s/go14customimport for details.
-
-
-Description of package lists
-
-Many commands apply to a set of packages:
-
-	go action [packages]
-
-Usually, [packages] is a list of import paths.
-
-An import path that is a rooted path or that begins with
-a . or .. element is interpreted as a file system path and
-denotes the package in that directory.
-
-Otherwise, the import path P denotes the package found in
-the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
-
-If no import paths are given, the action applies to the
-package in the current directory.
-
-There are three reserved names for paths that should not be used
-for packages to be built with the go tool:
-
-- "main" denotes the top-level package in a stand-alone executable.
-
-- "all" expands to all package directories found in all the GOPATH
-trees. For example, 'go list all' lists all the packages on the local
-system.
-
-- "std" is like all but expands to just the packages in the standard
-Go library.
-
-- "cmd" expands to the Go repository's commands and their
-internal libraries.
-
-An import path is a pattern if it includes one or more "..." wildcards,
-each of which can match any string, including the empty string and
-strings containing slashes.  Such a pattern expands to all package
-directories found in the GOPATH trees with names matching the
-patterns.  As a special case, x/... matches x as well as x's subdirectories.
-For example, net/... expands to net and packages in its subdirectories.
-
-An import path can also name a package to be downloaded from
-a remote repository.  Run 'go help importpath' for details.
-
-Every package in a program must have a unique import path.
-By convention, this is arranged by starting each path with a
-unique prefix that belongs to you.  For example, paths used
-internally at Google all begin with 'google', and paths
-denoting remote repositories begin with the path to the code,
-such as 'code.google.com/p/project'.
-
-As a special case, if the package list is a list of .go files from a
-single directory, the command is applied to a single synthesized
-package made up of exactly those files, ignoring any build constraints
-in those files and ignoring any other files in the directory.
-
-Directory and file names that begin with "." or "_" are ignored
-by the go tool, as are directories named "testdata".
-
-
-Description of testing flags
-
-The 'go test' command takes both flags that apply to 'go test' itself
-and flags that apply to the resulting test binary.
-
-Several of the flags control profiling and write an execution profile
-suitable for "go tool pprof"; run "go tool pprof help" for more
-information.  The --alloc_space, --alloc_objects, and --show_bytes
-options of pprof control how the information is presented.
-
-The following flags are recognized by the 'go test' command and
-control the execution of any test:
-
-	-bench regexp
-	    Run benchmarks matching the regular expression.
-	    By default, no benchmarks run. To run all benchmarks,
-	    use '-bench .' or '-bench=.'.
-
-	-benchmem
-	    Print memory allocation statistics for benchmarks.
-
-	-benchtime t
-	    Run enough iterations of each benchmark to take t, specified
-	    as a time.Duration (for example, -benchtime 1h30s).
-	    The default is 1 second (1s).
-
-	-blockprofile block.out
-	    Write a goroutine blocking profile to the specified file
-	    when all tests are complete.
-	    Writes test binary as -c would.
-
-	-blockprofilerate n
-	    Control the detail provided in goroutine blocking profiles by
-	    calling runtime.SetBlockProfileRate with n.
-	    See 'godoc runtime SetBlockProfileRate'.
-	    The profiler aims to sample, on average, one blocking event every
-	    n nanoseconds the program spends blocked.  By default,
-	    if -test.blockprofile is set without this flag, all blocking events
-	    are recorded, equivalent to -test.blockprofilerate=1.
-
-	-cover
-	    Enable coverage analysis.
-
-	-covermode set,count,atomic
-	    Set the mode for coverage analysis for the package[s]
-	    being tested. The default is "set" unless -race is enabled,
-	    in which case it is "atomic".
-	    The values:
-		set: bool: does this statement run?
-		count: int: how many times does this statement run?
-		atomic: int: count, but correct in multithreaded tests;
-			significantly more expensive.
-	    Sets -cover.
-
-	-coverpkg pkg1,pkg2,pkg3
-	    Apply coverage analysis in each test to the given list of packages.
-	    The default is for each test to analyze only the package being tested.
-	    Packages are specified as import paths.
-	    Sets -cover.
-
-	-coverprofile cover.out
-	    Write a coverage profile to the file after all tests have passed.
-	    Sets -cover.
-
-	-cpu 1,2,4
-	    Specify a list of GOMAXPROCS values for which the tests or
-	    benchmarks should be executed.  The default is the current value
-	    of GOMAXPROCS.
-
-	-cpuprofile cpu.out
-	    Write a CPU profile to the specified file before exiting.
-	    Writes test binary as -c would.
-
-	-memprofile mem.out
-	    Write a memory profile to the file after all tests have passed.
-	    Writes test binary as -c would.
-
-	-memprofilerate n
-	    Enable more precise (and expensive) memory profiles by setting
-	    runtime.MemProfileRate.  See 'godoc runtime MemProfileRate'.
-	    To profile all memory allocations, use -test.memprofilerate=1
-	    and pass --alloc_space flag to the pprof tool.
-
-	-outputdir directory
-	    Place output files from profiling in the specified directory,
-	    by default the directory in which "go test" is running.
-
-	-parallel n
-	    Allow parallel execution of test functions that call t.Parallel.
-	    The value of this flag is the maximum number of tests to run
-	    simultaneously; by default, it is set to the value of GOMAXPROCS.
-
-	-run regexp
-	    Run only those tests and examples matching the regular
-	    expression.
-
-	-short
-	    Tell long-running tests to shorten their run time.
-	    It is off by default but set during all.bash so that installing
-	    the Go tree can run a sanity check but not spend time running
-	    exhaustive tests.
-
-	-timeout t
-	    If a test runs longer than t, panic.
-
-	-trace trace.out
-	    Write an execution trace to the specified file before exiting.
-	    Writes test binary as -c would.
-
-	-v
-	    Verbose output: log all tests as they are run. Also print all
-	    text from Log and Logf calls even if the test succeeds.
-
-The test binary, called pkg.test where pkg is the name of the
-directory containing the package sources, can be invoked directly
-after building it with 'go test -c'. When invoking the test binary
-directly, each of the standard flag names must be prefixed with 'test.',
-as in -test.run=TestMyFunc or -test.v.
-
-When running 'go test', flags not listed above are passed through
-unaltered. For instance, the command
-
-	go test -x -v -cpuprofile=prof.out -dir=testdata -update
-
-will compile the test binary and then run it as
-
-	pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
-
-The test flags that generate profiles (other than for coverage) also
-leave the test binary in pkg.test for use when analyzing the profiles.
-
-Flags not recognized by 'go test' must be placed after any specified packages.
-
-
-Description of testing functions
-
-The 'go test' command expects to find test, benchmark, and example functions
-in the "*_test.go" files corresponding to the package under test.
-
-A test function is one named TestXXX (where XXX is any alphanumeric string
-not starting with a lower case letter) and should have the signature,
-
-	func TestXXX(t *testing.T) { ... }
-
-A benchmark function is one named BenchmarkXXX and should have the signature,
-
-	func BenchmarkXXX(b *testing.B) { ... }
-
-An example function is similar to a test function but, instead of using
-*testing.T to report success or failure, prints output to os.Stdout.
-That output is compared against the function's "Output:" comment, which
-must be the last comment in the function body (see example below). An
-example with no such comment, or with no text after "Output:" is compiled
-but not executed.
-
-Godoc displays the body of ExampleXXX to demonstrate the use
-of the function, constant, or variable XXX.  An example of a method M with
-receiver type T or *T is named ExampleT_M.  There may be multiple examples
-for a given function, constant, or variable, distinguished by a trailing _xxx,
-where xxx is a suffix not beginning with an upper case letter.
-
-Here is an example of an example:
-
-	func ExamplePrintln() {
-		Println("The output of\nthis example.")
-		// Output: The output of
-		// this example.
-	}
-
-The entire test file is presented as the example when it contains a single
-example function, at least one other function, type, variable, or constant
-declaration, and no test or benchmark functions.
-
-See the documentation of the testing package for more information.
-
-
-*/
 package main
+
+var cmdDoc = &Command{
+	Run:         runDoc,
+	UsageLine:   "doc [-u] [-c] [package|[package.]symbol[.method]]",
+	CustomFlags: true,
+	Short:       "show documentation for package or symbol",
+	Long: `
+
+Doc prints the documentation comments associated with the item identified by its
+arguments (a package, const, func, type, var, or method) followed by a one-line
+summary of each of the first-level items "under" that item (package-level declarations
+for a package, methods for a type, etc.).
+
+Doc accepts zero, one, or two arguments.
+
+Given no arguments, that is, when run as
+
+	go doc
+
+it prints the package documentation for the package in the current directory.
+
+When run with one argument, the argument is treated as a Go-syntax-like representation
+of the item to be documented. What the argument selects depends on what is installed
+in GOROOT and GOPATH, as well as the form of the argument, which is schematically
+one of these:
+
+	go doc <pkg>
+	go doc <sym>[.<method>]
+	go doc [<pkg>].<sym>[.<method>]
+
+The first item in this list matched by the argument is the one whose documentation
+is printed. (See the examples below.) For packages, the order of scanning is
+determined lexically, but the GOROOT tree is always scanned before GOPATH.
+
+If there is no package specified or matched, the package in the current directory
+is selected, so "go doc Foo" shows the documentation for symbol Foo in the current
+package.
+
+The package path must be either a qualified path or a proper suffix of a path. The
+go tool's usual package mechanism does not apply: package path elements like . and
+... are not implemented by go doc.
+
+When run with two arguments, the first must be a full package path (not just a
+suffix), and the second is a symbol or symbol and method; this is similar to the
+syntax accepted by godoc:
+
+	go doc <pkg> <sym>[.<method>]
+
+In all forms, when matching symbols, lower-case letters in the argument match
+either case but upper-case letters match exactly. This means that there may be
+multiple matches of a lower-case argument in a package if different symbols have
+different cases. If this occurs, documentation for all matches is printed.
+
+Examples:
+	go doc
+		Show documentation for current package.
+	go doc Foo
+		Show documentation for Foo in the current package.
+		(Foo starts with a capital letter so it cannot match a package path.)
+	go doc encoding/json
+		Show documentation for the encoding/json package.
+	go doc json
+		Shorthand for encoding/json.
+	go doc json.Number (or go doc json.number)
+		Show documentation and method summary for json.Number.
+	go doc json.Number.Int64 (or go doc json.number.int64)
+		Show documentation for json.Number's Int64 method.
+	go doc template.new
+		Show documentation for html/template's New function.
+		(html/template is lexically before text/template)
+	go doc text/template.new # One argument
+		Show documentation for text/template's New function.
+	go doc text/template new # Two arguments
+		Show documentation for text/template's New function.
+
+Flags:
+	-c
+		Respect case when matching symbols.
+	-u
+		Show documentation for unexported as well as exported
+		symbols and methods.
+`,
+}
+
+func runDoc(cmd *Command, args []string) {
+	run(buildToolExec, tool("doc"), args)
+}
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
index 8e9ad38..a17f6e7 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -13,11 +13,11 @@
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strconv"
 	"strings"
 	"unicode"
-	"unicode/utf8"
 )
 
 var cmdGenerate = &Command{
@@ -62,6 +62,8 @@
 		The execution operating system (linux, windows, etc.)
 	$GOFILE
 		The base name of the file.
+	$GOLINE
+		The line number of the directive in the source file.
 	$GOPACKAGE
 		The name of the package of the file containing the directive.
 	$DOLLAR
@@ -108,9 +110,10 @@
 Go generate accepts one specific flag:
 
 	-run=""
-		TODO: This flag is unimplemented.
-		if non-empty, specifies a regular expression to
-		select directives whose command matches the expression.
+		if non-empty, specifies a regular expression to select
+		directives whose full original source text (excluding
+		any trailing spaces and final newline) matches the
+		expression.
 
 It also accepts the standard build flags -v, -n, and -x.
 The -v flag prints the names of packages and files as they are
@@ -122,7 +125,10 @@
 	`,
 }
 
-var generateRunFlag string // generate -run flag
+var (
+	generateRunFlag string         // generate -run flag
+	generateRunRE   *regexp.Regexp // compiled expression for -run
+)
 
 func init() {
 	addBuildFlags(cmdGenerate)
@@ -130,6 +136,13 @@
 }
 
 func runGenerate(cmd *Command, args []string) {
+	if generateRunFlag != "" {
+		var err error
+		generateRunRE, err = regexp.Compile(generateRunFlag)
+		if err != nil {
+			log.Fatalf("generate: %s", err)
+		}
+	}
 	// Even if the arguments are .go files, this loop suffices.
 	for _, pkg := range packages(args) {
 		for _, file := range pkg.gofiles {
@@ -165,7 +178,7 @@
 	file     string // base name of file.
 	pkg      string
 	commands map[string][]string
-	lineNum  int
+	lineNum  int // current line number.
 }
 
 // run runs the generators in the current file.
@@ -223,6 +236,11 @@
 		if !isGoGenerate(buf) {
 			continue
 		}
+		if generateRunFlag != "" {
+			if !generateRunRE.Match(bytes.TrimSpace(buf)) {
+				continue
+			}
+		}
 
 		words := g.split(string(buf))
 		if len(words) == 0 {
@@ -308,7 +326,7 @@
 	}
 	// Substitute environment variables.
 	for i, word := range words {
-		words[i] = g.expandEnv(word)
+		words[i] = os.Expand(word, g.expandVar)
 	}
 	return words
 }
@@ -324,40 +342,25 @@
 	panic(stop)
 }
 
-// expandEnv expands any $XXX invocations in word.
-func (g *Generator) expandEnv(word string) string {
-	if !strings.ContainsRune(word, '$') {
-		return word
+// expandVar expands the $XXX invocation in word. It is called
+// by os.Expand.
+func (g *Generator) expandVar(word string) string {
+	switch word {
+	case "GOARCH":
+		return runtime.GOARCH
+	case "GOOS":
+		return runtime.GOOS
+	case "GOFILE":
+		return g.file
+	case "GOLINE":
+		return fmt.Sprint(g.lineNum)
+	case "GOPACKAGE":
+		return g.pkg
+	case "DOLLAR":
+		return "$"
+	default:
+		return os.Getenv(word)
 	}
-	var buf bytes.Buffer
-	var w int
-	var r rune
-	for i := 0; i < len(word); i += w {
-		r, w = utf8.DecodeRuneInString(word[i:])
-		if r != '$' {
-			buf.WriteRune(r)
-			continue
-		}
-		w += g.identLength(word[i+w:])
-		envVar := word[i+1 : i+w]
-		var sub string
-		switch envVar {
-		case "GOARCH":
-			sub = runtime.GOARCH
-		case "GOOS":
-			sub = runtime.GOOS
-		case "GOFILE":
-			sub = g.file
-		case "GOPACKAGE":
-			sub = g.pkg
-		case "DOLLAR":
-			sub = "$"
-		default:
-			sub = os.Getenv(envVar)
-		}
-		buf.WriteString(sub)
-	}
-	return buf.String()
 }
 
 // identLength returns the length of the identifier beginning the string.
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 2ab0353..56e8493 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -363,3 +363,43 @@
 line comment.
 	`,
 }
+
+var helpBuildmode = &Command{
+	UsageLine: "buildmode",
+	Short:     "description of build modes",
+	Long: `
+The 'go build' and 'go install' commands take a -buildmode argument which
+indicates which kind of object file is to be built. Currently supported values
+are:
+
+	-buildmode=archive
+		Build the listed non-main packages into .a files. Packages named
+		main are ignored.
+
+	-buildmode=c-archive
+		Build the listed main package, plus all packages it imports,
+		into a C archive file. The only callable symbols will be those
+		functions marked as exported. Requires exactly one main package
+		to be listed.
+
+	-buildmode=c-shared
+		Build the listed main packages, plus all packages that they
+		import, into C shared libraries. The only callable symbols will
+		be those functions marked as exported. Non-main packages are
+		ignored.
+
+	-buildmode=default
+		Listed main packages are built into executables and listed
+		non-main packages are built into .a files (the default
+		behavior).
+
+	-buildmode=shared
+		Combine all the listed non-main packages into a single shared
+		library that will be used when building with the -linkshared
+		option. Packages named main are ignored.
+
+	-buildmode=exe
+		Build the listed main packages and everything they import into
+		executables. Packages not named main are ignored.
+`,
+}
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
index 107b820..8b1247b 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -24,6 +24,16 @@
 // changed by tests, without modifying http.DefaultClient.
 var httpClient = http.DefaultClient
 
+type httpError struct {
+	status     string
+	statusCode int
+	url        string
+}
+
+func (e *httpError) Error() string {
+	return fmt.Sprintf("%s: %s", e.url, e.status)
+}
+
 // httpGET returns the data from an HTTP GET request for the given URL.
 func httpGET(url string) ([]byte, error) {
 	resp, err := httpClient.Get(url)
@@ -32,7 +42,9 @@
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("%s: %s", url, resp.Status)
+		err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url}
+
+		return nil, err
 	}
 	b, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index fbf9616..e500ece 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -36,6 +36,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?
@@ -126,6 +127,7 @@
 var nl = []byte{'\n'}
 
 func runList(cmd *Command, args []string) {
+	buildModeInit()
 	out := newTrackingWriter(os.Stdout)
 	defer out.w.Flush()
 
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 5e0ab79..b0d7448 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -77,6 +77,7 @@
 var commands = []*Command{
 	cmdBuild,
 	cmdClean,
+	cmdDoc,
 	cmdEnv,
 	cmdFix,
 	cmdFmt,
@@ -91,6 +92,7 @@
 	cmdVet,
 
 	helpC,
+	helpBuildmode,
 	helpFileType,
 	helpGopath,
 	helpImportPath,
@@ -212,8 +214,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
-// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
+// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
+// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
 
 /*
 {{range .}}{{if .Short}}{{.Short | capitalize}}
diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkalldocs.sh
similarity index 71%
rename from src/cmd/go/mkdoc.sh
rename to src/cmd/go/mkalldocs.sh
index 507a8ae..74e3125 100755
--- a/src/cmd/go/mkdoc.sh
+++ b/src/cmd/go/mkalldocs.sh
@@ -6,7 +6,7 @@
 set -e
 
 go build -o go.latest
-./go.latest help documentation | sed 's; \*/; * /;' >doc.go
-gofmt -w doc.go
+./go.latest help documentation | sed 's; \*/; * /;' >alldocs.go
+gofmt -w alldocs.go
 rm go.latest
 
diff --git a/src/cmd/go/note.go b/src/cmd/go/note.go
new file mode 100644
index 0000000..b82850d
--- /dev/null
+++ b/src/cmd/go/note.go
@@ -0,0 +1,84 @@
+// 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 !cmd_go_bootstrap
+
+// This is not built when bootstrapping to avoid having go_bootstrap depend on
+// debug/elf.
+
+package main
+
+import (
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+	"io"
+)
+
+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) {
+	full := rnd(sz, 4)
+	data := make([]byte, full)
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+func readnote(filename, name string, typ int32) ([]byte, error) {
+	f, err := elf.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	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 name == string(noteName) && typ == noteType {
+				return desc, nil
+			}
+		}
+	}
+	return nil, nil
+}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 8bf0f56..9466aad 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -11,6 +11,7 @@
 	"go/build"
 	"go/scanner"
 	"go/token"
+	"io/ioutil"
 	"os"
 	pathpkg "path"
 	"path/filepath"
@@ -32,6 +33,7 @@
 	Name          string `json:",omitempty"` // package name
 	Doc           string `json:",omitempty"` // package documentation string
 	Target        string `json:",omitempty"` // install path
+	Shlib         string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
 	Goroot        bool   `json:",omitempty"` // is this package found in the Go root?
 	Standard      bool   `json:",omitempty"` // is this package part of the standard Go library?
 	Stale         bool   `json:",omitempty"` // would 'go install' do anything for this package?
@@ -406,7 +408,9 @@
 	"cmd/api":                              toTool,
 	"cmd/asm":                              toTool,
 	"cmd/cgo":                              toTool,
+	"cmd/cover":                            toTool,
 	"cmd/dist":                             toTool,
+	"cmd/doc":                              toTool,
 	"cmd/fix":                              toTool,
 	"cmd/link":                             toTool,
 	"cmd/nm":                               toTool,
@@ -419,7 +423,6 @@
 	"cmd/pprof":                            toTool,
 	"cmd/trace":                            toTool,
 	"cmd/yacc":                             toTool,
-	"golang.org/x/tools/cmd/cover":         toTool,
 	"golang.org/x/tools/cmd/godoc":         toBin,
 	"golang.org/x/tools/cmd/vet":           toTool,
 	"code.google.com/p/go.tools/cmd/cover": stalePath,
@@ -484,7 +487,15 @@
 		return p
 	}
 
-	if p.Name == "main" {
+	useBindir := p.Name == "main"
+	if !p.Standard {
+		switch buildBuildmode {
+		case "c-archive", "c-shared":
+			useBindir = false
+		}
+	}
+
+	if useBindir {
 		// Report an error when the old code.google.com/p/go.tools paths are used.
 		if goTools[p.ImportPath] == stalePath {
 			newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
@@ -521,6 +532,15 @@
 		p.target = ""
 	} else {
 		p.target = p.build.PkgObj
+		if buildLinkshared {
+			shlibnamefile := p.target[:len(p.target)-2] + ".shlibname"
+			shlib, err := ioutil.ReadFile(shlibnamefile)
+			if err == nil {
+				p.Shlib = strings.TrimSpace(string(shlib))
+			} else if !os.IsNotExist(err) {
+				fatalf("unexpected error reading %s: %v", shlibnamefile, err)
+			}
+		}
 	}
 
 	importPaths := p.Imports
@@ -534,6 +554,14 @@
 	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
 		importPaths = append(importPaths, "syscall")
 	}
+
+	// Currently build mode c-shared, or -linkshared, forces
+	// external linking mode, and external linking mode forces an
+	// import of runtime/cgo.
+	if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildLinkshared) {
+		importPaths = append(importPaths, "runtime/cgo")
+	}
+
 	// Everything depends on runtime, except runtime and unsafe.
 	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
 		importPaths = append(importPaths, "runtime")
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index ef8aa95..f815cb9 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -64,6 +64,7 @@
 
 func runRun(cmd *Command, args []string) {
 	raceInit()
+	buildModeInit()
 	var b builder
 	b.init()
 	b.print = printStderr
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 39071e9..eb92f9e 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -738,12 +738,6 @@
 	ok=false
 fi
 
-TEST go get cover
-./testgo get golang.org/x/tools/cmd/cover || ok=false
-
-unset GOPATH
-rm -rf $d
-
 TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}"
 d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
 export GOPATH=$d
@@ -1069,28 +1063,40 @@
 
 TEST 'go generate handles simple command'
 if ! ./testgo generate ./testdata/generate/test1.go > testdata/std.out; then
-	echo "go test ./testdata/generate/test1.go failed to run"
+	echo "go generate ./testdata/generate/test1.go failed to run"
 	ok=false
 elif ! grep 'Success' testdata/std.out > /dev/null; then
-	echo "go test ./testdata/generate/test1.go generated wrong output"
+	echo "go generate ./testdata/generate/test1.go generated wrong output"
 	ok=false
 fi
 
 TEST 'go generate handles command alias'
 if ! ./testgo generate ./testdata/generate/test2.go > testdata/std.out; then
-	echo "go test ./testdata/generate/test2.go failed to run"
+	echo "go generate ./testdata/generate/test2.go failed to run"
 	ok=false
 elif ! grep 'Now is the time for all good men' testdata/std.out > /dev/null; then
-	echo "go test ./testdata/generate/test2.go generated wrong output"
+	echo "go generate ./testdata/generate/test2.go generated wrong output"
 	ok=false
 fi
 
 TEST 'go generate variable substitution'
 if ! ./testgo generate ./testdata/generate/test3.go > testdata/std.out; then
-	echo "go test ./testdata/generate/test3.go failed to run"
+	echo "go generate ./testdata/generate/test3.go failed to run"
 	ok=false
-elif ! grep "$GOARCH test3.go p xyzp/test3.go/123" testdata/std.out > /dev/null; then
-	echo "go test ./testdata/generate/test3.go generated wrong output"
+elif ! grep "$GOARCH test3.go:7 pabc xyzp/test3.go/123" testdata/std.out > /dev/null; then
+	echo "go generate ./testdata/generate/test3.go generated wrong output"
+	ok=false
+fi
+
+TEST 'go generate run flag'
+if ! ./testgo generate -run y.s ./testdata/generate/test4.go > testdata/std.out; then
+	echo "go test -run yes ./testdata/generate/test4.go failed to run"
+	ok=false
+elif ! grep "yes" testdata/std.out > /dev/null; then
+	echo "go generate -run yes ./testdata/generate/test4.go did not select yes"
+	ok=false
+elif grep "no" testdata/std.out > /dev/null; then
+	echo "go generate -run yes ./testdata/generate/test4.go selected no"
 	ok=false
 fi
 
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index e96ed22..22018f9 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -314,6 +314,7 @@
 	findExecCmd() // initialize cached result
 
 	raceInit()
+	buildModeInit()
 	pkgs := packagesForBuild(pkgArgs)
 	if len(pkgs) == 0 {
 		fatalf("no packages to test")
@@ -429,6 +430,10 @@
 
 		// Mark all the coverage packages for rebuilding with coverage.
 		for _, p := range testCoverPkgs {
+			// There is nothing to cover in package unsafe; it comes from the compiler.
+			if p.ImportPath == "unsafe" {
+				continue
+			}
 			p.Stale = true // rebuild
 			p.fake = true  // do not warn about rebuild
 			p.coverMode = testCoverMode
diff --git a/src/cmd/go/testdata/generate/test3.go b/src/cmd/go/testdata/generate/test3.go
index 41ffb7e..3d6a8a5 100644
--- a/src/cmd/go/testdata/generate/test3.go
+++ b/src/cmd/go/testdata/generate/test3.go
@@ -4,6 +4,6 @@
 
 // Test go generate variable substitution.
 
-//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
+//go:generate echo $GOARCH $GOFILE:$GOLINE ${GOPACKAGE}abc xyz$GOPACKAGE/$GOFILE/123
 
 package p
diff --git a/src/cmd/go/testdata/generate/test4.go b/src/cmd/go/testdata/generate/test4.go
new file mode 100644
index 0000000..a7631c4
--- /dev/null
+++ b/src/cmd/go/testdata/generate/test4.go
@@ -0,0 +1,10 @@
+// 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 -run flag
+
+//go:generate echo oh yes my man
+//go:generate echo no, no, a thousand times no
+
+package p
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index 5652e54..db1266e 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -48,6 +48,7 @@
 	{name: "tags"},
 	{name: "compiler"},
 	{name: "race", boolVar: &buildRace},
+	{name: "linkshared", boolVar: &buildLinkshared},
 	{name: "installsuffix"},
 
 	// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
@@ -115,7 +116,7 @@
 		var err error
 		switch f.name {
 		// bool flags.
-		case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
+		case "a", "c", "i", "n", "x", "v", "race", "cover", "work", "linkshared":
 			setBoolFlag(f.boolVar, value)
 		case "o":
 			testO = value
@@ -169,7 +170,7 @@
 			case "set", "count", "atomic":
 				testCoverMode = value
 			default:
-				fatalf("invalid flag argument for -cover: %q", value)
+				fatalf("invalid flag argument for -covermode: %q", value)
 			}
 			testCover = true
 		case "outputdir":
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
index 29feb1d..bf8ff03 100644
--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -68,7 +68,7 @@
 
 func isInGoToolsRepo(toolName string) bool {
 	switch toolName {
-	case "cover", "vet":
+	case "vet":
 		return true
 	}
 	return false
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 86f5ea8..408104d 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -9,12 +9,14 @@
 	"encoding/json"
 	"errors"
 	"fmt"
+	"internal/singleflight"
 	"log"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"regexp"
 	"strings"
+	"sync"
 )
 
 // A vcsCmd describes how to use a version control system
@@ -566,7 +568,7 @@
 // repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
 // statically known by repoRootForImportPathStatic.
 //
-// This handles "vanity import paths" like "name.tld/pkg/foo".
+// This handles custom import paths like "name.tld/pkg/foo".
 func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
 	slash := strings.Index(importPath, "/")
 	if slash < 0 {
@@ -585,7 +587,8 @@
 	if err != nil {
 		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
 	}
-	metaImport, err := matchGoImport(imports, importPath)
+	// Find the matched meta import.
+	mmi, err := matchGoImport(imports, importPath)
 	if err != nil {
 		if err != errNoMatch {
 			return nil, fmt.Errorf("parse %s: %v", urlStr, err)
@@ -593,7 +596,7 @@
 		return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
 	}
 	if buildV {
-		log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
+		log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
 	}
 	// If the import was "uni.edu/bob/project", which said the
 	// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
@@ -601,42 +604,89 @@
 	// "uni.edu" yet (possibly overwriting/preempting another
 	// non-evil student).  Instead, first verify the root and see
 	// if it matches Bob's claim.
-	if metaImport.Prefix != importPath {
+	if mmi.Prefix != importPath {
 		if buildV {
 			log.Printf("get %q: verifying non-authoritative meta tag", importPath)
 		}
 		urlStr0 := urlStr
-		urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
+		var imports []metaImport
+		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix)
 		if err != nil {
-			return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
-		}
-		imports, err := parseMetaGoImports(body)
-		if err != nil {
-			return nil, fmt.Errorf("parsing %s: %v", importPath, err)
-		}
-		if len(imports) == 0 {
-			return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+			return nil, err
 		}
 		metaImport2, err := matchGoImport(imports, importPath)
-		if err != nil || metaImport != metaImport2 {
-			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
+		if err != nil || mmi != metaImport2 {
+			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix)
 		}
 	}
 
-	if !strings.Contains(metaImport.RepoRoot, "://") {
-		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
+	if !strings.Contains(mmi.RepoRoot, "://") {
+		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
 	}
 	rr := &repoRoot{
-		vcs:  vcsByCmd(metaImport.VCS),
-		repo: metaImport.RepoRoot,
-		root: metaImport.Prefix,
+		vcs:  vcsByCmd(mmi.VCS),
+		repo: mmi.RepoRoot,
+		root: mmi.Prefix,
 	}
 	if rr.vcs == nil {
-		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
+		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
 	}
 	return rr, nil
 }
 
+var fetchGroup singleflight.Group
+var (
+	fetchCacheMu sync.Mutex
+	fetchCache   = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix
+)
+
+// metaImportsForPrefix takes a package's root import path as declared in a <meta> tag
+// and returns its HTML discovery URL and the parsed metaImport lines
+// found on the page.
+//
+// The importPath is of the form "golang.org/x/tools".
+// It is an error if no imports are found.
+// urlStr will still be valid if err != nil.
+// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
+func metaImportsForPrefix(importPrefix string) (urlStr string, imports []metaImport, err error) {
+	setCache := func(res fetchResult) (fetchResult, error) {
+		fetchCacheMu.Lock()
+		defer fetchCacheMu.Unlock()
+		fetchCache[importPrefix] = res
+		return res, nil
+	}
+
+	resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) {
+		fetchCacheMu.Lock()
+		if res, ok := fetchCache[importPrefix]; ok {
+			fetchCacheMu.Unlock()
+			return res, nil
+		}
+		fetchCacheMu.Unlock()
+
+		urlStr, body, err := httpsOrHTTP(importPrefix)
+		if err != nil {
+			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
+		}
+		imports, err := parseMetaGoImports(body)
+		if err != nil {
+			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
+		}
+		if len(imports) == 0 {
+			err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+		}
+		return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err})
+	})
+	res := resi.(fetchResult)
+	return res.urlStr, res.imports, res.err
+}
+
+type fetchResult struct {
+	urlStr  string // e.g. "https://foo.com/x/bar?go-get=1"
+	imports []metaImport
+	err     error
+}
+
 // metaImport represents the parsed <meta name="go-import"
 // content="prefix vcs reporoot" /> tags from HTML files.
 type metaImport struct {
@@ -808,10 +858,25 @@
 	url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
 	data, err := httpGET(url)
 	if err != nil {
-		return err
-	}
-	if err := json.Unmarshal(data, &resp); err != nil {
-		return fmt.Errorf("decoding %s: %v", url, err)
+		if httpErr, ok := err.(*httpError); ok && httpErr.statusCode == 403 {
+			// this may be a private repository. If so, attempt to determine which
+			// VCS it uses. See issue 5375.
+			root := match["root"]
+			for _, vcs := range []string{"git", "hg"} {
+				if vcsByCmd(vcs).ping("https", root) == nil {
+					resp.SCM = vcs
+					break
+				}
+			}
+		}
+
+		if resp.SCM == "" {
+			return err
+		}
+	} else {
+		if err := json.Unmarshal(data, &resp); err != nil {
+			return fmt.Errorf("decoding %s: %v", url, err)
+		}
 	}
 
 	if vcsByCmd(resp.SCM) != nil {
diff --git a/src/cmd/internal/asm/asm.go b/src/cmd/internal/asm/asm.go
index b67b4d7..b96c2cb 100644
--- a/src/cmd/internal/asm/asm.go
+++ b/src/cmd/internal/asm/asm.go
@@ -192,7 +192,7 @@
 	flag.Var((*count)(&debug['S']), "S", "print assembly and machine code")
 	flag.Var((*count)(&debug['m']), "m", "debug preprocessor macros")
 	flag.StringVar(&outfile, "o", "", "file: set output file")
-	flag.StringVar(&Ctxt.Trimpath, "trimpath", "", "prefix: remove prefix from recorded source file paths")
+	flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "prefix: remove prefix from recorded source file paths")
 
 	flag.Parse()
 
@@ -209,7 +209,7 @@
 	if assemble(flag.Arg(0)) != 0 {
 		errorexit()
 	}
-	obj.Bflush(&bstdout)
+	bstdout.Flush()
 	if nerrors > 0 {
 		errorexit()
 	}
@@ -244,7 +244,7 @@
 	}
 
 	obj.Writeobjdirect(Ctxt, &obuf)
-	obj.Bflush(&obuf)
+	obuf.Flush()
 	return 0
 }
 
diff --git a/src/cmd/internal/asm/lexbody.go b/src/cmd/internal/asm/lexbody.go
index 7943cba..b5e5d1e 100644
--- a/src/cmd/internal/asm/lexbody.go
+++ b/src/cmd/internal/asm/lexbody.go
@@ -98,7 +98,7 @@
 }
 
 func errorexit() {
-	obj.Bflush(&bstdout)
+	bstdout.Flush()
 	if outfile != "" {
 		os.Remove(outfile)
 	}
diff --git a/src/cmd/internal/gc/align.go b/src/cmd/internal/gc/align.go
index 9025b1a..789e59b 100644
--- a/src/cmd/internal/gc/align.go
+++ b/src/cmd/internal/gc/align.go
@@ -127,7 +127,7 @@
 		lineno = int32(t.Lineno)
 		if t.Broke == 0 {
 			t.Broke = 1
-			Yyerror("invalid recursive type %v", Tconv(t, 0))
+			Yyerror("invalid recursive type %v", t)
 		}
 
 		t.Width = 0
@@ -164,7 +164,7 @@
 	w := int64(0)
 	switch et {
 	default:
-		Fatal("dowidth: unknown type: %v", Tconv(t, 0))
+		Fatal("dowidth: unknown type: %v", t)
 
 		/* compiler-specific stuff */
 	case TINT8, TUINT8, TBOOL:
@@ -230,7 +230,7 @@
 
 	case TFORW: // should have been filled in
 		if t.Broke == 0 {
-			Yyerror("invalid recursive type %v", Tconv(t, 0))
+			Yyerror("invalid recursive type %v", t)
 		}
 		w = 1 // anything will do
 
@@ -273,12 +273,12 @@
 				t.Broke = 1
 			}
 		} else {
-			Fatal("dowidth %v", Tconv(t, 0)) // probably [...]T
+			Fatal("dowidth %v", t) // probably [...]T
 		}
 
 	case TSTRUCT:
 		if t.Funarg != 0 {
-			Fatal("dowidth fn struct %v", Tconv(t, 0))
+			Fatal("dowidth fn struct %v", t)
 		}
 		w = widstruct(t, t, 0, 1)
 
@@ -303,19 +303,19 @@
 		w = widstruct(t.Type, *Getoutarg(t1), w, Widthreg)
 		t1.Argwid = w
 		if w%int64(Widthreg) != 0 {
-			Warn("bad type %v %d\n", Tconv(t1, 0), w)
+			Warn("bad type %v %d\n", t1, w)
 		}
 		t.Align = 1
 	}
 
 	if Widthptr == 4 && w != int64(int32(w)) {
-		Yyerror("type %v too large", Tconv(t, 0))
+		Yyerror("type %v too large", t)
 	}
 
 	t.Width = w
 	if t.Align == 0 {
 		if w > 8 || w&(w-1) != 0 {
-			Fatal("invalid alignment for %v", Tconv(t, 0))
+			Fatal("invalid alignment for %v", t)
 		}
 		t.Align = uint8(w)
 	}
@@ -363,7 +363,7 @@
 	// function arg structs should not be checked
 	// outside of the enclosing function.
 	if t.Funarg != 0 {
-		Fatal("checkwidth %v", Tconv(t, 0))
+		Fatal("checkwidth %v", t)
 	}
 
 	if defercalc == 0 {
@@ -411,6 +411,8 @@
 	defercalc = 0
 }
 
+var itable *Type // distinguished *byte
+
 func typeinit() {
 	if Widthptr == 0 {
 		Fatal("typeinit before betypeinit")
@@ -485,8 +487,8 @@
 			okforarith[i] = true
 			okforconst[i] = true
 			issimple[i] = true
-			minfltval[i] = new(Mpflt)
-			maxfltval[i] = new(Mpflt)
+			minfltval[i] = newMpflt()
+			maxfltval[i] = newMpflt()
 		}
 
 		if Iscomplex[i] {
@@ -664,6 +666,9 @@
 
 	dowidth(Types[TSTRING])
 	dowidth(idealstring)
+
+	itable = typ(Tptr)
+	itable.Type = Types[TUINT8]
 }
 
 /*
diff --git a/src/cmd/internal/gc/big/accuracy_string.go b/src/cmd/internal/gc/big/accuracy_string.go
new file mode 100644
index 0000000..24ef7f1
--- /dev/null
+++ b/src/cmd/internal/gc/big/accuracy_string.go
@@ -0,0 +1,17 @@
+// generated by stringer -type=Accuracy; DO NOT EDIT
+
+package big
+
+import "fmt"
+
+const _Accuracy_name = "BelowExactAbove"
+
+var _Accuracy_index = [...]uint8{0, 5, 10, 15}
+
+func (i Accuracy) String() string {
+	i -= -1
+	if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) {
+		return fmt.Sprintf("Accuracy(%d)", i+-1)
+	}
+	return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
+}
diff --git a/src/cmd/internal/gc/big/arith.go b/src/cmd/internal/gc/big/arith.go
new file mode 100644
index 0000000..328c85c
--- /dev/null
+++ b/src/cmd/internal/gc/big/arith.go
@@ -0,0 +1,291 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides Go implementations of elementary multi-precision
+// arithmetic operations on word vectors. Needed for platforms without
+// assembly implementations of these routines.
+
+package big
+
+// A Word represents a single digit of a multi-precision unsigned integer.
+type Word uintptr
+
+const (
+	// Compute the size _S of a Word in bytes.
+	_m    = ^Word(0)
+	_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
+	_S    = 1 << _logS
+
+	_W = _S << 3 // word size in bits
+	_B = 1 << _W // digit base
+	_M = _B - 1  // digit mask
+
+	_W2 = _W / 2   // half word size in bits
+	_B2 = 1 << _W2 // half digit base
+	_M2 = _B2 - 1  // half digit mask
+)
+
+// ----------------------------------------------------------------------------
+// Elementary operations on words
+//
+// These operations are used by the vector operations below.
+
+// z1<<_W + z0 = x+y+c, with c == 0 or 1
+func addWW_g(x, y, c Word) (z1, z0 Word) {
+	yc := y + c
+	z0 = x + yc
+	if z0 < x || yc < y {
+		z1 = 1
+	}
+	return
+}
+
+// z1<<_W + z0 = x-y-c, with c == 0 or 1
+func subWW_g(x, y, c Word) (z1, z0 Word) {
+	yc := y + c
+	z0 = x - yc
+	if z0 > x || yc < y {
+		z1 = 1
+	}
+	return
+}
+
+// z1<<_W + z0 = x*y
+// Adapted from Warren, Hacker's Delight, p. 132.
+func mulWW_g(x, y Word) (z1, z0 Word) {
+	x0 := x & _M2
+	x1 := x >> _W2
+	y0 := y & _M2
+	y1 := y >> _W2
+	w0 := x0 * y0
+	t := x1*y0 + w0>>_W2
+	w1 := t & _M2
+	w2 := t >> _W2
+	w1 += x0 * y1
+	z1 = x1*y1 + w2 + w1>>_W2
+	z0 = x * y
+	return
+}
+
+// z1<<_W + z0 = x*y + c
+func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
+	z1, zz0 := mulWW_g(x, y)
+	if z0 = zz0 + c; z0 < zz0 {
+		z1++
+	}
+	return
+}
+
+// Length of x in bits.
+func bitLen_g(x Word) (n int) {
+	for ; x >= 0x8000; x >>= 16 {
+		n += 16
+	}
+	if x >= 0x80 {
+		x >>= 8
+		n += 8
+	}
+	if x >= 0x8 {
+		x >>= 4
+		n += 4
+	}
+	if x >= 0x2 {
+		x >>= 2
+		n += 2
+	}
+	if x >= 0x1 {
+		n++
+	}
+	return
+}
+
+// log2 computes the integer binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is -1.
+func log2(x Word) int {
+	return bitLen(x) - 1
+}
+
+// Number of leading zeros in x.
+func leadingZeros(x Word) uint {
+	return uint(_W - bitLen(x))
+}
+
+// q = (u1<<_W + u0 - r)/y
+// Adapted from Warren, Hacker's Delight, p. 152.
+func divWW_g(u1, u0, v Word) (q, r Word) {
+	if u1 >= v {
+		return 1<<_W - 1, 1<<_W - 1
+	}
+
+	s := leadingZeros(v)
+	v <<= s
+
+	vn1 := v >> _W2
+	vn0 := v & _M2
+	un32 := u1<<s | u0>>(_W-s)
+	un10 := u0 << s
+	un1 := un10 >> _W2
+	un0 := un10 & _M2
+	q1 := un32 / vn1
+	rhat := un32 - q1*vn1
+
+	for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+		q1--
+		rhat += vn1
+		if rhat >= _B2 {
+			break
+		}
+	}
+
+	un21 := un32*_B2 + un1 - q1*v
+	q0 := un21 / vn1
+	rhat = un21 - q0*vn1
+
+	for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+		q0--
+		rhat += vn1
+		if rhat >= _B2 {
+			break
+		}
+	}
+
+	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
+}
+
+// Keep for performance debugging.
+// Using addWW_g is likely slower.
+const use_addWW_g = false
+
+// The resulting carry c is either 0 or 1.
+func addVV_g(z, x, y []Word) (c Word) {
+	if use_addWW_g {
+		for i := range z {
+			c, z[i] = addWW_g(x[i], y[i], c)
+		}
+		return
+	}
+
+	for i, xi := range x[:len(z)] {
+		yi := y[i]
+		zi := xi + yi + c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
+	}
+	return
+}
+
+// The resulting carry c is either 0 or 1.
+func subVV_g(z, x, y []Word) (c Word) {
+	if use_addWW_g {
+		for i := range z {
+			c, z[i] = subWW_g(x[i], y[i], c)
+		}
+		return
+	}
+
+	for i, xi := range x[:len(z)] {
+		yi := y[i]
+		zi := xi - yi - c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
+	}
+	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 {
+		c = y
+		for i := range z {
+			c, z[i] = addWW_g(x[i], c, 0)
+		}
+		return
+	}
+
+	c = y
+	for i, xi := range x[:len(z)] {
+		zi := xi + c
+		z[i] = zi
+		c = xi &^ zi >> (_W - 1)
+	}
+	return
+}
+
+func subVW_g(z, x []Word, y Word) (c Word) {
+	if use_addWW_g {
+		c = y
+		for i := range z {
+			c, z[i] = subWW_g(x[i], c, 0)
+		}
+		return
+	}
+
+	c = y
+	for i, xi := range x[:len(z)] {
+		zi := xi - c
+		z[i] = zi
+		c = (zi &^ xi) >> (_W - 1)
+	}
+	return
+}
+
+func shlVU_g(z, x []Word, s uint) (c Word) {
+	if n := len(z); n > 0 {
+		ŝ := _W - s
+		w1 := x[n-1]
+		c = w1 >> ŝ
+		for i := n - 1; i > 0; i-- {
+			w := w1
+			w1 = x[i-1]
+			z[i] = w<<s | w1>>ŝ
+		}
+		z[0] = w1 << s
+	}
+	return
+}
+
+func shrVU_g(z, x []Word, s uint) (c Word) {
+	if n := len(z); n > 0 {
+		ŝ := _W - s
+		w1 := x[0]
+		c = w1 << ŝ
+		for i := 0; i < n-1; i++ {
+			w := w1
+			w1 = x[i+1]
+			z[i] = w>>s | w1<<ŝ
+		}
+		z[n-1] = w1 >> s
+	}
+	return
+}
+
+func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
+	c = r
+	for i := range z {
+		c, z[i] = mulAddWWW_g(x[i], y, c)
+	}
+	return
+}
+
+// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
+func addMulVVW_g(z, x []Word, y Word) (c Word) {
+	for i := range z {
+		z1, z0 := mulAddWWW_g(x[i], y, z[i])
+		c, z[i] = addWW_g(z0, c, 0)
+		c += z1
+	}
+	return
+}
+
+func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
+	r = xn
+	for i := len(z) - 1; i >= 0; i-- {
+		z[i], r = divWW_g(r, x[i], y)
+	}
+	return
+}
diff --git a/src/cmd/internal/gc/big/arith_decl.go b/src/cmd/internal/gc/big/arith_decl.go
new file mode 100644
index 0000000..fe13577
--- /dev/null
+++ b/src/cmd/internal/gc/big/arith_decl.go
@@ -0,0 +1,53 @@
+// 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 big
+
+func mulWW(x, y Word) (z1, z0 Word) {
+	return mulWW_g(x, y)
+}
+
+func divWW(x1, x0, y Word) (q, r Word) {
+	return divWW_g(x1, x0, y)
+}
+
+func addVV(z, x, y []Word) (c Word) {
+	return addVV_g(z, x, y)
+}
+
+func subVV(z, x, y []Word) (c Word) {
+	return subVV_g(z, x, y)
+}
+
+func addVW(z, x []Word, y Word) (c Word) {
+	return addVW_g(z, x, y)
+}
+
+func subVW(z, x []Word, y Word) (c Word) {
+	return subVW_g(z, x, y)
+}
+
+func shlVU(z, x []Word, s uint) (c Word) {
+	return shlVU_g(z, x, s)
+}
+
+func shrVU(z, x []Word, s uint) (c Word) {
+	return shrVU_g(z, x, s)
+}
+
+func mulAddVWW(z, x []Word, y, r Word) (c Word) {
+	return mulAddVWW_g(z, x, y, r)
+}
+
+func addMulVVW(z, x []Word, y Word) (c Word) {
+	return addMulVVW_g(z, x, y)
+}
+
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
+	return divWVW_g(z, xn, x, y)
+}
+
+func bitLen(x Word) (n int) {
+	return bitLen_g(x)
+}
diff --git a/src/cmd/internal/gc/big/arith_test.go b/src/cmd/internal/gc/big/arith_test.go
new file mode 100644
index 0000000..cd92dd7
--- /dev/null
+++ b/src/cmd/internal/gc/big/arith_test.go
@@ -0,0 +1,456 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+	"math/rand"
+	"testing"
+)
+
+type funWW func(x, y, c Word) (z1, z0 Word)
+type argWW struct {
+	x, y, c, z1, z0 Word
+}
+
+var sumWW = []argWW{
+	{0, 0, 0, 0, 0},
+	{0, 1, 0, 0, 1},
+	{0, 0, 1, 0, 1},
+	{0, 1, 1, 0, 2},
+	{12345, 67890, 0, 0, 80235},
+	{12345, 67890, 1, 0, 80236},
+	{_M, 1, 0, 1, 0},
+	{_M, 0, 1, 1, 0},
+	{_M, 1, 1, 1, 1},
+	{_M, _M, 0, 1, _M - 1},
+	{_M, _M, 1, 1, _M},
+}
+
+func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
+	z1, z0 := f(a.x, a.y, a.c)
+	if z1 != a.z1 || z0 != a.z0 {
+		t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
+	}
+}
+
+func TestFunWW(t *testing.T) {
+	for _, a := range sumWW {
+		arg := a
+		testFunWW(t, "addWW_g", addWW_g, arg)
+
+		arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
+		testFunWW(t, "addWW_g symmetric", addWW_g, arg)
+
+		arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
+		testFunWW(t, "subWW_g", subWW_g, arg)
+
+		arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
+		testFunWW(t, "subWW_g symmetric", subWW_g, arg)
+	}
+}
+
+type funVV func(z, x, y []Word) (c Word)
+type argVV struct {
+	z, x, y nat
+	c       Word
+}
+
+var sumVV = []argVV{
+	{},
+	{nat{0}, nat{0}, nat{0}, 0},
+	{nat{1}, nat{1}, nat{0}, 0},
+	{nat{0}, nat{_M}, nat{1}, 1},
+	{nat{80235}, nat{12345}, nat{67890}, 0},
+	{nat{_M - 1}, nat{_M}, nat{_M}, 1},
+	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
+	{nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
+	{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
+}
+
+func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
+	z := make(nat, len(a.z))
+	c := f(z, a.x, a.y)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if c != a.c {
+		t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+	}
+}
+
+func TestFunVV(t *testing.T) {
+	for _, a := range sumVV {
+		arg := a
+		testFunVV(t, "addVV_g", addVV_g, arg)
+		testFunVV(t, "addVV", addVV, arg)
+
+		arg = argVV{a.z, a.y, a.x, a.c}
+		testFunVV(t, "addVV_g symmetric", addVV_g, arg)
+		testFunVV(t, "addVV symmetric", addVV, arg)
+
+		arg = argVV{a.x, a.z, a.y, a.c}
+		testFunVV(t, "subVV_g", subVV_g, arg)
+		testFunVV(t, "subVV", subVV, arg)
+
+		arg = argVV{a.y, a.z, a.x, a.c}
+		testFunVV(t, "subVV_g symmetric", subVV_g, arg)
+		testFunVV(t, "subVV symmetric", subVV, arg)
+	}
+}
+
+// Always the same seed for reproducible results.
+var rnd = rand.New(rand.NewSource(0))
+
+func rndW() Word {
+	return Word(rnd.Int63()<<1 | rnd.Int63n(2))
+}
+
+func rndV(n int) []Word {
+	v := make([]Word, n)
+	for i := range v {
+		v[i] = rndW()
+	}
+	return v
+}
+
+func benchmarkFunVV(b *testing.B, f funVV, n int) {
+	x := rndV(n)
+	y := rndV(n)
+	z := make([]Word, n)
+	b.SetBytes(int64(n * _W))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		f(z, x, y)
+	}
+}
+
+func BenchmarkAddVV_1(b *testing.B)   { benchmarkFunVV(b, addVV, 1) }
+func BenchmarkAddVV_2(b *testing.B)   { benchmarkFunVV(b, addVV, 2) }
+func BenchmarkAddVV_3(b *testing.B)   { benchmarkFunVV(b, addVV, 3) }
+func BenchmarkAddVV_4(b *testing.B)   { benchmarkFunVV(b, addVV, 4) }
+func BenchmarkAddVV_5(b *testing.B)   { benchmarkFunVV(b, addVV, 5) }
+func BenchmarkAddVV_1e1(b *testing.B) { benchmarkFunVV(b, addVV, 1e1) }
+func BenchmarkAddVV_1e2(b *testing.B) { benchmarkFunVV(b, addVV, 1e2) }
+func BenchmarkAddVV_1e3(b *testing.B) { benchmarkFunVV(b, addVV, 1e3) }
+func BenchmarkAddVV_1e4(b *testing.B) { benchmarkFunVV(b, addVV, 1e4) }
+func BenchmarkAddVV_1e5(b *testing.B) { benchmarkFunVV(b, addVV, 1e5) }
+
+type funVW func(z, x []Word, y Word) (c Word)
+type argVW struct {
+	z, x nat
+	y    Word
+	c    Word
+}
+
+var sumVW = []argVW{
+	{},
+	{nil, nil, 2, 2},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{1}, nat{0}, 1, 0},
+	{nat{1}, nat{1}, 0, 0},
+	{nat{0}, nat{_M}, 1, 1},
+	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+}
+
+var prodVW = []argVW{
+	{},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{0}, nat{_M}, 0, 0},
+	{nat{0}, nat{0}, _M, 0},
+	{nat{1}, nat{1}, 1, 0},
+	{nat{22793}, nat{991}, 23, 0},
+	{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
+	{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
+	{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
+	{nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
+	{nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
+	{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
+}
+
+var lshVW = []argVW{
+	{},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{0}, nat{0}, 1, 0},
+	{nat{0}, nat{0}, 20, 0},
+
+	{nat{_M}, nat{_M}, 0, 0},
+	{nat{_M << 1 & _M}, nat{_M}, 1, 1},
+	{nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
+
+	{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+	{nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
+	{nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
+}
+
+var rshVW = []argVW{
+	{},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{0}, nat{0}, 1, 0},
+	{nat{0}, nat{0}, 20, 0},
+
+	{nat{_M}, nat{_M}, 0, 0},
+	{nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
+	{nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
+
+	{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+	{nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
+	{nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
+}
+
+func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
+	z := make(nat, len(a.z))
+	c := f(z, a.x, a.y)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if c != a.c {
+		t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+	}
+}
+
+func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
+	return func(z, x []Word, s Word) (c Word) {
+		return f(z, x, uint(s))
+	}
+}
+
+func TestFunVW(t *testing.T) {
+	for _, a := range sumVW {
+		arg := a
+		testFunVW(t, "addVW_g", addVW_g, arg)
+		testFunVW(t, "addVW", addVW, arg)
+
+		arg = argVW{a.x, a.z, a.y, a.c}
+		testFunVW(t, "subVW_g", subVW_g, arg)
+		testFunVW(t, "subVW", subVW, arg)
+	}
+
+	shlVW_g := makeFunVW(shlVU_g)
+	shlVW := makeFunVW(shlVU)
+	for _, a := range lshVW {
+		arg := a
+		testFunVW(t, "shlVU_g", shlVW_g, arg)
+		testFunVW(t, "shlVU", shlVW, arg)
+	}
+
+	shrVW_g := makeFunVW(shrVU_g)
+	shrVW := makeFunVW(shrVU)
+	for _, a := range rshVW {
+		arg := a
+		testFunVW(t, "shrVU_g", shrVW_g, arg)
+		testFunVW(t, "shrVU", shrVW, arg)
+	}
+}
+
+func benchmarkFunVW(b *testing.B, f funVW, n int) {
+	x := rndV(n)
+	y := rndW()
+	z := make([]Word, n)
+	b.SetBytes(int64(n * _S))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		f(z, x, y)
+	}
+}
+
+func BenchmarkAddVW_1(b *testing.B)   { benchmarkFunVW(b, addVW, 1) }
+func BenchmarkAddVW_2(b *testing.B)   { benchmarkFunVW(b, addVW, 2) }
+func BenchmarkAddVW_3(b *testing.B)   { benchmarkFunVW(b, addVW, 3) }
+func BenchmarkAddVW_4(b *testing.B)   { benchmarkFunVW(b, addVW, 4) }
+func BenchmarkAddVW_5(b *testing.B)   { benchmarkFunVW(b, addVW, 5) }
+func BenchmarkAddVW_1e1(b *testing.B) { benchmarkFunVW(b, addVW, 1e1) }
+func BenchmarkAddVW_1e2(b *testing.B) { benchmarkFunVW(b, addVW, 1e2) }
+func BenchmarkAddVW_1e3(b *testing.B) { benchmarkFunVW(b, addVW, 1e3) }
+func BenchmarkAddVW_1e4(b *testing.B) { benchmarkFunVW(b, addVW, 1e4) }
+func BenchmarkAddVW_1e5(b *testing.B) { benchmarkFunVW(b, addVW, 1e5) }
+
+type funVWW func(z, x []Word, y, r Word) (c Word)
+type argVWW struct {
+	z, x nat
+	y, r Word
+	c    Word
+}
+
+var prodVWW = []argVWW{
+	{},
+	{nat{0}, nat{0}, 0, 0, 0},
+	{nat{991}, nat{0}, 0, 991, 0},
+	{nat{0}, nat{_M}, 0, 0, 0},
+	{nat{991}, nat{_M}, 0, 991, 0},
+	{nat{0}, nat{0}, _M, 0, 0},
+	{nat{991}, nat{0}, _M, 991, 0},
+	{nat{1}, nat{1}, 1, 0, 0},
+	{nat{992}, nat{1}, 1, 991, 0},
+	{nat{22793}, nat{991}, 23, 0, 0},
+	{nat{22800}, nat{991}, 23, 7, 0},
+	{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
+	{nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
+	{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+	{nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+	{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
+	{nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
+	{nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
+	{nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
+	{nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
+	{nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+	{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
+	{nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+}
+
+func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
+	z := make(nat, len(a.z))
+	c := f(z, a.x, a.y, a.r)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if c != a.c {
+		t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+	}
+}
+
+// TODO(gri) mulAddVWW and divWVW are symmetric operations but
+//           their signature is not symmetric. Try to unify.
+
+type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
+type argWVW struct {
+	z  nat
+	xn Word
+	x  nat
+	y  Word
+	r  Word
+}
+
+func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
+	z := make(nat, len(a.z))
+	r := f(z, a.xn, a.x, a.y)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if r != a.r {
+		t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
+	}
+}
+
+func TestFunVWW(t *testing.T) {
+	for _, a := range prodVWW {
+		arg := a
+		testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
+		testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
+
+		if a.y != 0 && a.r < a.y {
+			arg := argWVW{a.x, a.c, a.z, a.y, a.r}
+			testFunWVW(t, "divWVW_g", divWVW_g, arg)
+			testFunWVW(t, "divWVW", divWVW, arg)
+		}
+	}
+}
+
+var mulWWTests = []struct {
+	x, y Word
+	q, r Word
+}{
+	{_M, _M, _M - 1, 1},
+	// 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
+}
+
+func TestMulWW(t *testing.T) {
+	for i, test := range mulWWTests {
+		q, r := mulWW_g(test.x, test.y)
+		if q != test.q || r != test.r {
+			t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+		}
+	}
+}
+
+var mulAddWWWTests = []struct {
+	x, y, c Word
+	q, r    Word
+}{
+	// TODO(agl): These will only work on 64-bit platforms.
+	// {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
+	// {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
+	{_M, _M, 0, _M - 1, 1},
+	{_M, _M, _M, _M, 0},
+}
+
+func TestMulAddWWW(t *testing.T) {
+	for i, test := range mulAddWWWTests {
+		q, r := mulAddWWW_g(test.x, test.y, test.c)
+		if q != test.q || r != test.r {
+			t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+		}
+	}
+}
+
+func benchmarkAddMulVVW(b *testing.B, n int) {
+	x := rndV(n)
+	y := rndW()
+	z := make([]Word, n)
+	b.SetBytes(int64(n * _W))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		addMulVVW(z, x, y)
+	}
+}
+
+func BenchmarkAddMulVVW_1(b *testing.B)   { benchmarkAddMulVVW(b, 1) }
+func BenchmarkAddMulVVW_2(b *testing.B)   { benchmarkAddMulVVW(b, 2) }
+func BenchmarkAddMulVVW_3(b *testing.B)   { benchmarkAddMulVVW(b, 3) }
+func BenchmarkAddMulVVW_4(b *testing.B)   { benchmarkAddMulVVW(b, 4) }
+func BenchmarkAddMulVVW_5(b *testing.B)   { benchmarkAddMulVVW(b, 5) }
+func BenchmarkAddMulVVW_1e1(b *testing.B) { benchmarkAddMulVVW(b, 1e1) }
+func BenchmarkAddMulVVW_1e2(b *testing.B) { benchmarkAddMulVVW(b, 1e2) }
+func BenchmarkAddMulVVW_1e3(b *testing.B) { benchmarkAddMulVVW(b, 1e3) }
+func BenchmarkAddMulVVW_1e4(b *testing.B) { benchmarkAddMulVVW(b, 1e4) }
+func BenchmarkAddMulVVW_1e5(b *testing.B) { benchmarkAddMulVVW(b, 1e5) }
+
+func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
+	for i := 0; i <= _W; i++ {
+		x := Word(1) << uint(i-1) // i == 0 => x == 0
+		n := f(x)
+		if n != i {
+			t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
+		}
+	}
+}
+
+func TestWordBitLen(t *testing.T) {
+	testWordBitLen(t, "bitLen", bitLen)
+	testWordBitLen(t, "bitLen_g", bitLen_g)
+}
+
+// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
+func benchmarkBitLenN(b *testing.B, nbits uint) {
+	testword := Word((uint64(1) << nbits) - 1)
+	for i := 0; i < b.N; i++ {
+		bitLen(testword)
+	}
+}
+
+// Individual bitLen tests.  Numbers chosen to examine both sides
+// of powers-of-two boundaries.
+func BenchmarkBitLen0(b *testing.B)  { benchmarkBitLenN(b, 0) }
+func BenchmarkBitLen1(b *testing.B)  { benchmarkBitLenN(b, 1) }
+func BenchmarkBitLen2(b *testing.B)  { benchmarkBitLenN(b, 2) }
+func BenchmarkBitLen3(b *testing.B)  { benchmarkBitLenN(b, 3) }
+func BenchmarkBitLen4(b *testing.B)  { benchmarkBitLenN(b, 4) }
+func BenchmarkBitLen5(b *testing.B)  { benchmarkBitLenN(b, 5) }
+func BenchmarkBitLen8(b *testing.B)  { benchmarkBitLenN(b, 8) }
+func BenchmarkBitLen9(b *testing.B)  { benchmarkBitLenN(b, 9) }
+func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) }
+func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) }
+func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) }
diff --git a/src/cmd/internal/gc/big/bits_test.go b/src/cmd/internal/gc/big/bits_test.go
new file mode 100644
index 0000000..3ce2422
--- /dev/null
+++ b/src/cmd/internal/gc/big/bits_test.go
@@ -0,0 +1,224 @@
+// 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.
+
+// This file implements the Bits type used for testing Float operations
+// via an independent (albeit slower) representations for floating-point
+// numbers.
+
+package big
+
+import (
+	"fmt"
+	"sort"
+	"testing"
+)
+
+// A Bits value b represents a finite floating-point number x of the form
+//
+//	x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1]
+//
+// The order of slice elements is not significant. Negative elements may be
+// used to form fractions. A Bits value is normalized if each b[i] occurs at
+// most once. For instance Bits{0, 0, 1} is not normalized but represents the
+// same floating-point number as Bits{2}, which is normalized. The zero (nil)
+// value of Bits is a ready to use Bits value and represents the value 0.
+type Bits []int
+
+func (x Bits) add(y Bits) Bits {
+	return append(x, y...)
+}
+
+func (x Bits) mul(y Bits) Bits {
+	var p Bits
+	for _, x := range x {
+		for _, y := range y {
+			p = append(p, x+y)
+		}
+	}
+	return p
+}
+
+func TestMulBits(t *testing.T) {
+	for _, test := range []struct {
+		x, y, want Bits
+	}{
+		{nil, nil, nil},
+		{Bits{}, Bits{}, nil},
+		{Bits{0}, Bits{0}, Bits{0}},
+		{Bits{0}, Bits{1}, Bits{1}},
+		{Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}},
+		{Bits{-1}, Bits{1}, Bits{0}},
+		{Bits{-10, -1, 0, 1, 10}, Bits{1, 2, 3}, Bits{-9, -8, -7, 0, 1, 2, 1, 2, 3, 2, 3, 4, 11, 12, 13}},
+	} {
+		got := fmt.Sprintf("%v", test.x.mul(test.y))
+		want := fmt.Sprintf("%v", test.want)
+		if got != want {
+			t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want)
+		}
+
+	}
+}
+
+// norm returns the normalized bits for x: It removes multiple equal entries
+// by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts
+// the result list for reproducible results.
+func (x Bits) norm() Bits {
+	m := make(map[int]bool)
+	for _, b := range x {
+		for m[b] {
+			m[b] = false
+			b++
+		}
+		m[b] = true
+	}
+	var z Bits
+	for b, set := range m {
+		if set {
+			z = append(z, b)
+		}
+	}
+	sort.Ints([]int(z))
+	return z
+}
+
+func TestNormBits(t *testing.T) {
+	for _, test := range []struct {
+		x, want Bits
+	}{
+		{nil, nil},
+		{Bits{}, Bits{}},
+		{Bits{0}, Bits{0}},
+		{Bits{0, 0}, Bits{1}},
+		{Bits{3, 1, 1}, Bits{2, 3}},
+		{Bits{10, 9, 8, 7, 6, 6}, Bits{11}},
+	} {
+		got := fmt.Sprintf("%v", test.x.norm())
+		want := fmt.Sprintf("%v", test.want)
+		if got != want {
+			t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
+		}
+
+	}
+}
+
+// round returns the Float value corresponding to x after rounding x
+// to prec bits according to mode.
+func (x Bits) round(prec uint, mode RoundingMode) *Float {
+	x = x.norm()
+
+	// determine range
+	var min, max int
+	for i, b := range x {
+		if i == 0 || b < min {
+			min = b
+		}
+		if i == 0 || b > max {
+			max = b
+		}
+	}
+	prec0 := uint(max + 1 - min)
+	if prec >= prec0 {
+		return x.Float()
+	}
+	// prec < prec0
+
+	// determine bit 0, rounding, and sticky bit, and result bits z
+	var bit0, rbit, sbit uint
+	var z Bits
+	r := max - int(prec)
+	for _, b := range x {
+		switch {
+		case b == r:
+			rbit = 1
+		case b < r:
+			sbit = 1
+		default:
+			// b > r
+			if b == r+1 {
+				bit0 = 1
+			}
+			z = append(z, b)
+		}
+	}
+
+	// round
+	f := z.Float() // rounded to zero
+	if mode == ToNearestAway {
+		panic("not yet implemented")
+	}
+	if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
+		// round away from zero
+		f.SetMode(ToZero).SetPrec(prec)
+		f.Add(f, Bits{int(r) + 1}.Float())
+	}
+	return f
+}
+
+// Float returns the *Float z of the smallest possible precision such that
+// z = sum(2**bits[i]), with i = range bits. If multiple bits[i] are equal,
+// they are added: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4.
+func (bits Bits) Float() *Float {
+	// handle 0
+	if len(bits) == 0 {
+		return new(Float)
+	}
+	// len(bits) > 0
+
+	// determine lsb exponent
+	var min int
+	for i, b := range bits {
+		if i == 0 || b < min {
+			min = b
+		}
+	}
+
+	// create bit pattern
+	x := NewInt(0)
+	for _, b := range bits {
+		badj := b - min
+		// propagate carry if necessary
+		for x.Bit(badj) != 0 {
+			x.SetBit(x, badj, 0)
+			badj++
+		}
+		x.SetBit(x, badj, 1)
+	}
+
+	// create corresponding float
+	z := new(Float).SetInt(x) // normalized
+	if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp {
+		z.exp = int32(e)
+	} else {
+		// this should never happen for our test cases
+		panic("exponent out of range")
+	}
+	return z
+}
+
+func TestFromBits(t *testing.T) {
+	for _, test := range []struct {
+		bits Bits
+		want string
+	}{
+		// 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"},
+
+		// 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 */},
+	} {
+		f := test.bits.Float()
+		if got := f.Format('p', 0); got != test.want {
+			t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/calibrate_test.go b/src/cmd/internal/gc/big/calibrate_test.go
new file mode 100644
index 0000000..f69ffbf
--- /dev/null
+++ b/src/cmd/internal/gc/big/calibrate_test.go
@@ -0,0 +1,88 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file prints execution times for the Mul benchmark
+// given different Karatsuba thresholds. The result may be
+// used to manually fine-tune the threshold constant. The
+// results are somewhat fragile; use repeated runs to get
+// a clear picture.
+
+// Usage: go test -run=TestCalibrate -calibrate
+
+package big
+
+import (
+	"flag"
+	"fmt"
+	"testing"
+	"time"
+)
+
+var calibrate = flag.Bool("calibrate", false, "run calibration test")
+
+func karatsubaLoad(b *testing.B) {
+	BenchmarkMul(b)
+}
+
+// measureKaratsuba returns the time to run a Karatsuba-relevant benchmark
+// given Karatsuba threshold th.
+func measureKaratsuba(th int) time.Duration {
+	th, karatsubaThreshold = karatsubaThreshold, th
+	res := testing.Benchmark(karatsubaLoad)
+	karatsubaThreshold = th
+	return time.Duration(res.NsPerOp())
+}
+
+func computeThresholds() {
+	fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
+	fmt.Printf("(run repeatedly for good results)\n")
+
+	// determine Tk, the work load execution time using basic multiplication
+	Tb := measureKaratsuba(1e9) // th == 1e9 => Karatsuba multiplication disabled
+	fmt.Printf("Tb = %10s\n", Tb)
+
+	// thresholds
+	th := 4
+	th1 := -1
+	th2 := -1
+
+	var deltaOld time.Duration
+	for count := -1; count != 0 && th < 128; count-- {
+		// determine Tk, the work load execution time using Karatsuba multiplication
+		Tk := measureKaratsuba(th)
+
+		// improvement over Tb
+		delta := (Tb - Tk) * 100 / Tb
+
+		fmt.Printf("th = %3d  Tk = %10s  %4d%%", th, Tk, delta)
+
+		// determine break-even point
+		if Tk < Tb && th1 < 0 {
+			th1 = th
+			fmt.Print("  break-even point")
+		}
+
+		// determine diminishing return
+		if 0 < delta && delta < deltaOld && th2 < 0 {
+			th2 = th
+			fmt.Print("  diminishing return")
+		}
+		deltaOld = delta
+
+		fmt.Println()
+
+		// trigger counter
+		if th1 >= 0 && th2 >= 0 && count < 0 {
+			count = 10 // this many extra measurements after we got both thresholds
+		}
+
+		th++
+	}
+}
+
+func TestCalibrate(t *testing.T) {
+	if *calibrate {
+		computeThresholds()
+	}
+}
diff --git a/src/cmd/internal/gc/big/decimal.go b/src/cmd/internal/gc/big/decimal.go
new file mode 100644
index 0000000..3d024dc
--- /dev/null
+++ b/src/cmd/internal/gc/big/decimal.go
@@ -0,0 +1,258 @@
+// 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.
+
+// This file implements multi-precision decimal numbers.
+// The implementation is for float to decimal conversion only;
+// not general purpose use.
+// The only operations are precise conversion from binary to
+// decimal and rounding.
+//
+// The key observation and some code (shr) is borrowed from
+// strconv/decimal.go: conversion of binary fractional values can be done
+// precisely in multi-precision decimal because 2 divides 10 (required for
+// >> of mantissa); but conversion of decimal floating-point values cannot
+// be done precisely in binary representation.
+//
+// In contrast to strconv/decimal.go, only right shift is implemented in
+// decimal format - left shift can be done precisely in binary format.
+
+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.
+type decimal struct {
+	mant []byte // mantissa ASCII digits, big-endian
+	exp  int    // exponent, valid if len(mant) > 0
+}
+
+// Maximum shift amount that can be done in one pass without overflow.
+// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
+const maxShift = _W - 4
+
+// TODO(gri) Since we know the desired decimal precision when converting
+// a floating-point number, we may be able to limit the number of decimal
+// digits that need to be computed by init by providing an additional
+// precision argument and keeping track of when a number was truncated early
+// (equivalent of "sticky bit" in binary rounding).
+
+// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
+// to avoid "infinitely" long running conversions (until we run out of space).
+
+// Init initializes x to the decimal representation of m << shift (for
+// shift >= 0), or m >> -shift (for shift < 0).
+func (x *decimal) init(m nat, shift int) {
+	// special case 0
+	if len(m) == 0 {
+		x.mant = x.mant[:0]
+		return
+	}
+
+	// Optimization: If we need to shift right, first remove any trailing
+	// zero bits from m to reduce shift amount that needs to be done in
+	// decimal format (since that is likely slower).
+	if shift < 0 {
+		ntz := m.trailingZeroBits()
+		s := uint(-shift)
+		if s >= ntz {
+			s = ntz // shift at most ntz bits
+		}
+		m = nat(nil).shr(m, s)
+		shift += int(s)
+	}
+
+	// Do any shift left in binary representation.
+	if shift > 0 {
+		m = nat(nil).shl(m, uint(shift))
+		shift = 0
+	}
+
+	// Convert mantissa into decimal representation.
+	s := m.decimalString() // TODO(gri) avoid string conversion here
+	n := len(s)
+	x.exp = n
+	// Trim trailing zeros; instead the exponent is tracking
+	// the decimal point independent of the number of digits.
+	for n > 0 && s[n-1] == '0' {
+		n--
+	}
+	x.mant = append(x.mant[:0], s[:n]...)
+
+	// Do any (remaining) shift right in decimal representation.
+	if shift < 0 {
+		for shift < -maxShift {
+			shr(x, maxShift)
+			shift += maxShift
+		}
+		shr(x, uint(-shift))
+	}
+}
+
+// Possibly optimization: The current implementation of nat.string takes
+// a charset argument. When a right shift is needed, we could provide
+// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
+// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
+// single +'0' pass at the end).
+
+// shr implements x >> s, for s <= maxShift.
+func shr(x *decimal, s uint) {
+	// Division by 1<<s using shift-and-subtract algorithm.
+
+	// pick up enough leading digits to cover first shift
+	r := 0 // read index
+	var n Word
+	for n>>s == 0 && r < len(x.mant) {
+		ch := Word(x.mant[r])
+		r++
+		n = n*10 + ch - '0'
+	}
+	if n == 0 {
+		// x == 0; shouldn't get here, but handle anyway
+		x.mant = x.mant[:0]
+		return
+	}
+	for n>>s == 0 {
+		r++
+		n *= 10
+	}
+	x.exp += 1 - r
+
+	// read a digit, write a digit
+	w := 0 // write index
+	for r < len(x.mant) {
+		ch := Word(x.mant[r])
+		r++
+		d := n >> s
+		n -= d << s
+		x.mant[w] = byte(d + '0')
+		w++
+		n = n*10 + ch - '0'
+	}
+
+	// write extra digits that still fit
+	for n > 0 && w < len(x.mant) {
+		d := n >> s
+		n -= d << s
+		x.mant[w] = byte(d + '0')
+		w++
+		n = n * 10
+	}
+	x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
+
+	// append additional digits that didn't fit
+	for n > 0 {
+		d := n >> s
+		n -= d << s
+		x.mant = append(x.mant, byte(d+'0'))
+		n = n * 10
+	}
+
+	trim(x)
+}
+
+func (x *decimal) String() string {
+	if len(x.mant) == 0 {
+		return "0"
+	}
+
+	var buf []byte
+	switch {
+	case x.exp <= 0:
+		// 0.00ddd
+		buf = append(buf, "0."...)
+		buf = appendZeros(buf, -x.exp)
+		buf = append(buf, x.mant...)
+
+	case /* 0 < */ x.exp < len(x.mant):
+		// dd.ddd
+		buf = append(buf, x.mant[:x.exp]...)
+		buf = append(buf, '.')
+		buf = append(buf, x.mant[x.exp:]...)
+
+	default: // len(x.mant) <= x.exp
+		// ddd00
+		buf = append(buf, x.mant...)
+		buf = appendZeros(buf, x.exp-len(x.mant))
+	}
+
+	return string(buf)
+}
+
+// appendZeros appends n 0 digits to buf and returns buf.
+func appendZeros(buf []byte, n int) []byte {
+	for ; n > 0; n-- {
+		buf = append(buf, '0')
+	}
+	return buf
+}
+
+// shouldRoundUp reports if x should be rounded up
+// if shortened to n digits. n must be a valid index
+// for x.mant.
+func shouldRoundUp(x *decimal, n int) bool {
+	if x.mant[n] == '5' && n+1 == len(x.mant) {
+		// exactly halfway - round to even
+		return n > 0 && (x.mant[n-1]-'0')&1 != 0
+	}
+	// not halfway - digit tells all (x.mant has no trailing zeros)
+	return x.mant[n] >= '5'
+}
+
+// round sets x to (at most) n mantissa digits by rounding it
+// to the nearest even value with n (or fever) mantissa digits.
+// If n < 0, x remains unchanged.
+func (x *decimal) round(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+
+	if shouldRoundUp(x, n) {
+		x.roundUp(n)
+	} else {
+		x.roundDown(n)
+	}
+}
+
+func (x *decimal) roundUp(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+	// 0 <= n < len(x.mant)
+
+	// find first digit < '9'
+	for n > 0 && x.mant[n-1] >= '9' {
+		n--
+	}
+
+	if n == 0 {
+		// all digits are '9's => round up to '1' and update exponent
+		x.mant[0] = '1' // ok since len(x.mant) > n
+		x.mant = x.mant[:1]
+		x.exp++
+		return
+	}
+
+	// n > 0 && x.mant[n-1] < '9'
+	x.mant[n-1]++
+	x.mant = x.mant[:n]
+	// x already trimmed
+}
+
+func (x *decimal) roundDown(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+	x.mant = x.mant[:n]
+	trim(x)
+}
+
+// trim cuts off any trailing zeros from x's mantissa;
+// they are meaningless for the value of x.
+func trim(x *decimal) {
+	i := len(x.mant)
+	for i > 0 && x.mant[i-1] == '0' {
+		i--
+	}
+	x.mant = x.mant[:i]
+}
diff --git a/src/cmd/internal/gc/big/decimal_test.go b/src/cmd/internal/gc/big/decimal_test.go
new file mode 100644
index 0000000..81e022a
--- /dev/null
+++ b/src/cmd/internal/gc/big/decimal_test.go
@@ -0,0 +1,106 @@
+// 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 big
+
+import "testing"
+
+func TestDecimalString(t *testing.T) {
+	for _, test := range []struct {
+		x    decimal
+		want string
+	}{
+		{want: "0"},
+		{decimal{nil, 1000}, "0"}, // exponent of 0 is ignored
+		{decimal{[]byte("12345"), 0}, "0.12345"},
+		{decimal{[]byte("12345"), -3}, "0.00012345"},
+		{decimal{[]byte("12345"), +3}, "123.45"},
+		{decimal{[]byte("12345"), +10}, "1234500000"},
+	} {
+		if got := test.x.String(); got != test.want {
+			t.Errorf("%v == %s; want %s", test.x, got, test.want)
+		}
+	}
+}
+
+func TestDecimalInit(t *testing.T) {
+	for _, test := range []struct {
+		x     Word
+		shift int
+		want  string
+	}{
+		{0, 0, "0"},
+		{0, -100, "0"},
+		{0, 100, "0"},
+		{1, 0, "1"},
+		{1, 10, "1024"},
+		{1, 100, "1267650600228229401496703205376"},
+		{1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"},
+		{12345678, 8, "3160493568"},
+		{12345678, -8, "48225.3046875"},
+		{195312, 9, "99999744"},
+		{1953125, 9, "1000000000"},
+	} {
+		var d decimal
+		d.init(nat{test.x}.norm(), test.shift)
+		if got := d.String(); got != test.want {
+			t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want)
+		}
+	}
+}
+
+func TestDecimalRounding(t *testing.T) {
+	for _, test := range []struct {
+		x              uint64
+		n              int
+		down, even, up string
+	}{
+		{0, 0, "0", "0", "0"},
+		{0, 1, "0", "0", "0"},
+
+		{1, 0, "0", "0", "10"},
+		{5, 0, "0", "0", "10"},
+		{9, 0, "0", "10", "10"},
+
+		{15, 1, "10", "20", "20"},
+		{45, 1, "40", "40", "50"},
+		{95, 1, "90", "100", "100"},
+
+		{12344999, 4, "12340000", "12340000", "12350000"},
+		{12345000, 4, "12340000", "12340000", "12350000"},
+		{12345001, 4, "12340000", "12350000", "12350000"},
+		{23454999, 4, "23450000", "23450000", "23460000"},
+		{23455000, 4, "23450000", "23460000", "23460000"},
+		{23455001, 4, "23450000", "23460000", "23460000"},
+
+		{99994999, 4, "99990000", "99990000", "100000000"},
+		{99995000, 4, "99990000", "100000000", "100000000"},
+		{99999999, 4, "99990000", "100000000", "100000000"},
+
+		{12994999, 4, "12990000", "12990000", "13000000"},
+		{12995000, 4, "12990000", "13000000", "13000000"},
+		{12999999, 4, "12990000", "13000000", "13000000"},
+	} {
+		x := nat(nil).setUint64(test.x)
+
+		var d decimal
+		d.init(x, 0)
+		d.roundDown(test.n)
+		if got := d.String(); got != test.down {
+			t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down)
+		}
+
+		d.init(x, 0)
+		d.round(test.n)
+		if got := d.String(); got != test.even {
+			t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even)
+		}
+
+		d.init(x, 0)
+		d.roundUp(test.n)
+		if got := d.String(); got != test.up {
+			t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up)
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/example_test.go b/src/cmd/internal/gc/big/example_test.go
new file mode 100644
index 0000000..078be47
--- /dev/null
+++ b/src/cmd/internal/gc/big/example_test.go
@@ -0,0 +1,51 @@
+// Copyright 2012 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 big_test
+
+import (
+	"fmt"
+	"log"
+	"math/big"
+)
+
+func ExampleRat_SetString() {
+	r := new(big.Rat)
+	r.SetString("355/113")
+	fmt.Println(r.FloatString(3))
+	// Output: 3.142
+}
+
+func ExampleInt_SetString() {
+	i := new(big.Int)
+	i.SetString("644", 8) // octal
+	fmt.Println(i)
+	// Output: 420
+}
+
+func ExampleRat_Scan() {
+	// The Scan function is rarely used directly;
+	// the fmt package recognizes it as an implementation of fmt.Scanner.
+	r := new(big.Rat)
+	_, err := fmt.Sscan("1.5000", r)
+	if err != nil {
+		log.Println("error scanning value:", err)
+	} else {
+		fmt.Println(r)
+	}
+	// Output: 3/2
+}
+
+func ExampleInt_Scan() {
+	// The Scan function is rarely used directly;
+	// the fmt package recognizes it as an implementation of fmt.Scanner.
+	i := new(big.Int)
+	_, err := fmt.Sscan("18446744073709551617", i)
+	if err != nil {
+		log.Println("error scanning value:", err)
+	} else {
+		fmt.Println(i)
+	}
+	// Output: 18446744073709551617
+}
diff --git a/src/cmd/internal/gc/big/float.go b/src/cmd/internal/gc/big/float.go
new file mode 100644
index 0000000..ed55e8e
--- /dev/null
+++ b/src/cmd/internal/gc/big/float.go
@@ -0,0 +1,1681 @@
+// 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.
+
+// This file implements multi-precision floating-point numbers.
+// Like in the GNU MPFR library (http://www.mpfr.org/), operands
+// can be of mixed precision. Unlike MPFR, the rounding mode is
+// not specified with each operation, but with each operand. The
+// rounding mode of the result operand determines the rounding
+// mode of an operation. This is a from-scratch implementation.
+
+package big
+
+import (
+	"fmt"
+	"math"
+)
+
+const debugFloat = true // enable for debugging
+
+// A nonzero finite Float represents a multi-precision floating point number
+//
+//   sign × mantissa × 2**exponent
+//
+// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp.
+// A Float may also be zero (+0, -0) or infinite (+Inf, -Inf).
+// All Floats are ordered, and the ordering of two Floats x and y
+// is defined by x.Cmp(y).
+//
+// Each Float value also has a precision, rounding mode, and accuracy.
+// The precision is the maximum number of mantissa bits available to
+// represent the value. The rounding mode specifies how a result should
+// be rounded to fit into the mantissa bits, and accuracy describes the
+// rounding error with respect to the exact result.
+//
+// Unless specified otherwise, all operations (including setters) that
+// specify a *Float variable for the result (usually via the receiver
+// with the exception of MantExp), round the numeric result according
+// to the precision and rounding mode of the result variable.
+//
+// If the provided result precision is 0 (see below), it is set to the
+// precision of the argument with the largest precision value before any
+// rounding takes place, and the rounding mode remains unchanged. Thus,
+// uninitialized Floats provided as result arguments will have their
+// precision set to a reasonable value determined by the operands and
+// their mode is the zero value for RoundingMode (ToNearestEven).
+//
+// By setting the desired precision to 24 or 53 and using matching rounding
+// mode (typically ToNearestEven), Float operations produce the same results
+// as the corresponding float32 or float64 IEEE-754 arithmetic for operands
+// that correspond to normal (i.e., not denormal) float32 or float64 numbers.
+// Exponent underflow and overflow lead to a 0 or an Infinity for different
+// values than IEEE-754 because Float exponents have a much larger range.
+//
+// The zero (uninitialized) value for a Float is ready to use and represents
+// the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven.
+//
+type Float struct {
+	prec uint32
+	mode RoundingMode
+	acc  Accuracy
+	form form
+	neg  bool
+	mant nat
+	exp  int32
+}
+
+// Float operations that would lead to a NaN under IEEE-754 rules cause
+// a run-time panic of ErrNaN type.
+type ErrNaN struct {
+	msg string
+}
+
+// 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.
+func NewFloat(x float64) *Float {
+	if math.IsNaN(x) {
+		panic(ErrNaN{"NewFloat(NaN)"})
+	}
+	return new(Float).SetFloat64(x)
+}
+
+// Exponent and precision limits.
+const (
+	MaxExp  = math.MaxInt32  // largest supported exponent
+	MinExp  = math.MinInt32  // smallest supported exponent
+	MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
+)
+
+// Internal representation: The mantissa bits x.mant of a nonzero finite
+// Float x are stored in a nat slice long enough to hold up to x.prec bits;
+// the slice may (but doesn't have to) be shorter if the mantissa contains
+// trailing 0 bits. x.mant is normalized if the msb of x.mant == 1 (i.e.,
+// the msb is shifted all the way "to the left"). Thus, if the mantissa has
+// trailing 0 bits or x.prec is not a multiple of the the Word size _W,
+// x.mant[0] has trailing zero bits. The msb of the mantissa corresponds
+// to the value 0.5; the exponent x.exp shifts the binary point as needed.
+//
+// A zero or non-finite Float x ignores x.mant and x.exp.
+//
+// x                 form      neg      mant         exp
+// ----------------------------------------------------------
+// ±0                zero      sign     -            -
+// 0 < |x| < +Inf    finite    sign     mantissa     exponent
+// ±Inf              inf       sign     -            -
+
+// A form value describes the internal representation.
+type form byte
+
+// The form value order is relevant - do not change!
+const (
+	zero form = iota
+	finite
+	inf
+)
+
+// RoundingMode determines how a Float value is rounded to the
+// desired precision. Rounding may change the Float value; the
+// rounding error is described by the Float's Accuracy.
+type RoundingMode byte
+
+// The following rounding modes are supported.
+const (
+	ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
+	ToNearestAway                     // == IEEE 754-2008 roundTiesToAway
+	ToZero                            // == IEEE 754-2008 roundTowardZero
+	AwayFromZero                      // no IEEE 754-2008 equivalent
+	ToNegativeInf                     // == IEEE 754-2008 roundTowardNegative
+	ToPositiveInf                     // == IEEE 754-2008 roundTowardPositive
+)
+
+//go:generate stringer -type=RoundingMode
+
+// Accuracy describes the rounding error produced by the most recent
+// operation that generated a Float value, relative to the exact value.
+type Accuracy int8
+
+// Constants describing the Accuracy of a Float.
+const (
+	Below Accuracy = -1
+	Exact Accuracy = 0
+	Above Accuracy = +1
+)
+
+//go:generate stringer -type=Accuracy
+
+// SetPrec sets z's precision to prec and returns the (possibly) rounded
+// value of z. Rounding occurs according to z's rounding mode if the mantissa
+// cannot be represented in prec bits without loss of precision.
+// SetPrec(0) maps all finite values to ±0; infinite values remain unchanged.
+// If prec > MaxPrec, it is set to MaxPrec.
+func (z *Float) SetPrec(prec uint) *Float {
+	z.acc = Exact // optimistically assume no rounding is needed
+
+	// special case
+	if prec == 0 {
+		z.prec = 0
+		if z.form == finite {
+			// truncate z to 0
+			z.acc = makeAcc(z.neg)
+			z.form = zero
+		}
+		return z
+	}
+
+	// general case
+	if prec > MaxPrec {
+		prec = MaxPrec
+	}
+	old := z.prec
+	z.prec = uint32(prec)
+	if z.prec < old {
+		z.round(0)
+	}
+	return z
+}
+
+func makeAcc(above bool) Accuracy {
+	if above {
+		return Above
+	}
+	return Below
+}
+
+// SetMode sets z's rounding mode to mode and returns an exact z.
+// z remains unchanged otherwise.
+// z.SetMode(z.Mode()) is a cheap way to set z's accuracy to Exact.
+func (z *Float) SetMode(mode RoundingMode) *Float {
+	z.mode = mode
+	z.acc = Exact
+	return z
+}
+
+// Prec returns the mantissa precision of x in bits.
+// The result may be 0 for |x| == 0 and |x| == Inf.
+func (x *Float) Prec() uint {
+	return uint(x.prec)
+}
+
+// MinPrec returns the minimum precision required to represent x exactly
+// (i.e., the smallest prec before x.SetPrec(prec) would start rounding x).
+// The result is 0 for |x| == 0 and |x| == Inf.
+func (x *Float) MinPrec() uint {
+	if x.form != finite {
+		return 0
+	}
+	return uint(len(x.mant))*_W - x.mant.trailingZeroBits()
+}
+
+// Mode returns the rounding mode of x.
+func (x *Float) Mode() RoundingMode {
+	return x.mode
+}
+
+// Acc returns the accuracy of x produced by the most recent operation.
+func (x *Float) Acc() Accuracy {
+	return x.acc
+}
+
+// Sign returns:
+//
+//	-1 if x <   0
+//	 0 if x is ±0
+//	+1 if x >   0
+//
+func (x *Float) Sign() int {
+	if debugFloat {
+		x.validate()
+	}
+	if x.form == zero {
+		return 0
+	}
+	if x.neg {
+		return -1
+	}
+	return 1
+}
+
+// MantExp breaks x into its mantissa and exponent components
+// and returns the exponent. If a non-nil mant argument is
+// provided its value is set to the mantissa of x, with the
+// same precision and rounding mode as x. The components
+// satisfy x == mant × 2**exp, with 0.5 <= |mant| < 1.0.
+// Calling MantExp with a nil argument is an efficient way to
+// get the exponent of the receiver.
+//
+// Special cases are:
+//
+//	(  ±0).MantExp(mant) = 0, with mant set to   ±0
+//	(±Inf).MantExp(mant) = 0, with mant set to ±Inf
+//
+// x and mant may be the same in which case x is set to its
+// mantissa value.
+func (x *Float) MantExp(mant *Float) (exp int) {
+	if debugFloat {
+		x.validate()
+	}
+	if x.form == finite {
+		exp = int(x.exp)
+	}
+	if mant != nil {
+		mant.Copy(x)
+		if mant.form == finite {
+			mant.exp = 0
+		}
+	}
+	return
+}
+
+func (z *Float) setExpAndRound(exp int64, sbit uint) {
+	if exp < MinExp {
+		// underflow
+		z.acc = makeAcc(z.neg)
+		z.form = zero
+		return
+	}
+
+	if exp > MaxExp {
+		// overflow
+		z.acc = makeAcc(!z.neg)
+		z.form = inf
+		return
+	}
+
+	z.form = finite
+	z.exp = int32(exp)
+	z.round(sbit)
+}
+
+// SetMantExp sets z to mant × 2**exp and and returns z.
+// The result z has the same precision and rounding mode
+// as mant. SetMantExp is an inverse of MantExp but does
+// not require 0.5 <= |mant| < 1.0. Specifically:
+//
+//	mant := new(Float)
+//	new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true
+//
+// Special cases are:
+//
+//	z.SetMantExp(  ±0, exp) =   ±0
+//	z.SetMantExp(±Inf, exp) = ±Inf
+//
+// z and mant may be the same in which case z's exponent
+// is set to exp.
+func (z *Float) SetMantExp(mant *Float, exp int) *Float {
+	if debugFloat {
+		z.validate()
+		mant.validate()
+	}
+	z.Copy(mant)
+	if z.form != finite {
+		return z
+	}
+	z.setExpAndRound(int64(z.exp)+int64(exp), 0)
+	return z
+}
+
+// Signbit returns true if x is negative or negative zero.
+func (x *Float) Signbit() bool {
+	return x.neg
+}
+
+// IsInf reports whether x is +Inf or -Inf.
+func (x *Float) IsInf() bool {
+	return x.form == inf
+}
+
+// IsInt reports whether x is an integer.
+// ±Inf values are not integers.
+func (x *Float) IsInt() bool {
+	if debugFloat {
+		x.validate()
+	}
+	// special cases
+	if x.form != finite {
+		return x.form == zero
+	}
+	// x.form == finite
+	if x.exp <= 0 {
+		return false
+	}
+	// x.exp > 0
+	return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa
+}
+
+// debugging support
+func (x *Float) validate() {
+	if !debugFloat {
+		// avoid performance bugs
+		panic("validate called but debugFloat is not set")
+	}
+	if x.form != finite {
+		return
+	}
+	m := len(x.mant)
+	if m == 0 {
+		panic("nonzero finite number with empty mantissa")
+	}
+	const msb = 1 << (_W - 1)
+	if x.mant[m-1]&msb == 0 {
+		panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
+	}
+	if x.prec == 0 {
+		panic("zero precision finite number")
+	}
+}
+
+// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly.
+// sbit must be 0 or 1 and summarizes any "sticky bit" information one might
+// have before calling round. z's mantissa must be normalized (with the msb set)
+// or empty.
+//
+// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the
+// sign of z. For correct rounding, the sign of z must be set correctly before
+// calling round.
+func (z *Float) round(sbit uint) {
+	if debugFloat {
+		z.validate()
+		if z.form > finite {
+			panic(fmt.Sprintf("round called for non-finite value %s", z))
+		}
+	}
+	// z.form <= finite
+
+	z.acc = Exact
+	if z.form == zero {
+		return
+	}
+	// z.form == finite && len(z.mant) > 0
+	// m > 0 implies z.prec > 0 (checked by validate)
+
+	m := uint32(len(z.mant)) // present mantissa length in words
+	bits := m * _W           // present mantissa bits
+	if bits <= z.prec {
+		// mantissa fits => nothing to do
+		return
+	}
+	// bits > z.prec
+
+	n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
+
+	// Rounding is based on two bits: the rounding bit (rbit) and the
+	// sticky bit (sbit). The rbit is the bit immediately before the
+	// z.prec leading mantissa bits (the "0.5"). The sbit is set if any
+	// of the bits before the rbit are set (the "0.25", "0.125", etc.):
+	//
+	//   rbit  sbit  => "fractional part"
+	//
+	//   0     0        == 0
+	//   0     1        >  0  , < 0.5
+	//   1     0        == 0.5
+	//   1     1        >  0.5, < 1.0
+
+	// bits > z.prec: mantissa too large => round
+	r := uint(bits - z.prec - 1) // rounding bit position; r >= 0
+	rbit := z.mant.bit(r)        // rounding bit
+	if sbit == 0 {
+		sbit = z.mant.sticky(r)
+	}
+	if debugFloat && sbit&^1 != 0 {
+		panic(fmt.Sprintf("invalid sbit %#x", sbit))
+	}
+
+	// convert ToXInf rounding modes
+	mode := z.mode
+	switch mode {
+	case ToNegativeInf:
+		mode = ToZero
+		if z.neg {
+			mode = AwayFromZero
+		}
+	case ToPositiveInf:
+		mode = AwayFromZero
+		if z.neg {
+			mode = ToZero
+		}
+	}
+
+	// cut off extra words
+	if m > n {
+		copy(z.mant, z.mant[m-n:]) // move n last words to front
+		z.mant = z.mant[:n]
+	}
+
+	// determine number of trailing zero bits t
+	t := n*_W - z.prec // 0 <= t < _W
+	lsb := Word(1) << t
+
+	// make rounding decision
+	// TODO(gri) This can be simplified (see Bits.round in bits_test.go).
+	switch mode {
+	case ToZero:
+		// nothing to do
+	case ToNearestEven, ToNearestAway:
+		if rbit == 0 {
+			// rounding bits == 0b0x
+			mode = ToZero
+		} else if sbit == 1 {
+			// rounding bits == 0b11
+			mode = AwayFromZero
+		}
+	case AwayFromZero:
+		if rbit|sbit == 0 {
+			mode = ToZero
+		}
+	default:
+		// ToXInf modes have been converted to ToZero or AwayFromZero
+		panic("unreachable")
+	}
+
+	// round and determine accuracy
+	switch mode {
+	case ToZero:
+		if rbit|sbit != 0 {
+			z.acc = Below
+		}
+
+	case ToNearestEven, ToNearestAway:
+		if debugFloat && rbit != 1 {
+			panic("internal error in rounding")
+		}
+		if mode == ToNearestEven && sbit == 0 && z.mant[0]&lsb == 0 {
+			z.acc = Below
+			break
+		}
+		// mode == ToNearestAway || sbit == 1 || z.mant[0]&lsb != 0
+		fallthrough
+
+	case AwayFromZero:
+		// add 1 to mantissa
+		if addVW(z.mant, z.mant, lsb) != 0 {
+			// overflow => shift mantissa right by 1 and add msb
+			shrVU(z.mant, z.mant, 1)
+			z.mant[n-1] |= 1 << (_W - 1)
+			// adjust exponent
+			if z.exp < MaxExp {
+				z.exp++
+			} else {
+				// exponent overflow
+				z.acc = makeAcc(!z.neg)
+				z.form = inf
+				return
+			}
+		}
+		z.acc = Above
+	}
+
+	// zero out trailing bits in least-significant word
+	z.mant[0] &^= lsb - 1
+
+	// update accuracy
+	if z.acc != Exact && z.neg {
+		z.acc = -z.acc
+	}
+
+	if debugFloat {
+		z.validate()
+	}
+
+	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
+	}
+	z.acc = Exact
+	z.neg = neg
+	if x == 0 {
+		z.form = zero
+		return z
+	}
+	// x != 0
+	z.form = finite
+	s := nlz64(x)
+	z.mant = z.mant.setUint64(x << s)
+	z.exp = int32(64 - s) // always fits
+	if z.prec < 64 {
+		z.round(0)
+	}
+	return z
+}
+
+// SetUint64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetUint64(x uint64) *Float {
+	return z.setBits64(false, x)
+}
+
+// SetInt64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetInt64(x int64) *Float {
+	u := x
+	if u < 0 {
+		u = -u
+	}
+	// We cannot simply call z.SetUint64(uint64(u)) and change
+	// the sign afterwards because the sign affects rounding.
+	return z.setBits64(x < 0, uint64(u))
+}
+
+// SetFloat64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 53 (and rounding will have
+// no effect). SetFloat64 panics with ErrNaN if x is a NaN.
+func (z *Float) SetFloat64(x float64) *Float {
+	if z.prec == 0 {
+		z.prec = 53
+	}
+	if math.IsNaN(x) {
+		panic(ErrNaN{"Float.SetFloat64(NaN)"})
+	}
+	z.acc = Exact
+	z.neg = math.Signbit(x) // handle -0, -Inf correctly
+	if x == 0 {
+		z.form = zero
+		return z
+	}
+	if math.IsInf(x, 0) {
+		z.form = inf
+		return z
+	}
+	// normalized x != 0
+	z.form = finite
+	fmant, exp := math.Frexp(x) // get normalized mantissa
+	z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
+	z.exp = int32(exp) // always fits
+	if z.prec < 53 {
+		z.round(0)
+	}
+	return z
+}
+
+// fnorm normalizes mantissa m by shifting it to the left
+// such that the msb of the most-significant word (msw) is 1.
+// It returns the shift amount. It assumes that len(m) != 0.
+func fnorm(m nat) int64 {
+	if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) {
+		panic("msw of mantissa is 0")
+	}
+	s := nlz(m[len(m)-1])
+	if s > 0 {
+		c := shlVU(m, m, s)
+		if debugFloat && c != 0 {
+			panic("nlz or shlVU incorrect")
+		}
+	}
+	return int64(s)
+}
+
+// SetInt sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the larger of x.BitLen()
+// or 64 (and rounding will have no effect).
+func (z *Float) SetInt(x *Int) *Float {
+	// TODO(gri) can be more efficient if z.prec > 0
+	// but small compared to the size of x, or if there
+	// are many trailing 0's.
+	bits := uint32(x.BitLen())
+	if z.prec == 0 {
+		z.prec = umax32(bits, 64)
+	}
+	z.acc = Exact
+	z.neg = x.neg
+	if len(x.abs) == 0 {
+		z.form = zero
+		return z
+	}
+	// x != 0
+	z.mant = z.mant.set(x.abs)
+	fnorm(z.mant)
+	z.setExpAndRound(int64(bits), 0)
+	return z
+}
+
+// SetRat sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the largest of a.BitLen(),
+// b.BitLen(), or 64; with x = a/b.
+func (z *Float) SetRat(x *Rat) *Float {
+	if x.IsInt() {
+		return z.SetInt(x.Num())
+	}
+	var a, b Float
+	a.SetInt(x.Num())
+	b.SetInt(x.Denom())
+	if z.prec == 0 {
+		z.prec = umax32(a.prec, b.prec)
+	}
+	return z.Quo(&a, &b)
+}
+
+// SetInf sets z to the infinite Float -Inf if signbit is
+// set, or +Inf if signbit is not set, and returns z. The
+// precision of z is unchanged and the result is always
+// Exact.
+func (z *Float) SetInf(signbit bool) *Float {
+	z.acc = Exact
+	z.form = inf
+	z.neg = signbit
+	return z
+}
+
+// Set sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the precision of x
+// before setting z (and rounding will have no effect).
+// Rounding is performed according to z's precision and rounding
+// mode; and z's accuracy reports the result error relative to the
+// exact (not rounded) result.
+func (z *Float) Set(x *Float) *Float {
+	if debugFloat {
+		x.validate()
+	}
+	z.acc = Exact
+	if z != x {
+		z.form = x.form
+		z.neg = x.neg
+		if x.form == finite {
+			z.exp = x.exp
+			z.mant = z.mant.set(x.mant)
+		}
+		if z.prec == 0 {
+			z.prec = x.prec
+		} else if z.prec < x.prec {
+			z.round(0)
+		}
+	}
+	return z
+}
+
+// Copy sets z to x, with the same precision, rounding mode, and
+// accuracy as x, and returns z. x is not changed even if z and
+// x are the same.
+func (z *Float) Copy(x *Float) *Float {
+	if debugFloat {
+		x.validate()
+	}
+	if z != x {
+		z.prec = x.prec
+		z.mode = x.mode
+		z.acc = x.acc
+		z.form = x.form
+		z.neg = x.neg
+		if z.form == finite {
+			z.mant = z.mant.set(x.mant)
+			z.exp = x.exp
+		}
+	}
+	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 {
+		return 0
+	}
+	// i > 0
+	v := uint64(x[i-1])
+	if _W == 32 {
+		v <<= 32
+		if i > 1 {
+			v |= uint64(x[i-2])
+		}
+	}
+	return v
+}
+
+// Uint64 returns the unsigned integer resulting from truncating x
+// towards zero. If 0 <= x <= math.MaxUint64, the result is Exact
+// if x is an integer and Below otherwise.
+// The result is (0, Above) for x < 0, and (math.MaxUint64, Below)
+// for x > math.MaxUint64.
+func (x *Float) Uint64() (uint64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		if x.neg {
+			return 0, Above
+		}
+		// 0 < x < +Inf
+		if x.exp <= 0 {
+			// 0 < x < 1
+			return 0, Below
+		}
+		// 1 <= x < Inf
+		if x.exp <= 64 {
+			// u = trunc(x) fits into a uint64
+			u := high64(x.mant) >> (64 - uint32(x.exp))
+			if x.MinPrec() <= 64 {
+				return u, Exact
+			}
+			return u, Below // x truncated
+		}
+		// x too large
+		return math.MaxUint64, Below
+
+	case zero:
+		return 0, Exact
+
+	case inf:
+		if x.neg {
+			return 0, Above
+		}
+		return math.MaxUint64, Below
+	}
+
+	panic("unreachable")
+}
+
+// Int64 returns the integer resulting from truncating x towards zero.
+// If math.MinInt64 <= x <= math.MaxInt64, the result is Exact if x is
+// an integer, and Above (x < 0) or Below (x > 0) otherwise.
+// The result is (math.MinInt64, Above) for x < math.MinInt64,
+// and (math.MaxInt64, Below) for x > math.MaxInt64.
+func (x *Float) Int64() (int64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		acc := makeAcc(x.neg)
+		if x.exp <= 0 {
+			// 0 < |x| < 1
+			return 0, acc
+		}
+		// x.exp > 0
+
+		// 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)))
+			if x.neg {
+				i = -i
+			}
+			if x.MinPrec() <= uint(x.exp) {
+				return i, Exact
+			}
+			return i, acc // x truncated
+		}
+		if x.neg {
+			// check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
+			if x.exp == 64 && x.MinPrec() == 1 {
+				acc = Exact
+			}
+			return math.MinInt64, acc
+		}
+		// x too large
+		return math.MaxInt64, Below
+
+	case zero:
+		return 0, Exact
+
+	case inf:
+		if x.neg {
+			return math.MinInt64, Above
+		}
+		return math.MaxInt64, Below
+	}
+
+	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.
+// If x is too large to be represented by a float32 (|x| > math.MaxFloat32),
+// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
+func (x *Float) Float32() (float32, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+
+		const (
+			fbits = 32                //        float size
+			mbits = 23                //        mantissa size (excluding implicit msb)
+			ebits = fbits - mbits - 1 //     8  exponent size
+			bias  = 1<<(ebits-1) - 1  //   127  exponent bias
+			dmin  = 1 - bias - mbits  //  -149  smallest unbiased exponent (denormal)
+			emin  = 1 - bias          //  -126  smallest unbiased exponent (normal)
+			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)
+
+		if x.exp < dmin+1 {
+			// underflow
+			if x.neg {
+				var z float32
+				return -z, Above
+			}
+			return 0.0, Below
+		}
+		// x.exp >= dmin+1
+
+		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.Set(x)
+
+		// 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
+		}
+
+		if r.exp > emax+1 {
+			// 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)
+		}
+
+		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 {
+			// denormal number
+			r.exp += mbits
+			c = 1.0 / (1 << mbits) // 2**-mbits
+		}
+		// emin+1 <= r.exp <= emax+1
+		e := uint32(r.exp-emin) << mbits
+
+		return c * math.Float32frombits(s|e|m), r.acc
+
+	case zero:
+		if x.neg {
+			var z float32
+			return -z, Exact
+		}
+		return 0.0, Exact
+
+	case inf:
+		if x.neg {
+			return float32(math.Inf(-1)), Exact
+		}
+		return float32(math.Inf(+1)), Exact
+	}
+
+	panic("unreachable")
+}
+
+// Float64 returns the float64 value nearest to x. If x is too small to be
+// represented by a float64 (|x| < math.SmallestNonzeroFloat64), the result
+// is (0, Below) or (-0, Above), respectively, depending on the sign of x.
+// If x is too large to be represented by a float64 (|x| > math.MaxFloat64),
+// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
+func (x *Float) Float64() (float64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+
+		const (
+			fbits = 64                //        float size
+			mbits = 52                //        mantissa size (excluding implicit msb)
+			ebits = fbits - mbits - 1 //    11  exponent size
+			bias  = 1<<(ebits-1) - 1  //  1023  exponent bias
+			dmin  = 1 - bias - mbits  // -1074  smallest unbiased exponent (denormal)
+			emin  = 1 - bias          // -1022  smallest unbiased exponent (normal)
+			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)
+
+		if x.exp < dmin+1 {
+			// underflow
+			if x.neg {
+				var z float64
+				return -z, Above
+			}
+			return 0.0, Below
+		}
+		// x.exp >= dmin+1
+
+		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.Set(x)
+
+		// 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
+		}
+
+		if r.exp > emax+1 {
+			// 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)
+		}
+
+		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 {
+			// denormal number
+			r.exp += mbits
+			c = 1.0 / (1 << mbits) // 2**-mbits
+		}
+		// emin+1 <= r.exp <= emax+1
+		e := uint64(r.exp-emin) << mbits
+
+		return c * math.Float64frombits(s|e|m), r.acc
+
+	case zero:
+		if x.neg {
+			var z float64
+			return -z, Exact
+		}
+		return 0.0, Exact
+
+	case inf:
+		if x.neg {
+			return math.Inf(-1), Exact
+		}
+		return math.Inf(+1), Exact
+	}
+
+	panic("unreachable")
+}
+
+// Int returns the result of truncating x towards zero;
+// or nil if x is an infinity.
+// The result is Exact if x.IsInt(); otherwise it is Below
+// for x > 0, and Above for x < 0.
+// If a non-nil *Int argument z is provided, Int stores
+// the result in z instead of allocating a new Int.
+func (x *Float) Int(z *Int) (*Int, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	if z == nil && x.form <= finite {
+		z = new(Int)
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		acc := makeAcc(x.neg)
+		if x.exp <= 0 {
+			// 0 < |x| < 1
+			return z.SetInt64(0), acc
+		}
+		// x.exp > 0
+
+		// 1 <= |x| < +Inf
+		// determine minimum required precision for x
+		allBits := uint(len(x.mant)) * _W
+		exp := uint(x.exp)
+		if x.MinPrec() <= exp {
+			acc = Exact
+		}
+		// shift mantissa as needed
+		if z == nil {
+			z = new(Int)
+		}
+		z.neg = x.neg
+		switch {
+		case exp > allBits:
+			z.abs = z.abs.shl(x.mant, exp-allBits)
+		default:
+			z.abs = z.abs.set(x.mant)
+		case exp < allBits:
+			z.abs = z.abs.shr(x.mant, allBits-exp)
+		}
+		return z, acc
+
+	case zero:
+		return z.SetInt64(0), Exact
+
+	case inf:
+		return nil, makeAcc(x.neg)
+	}
+
+	panic("unreachable")
+}
+
+// Rat returns the rational number corresponding to x;
+// or nil if x is an infinity.
+// The result is Exact is x is not an Inf.
+// If a non-nil *Rat argument z is provided, Rat stores
+// the result in z instead of allocating a new Rat.
+func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	if z == nil && x.form <= finite {
+		z = new(Rat)
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		allBits := int32(len(x.mant)) * _W
+		// build up numerator and denominator
+		z.a.neg = x.neg
+		switch {
+		case x.exp > allBits:
+			z.a.abs = z.a.abs.shl(x.mant, uint(x.exp-allBits))
+			z.b.abs = z.b.abs[:0] // == 1 (see Rat)
+			// z already in normal form
+		default:
+			z.a.abs = z.a.abs.set(x.mant)
+			z.b.abs = z.b.abs[:0] // == 1 (see Rat)
+			// z already in normal form
+		case x.exp < allBits:
+			z.a.abs = z.a.abs.set(x.mant)
+			t := z.b.abs.setUint64(1)
+			z.b.abs = t.shl(t, uint(allBits-x.exp))
+			z.norm()
+		}
+		return z, Exact
+
+	case zero:
+		return z.SetInt64(0), Exact
+
+	case inf:
+		return nil, makeAcc(x.neg)
+	}
+
+	panic("unreachable")
+}
+
+// Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
+// and returns z.
+func (z *Float) Abs(x *Float) *Float {
+	z.Set(x)
+	z.neg = false
+	return z
+}
+
+// Neg sets z to the (possibly rounded) value of x with its sign negated,
+// and returns z.
+func (z *Float) Neg(x *Float) *Float {
+	z.Set(x)
+	z.neg = !z.neg
+	return z
+}
+
+func validateBinaryOperands(x, y *Float) {
+	if !debugFloat {
+		// avoid performance bugs
+		panic("validateBinaryOperands called but debugFloat is not set")
+	}
+	if len(x.mant) == 0 {
+		panic("empty mantissa for x")
+	}
+	if len(y.mant) == 0 {
+		panic("empty mantissa for y")
+	}
+}
+
+// z = x + y, ignoring signs of x and y for the addition
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
+func (z *Float) uadd(x, y *Float) {
+	// Note: This implementation requires 2 shifts most of the
+	// time. It is also inefficient if exponents or precisions
+	// differ by wide margins. The following article describes
+	// an efficient (but much more complicated) implementation
+	// compatible with the internal representation used here:
+	//
+	// Vincent Lefèvre: "The Generic Multiple-Precision Floating-
+	// Point Addition With Exact Rounding (as in the MPFR Library)"
+	// http://www.vinc17.net/research/papers/rnc6.pdf
+
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	// compute exponents ex, ey for mantissa with "binary point"
+	// on the right (mantissa.0) - use int64 to avoid overflow
+	ex := int64(x.exp) - int64(len(x.mant))*_W
+	ey := int64(y.exp) - int64(len(y.mant))*_W
+
+	// TODO(gri) having a combined add-and-shift primitive
+	//           could make this code significantly faster
+	switch {
+	case ex < ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(y.mant, uint(ey-ex))
+		z.mant = z.mant.add(x.mant, t)
+	default:
+		// ex == ey, no shift needed
+		z.mant = z.mant.add(x.mant, y.mant)
+	case ex > ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(x.mant, uint(ex-ey))
+		z.mant = z.mant.add(t, y.mant)
+		ex = ey
+	}
+	// len(z.mant) > 0
+
+	z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
+}
+
+// z = x - y for |x| > |y|, ignoring signs of x and y for the subtraction
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
+func (z *Float) usub(x, y *Float) {
+	// This code is symmetric to uadd.
+	// We have not factored the common code out because
+	// eventually uadd (and usub) should be optimized
+	// by special-casing, and the code will diverge.
+
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	ex := int64(x.exp) - int64(len(x.mant))*_W
+	ey := int64(y.exp) - int64(len(y.mant))*_W
+
+	switch {
+	case ex < ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(y.mant, uint(ey-ex))
+		z.mant = t.sub(x.mant, t)
+	default:
+		// ex == ey, no shift needed
+		z.mant = z.mant.sub(x.mant, y.mant)
+	case ex > ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(x.mant, uint(ex-ey))
+		z.mant = t.sub(t, y.mant)
+		ex = ey
+	}
+
+	// operands may have cancelled each other out
+	if len(z.mant) == 0 {
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		return
+	}
+	// len(z.mant) > 0
+
+	z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
+}
+
+// z = x * y, ignoring signs of x and y for the multiplication
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
+func (z *Float) umul(x, y *Float) {
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	// Note: This is doing too much work if the precision
+	// of z is less than the sum of the precisions of x
+	// and y which is often the case (e.g., if all floats
+	// have the same precision).
+	// TODO(gri) Optimize this for the common case.
+
+	e := int64(x.exp) + int64(y.exp)
+	z.mant = z.mant.mul(x.mant, y.mant)
+
+	z.setExpAndRound(e-fnorm(z.mant), 0)
+}
+
+// z = x / y, ignoring signs of x and y for the division
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
+func (z *Float) uquo(x, y *Float) {
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	// mantissa length in words for desired result precision + 1
+	// (at least one extra bit so we get the rounding bit after
+	// the division)
+	n := int(z.prec/_W) + 1
+
+	// compute adjusted x.mant such that we get enough result precision
+	xadj := x.mant
+	if d := n - len(x.mant) + len(y.mant); d > 0 {
+		// d extra words needed => add d "0 digits" to x
+		xadj = make(nat, len(x.mant)+d)
+		copy(xadj[d:], x.mant)
+	}
+	// TODO(gri): If we have too many digits (d < 0), we should be able
+	// to shorten x for faster division. But we must be extra careful
+	// with rounding in that case.
+
+	// Compute d before division since there may be aliasing of x.mant
+	// (via xadj) or y.mant with z.mant.
+	d := len(xadj) - len(y.mant)
+
+	// divide
+	var r nat
+	z.mant, r = z.mant.div(nil, xadj, y.mant)
+	e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W
+
+	// The result is long enough to include (at least) the rounding bit.
+	// If there's a non-zero remainder, the corresponding fractional part
+	// (if it were computed), would have a non-zero sticky bit (if it were
+	// zero, it couldn't have a non-zero remainder).
+	var sbit uint
+	if len(r) > 0 {
+		sbit = 1
+	}
+
+	z.setExpAndRound(e-fnorm(z.mant), sbit)
+}
+
+// ucmp returns -1, 0, or +1, depending on whether
+// |x| < |y|, |x| == |y|, or |x| > |y|.
+// x and y must have a non-empty mantissa and valid exponent.
+func (x *Float) ucmp(y *Float) int {
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	switch {
+	case x.exp < y.exp:
+		return -1
+	case x.exp > y.exp:
+		return +1
+	}
+	// x.exp == y.exp
+
+	// compare mantissas
+	i := len(x.mant)
+	j := len(y.mant)
+	for i > 0 || j > 0 {
+		var xm, ym Word
+		if i > 0 {
+			i--
+			xm = x.mant[i]
+		}
+		if j > 0 {
+			j--
+			ym = y.mant[j]
+		}
+		switch {
+		case xm < ym:
+			return -1
+		case xm > ym:
+			return +1
+		}
+	}
+
+	return 0
+}
+
+// Handling of sign bit as defined by IEEE 754-2008, section 6.3:
+//
+// When neither the inputs nor result are NaN, the sign of a product or
+// quotient is the exclusive OR of the operands’ signs; the sign of a sum,
+// or of a difference x−y regarded as a sum x+(−y), differs from at most
+// one of the addends’ signs; and the sign of the result of conversions,
+// the quantize operation, the roundToIntegral operations, and the
+// roundToIntegralExact (see 5.3.1) is the sign of the first or only operand.
+// These rules shall apply even when operands or results are zero or infinite.
+//
+// When the sum of two operands with opposite signs (or the difference of
+// two operands with like signs) is exactly zero, the sign of that sum (or
+// difference) shall be +0 in all rounding-direction attributes except
+// roundTowardNegative; under that attribute, the sign of an exact zero
+// sum (or difference) shall be −0. However, x+x = x−(−x) retains the same
+// sign as x even when x is zero.
+//
+// See also: http://play.golang.org/p/RtH3UCt5IH
+
+// Add sets z to the rounded sum x+y and returns z. If z's precision is 0,
+// it is changed to the larger of x's or y's precision before the operation.
+// Rounding is performed according to z's precision and rounding mode; and
+// z's accuracy reports the result error relative to the exact (not rounded)
+// result. Add panics with ErrNaN if x and y are infinities with opposite
+// signs. The value of z is undefined in that case.
+//
+// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
+func (z *Float) Add(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	if x.form == finite && y.form == finite {
+		// x + y (commom case)
+		z.neg = x.neg
+		if x.neg == y.neg {
+			// x + y == x + y
+			// (-x) + (-y) == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x + (-y) == x - y == -(y - x)
+			// (-x) + y == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
+			}
+		}
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg != y.neg {
+		// +Inf + -Inf
+		// -Inf + +Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"addition of infinities with opposite signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 + ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && y.neg // -0 + -0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf + y
+		// x + ±0
+		return z.Set(x)
+	}
+
+	// ±0 + y
+	// x + ±Inf
+	return z.Set(y)
+}
+
+// Sub sets z to the rounded difference x-y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Sub panics with ErrNaN if x and y are infinities with equal
+// signs. The value of z is undefined in that case.
+func (z *Float) Sub(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	if x.form == finite && y.form == finite {
+		// x - y (common case)
+		z.neg = x.neg
+		if x.neg != y.neg {
+			// x - (-y) == x + y
+			// (-x) - y == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x - y == x - y == -(y - x)
+			// (-x) - (-y) == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
+			}
+		}
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg == y.neg {
+		// +Inf - +Inf
+		// -Inf - -Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"subtraction of infinities with equal signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 - ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && !y.neg // -0 - +0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf - y
+		// x - ±0
+		return z.Set(x)
+	}
+
+	// ±0 - y
+	// x - ±Inf
+	return z.Neg(y)
+}
+
+// Mul sets z to the rounded product x*y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Mul panics with ErrNaN if one operand is zero and the other
+// operand an infinity. The value of z is undefined in that case.
+func (z *Float) Mul(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	z.neg = x.neg != y.neg
+
+	if x.form == finite && y.form == finite {
+		// x * y (common case)
+		z.umul(x, y)
+		return z
+	}
+
+	z.acc = Exact
+	if x.form == zero && y.form == inf || x.form == inf && y.form == zero {
+		// ±0 * ±Inf
+		// ±Inf * ±0
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"multiplication of zero with infinity"})
+	}
+
+	if x.form == inf || y.form == inf {
+		// ±Inf * y
+		// x * ±Inf
+		z.form = inf
+		return z
+	}
+
+	// ±0 * y
+	// x * ±0
+	z.form = zero
+	return z
+}
+
+// Quo sets z to the rounded quotient x/y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Quo panics with ErrNaN if both operands are zero or infinities.
+// The value of z is undefined in that case.
+func (z *Float) Quo(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	z.neg = x.neg != y.neg
+
+	if x.form == finite && y.form == finite {
+		// x / y (common case)
+		z.uquo(x, y)
+		return z
+	}
+
+	z.acc = Exact
+	if x.form == zero && y.form == zero || x.form == inf && y.form == inf {
+		// ±0 / ±0
+		// ±Inf / ±Inf
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"division of zero by zero or infinity by infinity"})
+	}
+
+	if x.form == zero || y.form == inf {
+		// ±0 / y
+		// x / ±Inf
+		z.form = zero
+		return z
+	}
+
+	// x / ±0
+	// ±Inf / y
+	z.form = inf
+	return z
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
+//   +1 if x >  y
+//
+func (x *Float) Cmp(y *Float) int {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	mx := x.ord()
+	my := y.ord()
+	switch {
+	case mx < my:
+		return -1
+	case mx > my:
+		return +1
+	}
+	// mx == my
+
+	// only if |mx| == 1 we have to compare the mantissae
+	switch mx {
+	case -1:
+		return y.ucmp(x)
+	case +1:
+		return x.ucmp(y)
+	}
+
+	return 0
+}
+
+// ord classifies x and returns:
+//
+//	-2 if -Inf == x
+//	-1 if -Inf < x < 0
+//	 0 if x == 0 (signed or unsigned)
+//	+1 if 0 < x < +Inf
+//	+2 if x == +Inf
+//
+func (x *Float) ord() int {
+	var m int
+	switch x.form {
+	case finite:
+		m = 1
+	case zero:
+		return 0
+	case inf:
+		m = 2
+	}
+	if x.neg {
+		m = -m
+	}
+	return m
+}
+
+func umax32(x, y uint32) uint32 {
+	if x > y {
+		return x
+	}
+	return y
+}
diff --git a/src/cmd/internal/gc/big/float_test.go b/src/cmd/internal/gc/big/float_test.go
new file mode 100644
index 0000000..2a48ec4
--- /dev/null
+++ b/src/cmd/internal/gc/big/float_test.go
@@ -0,0 +1,1664 @@
+// 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.
+
+package big
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+func (x *Float) uint64() uint64 {
+	u, acc := x.Uint64()
+	if acc != Exact {
+		panic(fmt.Sprintf("%s is not a uint64", x.Format('g', 10)))
+	}
+	return u
+}
+
+func (x *Float) int64() int64 {
+	i, acc := x.Int64()
+	if acc != Exact {
+		panic(fmt.Sprintf("%s is not an int64", x.Format('g', 10)))
+	}
+	return i
+}
+
+func TestFloatZeroValue(t *testing.T) {
+	// zero (uninitialized) value is a ready-to-use 0.0
+	var x Float
+	if s := x.Format('f', 1); s != "0.0" {
+		t.Errorf("zero value = %s; want 0.0", s)
+	}
+
+	// zero value has precision 0
+	if prec := x.Prec(); prec != 0 {
+		t.Errorf("prec = %d; want 0", prec)
+	}
+
+	// zero value can be used in any and all positions of binary operations
+	make := func(x int) *Float {
+		var f Float
+		if x != 0 {
+			f.SetInt64(int64(x))
+		}
+		// x == 0 translates into the zero value
+		return &f
+	}
+	for _, test := range []struct {
+		z, x, y, want int
+		opname        rune
+		op            func(z, x, y *Float) *Float
+	}{
+		{0, 0, 0, 0, '+', (*Float).Add},
+		{0, 1, 2, 3, '+', (*Float).Add},
+		{1, 2, 0, 2, '+', (*Float).Add},
+		{2, 0, 1, 1, '+', (*Float).Add},
+
+		{0, 0, 0, 0, '-', (*Float).Sub},
+		{0, 1, 2, -1, '-', (*Float).Sub},
+		{1, 2, 0, 2, '-', (*Float).Sub},
+		{2, 0, 1, -1, '-', (*Float).Sub},
+
+		{0, 0, 0, 0, '*', (*Float).Mul},
+		{0, 1, 2, 2, '*', (*Float).Mul},
+		{1, 2, 0, 0, '*', (*Float).Mul},
+		{2, 0, 1, 0, '*', (*Float).Mul},
+
+		// {0, 0, 0, 0, '/', (*Float).Quo}, // panics
+		{0, 2, 1, 2, '/', (*Float).Quo},
+		{1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf
+		{2, 0, 1, 0, '/', (*Float).Quo},
+	} {
+		z := make(test.z)
+		test.op(z, make(test.x), make(test.y))
+		got := 0
+		if !z.IsInf() {
+			got = int(z.int64())
+		}
+		if got != test.want {
+			t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want)
+		}
+	}
+
+	// TODO(gri) test how precision is set for zero value results
+}
+
+func makeFloat(s string) *Float {
+	var x Float
+
+	switch s {
+	case "0":
+		return &x
+	case "-0":
+		return x.Neg(&x)
+	case "Inf", "+Inf":
+		return x.SetInf(false)
+	case "-Inf":
+		return x.SetInf(true)
+	}
+
+	x.SetPrec(1000)
+	if _, ok := x.SetString(s); !ok {
+		panic(fmt.Sprintf("%q is not a valid float", s))
+	}
+	return &x
+}
+
+func TestFloatSetPrec(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		prec uint
+		want string
+		acc  Accuracy
+	}{
+		// prec 0
+		{"0", 0, "0", Exact},
+		{"-0", 0, "-0", Exact},
+		{"-Inf", 0, "-Inf", Exact},
+		{"+Inf", 0, "+Inf", Exact},
+		{"123", 0, "0", Below},
+		{"-123", 0, "-0", Above},
+
+		// prec at upper limit
+		{"0", MaxPrec, "0", Exact},
+		{"-0", MaxPrec, "-0", Exact},
+		{"-Inf", MaxPrec, "-Inf", Exact},
+		{"+Inf", MaxPrec, "+Inf", Exact},
+
+		// just a few regular cases - general rounding is tested elsewhere
+		{"1.5", 1, "2", Above},
+		{"-1.5", 1, "-2", Below},
+		{"123", 1e6, "123", Exact},
+		{"-123", 1e6, "-123", Exact},
+	} {
+		x := makeFloat(test.x).SetPrec(test.prec)
+		prec := test.prec
+		if prec > MaxPrec {
+			prec = MaxPrec
+		}
+		if got := x.Prec(); got != prec {
+			t.Errorf("%s.SetPrec(%d).Prec() == %d; want %d", test.x, test.prec, got, prec)
+		}
+		if got, acc := x.String(), x.Acc(); got != test.want || acc != test.acc {
+			t.Errorf("%s.SetPrec(%d) = %s (%s); want %s (%s)", test.x, test.prec, got, acc, test.want, test.acc)
+		}
+	}
+}
+
+func TestFloatMinPrec(t *testing.T) {
+	const max = 100
+	for _, test := range []struct {
+		x    string
+		want uint
+	}{
+		{"0", 0},
+		{"-0", 0},
+		{"+Inf", 0},
+		{"-Inf", 0},
+		{"1", 1},
+		{"2", 1},
+		{"3", 2},
+		{"0x8001", 16},
+		{"0x8001p-1000", 16},
+		{"0x8001p+1000", 16},
+		{"0.1", max},
+	} {
+		x := makeFloat(test.x).SetPrec(max)
+		if got := x.MinPrec(); got != test.want {
+			t.Errorf("%s.MinPrec() = %d; want %d", test.x, got, test.want)
+		}
+	}
+}
+
+func TestFloatSign(t *testing.T) {
+	for _, test := range []struct {
+		x string
+		s int
+	}{
+		{"-Inf", -1},
+		{"-1", -1},
+		{"-0", 0},
+		{"+0", 0},
+		{"+1", +1},
+		{"+Inf", +1},
+	} {
+		x := makeFloat(test.x)
+		s := x.Sign()
+		if s != test.s {
+			t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s)
+		}
+	}
+}
+
+// alike(x, y) is like x.Cmp(y) == 0 but also considers the sign of 0 (0 != -0).
+func alike(x, y *Float) bool {
+	return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
+}
+
+func TestFloatMantExp(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		mant string
+		exp  int
+	}{
+		{"0", "0", 0},
+		{"+0", "0", 0},
+		{"-0", "-0", 0},
+		{"Inf", "+Inf", 0},
+		{"+Inf", "+Inf", 0},
+		{"-Inf", "-Inf", 0},
+		{"1.5", "0.75", 1},
+		{"1.024e3", "0.5", 11},
+		{"-0.125", "-0.5", -2},
+	} {
+		x := makeFloat(test.x)
+		mant := makeFloat(test.mant)
+		m := new(Float)
+		e := x.MantExp(m)
+		if !alike(m, mant) || e != test.exp {
+			t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, m.Format('g', 10), e, test.mant, test.exp)
+		}
+	}
+}
+
+func TestFloatMantExpAliasing(t *testing.T) {
+	x := makeFloat("0.5p10")
+	if e := x.MantExp(x); e != 10 {
+		t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e)
+	}
+	if want := makeFloat("0.5"); !alike(x, want) {
+		t.Fatalf("Float.MantExp aliasing error: got %s; want %s", x.Format('g', 10), want.Format('g', 10))
+	}
+}
+
+func TestFloatSetMantExp(t *testing.T) {
+	for _, test := range []struct {
+		frac string
+		exp  int
+		z    string
+	}{
+		{"0", 0, "0"},
+		{"+0", 0, "0"},
+		{"-0", 0, "-0"},
+		{"Inf", 1234, "+Inf"},
+		{"+Inf", -1234, "+Inf"},
+		{"-Inf", -1234, "-Inf"},
+		{"0", MinExp, "0"},
+		{"0.25", MinExp, "+0"},    // exponent underflow
+		{"-0.25", MinExp, "-0"},   // exponent underflow
+		{"1", MaxExp, "+Inf"},     // exponent overflow
+		{"2", MaxExp - 1, "+Inf"}, // exponent overflow
+		{"0.75", 1, "1.5"},
+		{"0.5", 11, "1024"},
+		{"-0.5", -2, "-0.125"},
+		{"32", 5, "1024"},
+		{"1024", -10, "1"},
+	} {
+		frac := makeFloat(test.frac)
+		want := makeFloat(test.z)
+		var z Float
+		z.SetMantExp(frac, test.exp)
+		if !alike(&z, want) {
+			t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Format('g', 10), test.z)
+		}
+		// test inverse property
+		mant := new(Float)
+		if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 {
+			t.Errorf("Inverse property not satisfied: got %s; want %s", z.Format('g', 10), test.z)
+		}
+	}
+}
+
+func TestFloatPredicates(t *testing.T) {
+	for _, test := range []struct {
+		x            string
+		sign         int
+		signbit, inf bool
+	}{
+		{x: "-Inf", sign: -1, signbit: true, inf: true},
+		{x: "-1", sign: -1, signbit: true},
+		{x: "-0", signbit: true},
+		{x: "0"},
+		{x: "1", sign: 1},
+		{x: "+Inf", sign: 1, inf: true},
+	} {
+		x := makeFloat(test.x)
+		if got := x.Signbit(); got != test.signbit {
+			t.Errorf("(%s).Signbit() = %v; want %v", test.x, got, test.signbit)
+		}
+		if got := x.Sign(); got != test.sign {
+			t.Errorf("(%s).Sign() = %d; want %d", test.x, got, test.sign)
+		}
+		if got := x.IsInf(); got != test.inf {
+			t.Errorf("(%s).IsInf() = %v; want %v", test.x, got, test.inf)
+		}
+	}
+}
+
+func TestFloatIsInt(t *testing.T) {
+	for _, test := range []string{
+		"0 int",
+		"-0 int",
+		"1 int",
+		"-1 int",
+		"0.5",
+		"1.23",
+		"1.23e1",
+		"1.23e2 int",
+		"0.000000001e+8",
+		"0.000000001e+9 int",
+		"1.2345e200 int",
+		"Inf",
+		"+Inf",
+		"-Inf",
+	} {
+		s := strings.TrimSuffix(test, " int")
+		want := s != test
+		if got := makeFloat(s).IsInt(); got != want {
+			t.Errorf("%s.IsInt() == %t", s, got)
+		}
+	}
+}
+
+func fromBinary(s string) int64 {
+	x, err := strconv.ParseInt(s, 2, 64)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func toBinary(x int64) string {
+	return strconv.FormatInt(x, 2)
+}
+
+func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
+	// verify test data
+	var ok bool
+	switch mode {
+	case ToNearestEven, ToNearestAway:
+		ok = true // nothing to do for now
+	case ToZero:
+		if x < 0 {
+			ok = r >= x
+		} else {
+			ok = r <= x
+		}
+	case AwayFromZero:
+		if x < 0 {
+			ok = r <= x
+		} else {
+			ok = r >= x
+		}
+	case ToNegativeInf:
+		ok = r <= x
+	case ToPositiveInf:
+		ok = r >= x
+	default:
+		panic("unreachable")
+	}
+	if !ok {
+		t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r))
+	}
+
+	// compute expected accuracy
+	a := Exact
+	switch {
+	case r < x:
+		a = Below
+	case r > x:
+		a = Above
+	}
+
+	// round
+	f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec)
+
+	// check result
+	r1 := f.int64()
+	p1 := f.Prec()
+	a1 := f.Acc()
+	if r1 != r || p1 != prec || a1 != a {
+		t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)",
+			toBinary(x), prec, mode,
+			toBinary(r1), p1, a1,
+			toBinary(r), prec, a)
+		return
+	}
+
+	// g and f should be the same
+	// (rounding by SetPrec after SetInt64 using default precision
+	// should be the same as rounding by SetInt64 after setting the
+	// precision)
+	g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
+	if !alike(g, f) {
+		t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s",
+			toBinary(x), prec, mode,
+			toBinary(g.int64()),
+			toBinary(r1),
+			toBinary(r),
+		)
+		return
+	}
+
+	// h and f should be the same
+	// (repeated rounding should be idempotent)
+	h := new(Float).SetMode(mode).SetPrec(prec).Set(f)
+	if !alike(h, f) {
+		t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s",
+			toBinary(x), prec, mode,
+			toBinary(h.int64()),
+			toBinary(r1),
+			toBinary(r),
+		)
+		return
+	}
+}
+
+// TestFloatRound tests basic rounding.
+func TestFloatRound(t *testing.T) {
+	for _, test := range []struct {
+		prec                        uint
+		x, zero, neven, naway, away string // input, results rounded to prec bits
+	}{
+		{5, "1000", "1000", "1000", "1000", "1000"},
+		{5, "1001", "1001", "1001", "1001", "1001"},
+		{5, "1010", "1010", "1010", "1010", "1010"},
+		{5, "1011", "1011", "1011", "1011", "1011"},
+		{5, "1100", "1100", "1100", "1100", "1100"},
+		{5, "1101", "1101", "1101", "1101", "1101"},
+		{5, "1110", "1110", "1110", "1110", "1110"},
+		{5, "1111", "1111", "1111", "1111", "1111"},
+
+		{4, "1000", "1000", "1000", "1000", "1000"},
+		{4, "1001", "1001", "1001", "1001", "1001"},
+		{4, "1010", "1010", "1010", "1010", "1010"},
+		{4, "1011", "1011", "1011", "1011", "1011"},
+		{4, "1100", "1100", "1100", "1100", "1100"},
+		{4, "1101", "1101", "1101", "1101", "1101"},
+		{4, "1110", "1110", "1110", "1110", "1110"},
+		{4, "1111", "1111", "1111", "1111", "1111"},
+
+		{3, "1000", "1000", "1000", "1000", "1000"},
+		{3, "1001", "1000", "1000", "1010", "1010"},
+		{3, "1010", "1010", "1010", "1010", "1010"},
+		{3, "1011", "1010", "1100", "1100", "1100"},
+		{3, "1100", "1100", "1100", "1100", "1100"},
+		{3, "1101", "1100", "1100", "1110", "1110"},
+		{3, "1110", "1110", "1110", "1110", "1110"},
+		{3, "1111", "1110", "10000", "10000", "10000"},
+
+		{3, "1000001", "1000000", "1000000", "1000000", "1010000"},
+		{3, "1001001", "1000000", "1010000", "1010000", "1010000"},
+		{3, "1010001", "1010000", "1010000", "1010000", "1100000"},
+		{3, "1011001", "1010000", "1100000", "1100000", "1100000"},
+		{3, "1100001", "1100000", "1100000", "1100000", "1110000"},
+		{3, "1101001", "1100000", "1110000", "1110000", "1110000"},
+		{3, "1110001", "1110000", "1110000", "1110000", "10000000"},
+		{3, "1111001", "1110000", "10000000", "10000000", "10000000"},
+
+		{2, "1000", "1000", "1000", "1000", "1000"},
+		{2, "1001", "1000", "1000", "1000", "1100"},
+		{2, "1010", "1000", "1000", "1100", "1100"},
+		{2, "1011", "1000", "1100", "1100", "1100"},
+		{2, "1100", "1100", "1100", "1100", "1100"},
+		{2, "1101", "1100", "1100", "1100", "10000"},
+		{2, "1110", "1100", "10000", "10000", "10000"},
+		{2, "1111", "1100", "10000", "10000", "10000"},
+
+		{2, "1000001", "1000000", "1000000", "1000000", "1100000"},
+		{2, "1001001", "1000000", "1000000", "1000000", "1100000"},
+		{2, "1010001", "1000000", "1100000", "1100000", "1100000"},
+		{2, "1011001", "1000000", "1100000", "1100000", "1100000"},
+		{2, "1100001", "1100000", "1100000", "1100000", "10000000"},
+		{2, "1101001", "1100000", "1100000", "1100000", "10000000"},
+		{2, "1110001", "1100000", "10000000", "10000000", "10000000"},
+		{2, "1111001", "1100000", "10000000", "10000000", "10000000"},
+
+		{1, "1000", "1000", "1000", "1000", "1000"},
+		{1, "1001", "1000", "1000", "1000", "10000"},
+		{1, "1010", "1000", "1000", "1000", "10000"},
+		{1, "1011", "1000", "1000", "1000", "10000"},
+		{1, "1100", "1000", "10000", "10000", "10000"},
+		{1, "1101", "1000", "10000", "10000", "10000"},
+		{1, "1110", "1000", "10000", "10000", "10000"},
+		{1, "1111", "1000", "10000", "10000", "10000"},
+
+		{1, "1000001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1001001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1010001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1011001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1100001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1101001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1110001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1111001", "1000000", "10000000", "10000000", "10000000"},
+	} {
+		x := fromBinary(test.x)
+		z := fromBinary(test.zero)
+		e := fromBinary(test.neven)
+		n := fromBinary(test.naway)
+		a := fromBinary(test.away)
+		prec := test.prec
+
+		testFloatRound(t, x, z, prec, ToZero)
+		testFloatRound(t, x, e, prec, ToNearestEven)
+		testFloatRound(t, x, n, prec, ToNearestAway)
+		testFloatRound(t, x, a, prec, AwayFromZero)
+
+		testFloatRound(t, x, z, prec, ToNegativeInf)
+		testFloatRound(t, x, a, prec, ToPositiveInf)
+
+		testFloatRound(t, -x, -a, prec, ToNegativeInf)
+		testFloatRound(t, -x, -z, prec, ToPositiveInf)
+	}
+}
+
+// TestFloatRound24 tests that rounding a float64 to 24 bits
+// matches IEEE-754 rounding to nearest when converting a
+// float64 to a float32 (excluding denormal numbers).
+func TestFloatRound24(t *testing.T) {
+	const x0 = 1<<26 - 0x10 // 11...110000 (26 bits)
+	for d := 0; d <= 0x10; d++ {
+		x := float64(x0 + d)
+		f := new(Float).SetPrec(24).SetFloat64(x)
+		got, _ := f.Float32()
+		want := float32(x)
+		if got != want {
+			t.Errorf("Round(%g, 24) = %g; want %g", x, got, want)
+		}
+	}
+}
+
+func TestFloatSetUint64(t *testing.T) {
+	for _, want := range []uint64{
+		0,
+		1,
+		2,
+		10,
+		100,
+		1<<32 - 1,
+		1 << 32,
+		1<<64 - 1,
+	} {
+		var f Float
+		f.SetUint64(want)
+		if got := f.uint64(); got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x uint64 = 0x8765432187654321 // 64 bits needed
+	for prec := uint(1); prec <= 64; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x)
+		got := f.uint64()
+		want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits
+		if got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetInt64(t *testing.T) {
+	for _, want := range []int64{
+		0,
+		1,
+		2,
+		10,
+		100,
+		1<<32 - 1,
+		1 << 32,
+		1<<63 - 1,
+	} {
+		for i := range [2]int{} {
+			if i&1 != 0 {
+				want = -want
+			}
+			var f Float
+			f.SetInt64(want)
+			if got := f.int64(); got != want {
+				t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
+			}
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x int64 = 0x7654321076543210 // 63 bits needed
+	for prec := uint(1); prec <= 63; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x)
+		got := f.int64()
+		want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits
+		if got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetFloat64(t *testing.T) {
+	for _, want := range []float64{
+		0,
+		1,
+		2,
+		12345,
+		1e10,
+		1e100,
+		3.14159265e10,
+		2.718281828e-123,
+		1.0 / 3,
+		math.MaxFloat32,
+		math.MaxFloat64,
+		math.SmallestNonzeroFloat32,
+		math.SmallestNonzeroFloat64,
+		math.Inf(-1),
+		math.Inf(0),
+		-math.Inf(1),
+	} {
+		for i := range [2]int{} {
+			if i&1 != 0 {
+				want = -want
+			}
+			var f Float
+			f.SetFloat64(want)
+			if got, acc := f.Float64(); got != want || acc != Exact {
+				t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Format('p', 0), acc, want)
+			}
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x uint64 = 0x8765432143218 // 53 bits needed
+	for prec := uint(1); prec <= 52; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x))
+		got, _ := f.Float64()
+		want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits
+		if got != want {
+			t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
+		}
+	}
+
+	// test NaN
+	defer func() {
+		if p, ok := recover().(ErrNaN); !ok {
+			t.Errorf("got %v; want ErrNaN panic", p)
+		}
+	}()
+	var f Float
+	f.SetFloat64(math.NaN())
+	// should not reach here
+	t.Errorf("got %s; want ErrNaN panic", f.Format('p', 0))
+}
+
+func TestFloatSetInt(t *testing.T) {
+	for _, want := range []string{
+		"0",
+		"1",
+		"-1",
+		"1234567890",
+		"123456789012345678901234567890",
+		"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	} {
+		var x Int
+		_, ok := x.SetString(want, 0)
+		if !ok {
+			t.Errorf("invalid integer %s", want)
+			continue
+		}
+		n := x.BitLen()
+
+		var f Float
+		f.SetInt(&x)
+
+		// check precision
+		if n < 64 {
+			n = 64
+		}
+		if prec := f.Prec(); prec != uint(n) {
+			t.Errorf("got prec = %d; want %d", prec, n)
+		}
+
+		// check value
+		got := f.Format('g', 100)
+		if got != want {
+			t.Errorf("got %s (%s); want %s", got, f.Format('p', 0), want)
+		}
+	}
+
+	// TODO(gri) test basic rounding behavior
+}
+
+func TestFloatSetRat(t *testing.T) {
+	for _, want := range []string{
+		"0",
+		"1",
+		"-1",
+		"1234567890",
+		"123456789012345678901234567890",
+		"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+		"1.2",
+		"3.14159265",
+		// TODO(gri) expand
+	} {
+		var x Rat
+		_, ok := x.SetString(want)
+		if !ok {
+			t.Errorf("invalid fraction %s", want)
+			continue
+		}
+		n := max(x.Num().BitLen(), x.Denom().BitLen())
+
+		var f1, f2 Float
+		f2.SetPrec(1000)
+		f1.SetRat(&x)
+		f2.SetRat(&x)
+
+		// check precision when set automatically
+		if n < 64 {
+			n = 64
+		}
+		if prec := f1.Prec(); prec != uint(n) {
+			t.Errorf("got prec = %d; want %d", prec, n)
+		}
+
+		got := f2.Format('g', 100)
+		if got != want {
+			t.Errorf("got %s (%s); want %s", got, f2.Format('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetInf(t *testing.T) {
+	var f Float
+	for _, test := range []struct {
+		signbit bool
+		prec    uint
+		want    string
+	}{
+		{false, 0, "+Inf"},
+		{true, 0, "-Inf"},
+		{false, 10, "+Inf"},
+		{true, 30, "-Inf"},
+	} {
+		x := f.SetPrec(test.prec).SetInf(test.signbit)
+		if got := x.String(); got != test.want || x.Prec() != test.prec {
+			t.Errorf("SetInf(%v) = %s (prec = %d); want %s (prec = %d)", test.signbit, got, x.Prec(), test.want, test.prec)
+		}
+	}
+}
+
+func TestFloatUint64(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out uint64
+		acc Accuracy
+	}{
+		{"-Inf", 0, Above},
+		{"-1", 0, Above},
+		{"-1e-1000", 0, Above},
+		{"-0", 0, Exact},
+		{"0", 0, Exact},
+		{"1e-1000", 0, Below},
+		{"1", 1, Exact},
+		{"1.000000000000000000001", 1, Below},
+		{"12345.0", 12345, Exact},
+		{"12345.000000000000000000001", 12345, Below},
+		{"18446744073709551615", 18446744073709551615, Exact},
+		{"18446744073709551615.000000000000000000001", math.MaxUint64, Below},
+		{"18446744073709551616", math.MaxUint64, Below},
+		{"1e10000", math.MaxUint64, Below},
+		{"+Inf", math.MaxUint64, Below},
+	} {
+		x := makeFloat(test.x)
+		out, acc := x.Uint64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+		}
+	}
+}
+
+func TestFloatInt64(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out int64
+		acc Accuracy
+	}{
+		{"-Inf", math.MinInt64, Above},
+		{"-1e10000", math.MinInt64, Above},
+		{"-9223372036854775809", math.MinInt64, Above},
+		{"-9223372036854775808.000000000000000000001", math.MinInt64, Above},
+		{"-9223372036854775808", -9223372036854775808, Exact},
+		{"-9223372036854775807.000000000000000000001", -9223372036854775807, Above},
+		{"-9223372036854775807", -9223372036854775807, Exact},
+		{"-12345.000000000000000000001", -12345, Above},
+		{"-12345.0", -12345, Exact},
+		{"-1.000000000000000000001", -1, Above},
+		{"-1.5", -1, Above},
+		{"-1", -1, Exact},
+		{"-1e-1000", 0, Above},
+		{"0", 0, Exact},
+		{"1e-1000", 0, Below},
+		{"1", 1, Exact},
+		{"1.000000000000000000001", 1, Below},
+		{"1.5", 1, Below},
+		{"12345.0", 12345, Exact},
+		{"12345.000000000000000000001", 12345, Below},
+		{"9223372036854775807", 9223372036854775807, Exact},
+		{"9223372036854775807.000000000000000000001", math.MaxInt64, Below},
+		{"9223372036854775808", math.MaxInt64, Below},
+		{"1e10000", math.MaxInt64, Below},
+		{"+Inf", math.MaxInt64, Below},
+	} {
+		x := makeFloat(test.x)
+		out, acc := x.Int64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+		}
+	}
+}
+
+func TestFloatFloat32(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		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},
+		{"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
+		{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
+		{"+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)
+		}
+
+		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)
+		}
+
+		// 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)
+		}
+	}
+}
+
+func TestFloatFloat64(t *testing.T) {
+	const smallestNormalFloat64 = 2.2250738585072014e-308 // 1p-1022
+	for _, test := range []struct {
+		x   string
+		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},
+		{"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
+		{"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding
+		{"+Inf", math.Inf(+1), Exact},
+
+		// selected denormalized values that were handled incorrectly in the past
+		{"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
+		{"4503599627370495p-1074", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
+
+		// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+		{"2.2250738585072011e-308", 2.225073858507201e-308, Below},
+		// 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)
+		}
+
+		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)
+		}
+
+		// 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)
+		}
+	}
+}
+
+func TestFloatInt(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		want string
+		acc  Accuracy
+	}{
+		{"0", "0", Exact},
+		{"+0", "0", Exact},
+		{"-0", "0", Exact},
+		{"Inf", "nil", Below},
+		{"+Inf", "nil", Below},
+		{"-Inf", "nil", Above},
+		{"1", "1", Exact},
+		{"-1", "-1", Exact},
+		{"1.23", "1", Below},
+		{"-1.23", "-1", Above},
+		{"123e-2", "1", Below},
+		{"123e-3", "0", Below},
+		{"123e-4", "0", Below},
+		{"1e-1000", "0", Below},
+		{"-1e-1000", "0", Above},
+		{"1e+10", "10000000000", Exact},
+		{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
+	} {
+		x := makeFloat(test.x)
+		res, acc := x.Int(nil)
+		got := "nil"
+		if res != nil {
+			got = res.String()
+		}
+		if got != test.want || acc != test.acc {
+			t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc)
+		}
+	}
+
+	// check that supplied *Int is used
+	for _, f := range []string{"0", "1", "-1", "1234"} {
+		x := makeFloat(f)
+		i := new(Int)
+		if res, _ := x.Int(i); res != i {
+			t.Errorf("(%s).Int is not using supplied *Int", f)
+		}
+	}
+}
+
+func TestFloatRat(t *testing.T) {
+	for _, test := range []struct {
+		x, want string
+		acc     Accuracy
+	}{
+		{"0", "0/1", Exact},
+		{"+0", "0/1", Exact},
+		{"-0", "0/1", Exact},
+		{"Inf", "nil", Below},
+		{"+Inf", "nil", Below},
+		{"-Inf", "nil", Above},
+		{"1", "1/1", Exact},
+		{"-1", "-1/1", Exact},
+		{"1.25", "5/4", Exact},
+		{"-1.25", "-5/4", Exact},
+		{"1e10", "10000000000/1", Exact},
+		{"1p10", "1024/1", Exact},
+		{"-1p-10", "-1/1024", Exact},
+		{"3.14159265", "7244019449799623199/2305843009213693952", Exact},
+	} {
+		x := makeFloat(test.x).SetPrec(64)
+		res, acc := x.Rat(nil)
+		got := "nil"
+		if res != nil {
+			got = res.String()
+		}
+		if got != test.want {
+			t.Errorf("%s: got %s; want %s", test.x, got, test.want)
+			continue
+		}
+		if acc != test.acc {
+			t.Errorf("%s: got %s; want %s", test.x, acc, test.acc)
+			continue
+		}
+
+		// inverse conversion
+		if res != nil {
+			got := new(Float).SetPrec(64).SetRat(res)
+			if got.Cmp(x) != 0 {
+				t.Errorf("%s: got %s; want %s", test.x, got, x)
+			}
+		}
+	}
+
+	// check that supplied *Rat is used
+	for _, f := range []string{"0", "1", "-1", "1234"} {
+		x := makeFloat(f)
+		r := new(Rat)
+		if res, _ := x.Rat(r); res != r {
+			t.Errorf("(%s).Rat is not using supplied *Rat", f)
+		}
+	}
+}
+
+func TestFloatAbs(t *testing.T) {
+	for _, test := range []string{
+		"0",
+		"1",
+		"1234",
+		"1.23e-2",
+		"1e-1000",
+		"1e1000",
+		"Inf",
+	} {
+		p := makeFloat(test)
+		a := new(Float).Abs(p)
+		if !alike(a, p) {
+			t.Errorf("%s: got %s; want %s", test, a.Format('g', 10), test)
+		}
+
+		n := makeFloat("-" + test)
+		a.Abs(n)
+		if !alike(a, p) {
+			t.Errorf("-%s: got %s; want %s", test, a.Format('g', 10), test)
+		}
+	}
+}
+
+func TestFloatNeg(t *testing.T) {
+	for _, test := range []string{
+		"0",
+		"1",
+		"1234",
+		"1.23e-2",
+		"1e-1000",
+		"1e1000",
+		"Inf",
+	} {
+		p1 := makeFloat(test)
+		n1 := makeFloat("-" + test)
+		n2 := new(Float).Neg(p1)
+		p2 := new(Float).Neg(n2)
+		if !alike(n2, n1) {
+			t.Errorf("%s: got %s; want %s", test, n2.Format('g', 10), n1.Format('g', 10))
+		}
+		if !alike(p2, p1) {
+			t.Errorf("%s: got %s; want %s", test, p2.Format('g', 10), p1.Format('g', 10))
+		}
+	}
+}
+
+func TestFloatInc(t *testing.T) {
+	const n = 10
+	for _, prec := range precList {
+		if 1<<prec < n {
+			continue // prec must be large enough to hold all numbers from 0 to n
+		}
+		var x, one Float
+		x.SetPrec(prec)
+		one.SetInt64(1)
+		for i := 0; i < n; i++ {
+			x.Add(&x, &one)
+		}
+		if x.Cmp(new(Float).SetInt64(n)) != 0 {
+			t.Errorf("prec = %d: got %s; want %d", prec, &x, n)
+		}
+	}
+}
+
+// Selected precisions with which to run various tests.
+var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000}
+
+// Selected bits with which to run various tests.
+// Each entry is a list of bits representing a floating-point number (see fromBits).
+var bitsList = [...]Bits{
+	{},           // = 0
+	{0},          // = 1
+	{1},          // = 2
+	{-1},         // = 1/2
+	{10},         // = 2**10 == 1024
+	{-10},        // = 2**-10 == 1/1024
+	{100, 10, 1}, // = 2**100 + 2**10 + 2**1
+	{0, -1, -2, -10},
+	// TODO(gri) add more test cases
+}
+
+// TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual"
+// addition/subtraction of arguments represented by Bits values with the
+// respective Float addition/subtraction for a variety of precisions
+// and rounding modes.
+func TestFloatAdd(t *testing.T) {
+	for _, xbits := range bitsList {
+		for _, ybits := range bitsList {
+			// exact values
+			x := xbits.Float()
+			y := ybits.Float()
+			zbits := xbits.add(ybits)
+			z := zbits.Float()
+
+			for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+				for _, prec := range precList {
+					got := new(Float).SetPrec(prec).SetMode(mode)
+					got.Add(x, y)
+					want := zbits.round(prec, mode)
+					if got.Cmp(want) != 0 {
+						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t+    %s %v\n\t=    %s\n\twant %s",
+							i, prec, mode, x, xbits, y, ybits, got, want)
+					}
+
+					got.Sub(z, x)
+					want = ybits.round(prec, mode)
+					if got.Cmp(want) != 0 {
+						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t-    %s %v\n\t=    %s\n\twant %s",
+							i, prec, mode, z, zbits, x, xbits, got, want)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatAdd32 tests that Float.Add/Sub of numbers with
+// 24bit mantissa behaves like float32 addition/subtraction
+// (excluding denormal numbers).
+func TestFloatAdd32(t *testing.T) {
+	// chose base such that we cross the mantissa precision limit
+	const base = 1<<26 - 0x10 // 11...110000 (26 bits)
+	for d := 0; d <= 0x10; d++ {
+		for i := range [2]int{} {
+			x0, y0 := float64(base), float64(d)
+			if i&1 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(24)
+
+			z.Add(x, y)
+			got, acc := z.Float32()
+			want := float32(y0) + float32(x0)
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
+			}
+
+			z.Sub(z, y)
+			got, acc = z.Float32()
+			want = float32(want) - float32(y0)
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
+			}
+		}
+	}
+}
+
+// TestFloatAdd64 tests that Float.Add/Sub of numbers with
+// 53bit mantissa behaves like float64 addition/subtraction.
+func TestFloatAdd64(t *testing.T) {
+	// chose base such that we cross the mantissa precision limit
+	const base = 1<<55 - 0x10 // 11...110000 (55 bits)
+	for d := 0; d <= 0x10; d++ {
+		for i := range [2]int{} {
+			x0, y0 := float64(base), float64(d)
+			if i&1 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(53)
+
+			z.Add(x, y)
+			got, acc := z.Float64()
+			want := x0 + y0
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
+			}
+
+			z.Sub(z, y)
+			got, acc = z.Float64()
+			want -= y0
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
+			}
+		}
+	}
+}
+
+// TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
+// multiplication/division of arguments represented by Bits values with the
+// respective Float multiplication/division for a variety of precisions
+// and rounding modes.
+func TestFloatMul(t *testing.T) {
+	for _, xbits := range bitsList {
+		for _, ybits := range bitsList {
+			// exact values
+			x := xbits.Float()
+			y := ybits.Float()
+			zbits := xbits.mul(ybits)
+			z := zbits.Float()
+
+			for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+				for _, prec := range precList {
+					got := new(Float).SetPrec(prec).SetMode(mode)
+					got.Mul(x, y)
+					want := zbits.round(prec, mode)
+					if got.Cmp(want) != 0 {
+						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t*    %s %v\n\t=    %s\n\twant %s",
+							i, prec, mode, x, xbits, y, ybits, got, want)
+					}
+
+					if x.Sign() == 0 {
+						continue // ignore div-0 case (not invertable)
+					}
+					got.Quo(z, x)
+					want = ybits.round(prec, mode)
+					if got.Cmp(want) != 0 {
+						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t/    %s %v\n\t=    %s\n\twant %s",
+							i, prec, mode, z, zbits, x, xbits, got, want)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatMul64 tests that Float.Mul/Quo of numbers with
+// 53bit mantissa behaves like float64 multiplication/division.
+func TestFloatMul64(t *testing.T) {
+	for _, test := range []struct {
+		x, y float64
+	}{
+		{0, 0},
+		{0, 1},
+		{1, 1},
+		{1, 1.5},
+		{1.234, 0.5678},
+		{2.718281828, 3.14159265358979},
+		{2.718281828e10, 3.14159265358979e-32},
+		{1.0 / 3, 1e200},
+	} {
+		for i := range [8]int{} {
+			x0, y0 := test.x, test.y
+			if i&1 != 0 {
+				x0 = -x0
+			}
+			if i&2 != 0 {
+				y0 = -y0
+			}
+			if i&4 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(53)
+
+			z.Mul(x, y)
+			got, _ := z.Float64()
+			want := x0 * y0
+			if got != want {
+				t.Errorf("%g * %g = %g; want %g", x0, y0, got, want)
+			}
+
+			if y0 == 0 {
+				continue // avoid division-by-zero
+			}
+			z.Quo(z, y)
+			got, _ = z.Float64()
+			want /= y0
+			if got != want {
+				t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want)
+			}
+		}
+	}
+}
+
+func TestIssue6866(t *testing.T) {
+	for _, prec := range precList {
+		two := new(Float).SetPrec(prec).SetInt64(2)
+		one := new(Float).SetPrec(prec).SetInt64(1)
+		three := new(Float).SetPrec(prec).SetInt64(3)
+		msix := new(Float).SetPrec(prec).SetInt64(-6)
+		psix := new(Float).SetPrec(prec).SetInt64(+6)
+
+		p := new(Float).SetPrec(prec)
+		z1 := new(Float).SetPrec(prec)
+		z2 := new(Float).SetPrec(prec)
+
+		// z1 = 2 + 1.0/3*-6
+		p.Quo(one, three)
+		p.Mul(p, msix)
+		z1.Add(two, p)
+
+		// z2 = 2 - 1.0/3*+6
+		p.Quo(one, three)
+		p.Mul(p, psix)
+		z2.Sub(two, p)
+
+		if z1.Cmp(z2) != 0 {
+			t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2)
+		}
+		if z1.Sign() != 0 {
+			t.Errorf("prec %d: got z1 = %s; want 0", prec, z1)
+		}
+		if z2.Sign() != 0 {
+			t.Errorf("prec %d: got z2 = %s; want 0", prec, z2)
+		}
+	}
+}
+
+func TestFloatQuo(t *testing.T) {
+	// TODO(gri) make the test vary these precisions
+	preci := 200 // precision of integer part
+	precf := 20  // precision of fractional part
+
+	for i := 0; i < 8; i++ {
+		// compute accurate (not rounded) result z
+		bits := Bits{preci - 1}
+		if i&3 != 0 {
+			bits = append(bits, 0)
+		}
+		if i&2 != 0 {
+			bits = append(bits, -1)
+		}
+		if i&1 != 0 {
+			bits = append(bits, -precf)
+		}
+		z := bits.Float()
+
+		// compute accurate x as z*y
+		y := NewFloat(3.14159265358979323e123)
+
+		x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero)
+		x.Mul(z, y)
+
+		// leave for debugging
+		// fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z)
+
+		if got := x.Acc(); got != Exact {
+			t.Errorf("got acc = %s; want exact", got)
+		}
+
+		// round accurate z for a variety of precisions and
+		// modes and compare against result of x / y.
+		for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+			for d := -5; d < 5; d++ {
+				prec := uint(preci + d)
+				got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y)
+				want := bits.round(prec, mode)
+				if got.Cmp(want) != 0 {
+					t.Errorf("i = %d, prec = %d, %s:\n\t     %s\n\t/    %s\n\t=    %s\n\twant %s",
+						i, prec, mode, x, y, got, want)
+				}
+			}
+		}
+	}
+}
+
+// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
+// it serves as a smoke test for basic correctness of division.
+func TestFloatQuoSmoke(t *testing.T) {
+	n := 1000
+	if testing.Short() {
+		n = 10
+	}
+
+	const dprec = 3         // max. precision variation
+	const prec = 10 + dprec // enough bits to hold n precisely
+	for x := -n; x <= n; x++ {
+		for y := -n; y < n; y++ {
+			if y == 0 {
+				continue
+			}
+
+			a := float64(x)
+			b := float64(y)
+			c := a / b
+
+			// vary operand precision (only ok as long as a, b can be represented correctly)
+			for ad := -dprec; ad <= dprec; ad++ {
+				for bd := -dprec; bd <= dprec; bd++ {
+					A := new(Float).SetPrec(uint(prec + ad)).SetFloat64(a)
+					B := new(Float).SetPrec(uint(prec + bd)).SetFloat64(b)
+					C := new(Float).SetPrec(53).Quo(A, B) // C has float64 mantissa width
+
+					cc, acc := C.Float64()
+					if cc != c {
+						t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Format('g', 5), c)
+						continue
+					}
+					if acc != Exact {
+						t.Errorf("%g/%g got %s result; want exact result", a, b, acc)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatArithmeticSpecialValues tests that Float operations produce the
+// correct results for combinations of zero (±0), finite (±1 and ±2.71828),
+// and infinite (±Inf) operands.
+func TestFloatArithmeticSpecialValues(t *testing.T) {
+	zero := 0.0
+	args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
+	xx := new(Float)
+	yy := new(Float)
+	got := new(Float)
+	want := new(Float)
+	for i := 0; i < 4; i++ {
+		for _, x := range args {
+			xx.SetFloat64(x)
+			// check conversion is correct
+			// (no need to do this for y, since we see exactly the
+			// same values there)
+			if got, acc := xx.Float64(); got != x || acc != Exact {
+				t.Errorf("Float(%g) == %g (%s)", x, got, acc)
+			}
+			for _, y := range args {
+				yy.SetFloat64(y)
+				var (
+					op string
+					z  float64
+					f  func(z, x, y *Float) *Float
+				)
+				switch i {
+				case 0:
+					op = "+"
+					z = x + y
+					f = (*Float).Add
+				case 1:
+					op = "-"
+					z = x - y
+					f = (*Float).Sub
+				case 2:
+					op = "*"
+					z = x * y
+					f = (*Float).Mul
+				case 3:
+					op = "/"
+					z = x / y
+					f = (*Float).Quo
+				default:
+					panic("unreachable")
+				}
+				var errnan bool // set if execution of f panicked with ErrNaN
+				// protect execution of f
+				func() {
+					defer func() {
+						if p := recover(); p != nil {
+							_ = p.(ErrNaN) // re-panic if not ErrNaN
+							errnan = true
+						}
+					}()
+					f(got, xx, yy)
+				}()
+				if math.IsNaN(z) {
+					if !errnan {
+						t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got)
+					}
+					continue
+				}
+				if errnan {
+					t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want)
+					continue
+				}
+				want.SetFloat64(z)
+				if !alike(got, want) {
+					t.Errorf("%5g %s %5g = %5s; want %5s", x, op, y, got, want)
+				}
+			}
+		}
+	}
+}
+
+func TestFloatArithmeticOverflow(t *testing.T) {
+	for _, test := range []struct {
+		prec       uint
+		mode       RoundingMode
+		op         byte
+		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", "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, 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, 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, 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, '*', "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-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 /
+	} {
+		x := makeFloat(test.x)
+		y := makeFloat(test.y)
+		z := new(Float).SetPrec(test.prec).SetMode(test.mode)
+		switch test.op {
+		case '+':
+			z.Add(x, y)
+		case '-':
+			z.Sub(x, y)
+		case '*':
+			z.Mul(x, y)
+		case '/':
+			z.Quo(x, y)
+		default:
+			panic("unreachable")
+		}
+		if got := z.Format('p', 0); got != test.want || z.Acc() != test.acc {
+			t.Errorf(
+				"prec = %d (%s): %s %c %s = %s (%s); want %s (%s)",
+				test.prec, test.mode, x.Format('p', 0), test.op, y.Format('p', 0), got, z.Acc(), test.want, test.acc,
+			)
+		}
+	}
+}
+
+// TODO(gri) Add tests that check correctness in the presence of aliasing.
+
+// For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected
+// by the sign of the value to be rounded. Test that rounding happens after
+// the sign of a result has been set.
+// This test uses specific values that are known to fail if rounding is
+// "factored" out before setting the result sign.
+func TestFloatArithmeticRounding(t *testing.T) {
+	for _, test := range []struct {
+		mode       RoundingMode
+		prec       uint
+		x, y, want int64
+		op         byte
+	}{
+		{ToZero, 3, -0x8, -0x1, -0x8, '+'},
+		{AwayFromZero, 3, -0x8, -0x1, -0xa, '+'},
+		{ToNegativeInf, 3, -0x8, -0x1, -0xa, '+'},
+
+		{ToZero, 3, -0x8, 0x1, -0x8, '-'},
+		{AwayFromZero, 3, -0x8, 0x1, -0xa, '-'},
+		{ToNegativeInf, 3, -0x8, 0x1, -0xa, '-'},
+
+		{ToZero, 3, -0x9, 0x1, -0x8, '*'},
+		{AwayFromZero, 3, -0x9, 0x1, -0xa, '*'},
+		{ToNegativeInf, 3, -0x9, 0x1, -0xa, '*'},
+
+		{ToZero, 3, -0x9, 0x1, -0x8, '/'},
+		{AwayFromZero, 3, -0x9, 0x1, -0xa, '/'},
+		{ToNegativeInf, 3, -0x9, 0x1, -0xa, '/'},
+	} {
+		var x, y, z Float
+		x.SetInt64(test.x)
+		y.SetInt64(test.y)
+		z.SetPrec(test.prec).SetMode(test.mode)
+		switch test.op {
+		case '+':
+			z.Add(&x, &y)
+		case '-':
+			z.Sub(&x, &y)
+		case '*':
+			z.Mul(&x, &y)
+		case '/':
+			z.Quo(&x, &y)
+		default:
+			panic("unreachable")
+		}
+		if got, acc := z.Int64(); got != test.want || acc != Exact {
+			t.Errorf("%s, %d bits: %d %c %d = %d (%s); want %d (Exact)",
+				test.mode, test.prec, test.x, test.op, test.y, got, acc, test.want,
+			)
+		}
+	}
+}
+
+// TestFloatCmpSpecialValues tests that Cmp produces the correct results for
+// combinations of zero (±0), finite (±1 and ±2.71828), and infinite (±Inf)
+// operands.
+func TestFloatCmpSpecialValues(t *testing.T) {
+	zero := 0.0
+	args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
+	xx := new(Float)
+	yy := new(Float)
+	for i := 0; i < 4; i++ {
+		for _, x := range args {
+			xx.SetFloat64(x)
+			// check conversion is correct
+			// (no need to do this for y, since we see exactly the
+			// same values there)
+			if got, acc := xx.Float64(); got != x || acc != Exact {
+				t.Errorf("Float(%g) == %g (%s)", x, got, acc)
+			}
+			for _, y := range args {
+				yy.SetFloat64(y)
+				got := xx.Cmp(yy)
+				want := 0
+				switch {
+				case x < y:
+					want = -1
+				case x > y:
+					want = +1
+				}
+				if got != want {
+					t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/floatconv.go b/src/cmd/internal/gc/big/floatconv.go
new file mode 100644
index 0000000..b929d12
--- /dev/null
+++ b/src/cmd/internal/gc/big/floatconv.go
@@ -0,0 +1,373 @@
+// 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.
+
+// This file implements float-to-string conversion functions.
+
+package big
+
+import (
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s must be a floating-point number of the same format as accepted
+// by Scan, with number prefixes permitted.
+func (z *Float) SetString(s string) (*Float, bool) {
+	r := strings.NewReader(s)
+
+	f, _, err := z.Scan(r, 0)
+	if err != nil {
+		return nil, false
+	}
+
+	// there should be no unread characters left
+	if _, err = r.ReadByte(); err != io.EOF {
+		return nil, false
+	}
+
+	return f, true
+}
+
+// Scan scans the number corresponding to the longest possible prefix
+// of r representing a floating-point number with a mantissa in the
+// given conversion base (the exponent is always a decimal number).
+// It sets z to the (possibly rounded) value of the corresponding
+// floating-point number, and returns z, the actual base b, and an
+// error err, if any. If z's precision is 0, it is changed to 64
+// before rounding takes effect. The number must be of the form:
+//
+//	number   = [ sign ] [ prefix ] mantissa [ exponent ] .
+//	sign     = "+" | "-" .
+//      prefix   = "0" ( "x" | "X" | "b" | "B" ) .
+//	mantissa = digits | digits "." [ digits ] | "." digits .
+//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// The base argument must be 0, 2, 10, or 16. Providing an invalid base
+// argument will lead to a run-time panic.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects
+// base 2; otherwise, the actual base is 10 and no prefix is accepted.
+// The octal prefix "0" is not supported (a leading "0" is simply
+// considered a "0").
+//
+// A "p" exponent indicates a binary (rather then decimal) exponent;
+// for instance "0x1.fffffffffffffp1023" (using base 0) represents the
+// maximum float64 value. For hexadecimal mantissae, the exponent must
+// be binary, if present (an "e" or "E" exponent indicator cannot be
+// distinguished from a mantissa digit).
+//
+// The returned *Float f is nil and the value of z is valid but not
+// defined if an error is reported.
+//
+// BUG(gri) The Float.Scan signature conflicts with Scan(s fmt.ScanState, ch rune) error.
+func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
+	prec := z.prec
+	if prec == 0 {
+		prec = 64
+	}
+
+	// A reasonable value in case of an error.
+	z.form = zero
+
+	// sign
+	z.neg, err = scanSign(r)
+	if err != nil {
+		return
+	}
+
+	// mantissa
+	var fcount int // fractional digit count; valid if <= 0
+	z.mant, b, fcount, err = z.mant.scan(r, base, true)
+	if err != nil {
+		return
+	}
+
+	// exponent
+	var exp int64
+	var ebase int
+	exp, ebase, err = scanExponent(r, true)
+	if err != nil {
+		return
+	}
+
+	// special-case 0
+	if len(z.mant) == 0 {
+		z.prec = prec
+		z.acc = Exact
+		z.form = zero
+		f = z
+		return
+	}
+	// len(z.mant) > 0
+
+	// The mantissa may have a decimal point (fcount <= 0) and there
+	// may be a nonzero exponent exp. The decimal point amounts to a
+	// division by b**(-fcount). An exponent means multiplication by
+	// ebase**exp. Finally, mantissa normalization (shift left) requires
+	// a correcting multiplication by 2**(-shiftcount). Multiplications
+	// are commutative, so we can apply them in any order as long as there
+	// is no loss of precision. We only have powers of 2 and 10; keep
+	// track via separate exponents exp2 and exp10.
+
+	// normalize mantissa and get initial binary exponent
+	var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
+
+	// determine binary or decimal exponent contribution of decimal point
+	var exp10 int64
+	if fcount < 0 {
+		// The mantissa has a "decimal" point ddd.dddd; and
+		// -fcount is the number of digits to the right of '.'.
+		// Adjust relevant exponent accodingly.
+		switch b {
+		case 16:
+			fcount *= 4 // hexadecimal digits are 4 bits each
+			fallthrough
+		case 2:
+			exp2 += int64(fcount)
+		default: // b == 10
+			exp10 = int64(fcount)
+		}
+		// we don't need fcount anymore
+	}
+
+	// take actual exponent into account
+	if ebase == 2 {
+		exp2 += exp
+	} else { // ebase == 10
+		exp10 += exp
+	}
+	// we don't need exp anymore
+
+	// apply 2**exp2
+	if MinExp <= exp2 && exp2 <= MaxExp {
+		z.prec = prec
+		z.form = finite
+		z.exp = int32(exp2)
+		f = z
+	} else {
+		err = fmt.Errorf("exponent overflow")
+		return
+	}
+
+	if exp10 == 0 {
+		// no decimal exponent to consider
+		z.round(0)
+		return
+	}
+	// exp10 != 0
+
+	// apply 10**exp10
+	p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
+	if exp10 < 0 {
+		z.uquo(z, p.pow10(-exp10))
+	} else {
+		z.umul(z, p.pow10(exp10))
+	}
+
+	return
+}
+
+// These powers of 10 can be represented exactly as a float64.
+var pow10tab = [...]float64{
+	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// pow10 sets z to 10**n and returns z.
+// n must not be negative.
+func (z *Float) pow10(n int64) *Float {
+	if n < 0 {
+		panic("pow10 called with negative argument")
+	}
+
+	const m = int64(len(pow10tab) - 1)
+	if n <= m {
+		return z.SetFloat64(pow10tab[n])
+	}
+	// n > m
+
+	z.SetFloat64(pow10tab[m])
+	n -= m
+
+	// use more bits for f than for z
+	// TODO(gri) what is the right number?
+	f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
+
+	for n > 0 {
+		if n&1 != 0 {
+			z.Mul(z, f)
+		}
+		f.Mul(f, f)
+		n >>= 1
+	}
+
+	return z
+}
+
+// Parse is like z.Scan(r, base), but instead of reading from an
+// io.ByteScanner, it parses the string s. An error is also returned
+// if the string contains invalid or trailing bytes not belonging to
+// the number.
+func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
+	r := strings.NewReader(s)
+
+	if f, b, err = z.Scan(r, base); err != nil {
+		return
+	}
+
+	// entire string must have been consumed
+	if ch, err2 := r.ReadByte(); err2 == nil {
+		err = fmt.Errorf("expected end of string, found %q", ch)
+	} else if err2 != io.EOF {
+		err = err2
+	}
+
+	return
+}
+
+// ScanFloat is like f.Scan(r, base) with f set to the given precision
+// and rounding mode.
+func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+	return new(Float).SetPrec(prec).SetMode(mode).Scan(r, base)
+}
+
+// ParseFloat is like f.Parse(s, base) with f set to the given precision
+// and rounding mode.
+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/cmd/internal/gc/big/floatconv_test.go b/src/cmd/internal/gc/big/floatconv_test.go
new file mode 100644
index 0000000..96c01ee
--- /dev/null
+++ b/src/cmd/internal/gc/big/floatconv_test.go
@@ -0,0 +1,397 @@
+// 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 big
+
+import (
+	"math"
+	"strconv"
+	"testing"
+)
+
+func TestFloatSetFloat64String(t *testing.T) {
+	for _, test := range []struct {
+		s string
+		x float64
+	}{
+		// basics
+		{"0", 0},
+		{"-0", -0},
+		{"+0", 0},
+		{"1", 1},
+		{"-1", -1},
+		{"+1", 1},
+		{"1.234", 1.234},
+		{"-1.234", -1.234},
+		{"+1.234", 1.234},
+		{".1", 0.1},
+		{"1.", 1},
+		{"+1.", 1},
+
+		// various zeros
+		{"0e100", 0},
+		{"-0e+100", 0},
+		{"+0e-100", 0},
+		{"0E100", 0},
+		{"-0E+100", 0},
+		{"+0E-100", 0},
+
+		// various decimal exponent formats
+		{"1.e10", 1e10},
+		{"1e+10", 1e10},
+		{"+1e-10", 1e-10},
+		{"1E10", 1e10},
+		{"1.E+10", 1e10},
+		{"+1E-10", 1e-10},
+
+		// misc decimal values
+		{"3.14159265", 3.14159265},
+		{"-687436.79457e-245", -687436.79457e-245},
+		{"-687436.79457E245", -687436.79457e245},
+		{".0000000000000000000000000000000000000001", 1e-40},
+		{"+10000000000000000000000000000000000000000e-0", 1e40},
+
+		// decimal mantissa, binary exponent
+		{"0p0", 0},
+		{"-0p0", -0},
+		{"1p10", 1 << 10},
+		{"1p+10", 1 << 10},
+		{"+1p-10", 1.0 / (1 << 10)},
+		{"1024p-12", 0.25},
+		{"-1p10", -1024},
+		{"1.5p1", 3},
+
+		// binary mantissa, decimal exponent
+		{"0b0", 0},
+		{"-0b0", -0},
+		{"0b0e+10", 0},
+		{"-0b0e-10", -0},
+		{"0b1010", 10},
+		{"0B1010E2", 1000},
+		{"0b.1", 0.5},
+		{"0b.001", 0.125},
+		{"0b.001e3", 125},
+
+		// binary mantissa, binary exponent
+		{"0b0p+10", 0},
+		{"-0b0p-10", -0},
+		{"0b.1010p4", 10},
+		{"0b1p-1", 0.5},
+		{"0b001p-3", 0.125},
+		{"0b.001p3", 1},
+		{"0b0.01p2", 1},
+
+		// hexadecimal mantissa and exponent
+		{"0x0", 0},
+		{"-0x0", -0},
+		{"0x0p+10", 0},
+		{"-0x0p-10", -0},
+		{"0xff", 255},
+		{"0X.8p1", 1},
+		{"-0X0.00008p16", -0.5},
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64},
+		{"0x1.fffffffffffffp1023", math.MaxFloat64},
+	} {
+		var x Float
+		x.SetPrec(53)
+		_, ok := x.SetString(test.s)
+		if !ok {
+			t.Errorf("%s: parse error", test.s)
+			continue
+		}
+		f, _ := x.Float64()
+		want := new(Float).SetFloat64(test.x)
+		if x.Cmp(want) != 0 {
+			t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
+		}
+	}
+}
+
+const (
+	below1e23 = 99999999999999974834176
+	above1e23 = 100000000000000008388608
+)
+
+func TestFloat64Format(t *testing.T) {
+	for _, test := range []struct {
+		x      float64
+		format byte
+		prec   int
+		want   string
+	}{
+		{0, 'f', 0, "0"},
+		{math.Copysign(0, -1), 'f', 0, "-0"},
+		{1, 'f', 0, "1"},
+		{-1, 'f', 0, "-1"},
+
+		{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"},
+
+		{1.459, 'f', 0, "1"},
+		{2.459, 'f', 1, "2.5"},
+		{3.459, 'f', 2, "3.46"},
+		{4.459, 'f', 3, "4.459"},
+		{5.459, 'f', 4, "5.4590"},
+
+		{0, 'b', 0, "0"},
+		{math.Copysign(0, -1), 'b', 0, "-0"},
+		{1.0, 'b', 0, "4503599627370496p-52"},
+		{-1.0, 'b', 0, "-4503599627370496p-52"},
+		{4503599627370496, 'b', 0, "4503599627370496p+0"},
+
+		{0, 'p', 0, "0"},
+		{math.Copysign(0, -1), 'p', 0, "-0"},
+		{1024.0, 'p', 0, "0x.8p11"},
+		{-1024.0, 'p', 0, "-0x.8p11"},
+
+		// all test cases below from strconv/ftoa_test.go
+		{1, 'e', 5, "1.00000e+00"},
+		{1, 'f', 5, "1.00000"},
+		{1, 'g', 5, "1"},
+		// {1, 'g', -1, "1"},
+		// {20, 'g', -1, "20"},
+		// {1234567.8, 'g', -1, "1.2345678e+06"},
+		// {200000, 'g', -1, "200000"},
+		// {2000000, 'g', -1, "2e+06"},
+
+		// g conversion and zero suppression
+		{400, 'g', 2, "4e+02"},
+		{40, 'g', 2, "40"},
+		{4, 'g', 2, "4"},
+		{.4, 'g', 2, "0.4"},
+		{.04, 'g', 2, "0.04"},
+		{.004, 'g', 2, "0.004"},
+		{.0004, 'g', 2, "0.0004"},
+		{.00004, 'g', 2, "4e-05"},
+		{.000004, 'g', 2, "4e-06"},
+
+		{0, 'e', 5, "0.00000e+00"},
+		{0, 'f', 5, "0.00000"},
+		{0, 'g', 5, "0"},
+		// {0, 'g', -1, "0"},
+
+		{-1, 'e', 5, "-1.00000e+00"},
+		{-1, 'f', 5, "-1.00000"},
+		{-1, 'g', 5, "-1"},
+		// {-1, 'g', -1, "-1"},
+
+		{12, 'e', 5, "1.20000e+01"},
+		{12, 'f', 5, "12.00000"},
+		{12, 'g', 5, "12"},
+		// {12, 'g', -1, "12"},
+
+		{123456700, 'e', 5, "1.23457e+08"},
+		{123456700, 'f', 5, "123456700.00000"},
+		{123456700, 'g', 5, "1.2346e+08"},
+		// {123456700, 'g', -1, "1.234567e+08"},
+
+		{1.2345e6, 'e', 5, "1.23450e+06"},
+		{1.2345e6, 'f', 5, "1234500.00000"},
+		{1.2345e6, 'g', 5, "1.2345e+06"},
+
+		{1e23, 'e', 17, "9.99999999999999916e+22"},
+		{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+		{1e23, 'g', 17, "9.9999999999999992e+22"},
+
+		// {1e23, 'e', -1, "1e+23"},
+		// {1e23, 'f', -1, "100000000000000000000000"},
+		// {1e23, 'g', -1, "1e+23"},
+
+		{below1e23, 'e', 17, "9.99999999999999748e+22"},
+		{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+		{below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+		// {below1e23, 'e', -1, "9.999999999999997e+22"},
+		// {below1e23, 'f', -1, "99999999999999970000000"},
+		// {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+		{above1e23, 'e', 17, "1.00000000000000008e+23"},
+		{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+		// {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+		// {above1e23, 'e', -1, "1.0000000000000001e+23"},
+		// {above1e23, 'f', -1, "100000000000000010000000"},
+		// {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+		// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+		// {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+		// {32, 'g', -1, "32"},
+		// {32, 'g', 0, "3e+01"},
+
+		// {100, 'x', -1, "%x"},
+
+		// {math.NaN(), 'g', -1, "NaN"},
+		// {-math.NaN(), 'g', -1, "NaN"},
+		{math.Inf(0), 'g', -1, "+Inf"},
+		{math.Inf(-1), 'g', -1, "-Inf"},
+		{-math.Inf(0), 'g', -1, "-Inf"},
+
+		{-1, 'b', -1, "-4503599627370496p-52"},
+
+		// fixed bugs
+		{0.9, 'f', 1, "0.9"},
+		{0.09, 'f', 1, "0.1"},
+		{0.0999, 'f', 1, "0.1"},
+		{0.05, 'f', 1, "0.1"},
+		{0.05, 'f', 0, "0"},
+		{0.5, 'f', 1, "0.5"},
+		{0.5, 'f', 0, "0"},
+		{1.5, 'f', 0, "2"},
+
+		// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+		// {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
+		// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+		// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+
+		// Issue 2625.
+		{383260575764816448, 'f', 0, "383260575764816448"},
+		// {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+	} {
+		f := new(Float).SetFloat64(test.x)
+		got := f.Format(test.format, test.prec)
+		if got != test.want {
+			t.Errorf("%v: got %s; want %s", test, got, test.want)
+		}
+
+		if test.format == 'b' && test.x == 0 {
+			continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
+		}
+		if test.format == 'p' {
+			continue // 'p' format not supported in strconv.Format
+		}
+
+		// verify that Float format matches strconv format
+		want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
+		if got != want {
+			t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
+		}
+	}
+}
+
+func TestFloatFormat(t *testing.T) {
+	for _, test := range []struct {
+		x      string
+		prec   uint
+		format byte
+		digits int
+		want   string
+	}{
+		{"0", 10, 'f', 0, "0"},
+		{"-0", 10, 'f', 0, "-0"},
+		{"1", 10, 'f', 0, "1"},
+		{"-1", 10, 'f', 0, "-1"},
+
+		{"1.459", 100, 'e', 0, "1e+00"},
+		{"2.459", 100, 'e', 1, "2.5e+00"},
+		{"3.459", 100, 'e', 2, "3.46e+00"},
+		{"4.459", 100, 'e', 3, "4.459e+00"},
+		{"5.459", 100, 'e', 4, "5.4590e+00"},
+
+		{"1.459", 100, 'E', 0, "1E+00"},
+		{"2.459", 100, 'E', 1, "2.5E+00"},
+		{"3.459", 100, 'E', 2, "3.46E+00"},
+		{"4.459", 100, 'E', 3, "4.459E+00"},
+		{"5.459", 100, 'E', 4, "5.4590E+00"},
+
+		{"1.459", 100, 'f', 0, "1"},
+		{"2.459", 100, 'f', 1, "2.5"},
+		{"3.459", 100, 'f', 2, "3.46"},
+		{"4.459", 100, 'f', 3, "4.459"},
+		{"5.459", 100, 'f', 4, "5.4590"},
+
+		{"1.459", 100, 'g', 0, "1"},
+		{"2.459", 100, 'g', 1, "2"},
+		{"3.459", 100, 'g', 2, "3.5"},
+		{"4.459", 100, 'g', 3, "4.46"},
+		{"5.459", 100, 'g', 4, "5.459"},
+
+		{"1459", 53, 'g', 0, "1e+03"},
+		{"2459", 53, 'g', 1, "2e+03"},
+		{"3459", 53, 'g', 2, "3.5e+03"},
+		{"4459", 53, 'g', 3, "4.46e+03"},
+		{"5459", 53, 'g', 4, "5459"},
+
+		{"1459", 53, 'G', 0, "1E+03"},
+		{"2459", 53, 'G', 1, "2E+03"},
+		{"3459", 53, 'G', 2, "3.5E+03"},
+		{"4459", 53, 'G', 3, "4.46E+03"},
+		{"5459", 53, 'G', 4, "5459"},
+
+		{"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
+		{"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
+		{"3", 10, 'g', 40, "3"},
+
+		{"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
+		{"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
+		{"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"},
+		{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
+		{"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"},
+
+		// TODO(gri) need tests for actual large Floats
+
+		{"0", 53, 'b', 0, "0"},
+		{"-0", 53, 'b', 0, "-0"},
+		{"1.0", 53, 'b', 0, "4503599627370496p-52"},
+		{"-1.0", 53, 'b', 0, "-4503599627370496p-52"},
+		{"4503599627370496", 53, 'b', 0, "4503599627370496p+0"},
+
+		// issue 9939
+		{"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"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"},
+
+		{"0", 64, 'p', 0, "0"},
+		{"-0", 64, 'p', 0, "-0"},
+		{"1024.0", 64, 'p', 0, "0x.8p11"},
+		{"-1024.0", 64, 'p', 0, "-0x.8p11"},
+
+		// unsupported format
+		{"3.14", 64, 'x', 0, "%x"},
+	} {
+		f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
+		if err != nil {
+			t.Errorf("%v: %s", test, err)
+			continue
+		}
+
+		got := f.Format(test.format, test.digits)
+		if got != test.want {
+			t.Errorf("%v: got %s; want %s", test, got, test.want)
+		}
+
+		// compare with strconv.FormatFloat output if possible
+		// ('p' format is not supported by strconv.FormatFloat,
+		// and its output for 0.0 prints a biased exponent value
+		// as in 0p-1074 which makes no sense to emulate here)
+		if test.prec == 53 && test.format != 'p' && f.Sign() != 0 {
+			f64, acc := f.Float64()
+			if acc != Exact {
+				t.Errorf("%v: expected exact conversion to float64", test)
+				continue
+			}
+			got := strconv.FormatFloat(f64, test.format, test.digits, 64)
+			if got != test.want {
+				t.Errorf("%v: got %s; want %s", test, got, test.want)
+			}
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/floatexample_test.go b/src/cmd/internal/gc/big/floatexample_test.go
new file mode 100644
index 0000000..7db1023
--- /dev/null
+++ b/src/cmd/internal/gc/big/floatexample_test.go
@@ -0,0 +1,111 @@
+// 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 big_test
+
+import (
+	"fmt"
+	"math"
+	"math/big"
+)
+
+func ExampleFloat_Add() {
+	// Operating on numbers of different precision.
+	var x, y, z big.Float
+	x.SetInt64(1000)          // x is automatically set to 64bit precision
+	y.SetFloat64(2.718281828) // y is automatically set to 53bit precision
+	z.SetPrec(32)
+	z.Add(&x, &y)
+	fmt.Printf("x = %s (%s, prec = %d, acc = %s)\n", &x, x.Format('p', 0), x.Prec(), x.Acc())
+	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)
+}
+
+func Example_Shift() {
+	// Implementing Float "shift" by modifying the (binary) exponents directly.
+	for s := -5; s <= 5; s++ {
+		x := big.NewFloat(0.5)
+		x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s
+		fmt.Println(x)
+	}
+	// Output:
+	// 0.015625
+	// 0.03125
+	// 0.0625
+	// 0.125
+	// 0.25
+	// 0.5
+	// 1
+	// 2
+	// 4
+	// 8
+	// 16
+}
+
+func ExampleFloat_Cmp() {
+	inf := math.Inf(1)
+	zero := 0.0
+
+	operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf}
+
+	fmt.Println("   x     y  cmp")
+	fmt.Println("---------------")
+	for _, x64 := range operands {
+		x := big.NewFloat(x64)
+		for _, y64 := range operands {
+			y := big.NewFloat(y64)
+			fmt.Printf("%4s  %4s  %3d\n", x, y, x.Cmp(y))
+		}
+		fmt.Println()
+	}
+
+	// Output:
+	//    x     y  cmp
+	// ---------------
+	// -Inf  -Inf    0
+	// -Inf  -1.2   -1
+	// -Inf    -0   -1
+	// -Inf     0   -1
+	// -Inf   1.2   -1
+	// -Inf  +Inf   -1
+	//
+	// -1.2  -Inf    1
+	// -1.2  -1.2    0
+	// -1.2    -0   -1
+	// -1.2     0   -1
+	// -1.2   1.2   -1
+	// -1.2  +Inf   -1
+	//
+	//   -0  -Inf    1
+	//   -0  -1.2    1
+	//   -0    -0    0
+	//   -0     0    0
+	//   -0   1.2   -1
+	//   -0  +Inf   -1
+	//
+	//    0  -Inf    1
+	//    0  -1.2    1
+	//    0    -0    0
+	//    0     0    0
+	//    0   1.2   -1
+	//    0  +Inf   -1
+	//
+	//  1.2  -Inf    1
+	//  1.2  -1.2    1
+	//  1.2    -0    1
+	//  1.2     0    1
+	//  1.2   1.2    0
+	//  1.2  +Inf   -1
+	//
+	// +Inf  -Inf    1
+	// +Inf  -1.2    1
+	// +Inf    -0    1
+	// +Inf     0    1
+	// +Inf   1.2    1
+	// +Inf  +Inf    0
+}
diff --git a/src/cmd/internal/gc/big/ftoa.go b/src/cmd/internal/gc/big/ftoa.go
new file mode 100644
index 0000000..0a9edfd
--- /dev/null
+++ b/src/cmd/internal/gc/big/ftoa.go
@@ -0,0 +1,190 @@
+// 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.
+
+// 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
+
+package big
+
+import "strconv"
+
+// TODO(gri) Consider moving sign into decimal - could make the signatures below cleaner.
+
+// 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")
+	}
+
+	// 1) convert Float to multiprecision decimal
+	var mant nat
+	if f.form == finite {
+		mant = f.mant
+	}
+	var d decimal
+	d.init(mant, int(f.exp)-f.mant.bitLen())
+
+	// 2) round to desired precision
+	shortest := false
+	if prec < 0 {
+		shortest = true
+		panic("unimplemented")
+		// TODO(gri) complete this
+		// roundShortest(&d, f.mant, int(f.exp))
+		// Precision for shortest representation mode.
+		switch fmt {
+		case 'e', 'E':
+			prec = len(d.mant) - 1
+		case 'f':
+			prec = max(len(d.mant)-d.exp, 0)
+		case 'g', 'G':
+			prec = len(d.mant)
+		}
+	} else {
+		// round appropriately
+		switch fmt {
+		case 'e', 'E':
+			// one digit before and number of digits after decimal point
+			d.round(1 + prec)
+		case 'f':
+			// number of digits before and after decimal point
+			d.round(d.exp + prec)
+		case 'g', 'G':
+			if prec == 0 {
+				prec = 1
+			}
+			d.round(prec)
+		}
+	}
+
+	// 3) read digits out and format
+	switch fmt {
+	case 'e', 'E':
+		return fmtE(buf, fmt, prec, f.neg, d)
+	case 'f':
+		return fmtF(buf, prec, f.neg, d)
+	case 'g', 'G':
+		// trim trailing fractional zeros in %e format
+		eprec := prec
+		if eprec > len(d.mant) && len(d.mant) >= d.exp {
+			eprec = len(d.mant)
+		}
+		// %e is used if the exponent from the conversion
+		// is less than -4 or greater than or equal to the precision.
+		// If precision was the shortest possible, use eprec = 6 for
+		// this decision.
+		if shortest {
+			eprec = 6
+		}
+		exp := d.exp - 1
+		if exp < -4 || exp >= eprec {
+			if prec > len(d.mant) {
+				prec = len(d.mant)
+			}
+			return fmtE(buf, fmt+'e'-'g', prec-1, f.neg, d)
+		}
+		if prec > d.exp {
+			prec = len(d.mant)
+		}
+		return fmtF(buf, max(prec-d.exp, 0), f.neg, d)
+	}
+
+	// unknown format
+	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, '-')
+	}
+
+	// first digit
+	ch := byte('0')
+	if len(d.mant) > 0 {
+		ch = d.mant[0]
+	}
+	buf = append(buf, ch)
+
+	// .moredigits
+	if prec > 0 {
+		buf = append(buf, '.')
+		i := 1
+		m := min(len(d.mant), prec+1)
+		if i < m {
+			buf = append(buf, d.mant[i:m]...)
+			i = m
+		}
+		for ; i <= prec; i++ {
+			buf = append(buf, '0')
+		}
+	}
+
+	// e±
+	buf = append(buf, fmt)
+	var exp int64
+	if len(d.mant) > 0 {
+		exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
+	}
+	if exp < 0 {
+		ch = '-'
+		exp = -exp
+	} else {
+		ch = '+'
+	}
+	buf = append(buf, ch)
+
+	// dd...d
+	if exp < 10 {
+		buf = append(buf, '0') // at least 2 exponent digits
+	}
+	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, '-')
+	}
+
+	// integer, padded with zeros as needed
+	if d.exp > 0 {
+		m := min(len(d.mant), d.exp)
+		buf = append(buf, d.mant[:m]...)
+		for ; m < d.exp; m++ {
+			buf = append(buf, '0')
+		}
+	} else {
+		buf = append(buf, '0')
+	}
+
+	// fraction
+	if prec > 0 {
+		buf = append(buf, '.')
+		for i := 0; i < prec; i++ {
+			ch := byte('0')
+			if j := d.exp + i; 0 <= j && j < len(d.mant) {
+				ch = d.mant[j]
+			}
+			buf = append(buf, ch)
+		}
+	}
+
+	return buf
+}
+
+func min(x, y int) int {
+	if x < y {
+		return x
+	}
+	return y
+}
diff --git a/src/cmd/internal/gc/big/gcd_test.go b/src/cmd/internal/gc/big/gcd_test.go
new file mode 100644
index 0000000..c0b9f58
--- /dev/null
+++ b/src/cmd/internal/gc/big/gcd_test.go
@@ -0,0 +1,47 @@
+// Copyright 2012 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.
+
+// This file implements a GCD benchmark.
+// Usage: go test math/big -test.bench GCD
+
+package big
+
+import (
+	"math/rand"
+	"testing"
+)
+
+// randInt returns a pseudo-random Int in the range [1<<(size-1), (1<<size) - 1]
+func randInt(r *rand.Rand, size uint) *Int {
+	n := new(Int).Lsh(intOne, size-1)
+	x := new(Int).Rand(r, n)
+	return x.Add(x, n) // make sure result > 1<<(size-1)
+}
+
+func runGCD(b *testing.B, aSize, bSize uint) {
+	b.StopTimer()
+	var r = rand.New(rand.NewSource(1234))
+	aa := randInt(r, aSize)
+	bb := randInt(r, bSize)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		new(Int).GCD(nil, nil, aa, bb)
+	}
+}
+
+func BenchmarkGCD10x10(b *testing.B)         { runGCD(b, 10, 10) }
+func BenchmarkGCD10x100(b *testing.B)        { runGCD(b, 10, 100) }
+func BenchmarkGCD10x1000(b *testing.B)       { runGCD(b, 10, 1000) }
+func BenchmarkGCD10x10000(b *testing.B)      { runGCD(b, 10, 10000) }
+func BenchmarkGCD10x100000(b *testing.B)     { runGCD(b, 10, 100000) }
+func BenchmarkGCD100x100(b *testing.B)       { runGCD(b, 100, 100) }
+func BenchmarkGCD100x1000(b *testing.B)      { runGCD(b, 100, 1000) }
+func BenchmarkGCD100x10000(b *testing.B)     { runGCD(b, 100, 10000) }
+func BenchmarkGCD100x100000(b *testing.B)    { runGCD(b, 100, 100000) }
+func BenchmarkGCD1000x1000(b *testing.B)     { runGCD(b, 1000, 1000) }
+func BenchmarkGCD1000x10000(b *testing.B)    { runGCD(b, 1000, 10000) }
+func BenchmarkGCD1000x100000(b *testing.B)   { runGCD(b, 1000, 100000) }
+func BenchmarkGCD10000x10000(b *testing.B)   { runGCD(b, 10000, 10000) }
+func BenchmarkGCD10000x100000(b *testing.B)  { runGCD(b, 10000, 100000) }
+func BenchmarkGCD100000x100000(b *testing.B) { runGCD(b, 100000, 100000) }
diff --git a/src/cmd/internal/gc/big/hilbert_test.go b/src/cmd/internal/gc/big/hilbert_test.go
new file mode 100644
index 0000000..1a84341
--- /dev/null
+++ b/src/cmd/internal/gc/big/hilbert_test.go
@@ -0,0 +1,160 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A little test program and benchmark for rational arithmetics.
+// Computes a Hilbert matrix, its inverse, multiplies them
+// and verifies that the product is the identity matrix.
+
+package big
+
+import (
+	"fmt"
+	"testing"
+)
+
+type matrix struct {
+	n, m int
+	a    []*Rat
+}
+
+func (a *matrix) at(i, j int) *Rat {
+	if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+		panic("index out of range")
+	}
+	return a.a[i*a.m+j]
+}
+
+func (a *matrix) set(i, j int, x *Rat) {
+	if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+		panic("index out of range")
+	}
+	a.a[i*a.m+j] = x
+}
+
+func newMatrix(n, m int) *matrix {
+	if !(0 <= n && 0 <= m) {
+		panic("illegal matrix")
+	}
+	a := new(matrix)
+	a.n = n
+	a.m = m
+	a.a = make([]*Rat, n*m)
+	return a
+}
+
+func newUnit(n int) *matrix {
+	a := newMatrix(n, n)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			x := NewRat(0, 1)
+			if i == j {
+				x.SetInt64(1)
+			}
+			a.set(i, j, x)
+		}
+	}
+	return a
+}
+
+func newHilbert(n int) *matrix {
+	a := newMatrix(n, n)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			a.set(i, j, NewRat(1, int64(i+j+1)))
+		}
+	}
+	return a
+}
+
+func newInverseHilbert(n int) *matrix {
+	a := newMatrix(n, n)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			x1 := new(Rat).SetInt64(int64(i + j + 1))
+			x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
+			x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
+			x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
+
+			x1.Mul(x1, x2)
+			x1.Mul(x1, x3)
+			x1.Mul(x1, x4)
+			x1.Mul(x1, x4)
+
+			if (i+j)&1 != 0 {
+				x1.Neg(x1)
+			}
+
+			a.set(i, j, x1)
+		}
+	}
+	return a
+}
+
+func (a *matrix) mul(b *matrix) *matrix {
+	if a.m != b.n {
+		panic("illegal matrix multiply")
+	}
+	c := newMatrix(a.n, b.m)
+	for i := 0; i < c.n; i++ {
+		for j := 0; j < c.m; j++ {
+			x := NewRat(0, 1)
+			for k := 0; k < a.m; k++ {
+				x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
+			}
+			c.set(i, j, x)
+		}
+	}
+	return c
+}
+
+func (a *matrix) eql(b *matrix) bool {
+	if a.n != b.n || a.m != b.m {
+		return false
+	}
+	for i := 0; i < a.n; i++ {
+		for j := 0; j < a.m; j++ {
+			if a.at(i, j).Cmp(b.at(i, j)) != 0 {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+func (a *matrix) String() string {
+	s := ""
+	for i := 0; i < a.n; i++ {
+		for j := 0; j < a.m; j++ {
+			s += fmt.Sprintf("\t%s", a.at(i, j))
+		}
+		s += "\n"
+	}
+	return s
+}
+
+func doHilbert(t *testing.T, n int) {
+	a := newHilbert(n)
+	b := newInverseHilbert(n)
+	I := newUnit(n)
+	ab := a.mul(b)
+	if !ab.eql(I) {
+		if t == nil {
+			panic("Hilbert failed")
+		}
+		t.Errorf("a   = %s\n", a)
+		t.Errorf("b   = %s\n", b)
+		t.Errorf("a*b = %s\n", ab)
+		t.Errorf("I   = %s\n", I)
+	}
+}
+
+func TestHilbert(t *testing.T) {
+	doHilbert(t, 10)
+}
+
+func BenchmarkHilbert(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		doHilbert(nil, 10)
+	}
+}
diff --git a/src/cmd/internal/gc/big/int.go b/src/cmd/internal/gc/big/int.go
new file mode 100644
index 0000000..7b419bf
--- /dev/null
+++ b/src/cmd/internal/gc/big/int.go
@@ -0,0 +1,848 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements signed multi-precision integers.
+
+package big
+
+import (
+	"fmt"
+	"io"
+	"math/rand"
+	"strings"
+)
+
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
+	neg bool // sign
+	abs nat  // absolute value of the integer
+}
+
+var intOne = &Int{false, natOne}
+
+// Sign returns:
+//
+//	-1 if x <  0
+//	 0 if x == 0
+//	+1 if x >  0
+//
+func (x *Int) Sign() int {
+	if len(x.abs) == 0 {
+		return 0
+	}
+	if x.neg {
+		return -1
+	}
+	return 1
+}
+
+// SetInt64 sets z to x and returns z.
+func (z *Int) SetInt64(x int64) *Int {
+	neg := false
+	if x < 0 {
+		neg = true
+		x = -x
+	}
+	z.abs = z.abs.setUint64(uint64(x))
+	z.neg = neg
+	return z
+}
+
+// SetUint64 sets z to x and returns z.
+func (z *Int) SetUint64(x uint64) *Int {
+	z.abs = z.abs.setUint64(x)
+	z.neg = false
+	return z
+}
+
+// NewInt allocates and returns a new Int set to x.
+func NewInt(x int64) *Int {
+	return new(Int).SetInt64(x)
+}
+
+// Set sets z to x and returns z.
+func (z *Int) Set(x *Int) *Int {
+	if z != x {
+		z.abs = z.abs.set(x.abs)
+		z.neg = x.neg
+	}
+	return z
+}
+
+// Bits provides raw (unchecked but fast) access to x by returning its
+// absolute value as a little-endian Word slice. The result and x share
+// the same underlying array.
+// Bits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (x *Int) Bits() []Word {
+	return x.abs
+}
+
+// SetBits provides raw (unchecked but fast) access to z by setting its
+// value to abs, interpreted as a little-endian Word slice, and returning
+// z. The result and abs share the same underlying array.
+// SetBits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (z *Int) SetBits(abs []Word) *Int {
+	z.abs = nat(abs).norm()
+	z.neg = false
+	return z
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Int) Abs(x *Int) *Int {
+	z.Set(x)
+	z.neg = false
+	return z
+}
+
+// Neg sets z to -x and returns z.
+func (z *Int) Neg(x *Int) *Int {
+	z.Set(x)
+	z.neg = len(z.abs) > 0 && !z.neg // 0 has no sign
+	return z
+}
+
+// Add sets z to the sum x+y and returns z.
+func (z *Int) Add(x, y *Int) *Int {
+	neg := x.neg
+	if x.neg == y.neg {
+		// x + y == x + y
+		// (-x) + (-y) == -(x + y)
+		z.abs = z.abs.add(x.abs, y.abs)
+	} else {
+		// x + (-y) == x - y == -(y - x)
+		// (-x) + y == y - x == -(x - y)
+		if x.abs.cmp(y.abs) >= 0 {
+			z.abs = z.abs.sub(x.abs, y.abs)
+		} else {
+			neg = !neg
+			z.abs = z.abs.sub(y.abs, x.abs)
+		}
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+	return z
+}
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Int) Sub(x, y *Int) *Int {
+	neg := x.neg
+	if x.neg != y.neg {
+		// x - (-y) == x + y
+		// (-x) - y == -(x + y)
+		z.abs = z.abs.add(x.abs, y.abs)
+	} else {
+		// x - y == x - y == -(y - x)
+		// (-x) - (-y) == y - x == -(x - y)
+		if x.abs.cmp(y.abs) >= 0 {
+			z.abs = z.abs.sub(x.abs, y.abs)
+		} else {
+			neg = !neg
+			z.abs = z.abs.sub(y.abs, x.abs)
+		}
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+	return z
+}
+
+// Mul sets z to the product x*y and returns z.
+func (z *Int) Mul(x, y *Int) *Int {
+	// x * y == x * y
+	// x * (-y) == -(x * y)
+	// (-x) * y == -(x * y)
+	// (-x) * (-y) == x * y
+	z.abs = z.abs.mul(x.abs, y.abs)
+	z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+	return z
+}
+
+// MulRange sets z to the product of all integers
+// in the range [a, b] inclusively and returns z.
+// If a > b (empty range), the result is 1.
+func (z *Int) MulRange(a, b int64) *Int {
+	switch {
+	case a > b:
+		return z.SetInt64(1) // empty range
+	case a <= 0 && b >= 0:
+		return z.SetInt64(0) // range includes 0
+	}
+	// a <= b && (b < 0 || a > 0)
+
+	neg := false
+	if a < 0 {
+		neg = (b-a)&1 == 0
+		a, b = -b, -a
+	}
+
+	z.abs = z.abs.mulRange(uint64(a), uint64(b))
+	z.neg = neg
+	return z
+}
+
+// Binomial sets z to the binomial coefficient of (n, k) and returns z.
+func (z *Int) Binomial(n, k int64) *Int {
+	// reduce the number of multiplications by reducing k
+	if n/2 < k && k <= n {
+		k = n - k // Binomial(n, k) == Binomial(n, n-k)
+	}
+	var a, b Int
+	a.MulRange(n-k+1, n)
+	b.MulRange(1, k)
+	return z.Quo(&a, &b)
+}
+
+// Quo sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Quo implements truncated division (like Go); see QuoRem for more details.
+func (z *Int) Quo(x, y *Int) *Int {
+	z.abs, _ = z.abs.div(nil, x.abs, y.abs)
+	z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+	return z
+}
+
+// Rem sets z to the remainder x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Rem implements truncated modulus (like Go); see QuoRem for more details.
+func (z *Int) Rem(x, y *Int) *Int {
+	_, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
+	z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
+	return z
+}
+
+// QuoRem sets z to the quotient x/y and r to the remainder x%y
+// and returns the pair (z, r) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// QuoRem implements T-division and modulus (like Go):
+//
+//	q = x/y      with the result truncated to zero
+//	r = x - y*q
+//
+// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+// See DivMod for Euclidean division and modulus (unlike Go).
+//
+func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
+	z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
+	z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
+	return z, r
+}
+
+// Div sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Div implements Euclidean division (unlike Go); see DivMod for more details.
+func (z *Int) Div(x, y *Int) *Int {
+	y_neg := y.neg // z may be an alias for y
+	var r Int
+	z.QuoRem(x, y, &r)
+	if r.neg {
+		if y_neg {
+			z.Add(z, intOne)
+		} else {
+			z.Sub(z, intOne)
+		}
+	}
+	return z
+}
+
+// Mod sets z to the modulus x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
+func (z *Int) Mod(x, y *Int) *Int {
+	y0 := y // save y
+	if z == y || alias(z.abs, y.abs) {
+		y0 = new(Int).Set(y)
+	}
+	var q Int
+	q.QuoRem(x, y, z)
+	if z.neg {
+		if y0.neg {
+			z.Sub(z, y0)
+		} else {
+			z.Add(z, y0)
+		}
+	}
+	return z
+}
+
+// DivMod sets z to the quotient x div y and m to the modulus x mod y
+// and returns the pair (z, m) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// DivMod implements Euclidean division and modulus (unlike Go):
+//
+//	q = x div y  such that
+//	m = x - y*q  with 0 <= m < |q|
+//
+// (See Raymond T. Boute, ``The Euclidean definition of the functions
+// div and mod''. ACM Transactions on Programming Languages and
+// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
+// ACM press.)
+// See QuoRem for T-division and modulus (like Go).
+//
+func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
+	y0 := y // save y
+	if z == y || alias(z.abs, y.abs) {
+		y0 = new(Int).Set(y)
+	}
+	z.QuoRem(x, y, m)
+	if m.neg {
+		if y0.neg {
+			z.Add(z, intOne)
+			m.Sub(m, y0)
+		} else {
+			z.Sub(z, intOne)
+			m.Add(m, y0)
+		}
+	}
+	return z, m
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y
+//   +1 if x >  y
+//
+func (x *Int) Cmp(y *Int) (r int) {
+	// x cmp y == x cmp y
+	// x cmp (-y) == x
+	// (-x) cmp y == y
+	// (-x) cmp (-y) == -(x cmp y)
+	switch {
+	case x.neg == y.neg:
+		r = x.abs.cmp(y.abs)
+		if x.neg {
+			r = -r
+		}
+	case x.neg:
+		r = -1
+	default:
+		r = 1
+	}
+	return
+}
+
+// low32 returns the least significant 32 bits of z.
+func low32(z nat) uint32 {
+	if len(z) == 0 {
+		return 0
+	}
+	return uint32(z[0])
+}
+
+// low64 returns the least significant 64 bits of z.
+func low64(z nat) uint64 {
+	if len(z) == 0 {
+		return 0
+	}
+	v := uint64(z[0])
+	if _W == 32 && len(z) > 1 {
+		v |= uint64(z[1]) << 32
+	}
+	return v
+}
+
+// Int64 returns the int64 representation of x.
+// If x cannot be represented in an int64, the result is undefined.
+func (x *Int) Int64() int64 {
+	v := int64(low64(x.abs))
+	if x.neg {
+		v = -v
+	}
+	return v
+}
+
+// Uint64 returns the uint64 representation of x.
+// If x cannot be represented in a uint64, the result is undefined.
+func (x *Int) Uint64() uint64 {
+	return low64(x.abs)
+}
+
+// SetString sets z to the value of s, interpreted in the given base,
+// and returns z and a boolean indicating success. If SetString fails,
+// the value of z is undefined but the returned value is nil.
+//
+// The base argument must be 0 or a value between 2 and MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) SetString(s string, base int) (*Int, bool) {
+	r := strings.NewReader(s)
+	_, _, err := z.scan(r, base)
+	if err != nil {
+		return nil, false
+	}
+	_, err = r.ReadByte()
+	if err != io.EOF {
+		return nil, false
+	}
+	return z, true // err == io.EOF => scan consumed all of s
+}
+
+// SetBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z *Int) SetBytes(buf []byte) *Int {
+	z.abs = z.abs.setBytes(buf)
+	z.neg = false
+	return z
+}
+
+// Bytes returns the absolute value of x as a big-endian byte slice.
+func (x *Int) Bytes() []byte {
+	buf := make([]byte, len(x.abs)*_S)
+	return buf[x.abs.bytes(buf):]
+}
+
+// BitLen returns the length of the absolute value of x in bits.
+// The bit length of 0 is 0.
+func (x *Int) BitLen() int {
+	return x.abs.bitLen()
+}
+
+// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
+// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
+// See Knuth, volume 2, section 4.6.3.
+func (z *Int) Exp(x, y, m *Int) *Int {
+	var yWords nat
+	if !y.neg {
+		yWords = y.abs
+	}
+	// y >= 0
+
+	var mWords nat
+	if m != nil {
+		mWords = m.abs // m.abs may be nil for m == 0
+	}
+
+	z.abs = z.abs.expNN(x.abs, yWords, mWords)
+	z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
+	if z.neg && len(mWords) > 0 {
+		// make modulus result positive
+		z.abs = z.abs.sub(mWords, z.abs) // z == x**y mod |m| && 0 <= z < |m|
+		z.neg = false
+	}
+
+	return z
+}
+
+// GCD sets z to the greatest common divisor of a and b, which both must
+// be > 0, and returns z.
+// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
+// If either a or b is <= 0, GCD sets z = x = y = 0.
+func (z *Int) GCD(x, y, a, b *Int) *Int {
+	if a.Sign() <= 0 || b.Sign() <= 0 {
+		z.SetInt64(0)
+		if x != nil {
+			x.SetInt64(0)
+		}
+		if y != nil {
+			y.SetInt64(0)
+		}
+		return z
+	}
+	if x == nil && y == nil {
+		return z.binaryGCD(a, b)
+	}
+
+	A := new(Int).Set(a)
+	B := new(Int).Set(b)
+
+	X := new(Int)
+	Y := new(Int).SetInt64(1)
+
+	lastX := new(Int).SetInt64(1)
+	lastY := new(Int)
+
+	q := new(Int)
+	temp := new(Int)
+
+	for len(B.abs) > 0 {
+		r := new(Int)
+		q, r = q.QuoRem(A, B, r)
+
+		A, B = B, r
+
+		temp.Set(X)
+		X.Mul(X, q)
+		X.neg = !X.neg
+		X.Add(X, lastX)
+		lastX.Set(temp)
+
+		temp.Set(Y)
+		Y.Mul(Y, q)
+		Y.neg = !Y.neg
+		Y.Add(Y, lastY)
+		lastY.Set(temp)
+	}
+
+	if x != nil {
+		*x = *lastX
+	}
+
+	if y != nil {
+		*y = *lastY
+	}
+
+	*z = *A
+	return z
+}
+
+// binaryGCD sets z to the greatest common divisor of a and b, which both must
+// be > 0, and returns z.
+// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm B.
+func (z *Int) binaryGCD(a, b *Int) *Int {
+	u := z
+	v := new(Int)
+
+	// use one Euclidean iteration to ensure that u and v are approx. the same size
+	switch {
+	case len(a.abs) > len(b.abs):
+		u.Set(b)
+		v.Rem(a, b)
+	case len(a.abs) < len(b.abs):
+		u.Set(a)
+		v.Rem(b, a)
+	default:
+		u.Set(a)
+		v.Set(b)
+	}
+
+	// v might be 0 now
+	if len(v.abs) == 0 {
+		return u
+	}
+	// u > 0 && v > 0
+
+	// determine largest k such that u = u' << k, v = v' << k
+	k := u.abs.trailingZeroBits()
+	if vk := v.abs.trailingZeroBits(); vk < k {
+		k = vk
+	}
+	u.Rsh(u, k)
+	v.Rsh(v, k)
+
+	// determine t (we know that u > 0)
+	t := new(Int)
+	if u.abs[0]&1 != 0 {
+		// u is odd
+		t.Neg(v)
+	} else {
+		t.Set(u)
+	}
+
+	for len(t.abs) > 0 {
+		// reduce t
+		t.Rsh(t, t.abs.trailingZeroBits())
+		if t.neg {
+			v, t = t, v
+			v.neg = len(v.abs) > 0 && !v.neg // 0 has no sign
+		} else {
+			u, t = t, u
+		}
+		t.Sub(u, v)
+	}
+
+	return z.Lsh(u, k)
+}
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If it returns true, x is prime with probability 1 - 1/4^n.
+// If it returns false, x is not prime. n must be > 0.
+func (x *Int) ProbablyPrime(n int) bool {
+	if n <= 0 {
+		panic("non-positive n for ProbablyPrime")
+	}
+	return !x.neg && x.abs.probablyPrime(n)
+}
+
+// Rand sets z to a pseudo-random number in [0, n) and returns z.
+func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
+	z.neg = false
+	if n.neg == true || len(n.abs) == 0 {
+		z.abs = nil
+		return z
+	}
+	z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
+	return z
+}
+
+// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
+// and returns z. If g and n are not relatively prime, the result is undefined.
+func (z *Int) ModInverse(g, n *Int) *Int {
+	var d Int
+	d.GCD(z, nil, g, n)
+	// x and y are such that g*x + n*y = d. Since g and n are
+	// relatively prime, d = 1. Taking that modulo n results in
+	// g*x = 1, therefore x is the inverse element.
+	if z.neg {
+		z.Add(z, n)
+	}
+	return z
+}
+
+// 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)
+	z.neg = x.neg
+	return z
+}
+
+// Rsh sets z = x >> n and returns z.
+func (z *Int) Rsh(x *Int, n uint) *Int {
+	if x.neg {
+		// (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+		t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
+		t = t.shr(t, n)
+		z.abs = t.add(t, natOne)
+		z.neg = true // z cannot be zero if x is negative
+		return z
+	}
+
+	z.abs = z.abs.shr(x.abs, n)
+	z.neg = false
+	return z
+}
+
+// Bit returns the value of the i'th bit of x. That is, it
+// returns (x>>i)&1. The bit index i must be >= 0.
+func (x *Int) Bit(i int) uint {
+	if i == 0 {
+		// optimization for common case: odd/even test of x
+		if len(x.abs) > 0 {
+			return uint(x.abs[0] & 1) // bit 0 is same for -x
+		}
+		return 0
+	}
+	if i < 0 {
+		panic("negative bit index")
+	}
+	if x.neg {
+		t := nat(nil).sub(x.abs, natOne)
+		return t.bit(uint(i)) ^ 1
+	}
+
+	return x.abs.bit(uint(i))
+}
+
+// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
+// That is, if b is 1 SetBit sets z = x | (1 << i);
+// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
+// SetBit will panic.
+func (z *Int) SetBit(x *Int, i int, b uint) *Int {
+	if i < 0 {
+		panic("negative bit index")
+	}
+	if x.neg {
+		t := z.abs.sub(x.abs, natOne)
+		t = t.setBit(t, uint(i), b^1)
+		z.abs = t.add(t, natOne)
+		z.neg = len(z.abs) > 0
+		return z
+	}
+	z.abs = z.abs.setBit(x.abs, uint(i), b)
+	z.neg = false
+	return z
+}
+
+// And sets z = x & y and returns z.
+func (z *Int) And(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
+			z.neg = true // z cannot be zero if x and y are negative
+			return z
+		}
+
+		// x & y == x & y
+		z.abs = z.abs.and(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	// x.neg != y.neg
+	if x.neg {
+		x, y = y, x // & is symmetric
+	}
+
+	// x & (-y) == x & ^(y-1) == x &^ (y-1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.andNot(x.abs, y1)
+	z.neg = false
+	return z
+}
+
+// AndNot sets z = x &^ y and returns z.
+func (z *Int) AndNot(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.andNot(y1, x1)
+			z.neg = false
+			return z
+		}
+
+		// x &^ y == x &^ y
+		z.abs = z.abs.andNot(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	if x.neg {
+		// (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+		x1 := nat(nil).sub(x.abs, natOne)
+		z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
+		z.neg = true // z cannot be zero if x is negative and y is positive
+		return z
+	}
+
+	// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.and(x.abs, y1)
+	z.neg = false
+	return z
+}
+
+// Or sets z = x | y and returns z.
+func (z *Int) Or(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
+			z.neg = true // z cannot be zero if x and y are negative
+			return z
+		}
+
+		// x | y == x | y
+		z.abs = z.abs.or(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	// x.neg != y.neg
+	if x.neg {
+		x, y = y, x // | is symmetric
+	}
+
+	// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
+	z.neg = true // z cannot be zero if one of x or y is negative
+	return z
+}
+
+// Xor sets z = x ^ y and returns z.
+func (z *Int) Xor(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.xor(x1, y1)
+			z.neg = false
+			return z
+		}
+
+		// x ^ y == x ^ y
+		z.abs = z.abs.xor(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	// x.neg != y.neg
+	if x.neg {
+		x, y = y, x // ^ is symmetric
+	}
+
+	// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
+	z.neg = true // z cannot be zero if only one of x or y is negative
+	return z
+}
+
+// Not sets z = ^x and returns z.
+func (z *Int) Not(x *Int) *Int {
+	if x.neg {
+		// ^(-x) == ^(^(x-1)) == x-1
+		z.abs = z.abs.sub(x.abs, natOne)
+		z.neg = false
+		return z
+	}
+
+	// ^x == -x-1 == -(x+1)
+	z.abs = z.abs.add(x.abs, natOne)
+	z.neg = true // z cannot be zero if x is positive
+	return z
+}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const intGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Int) GobEncode() ([]byte, error) {
+	if x == nil {
+		return nil, nil
+	}
+	buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
+	i := x.abs.bytes(buf) - 1            // i >= 0
+	b := intGobVersion << 1              // make space for sign bit
+	if x.neg {
+		b |= 1
+	}
+	buf[i] = b
+	return buf[i:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) error {
+	if len(buf) == 0 {
+		// Other side sent a nil or default value.
+		*z = Int{}
+		return nil
+	}
+	b := buf[0]
+	if b>>1 != intGobVersion {
+		return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
+	}
+	z.neg = b&1 != 0
+	z.abs = z.abs.setBytes(buf[1:])
+	return nil
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (z *Int) MarshalJSON() ([]byte, error) {
+	// TODO(gri): get rid of the []byte/string conversions
+	return []byte(z.String()), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (z *Int) UnmarshalJSON(text []byte) error {
+	// TODO(gri): get rid of the []byte/string conversions
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+	}
+	return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (z *Int) MarshalText() (text []byte, err error) {
+	return []byte(z.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Int) UnmarshalText(text []byte) error {
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+	}
+	return nil
+}
diff --git a/src/cmd/internal/gc/big/int_test.go b/src/cmd/internal/gc/big/int_test.go
new file mode 100644
index 0000000..a972a72
--- /dev/null
+++ b/src/cmd/internal/gc/big/int_test.go
@@ -0,0 +1,1387 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+	"bytes"
+	"encoding/gob"
+	"encoding/hex"
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"math/rand"
+	"testing"
+	"testing/quick"
+)
+
+func isNormalized(x *Int) bool {
+	if len(x.abs) == 0 {
+		return !x.neg
+	}
+	// len(x.abs) > 0
+	return x.abs[len(x.abs)-1] != 0
+}
+
+type funZZ func(z, x, y *Int) *Int
+type argZZ struct {
+	z, x, y *Int
+}
+
+var sumZZ = []argZZ{
+	{NewInt(0), NewInt(0), NewInt(0)},
+	{NewInt(1), NewInt(1), NewInt(0)},
+	{NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
+	{NewInt(-1), NewInt(-1), NewInt(0)},
+	{NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
+	{NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
+}
+
+var prodZZ = []argZZ{
+	{NewInt(0), NewInt(0), NewInt(0)},
+	{NewInt(0), NewInt(1), NewInt(0)},
+	{NewInt(1), NewInt(1), NewInt(1)},
+	{NewInt(-991 * 991), NewInt(991), NewInt(-991)},
+	// TODO(gri) add larger products
+}
+
+func TestSignZ(t *testing.T) {
+	var zero Int
+	for _, a := range sumZZ {
+		s := a.z.Sign()
+		e := a.z.Cmp(&zero)
+		if s != e {
+			t.Errorf("got %d; want %d for z = %v", s, e, a.z)
+		}
+	}
+}
+
+func TestSetZ(t *testing.T) {
+	for _, a := range sumZZ {
+		var z Int
+		z.Set(a.z)
+		if !isNormalized(&z) {
+			t.Errorf("%v is not normalized", z)
+		}
+		if (&z).Cmp(a.z) != 0 {
+			t.Errorf("got z = %v; want %v", z, a.z)
+		}
+	}
+}
+
+func TestAbsZ(t *testing.T) {
+	var zero Int
+	for _, a := range sumZZ {
+		var z Int
+		z.Abs(a.z)
+		var e Int
+		e.Set(a.z)
+		if e.Cmp(&zero) < 0 {
+			e.Sub(&zero, &e)
+		}
+		if z.Cmp(&e) != 0 {
+			t.Errorf("got z = %v; want %v", z, e)
+		}
+	}
+}
+
+func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
+	var z Int
+	f(&z, a.x, a.y)
+	if !isNormalized(&z) {
+		t.Errorf("%s%v is not normalized", msg, z)
+	}
+	if (&z).Cmp(a.z) != 0 {
+		t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
+	}
+}
+
+func TestSumZZ(t *testing.T) {
+	AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
+	SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
+	for _, a := range sumZZ {
+		arg := a
+		testFunZZ(t, "AddZZ", AddZZ, arg)
+
+		arg = argZZ{a.z, a.y, a.x}
+		testFunZZ(t, "AddZZ symmetric", AddZZ, arg)
+
+		arg = argZZ{a.x, a.z, a.y}
+		testFunZZ(t, "SubZZ", SubZZ, arg)
+
+		arg = argZZ{a.y, a.z, a.x}
+		testFunZZ(t, "SubZZ symmetric", SubZZ, arg)
+	}
+}
+
+func TestProdZZ(t *testing.T) {
+	MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
+	for _, a := range prodZZ {
+		arg := a
+		testFunZZ(t, "MulZZ", MulZZ, arg)
+
+		arg = argZZ{a.z, a.y, a.x}
+		testFunZZ(t, "MulZZ symmetric", MulZZ, arg)
+	}
+}
+
+// mulBytes returns x*y via grade school multiplication. Both inputs
+// and the result are assumed to be in big-endian representation (to
+// match the semantics of Int.Bytes and Int.SetBytes).
+func mulBytes(x, y []byte) []byte {
+	z := make([]byte, len(x)+len(y))
+
+	// multiply
+	k0 := len(z) - 1
+	for j := len(y) - 1; j >= 0; j-- {
+		d := int(y[j])
+		if d != 0 {
+			k := k0
+			carry := 0
+			for i := len(x) - 1; i >= 0; i-- {
+				t := int(z[k]) + int(x[i])*d + carry
+				z[k], carry = byte(t), t>>8
+				k--
+			}
+			z[k] = byte(carry)
+		}
+		k0--
+	}
+
+	// normalize (remove leading 0's)
+	i := 0
+	for i < len(z) && z[i] == 0 {
+		i++
+	}
+
+	return z[i:]
+}
+
+func checkMul(a, b []byte) bool {
+	var x, y, z1 Int
+	x.SetBytes(a)
+	y.SetBytes(b)
+	z1.Mul(&x, &y)
+
+	var z2 Int
+	z2.SetBytes(mulBytes(a, b))
+
+	return z1.Cmp(&z2) == 0
+}
+
+func TestMul(t *testing.T) {
+	if err := quick.Check(checkMul, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+var mulRangesZ = []struct {
+	a, b int64
+	prod string
+}{
+	// entirely positive ranges are covered by mulRangesN
+	{-1, 1, "0"},
+	{-2, -1, "2"},
+	{-3, -2, "6"},
+	{-3, -1, "-6"},
+	{1, 3, "6"},
+	{-10, -10, "-10"},
+	{0, -1, "1"},                      // empty range
+	{-1, -100, "1"},                   // empty range
+	{-1, 1, "0"},                      // range includes 0
+	{-1e9, 0, "0"},                    // range includes 0
+	{-1e9, 1e9, "0"},                  // range includes 0
+	{-10, -1, "3628800"},              // 10!
+	{-20, -2, "-2432902008176640000"}, // -20!
+	{-99, -1,
+		"-933262154439441526816992388562667004907159682643816214685929" +
+			"638952175999932299156089414639761565182862536979208272237582" +
+			"511852109168640000000000000000000000", // -99!
+	},
+}
+
+func TestMulRangeZ(t *testing.T) {
+	var tmp Int
+	// test entirely positive ranges
+	for i, r := range mulRangesN {
+		prod := tmp.MulRange(int64(r.a), int64(r.b)).String()
+		if prod != r.prod {
+			t.Errorf("#%da: got %s; want %s", i, prod, r.prod)
+		}
+	}
+	// test other ranges
+	for i, r := range mulRangesZ {
+		prod := tmp.MulRange(r.a, r.b).String()
+		if prod != r.prod {
+			t.Errorf("#%db: got %s; want %s", i, prod, r.prod)
+		}
+	}
+}
+
+func TestBinomial(t *testing.T) {
+	var z Int
+	for _, test := range []struct {
+		n, k int64
+		want string
+	}{
+		{0, 0, "1"},
+		{0, 1, "0"},
+		{1, 0, "1"},
+		{1, 1, "1"},
+		{1, 10, "0"},
+		{4, 0, "1"},
+		{4, 1, "4"},
+		{4, 2, "6"},
+		{4, 3, "4"},
+		{4, 4, "1"},
+		{10, 1, "10"},
+		{10, 9, "10"},
+		{10, 5, "252"},
+		{11, 5, "462"},
+		{11, 6, "462"},
+		{100, 10, "17310309456440"},
+		{100, 90, "17310309456440"},
+		{1000, 10, "263409560461970212832400"},
+		{1000, 990, "263409560461970212832400"},
+	} {
+		if got := z.Binomial(test.n, test.k).String(); got != test.want {
+			t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want)
+		}
+	}
+}
+
+func BenchmarkBinomial(b *testing.B) {
+	var z Int
+	for i := b.N - 1; i >= 0; i-- {
+		z.Binomial(1000, 990)
+	}
+}
+
+// Examples from the Go Language Spec, section "Arithmetic operators"
+var divisionSignsTests = []struct {
+	x, y int64
+	q, r int64 // T-division
+	d, m int64 // Euclidian division
+}{
+	{5, 3, 1, 2, 1, 2},
+	{-5, 3, -1, -2, -2, 1},
+	{5, -3, -1, 2, -1, 2},
+	{-5, -3, 1, -2, 2, 1},
+	{1, 2, 0, 1, 0, 1},
+	{8, 4, 2, 0, 2, 0},
+}
+
+func TestDivisionSigns(t *testing.T) {
+	for i, test := range divisionSignsTests {
+		x := NewInt(test.x)
+		y := NewInt(test.y)
+		q := NewInt(test.q)
+		r := NewInt(test.r)
+		d := NewInt(test.d)
+		m := NewInt(test.m)
+
+		q1 := new(Int).Quo(x, y)
+		r1 := new(Int).Rem(x, y)
+		if !isNormalized(q1) {
+			t.Errorf("#%d Quo: %v is not normalized", i, *q1)
+		}
+		if !isNormalized(r1) {
+			t.Errorf("#%d Rem: %v is not normalized", i, *r1)
+		}
+		if q1.Cmp(q) != 0 || r1.Cmp(r) != 0 {
+			t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q1, r1, q, r)
+		}
+
+		q2, r2 := new(Int).QuoRem(x, y, new(Int))
+		if !isNormalized(q2) {
+			t.Errorf("#%d Quo: %v is not normalized", i, *q2)
+		}
+		if !isNormalized(r2) {
+			t.Errorf("#%d Rem: %v is not normalized", i, *r2)
+		}
+		if q2.Cmp(q) != 0 || r2.Cmp(r) != 0 {
+			t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q2, r2, q, r)
+		}
+
+		d1 := new(Int).Div(x, y)
+		m1 := new(Int).Mod(x, y)
+		if !isNormalized(d1) {
+			t.Errorf("#%d Div: %v is not normalized", i, *d1)
+		}
+		if !isNormalized(m1) {
+			t.Errorf("#%d Mod: %v is not normalized", i, *m1)
+		}
+		if d1.Cmp(d) != 0 || m1.Cmp(m) != 0 {
+			t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d1, m1, d, m)
+		}
+
+		d2, m2 := new(Int).DivMod(x, y, new(Int))
+		if !isNormalized(d2) {
+			t.Errorf("#%d Div: %v is not normalized", i, *d2)
+		}
+		if !isNormalized(m2) {
+			t.Errorf("#%d Mod: %v is not normalized", i, *m2)
+		}
+		if d2.Cmp(d) != 0 || m2.Cmp(m) != 0 {
+			t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d2, m2, d, m)
+		}
+	}
+}
+
+func norm(x nat) nat {
+	i := len(x)
+	for i > 0 && x[i-1] == 0 {
+		i--
+	}
+	return x[:i]
+}
+
+func TestBits(t *testing.T) {
+	for _, test := range []nat{
+		nil,
+		{0},
+		{1},
+		{0, 1, 2, 3, 4},
+		{4, 3, 2, 1, 0},
+		{4, 3, 2, 1, 0, 0, 0, 0},
+	} {
+		var z Int
+		z.neg = true
+		got := z.SetBits(test)
+		want := norm(test)
+		if got.abs.cmp(want) != 0 {
+			t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
+		}
+
+		if got.neg {
+			t.Errorf("SetBits(%v): got negative result", test)
+		}
+
+		bits := nat(z.Bits())
+		if bits.cmp(want) != 0 {
+			t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
+		}
+	}
+}
+
+func checkSetBytes(b []byte) bool {
+	hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
+	hex2 := hex.EncodeToString(b)
+
+	for len(hex1) < len(hex2) {
+		hex1 = "0" + hex1
+	}
+
+	for len(hex1) > len(hex2) {
+		hex2 = "0" + hex2
+	}
+
+	return hex1 == hex2
+}
+
+func TestSetBytes(t *testing.T) {
+	if err := quick.Check(checkSetBytes, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func checkBytes(b []byte) bool {
+	b2 := new(Int).SetBytes(b).Bytes()
+	return bytes.Equal(b, b2)
+}
+
+func TestBytes(t *testing.T) {
+	if err := quick.Check(checkBytes, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func checkQuo(x, y []byte) bool {
+	u := new(Int).SetBytes(x)
+	v := new(Int).SetBytes(y)
+
+	if len(v.abs) == 0 {
+		return true
+	}
+
+	r := new(Int)
+	q, r := new(Int).QuoRem(u, v, r)
+
+	if r.Cmp(v) >= 0 {
+		return false
+	}
+
+	uprime := new(Int).Set(q)
+	uprime.Mul(uprime, v)
+	uprime.Add(uprime, r)
+
+	return uprime.Cmp(u) == 0
+}
+
+var quoTests = []struct {
+	x, y string
+	q, r string
+}{
+	{
+		"476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
+		"9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
+		"50911",
+		"1",
+	},
+	{
+		"11510768301994997771168",
+		"1328165573307167369775",
+		"8",
+		"885443715537658812968",
+	},
+}
+
+func TestQuo(t *testing.T) {
+	if err := quick.Check(checkQuo, nil); err != nil {
+		t.Error(err)
+	}
+
+	for i, test := range quoTests {
+		x, _ := new(Int).SetString(test.x, 10)
+		y, _ := new(Int).SetString(test.y, 10)
+		expectedQ, _ := new(Int).SetString(test.q, 10)
+		expectedR, _ := new(Int).SetString(test.r, 10)
+
+		r := new(Int)
+		q, r := new(Int).QuoRem(x, y, r)
+
+		if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
+			t.Errorf("#%d got (%s, %s) want (%s, %s)", i, q, r, expectedQ, expectedR)
+		}
+	}
+}
+
+func TestQuoStepD6(t *testing.T) {
+	// See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
+	// a code path which only triggers 1 in 10^{-19} cases.
+
+	u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
+	v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
+
+	r := new(Int)
+	q, r := new(Int).QuoRem(u, v, r)
+	const expectedQ64 = "18446744073709551613"
+	const expectedR64 = "3138550867693340382088035895064302439801311770021610913807"
+	const expectedQ32 = "4294967293"
+	const expectedR32 = "39614081266355540837921718287"
+	if q.String() != expectedQ64 && q.String() != expectedQ32 ||
+		r.String() != expectedR64 && r.String() != expectedR32 {
+		t.Errorf("got (%s, %s) want (%s, %s) or (%s, %s)", q, r, expectedQ64, expectedR64, expectedQ32, expectedR32)
+	}
+}
+
+var bitLenTests = []struct {
+	in  string
+	out int
+}{
+	{"-1", 1},
+	{"0", 0},
+	{"1", 1},
+	{"2", 2},
+	{"4", 3},
+	{"0xabc", 12},
+	{"0x8000", 16},
+	{"0x80000000", 32},
+	{"0x800000000000", 48},
+	{"0x8000000000000000", 64},
+	{"0x80000000000000000000", 80},
+	{"-0x4000000000000000000000", 87},
+}
+
+func TestBitLen(t *testing.T) {
+	for i, test := range bitLenTests {
+		x, ok := new(Int).SetString(test.in, 0)
+		if !ok {
+			t.Errorf("#%d test input invalid: %s", i, test.in)
+			continue
+		}
+
+		if n := x.BitLen(); n != test.out {
+			t.Errorf("#%d got %d want %d", i, n, test.out)
+		}
+	}
+}
+
+var expTests = []struct {
+	x, y, m string
+	out     string
+}{
+	// y <= 0
+	{"0", "0", "", "1"},
+	{"1", "0", "", "1"},
+	{"-10", "0", "", "1"},
+	{"1234", "-1", "", "1"},
+
+	// m == 1
+	{"0", "0", "1", "0"},
+	{"1", "0", "1", "0"},
+	{"-10", "0", "1", "0"},
+	{"1234", "-1", "1", "0"},
+
+	// misc
+	{"5", "-7", "", "1"},
+	{"-5", "-7", "", "1"},
+	{"5", "0", "", "1"},
+	{"-5", "0", "", "1"},
+	{"5", "1", "", "5"},
+	{"-5", "1", "", "-5"},
+	{"-5", "1", "7", "2"},
+	{"-2", "3", "2", "0"},
+	{"5", "2", "", "25"},
+	{"1", "65537", "2", "1"},
+	{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+	{"0x8000000000000000", "2", "6719", "4944"},
+	{"0x8000000000000000", "3", "6719", "5447"},
+	{"0x8000000000000000", "1000", "6719", "1603"},
+	{"0x8000000000000000", "1000000", "6719", "3199"},
+	{"0x8000000000000000", "-1000000", "6719", "1"},
+	{
+		"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+		"298472983472983471903246121093472394872319615612417471234712061",
+		"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+		"23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+	},
+	// test case for issue 8822
+	{
+		"-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B988E23D4D954F322C3540541BC649ABD504C50FADFD9F0987D58A2BF689313A285E773FF02899A6EF887D1D4A0D2",
+		"0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+		"0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73",
+		"21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442",
+	},
+}
+
+func TestExp(t *testing.T) {
+	for i, test := range expTests {
+		x, ok1 := new(Int).SetString(test.x, 0)
+		y, ok2 := new(Int).SetString(test.y, 0)
+		out, ok3 := new(Int).SetString(test.out, 0)
+
+		var ok4 bool
+		var m *Int
+
+		if len(test.m) == 0 {
+			m, ok4 = nil, true
+		} else {
+			m, ok4 = new(Int).SetString(test.m, 0)
+		}
+
+		if !ok1 || !ok2 || !ok3 || !ok4 {
+			t.Errorf("#%d: error in input", i)
+			continue
+		}
+
+		z1 := new(Int).Exp(x, y, m)
+		if !isNormalized(z1) {
+			t.Errorf("#%d: %v is not normalized", i, *z1)
+		}
+		if z1.Cmp(out) != 0 {
+			t.Errorf("#%d: got %s want %s", i, z1, out)
+		}
+
+		if m == nil {
+			// The result should be the same as for m == 0;
+			// specifically, there should be no div-zero panic.
+			m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0
+			z2 := new(Int).Exp(x, y, m)
+			if z2.Cmp(z1) != 0 {
+				t.Errorf("#%d: got %s want %s", i, z2, z1)
+			}
+		}
+	}
+}
+
+func checkGcd(aBytes, bBytes []byte) bool {
+	x := new(Int)
+	y := new(Int)
+	a := new(Int).SetBytes(aBytes)
+	b := new(Int).SetBytes(bBytes)
+
+	d := new(Int).GCD(x, y, a, b)
+	x.Mul(x, a)
+	y.Mul(y, b)
+	x.Add(x, y)
+
+	return x.Cmp(d) == 0
+}
+
+var gcdTests = []struct {
+	d, x, y, a, b string
+}{
+	// a <= 0 || b <= 0
+	{"0", "0", "0", "0", "0"},
+	{"0", "0", "0", "0", "7"},
+	{"0", "0", "0", "11", "0"},
+	{"0", "0", "0", "-77", "35"},
+	{"0", "0", "0", "64515", "-24310"},
+	{"0", "0", "0", "-64515", "-24310"},
+
+	{"1", "-9", "47", "120", "23"},
+	{"7", "1", "-2", "77", "35"},
+	{"935", "-3", "8", "64515", "24310"},
+	{"935000000000000000", "-3", "8", "64515000000000000000", "24310000000000000000"},
+	{"1", "-221", "22059940471369027483332068679400581064239780177629666810348940098015901108344", "98920366548084643601728869055592650835572950932266967461790948584315647051443", "991"},
+
+	// test early exit (after one Euclidean iteration) in binaryGCD
+	{"1", "", "", "1", "98920366548084643601728869055592650835572950932266967461790948584315647051443"},
+}
+
+func testGcd(t *testing.T, d, x, y, a, b *Int) {
+	var X *Int
+	if x != nil {
+		X = new(Int)
+	}
+	var Y *Int
+	if y != nil {
+		Y = new(Int)
+	}
+
+	D := new(Int).GCD(X, Y, a, b)
+	if D.Cmp(d) != 0 {
+		t.Errorf("GCD(%s, %s): got d = %s, want %s", a, b, D, d)
+	}
+	if x != nil && X.Cmp(x) != 0 {
+		t.Errorf("GCD(%s, %s): got x = %s, want %s", a, b, X, x)
+	}
+	if y != nil && Y.Cmp(y) != 0 {
+		t.Errorf("GCD(%s, %s): got y = %s, want %s", a, b, Y, y)
+	}
+
+	// binaryGCD requires a > 0 && b > 0
+	if a.Sign() <= 0 || b.Sign() <= 0 {
+		return
+	}
+
+	D.binaryGCD(a, b)
+	if D.Cmp(d) != 0 {
+		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d)
+	}
+}
+
+func TestGcd(t *testing.T) {
+	for _, test := range gcdTests {
+		d, _ := new(Int).SetString(test.d, 0)
+		x, _ := new(Int).SetString(test.x, 0)
+		y, _ := new(Int).SetString(test.y, 0)
+		a, _ := new(Int).SetString(test.a, 0)
+		b, _ := new(Int).SetString(test.b, 0)
+
+		testGcd(t, d, nil, nil, a, b)
+		testGcd(t, d, x, nil, a, b)
+		testGcd(t, d, nil, y, a, b)
+		testGcd(t, d, x, y, a, b)
+	}
+
+	quick.Check(checkGcd, nil)
+}
+
+var primes = []string{
+	"2",
+	"3",
+	"5",
+	"7",
+	"11",
+
+	"13756265695458089029",
+	"13496181268022124907",
+	"10953742525620032441",
+	"17908251027575790097",
+
+	// http://golang.org/issue/638
+	"18699199384836356663",
+
+	"98920366548084643601728869055592650835572950932266967461790948584315647051443",
+	"94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+	// http://primes.utm.edu/lists/small/small3.html
+	"449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+	"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+	"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+	"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+}
+
+var composites = []string{
+	"0",
+	"1",
+	"21284175091214687912771199898307297748211672914763848041968395774954376176754",
+	"6084766654921918907427900243509372380954290099172559290432744450051395395951",
+	"84594350493221918389213352992032324280367711247940675652888030554255915464401",
+	"82793403787388584738507275144194252681",
+}
+
+func TestProbablyPrime(t *testing.T) {
+	nreps := 20
+	if testing.Short() {
+		nreps = 1
+	}
+	for i, s := range primes {
+		p, _ := new(Int).SetString(s, 10)
+		if !p.ProbablyPrime(nreps) {
+			t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+		}
+	}
+
+	for i, s := range composites {
+		c, _ := new(Int).SetString(s, 10)
+		if c.ProbablyPrime(nreps) {
+			t.Errorf("#%d composite found to be prime (%s)", i, s)
+		}
+		if testing.Short() {
+			break
+		}
+	}
+
+	// check that ProbablyPrime panics if n <= 0
+	c := NewInt(11) // a prime
+	for _, n := range []int{-1, 0, 1} {
+		func() {
+			defer func() {
+				if n <= 0 && recover() == nil {
+					t.Fatalf("expected panic from ProbablyPrime(%d)", n)
+				}
+			}()
+			if !c.ProbablyPrime(n) {
+				t.Fatalf("%v should be a prime", c)
+			}
+		}()
+	}
+}
+
+type intShiftTest struct {
+	in    string
+	shift uint
+	out   string
+}
+
+var rshTests = []intShiftTest{
+	{"0", 0, "0"},
+	{"-0", 0, "0"},
+	{"0", 1, "0"},
+	{"0", 2, "0"},
+	{"1", 0, "1"},
+	{"1", 1, "0"},
+	{"1", 2, "0"},
+	{"2", 0, "2"},
+	{"2", 1, "1"},
+	{"-1", 0, "-1"},
+	{"-1", 1, "-1"},
+	{"-1", 10, "-1"},
+	{"-100", 2, "-25"},
+	{"-100", 3, "-13"},
+	{"-100", 100, "-1"},
+	{"4294967296", 0, "4294967296"},
+	{"4294967296", 1, "2147483648"},
+	{"4294967296", 2, "1073741824"},
+	{"18446744073709551616", 0, "18446744073709551616"},
+	{"18446744073709551616", 1, "9223372036854775808"},
+	{"18446744073709551616", 2, "4611686018427387904"},
+	{"18446744073709551616", 64, "1"},
+	{"340282366920938463463374607431768211456", 64, "18446744073709551616"},
+	{"340282366920938463463374607431768211456", 128, "1"},
+}
+
+func TestRsh(t *testing.T) {
+	for i, test := range rshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		out := new(Int).Rsh(in, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if out.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, expected)
+		}
+	}
+}
+
+func TestRshSelf(t *testing.T) {
+	for i, test := range rshTests {
+		z, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		z.Rsh(z, test.shift)
+
+		if !isNormalized(z) {
+			t.Errorf("#%d: %v is not normalized", i, *z)
+		}
+		if z.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, z, expected)
+		}
+	}
+}
+
+var lshTests = []intShiftTest{
+	{"0", 0, "0"},
+	{"0", 1, "0"},
+	{"0", 2, "0"},
+	{"1", 0, "1"},
+	{"1", 1, "2"},
+	{"1", 2, "4"},
+	{"2", 0, "2"},
+	{"2", 1, "4"},
+	{"2", 2, "8"},
+	{"-87", 1, "-174"},
+	{"4294967296", 0, "4294967296"},
+	{"4294967296", 1, "8589934592"},
+	{"4294967296", 2, "17179869184"},
+	{"18446744073709551616", 0, "18446744073709551616"},
+	{"9223372036854775808", 1, "18446744073709551616"},
+	{"4611686018427387904", 2, "18446744073709551616"},
+	{"1", 64, "18446744073709551616"},
+	{"18446744073709551616", 64, "340282366920938463463374607431768211456"},
+	{"1", 128, "340282366920938463463374607431768211456"},
+}
+
+func TestLsh(t *testing.T) {
+	for i, test := range lshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		out := new(Int).Lsh(in, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if out.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, expected)
+		}
+	}
+}
+
+func TestLshSelf(t *testing.T) {
+	for i, test := range lshTests {
+		z, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		z.Lsh(z, test.shift)
+
+		if !isNormalized(z) {
+			t.Errorf("#%d: %v is not normalized", i, *z)
+		}
+		if z.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, z, expected)
+		}
+	}
+}
+
+func TestLshRsh(t *testing.T) {
+	for i, test := range rshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		out := new(Int).Lsh(in, test.shift)
+		out = out.Rsh(out, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if in.Cmp(out) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, in)
+		}
+	}
+	for i, test := range lshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		out := new(Int).Lsh(in, test.shift)
+		out.Rsh(out, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if in.Cmp(out) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, in)
+		}
+	}
+}
+
+var int64Tests = []int64{
+	0,
+	1,
+	-1,
+	4294967295,
+	-4294967295,
+	4294967296,
+	-4294967296,
+	9223372036854775807,
+	-9223372036854775807,
+	-9223372036854775808,
+}
+
+func TestInt64(t *testing.T) {
+	for i, testVal := range int64Tests {
+		in := NewInt(testVal)
+		out := in.Int64()
+
+		if out != testVal {
+			t.Errorf("#%d got %d want %d", i, out, testVal)
+		}
+	}
+}
+
+var uint64Tests = []uint64{
+	0,
+	1,
+	4294967295,
+	4294967296,
+	8589934591,
+	8589934592,
+	9223372036854775807,
+	9223372036854775808,
+	18446744073709551615, // 1<<64 - 1
+}
+
+func TestUint64(t *testing.T) {
+	in := new(Int)
+	for i, testVal := range uint64Tests {
+		in.SetUint64(testVal)
+		out := in.Uint64()
+
+		if out != testVal {
+			t.Errorf("#%d got %d want %d", i, out, testVal)
+		}
+
+		str := fmt.Sprint(testVal)
+		strOut := in.String()
+		if strOut != str {
+			t.Errorf("#%d.String got %s want %s", i, strOut, str)
+		}
+	}
+}
+
+var bitwiseTests = []struct {
+	x, y                 string
+	and, or, xor, andNot string
+}{
+	{"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
+	{"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
+	{"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
+	{"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
+	{"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
+	{"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
+	{"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
+	{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
+	{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
+	{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+	{"0xff", "-0x0a", "0xf6", "-0x01", "-0xf7", "0x09"},
+	{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
+	{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
+	{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
+	{
+		"0x1000009dc6e3d9822cba04129bcbe3401",
+		"0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+		"0x1000001186210100001000009048c2001",
+		"0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+		"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+		"0x8c40c2d8822caa04120b8321400",
+	},
+	{
+		"0x1000009dc6e3d9822cba04129bcbe3401",
+		"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+		"0x8c40c2d8822caa04120b8321401",
+		"-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
+		"-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
+		"0x1000001186210100001000009048c2000",
+	},
+	{
+		"-0x1000009dc6e3d9822cba04129bcbe3401",
+		"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+		"-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+		"-0x1000001186210100001000009048c2001",
+		"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+		"0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
+	},
+}
+
+type bitFun func(z, x, y *Int) *Int
+
+func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+	expected := new(Int)
+	expected.SetString(exp, 0)
+
+	out := f(new(Int), x, y)
+	if out.Cmp(expected) != 0 {
+		t.Errorf("%s: got %s want %s", msg, out, expected)
+	}
+}
+
+func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+	self := new(Int)
+	self.Set(x)
+	expected := new(Int)
+	expected.SetString(exp, 0)
+
+	self = f(self, self, y)
+	if self.Cmp(expected) != 0 {
+		t.Errorf("%s: got %s want %s", msg, self, expected)
+	}
+}
+
+func altBit(x *Int, i int) uint {
+	z := new(Int).Rsh(x, uint(i))
+	z = z.And(z, NewInt(1))
+	if z.Cmp(new(Int)) != 0 {
+		return 1
+	}
+	return 0
+}
+
+func altSetBit(z *Int, x *Int, i int, b uint) *Int {
+	one := NewInt(1)
+	m := one.Lsh(one, uint(i))
+	switch b {
+	case 1:
+		return z.Or(x, m)
+	case 0:
+		return z.AndNot(x, m)
+	}
+	panic("set bit is not 0 or 1")
+}
+
+func testBitset(t *testing.T, x *Int) {
+	n := x.BitLen()
+	z := new(Int).Set(x)
+	z1 := new(Int).Set(x)
+	for i := 0; i < n+10; i++ {
+		old := z.Bit(i)
+		old1 := altBit(z1, i)
+		if old != old1 {
+			t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
+		}
+		z := new(Int).SetBit(z, i, 1)
+		z1 := altSetBit(new(Int), z1, i, 1)
+		if z.Bit(i) == 0 {
+			t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
+		}
+		if z.Cmp(z1) != 0 {
+			t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
+		}
+		z.SetBit(z, i, 0)
+		altSetBit(z1, z1, i, 0)
+		if z.Bit(i) != 0 {
+			t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
+		}
+		if z.Cmp(z1) != 0 {
+			t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
+		}
+		altSetBit(z1, z1, i, old)
+		z.SetBit(z, i, old)
+		if z.Cmp(z1) != 0 {
+			t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
+		}
+	}
+	if z.Cmp(x) != 0 {
+		t.Errorf("bitset: got %s want %s", z, x)
+	}
+}
+
+var bitsetTests = []struct {
+	x string
+	i int
+	b uint
+}{
+	{"0", 0, 0},
+	{"0", 200, 0},
+	{"1", 0, 1},
+	{"1", 1, 0},
+	{"-1", 0, 1},
+	{"-1", 200, 1},
+	{"0x2000000000000000000000000000", 108, 0},
+	{"0x2000000000000000000000000000", 109, 1},
+	{"0x2000000000000000000000000000", 110, 0},
+	{"-0x2000000000000000000000000001", 108, 1},
+	{"-0x2000000000000000000000000001", 109, 0},
+	{"-0x2000000000000000000000000001", 110, 1},
+}
+
+func TestBitSet(t *testing.T) {
+	for _, test := range bitwiseTests {
+		x := new(Int)
+		x.SetString(test.x, 0)
+		testBitset(t, x)
+		x = new(Int)
+		x.SetString(test.y, 0)
+		testBitset(t, x)
+	}
+	for i, test := range bitsetTests {
+		x := new(Int)
+		x.SetString(test.x, 0)
+		b := x.Bit(test.i)
+		if b != test.b {
+			t.Errorf("#%d got %v want %v", i, b, test.b)
+		}
+	}
+	z := NewInt(1)
+	z.SetBit(NewInt(0), 2, 1)
+	if z.Cmp(NewInt(4)) != 0 {
+		t.Errorf("destination leaked into result; got %s want 4", z)
+	}
+}
+
+func BenchmarkBitset(b *testing.B) {
+	z := new(Int)
+	z.SetBit(z, 512, 1)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		z.SetBit(z, i&512, 1)
+	}
+}
+
+func BenchmarkBitsetNeg(b *testing.B) {
+	z := NewInt(-1)
+	z.SetBit(z, 512, 0)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		z.SetBit(z, i&512, 0)
+	}
+}
+
+func BenchmarkBitsetOrig(b *testing.B) {
+	z := new(Int)
+	altSetBit(z, z, 512, 1)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		altSetBit(z, z, i&512, 1)
+	}
+}
+
+func BenchmarkBitsetNegOrig(b *testing.B) {
+	z := NewInt(-1)
+	altSetBit(z, z, 512, 0)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		altSetBit(z, z, i&512, 0)
+	}
+}
+
+func TestBitwise(t *testing.T) {
+	x := new(Int)
+	y := new(Int)
+	for _, test := range bitwiseTests {
+		x.SetString(test.x, 0)
+		y.SetString(test.y, 0)
+
+		testBitFun(t, "and", (*Int).And, x, y, test.and)
+		testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
+		testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+		testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+		testBitFun(t, "or", (*Int).Or, x, y, test.or)
+		testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
+		testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
+		testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
+	}
+}
+
+var notTests = []struct {
+	in  string
+	out string
+}{
+	{"0", "-1"},
+	{"1", "-2"},
+	{"7", "-8"},
+	{"0", "-1"},
+	{"-81910", "81909"},
+	{
+		"298472983472983471903246121093472394872319615612417471234712061",
+		"-298472983472983471903246121093472394872319615612417471234712062",
+	},
+}
+
+func TestNot(t *testing.T) {
+	in := new(Int)
+	out := new(Int)
+	expected := new(Int)
+	for i, test := range notTests {
+		in.SetString(test.in, 10)
+		expected.SetString(test.out, 10)
+		out = out.Not(in)
+		if out.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, expected)
+		}
+		out = out.Not(out)
+		if out.Cmp(in) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, in)
+		}
+	}
+}
+
+var modInverseTests = []struct {
+	element string
+	modulus string
+}{
+	{"1234567", "458948883992"},
+	{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+}
+
+func TestModInverse(t *testing.T) {
+	var element, modulus, gcd, inverse Int
+	one := NewInt(1)
+	for i, test := range modInverseTests {
+		(&element).SetString(test.element, 10)
+		(&modulus).SetString(test.modulus, 10)
+		(&inverse).ModInverse(&element, &modulus)
+		(&inverse).Mul(&inverse, &element)
+		(&inverse).Mod(&inverse, &modulus)
+		if (&inverse).Cmp(one) != 0 {
+			t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse)
+		}
+	}
+	// exhaustive test for small values
+	for n := 2; n < 100; n++ {
+		(&modulus).SetInt64(int64(n))
+		for x := 1; x < n; x++ {
+			(&element).SetInt64(int64(x))
+			(&gcd).GCD(nil, nil, &element, &modulus)
+			if (&gcd).Cmp(one) != 0 {
+				continue
+			}
+			(&inverse).ModInverse(&element, &modulus)
+			(&inverse).Mul(&inverse, &element)
+			(&inverse).Mod(&inverse, &modulus)
+			if (&inverse).Cmp(one) != 0 {
+				t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse)
+			}
+		}
+	}
+}
+
+var encodingTests = []string{
+	"-539345864568634858364538753846587364875430589374589",
+	"-678645873",
+	"-100",
+	"-2",
+	"-1",
+	"0",
+	"1",
+	"2",
+	"10",
+	"42",
+	"1234567890",
+	"298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestIntGobEncoding(t *testing.T) {
+	var medium bytes.Buffer
+	enc := gob.NewEncoder(&medium)
+	dec := gob.NewDecoder(&medium)
+	for _, test := range encodingTests {
+		medium.Reset() // empty buffer for each test case (in case of failures)
+		var tx Int
+		tx.SetString(test, 10)
+		if err := enc.Encode(&tx); err != nil {
+			t.Errorf("encoding of %s failed: %s", &tx, err)
+		}
+		var rx Int
+		if err := dec.Decode(&rx); err != nil {
+			t.Errorf("decoding of %s failed: %s", &tx, err)
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilIntInSlice(t *testing.T) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	dec := gob.NewDecoder(buf)
+
+	var in = make([]*Int, 1)
+	err := enc.Encode(&in)
+	if err != nil {
+		t.Errorf("gob encode failed: %q", err)
+	}
+	var out []*Int
+	err = dec.Decode(&out)
+	if err != nil {
+		t.Fatalf("gob decode failed: %q", err)
+	}
+	if len(out) != 1 {
+		t.Fatalf("wrong len; want 1 got %d", len(out))
+	}
+	var zero Int
+	if out[0].Cmp(&zero) != 0 {
+		t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
+	}
+}
+
+func TestIntJSONEncoding(t *testing.T) {
+	for _, test := range encodingTests {
+		var tx Int
+		tx.SetString(test, 10)
+		b, err := json.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+		}
+		var rx Int
+		if err := json.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+var intVals = []string{
+	"-141592653589793238462643383279502884197169399375105820974944592307816406286",
+	"-1415926535897932384626433832795028841971",
+	"-141592653589793",
+	"-1",
+	"0",
+	"1",
+	"141592653589793",
+	"1415926535897932384626433832795028841971",
+	"141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+func TestIntJSONEncodingTextMarshaller(t *testing.T) {
+	for _, num := range intVals {
+		var tx Int
+		tx.SetString(num, 0)
+		b, err := json.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		var rx Int
+		if err := json.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+func TestIntXMLEncodingTextMarshaller(t *testing.T) {
+	for _, num := range intVals {
+		var tx Int
+		tx.SetString(num, 0)
+		b, err := xml.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		var rx Int
+		if err := xml.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+func TestIssue2607(t *testing.T) {
+	// This code sequence used to hang.
+	n := NewInt(10)
+	n.Rand(rand.New(rand.NewSource(9)), n)
+}
diff --git a/src/cmd/internal/gc/big/intconv.go b/src/cmd/internal/gc/big/intconv.go
new file mode 100644
index 0000000..9c68a22
--- /dev/null
+++ b/src/cmd/internal/gc/big/intconv.go
@@ -0,0 +1,228 @@
+// 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.
+
+// This file implements int-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+)
+
+func (x *Int) String() string {
+	switch {
+	case x == nil:
+		return "<nil>"
+	case x.neg:
+		return "-" + x.abs.decimalString()
+	}
+	return x.abs.decimalString()
+}
+
+func charset(ch rune) string {
+	switch ch {
+	case 'b':
+		return lowercaseDigits[0:2]
+	case 'o':
+		return lowercaseDigits[0:8]
+	case 'd', 's', 'v':
+		return lowercaseDigits[0:10]
+	case 'x':
+		return lowercaseDigits[0:16]
+	case 'X':
+		return uppercaseDigits[0:16]
+	}
+	return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+	if len(text) > 0 {
+		b := []byte(text)
+		for ; count > 0; count-- {
+			s.Write(b)
+		}
+	}
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch rune) {
+	cs := charset(ch)
+
+	// special cases
+	switch {
+	case cs == "":
+		// unknown format
+		fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+		return
+	case x == nil:
+		fmt.Fprint(s, "<nil>")
+		return
+	}
+
+	// determine sign character
+	sign := ""
+	switch {
+	case x.neg:
+		sign = "-"
+	case s.Flag('+'): // supersedes ' ' when both specified
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	// determine prefix characters for indicating output base
+	prefix := ""
+	if s.Flag('#') {
+		switch ch {
+		case 'o': // octal
+			prefix = "0"
+		case 'x': // hexadecimal
+			prefix = "0x"
+		case 'X':
+			prefix = "0X"
+		}
+	}
+
+	// determine digits with base set by len(cs) and digit characters from cs
+	digits := x.abs.string(cs)
+
+	// number of characters for the three classes of number padding
+	var left int   // space characters to left of digits for right justification ("%8d")
+	var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+	var right int  // space characters to right of digits for left justification ("%-8d")
+
+	// determine number padding from precision: the least number of digits to output
+	precision, precisionSet := s.Precision()
+	if precisionSet {
+		switch {
+		case len(digits) < precision:
+			zeroes = precision - len(digits) // count of zero padding
+		case digits == "0" && precision == 0:
+			return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+		}
+	}
+
+	// determine field pad from width: the least number of characters to output
+	length := len(sign) + len(prefix) + zeroes + len(digits)
+	if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+		switch d := width - length; {
+		case s.Flag('-'):
+			// pad on the right with spaces; supersedes '0' when both specified
+			right = d
+		case s.Flag('0') && !precisionSet:
+			// pad with zeroes unless precision also specified
+			zeroes = d
+		default:
+			// pad on the left with spaces
+			left = d
+		}
+	}
+
+	// print number as [left pad][sign][prefix][zero pad][digits][right pad]
+	writeMultiple(s, " ", left)
+	writeMultiple(s, sign, 1)
+	writeMultiple(s, prefix, 1)
+	writeMultiple(s, "0", zeroes)
+	writeMultiple(s, digits, 1)
+	writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined but the returned value is nil. The
+// syntax follows the syntax of integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
+	// determine sign
+	neg, err := scanSign(r)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	// determine mantissa
+	z.abs, base, _, err = z.abs.scan(r, base, false)
+	if err != nil {
+		return nil, base, err
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+	return z, base, nil
+}
+
+func scanSign(r io.ByteScanner) (neg bool, err error) {
+	var ch byte
+	if ch, err = r.ReadByte(); err != nil {
+		return false, err
+	}
+	switch ch {
+	case '-':
+		neg = true
+	case '+':
+		// nothing to do
+	default:
+		r.UnreadByte()
+	}
+	return
+}
+
+// byteReader is a local wrapper around fmt.ScanState;
+// it implements the ByteReader interface.
+type byteReader struct {
+	fmt.ScanState
+}
+
+func (r byteReader) ReadByte() (byte, error) {
+	ch, size, err := r.ReadRune()
+	if size != 1 && err == nil {
+		err = fmt.Errorf("invalid rune %#U", ch)
+	}
+	return byte(ch), err
+}
+
+func (r byteReader) UnreadByte() error {
+	return r.UnreadRune()
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
+	s.SkipSpace() // skip leading space characters
+	base := 0
+	switch ch {
+	case 'b':
+		base = 2
+	case 'o':
+		base = 8
+	case 'd':
+		base = 10
+	case 'x', 'X':
+		base = 16
+	case 's', 'v':
+		// let scan determine the base
+	default:
+		return errors.New("Int.Scan: invalid verb")
+	}
+	_, _, err := z.scan(byteReader{s}, base)
+	return err
+}
diff --git a/src/cmd/internal/gc/big/intconv_test.go b/src/cmd/internal/gc/big/intconv_test.go
new file mode 100644
index 0000000..2deb84b
--- /dev/null
+++ b/src/cmd/internal/gc/big/intconv_test.go
@@ -0,0 +1,342 @@
+// 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 big
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+)
+
+var stringTests = []struct {
+	in   string
+	out  string
+	base int
+	val  int64
+	ok   bool
+}{
+	{in: "", ok: false},
+	{in: "a", ok: false},
+	{in: "z", ok: false},
+	{in: "+", ok: false},
+	{in: "-", ok: false},
+	{in: "0b", ok: false},
+	{in: "0x", ok: false},
+	{in: "2", base: 2, ok: false},
+	{in: "0b2", base: 0, ok: false},
+	{in: "08", ok: false},
+	{in: "8", base: 8, ok: false},
+	{in: "0xg", base: 0, ok: false},
+	{in: "g", base: 16, ok: false},
+	{"0", "0", 0, 0, true},
+	{"0", "0", 10, 0, true},
+	{"0", "0", 16, 0, true},
+	{"+0", "0", 0, 0, true},
+	{"-0", "0", 0, 0, true},
+	{"10", "10", 0, 10, true},
+	{"10", "10", 10, 10, true},
+	{"10", "10", 16, 16, true},
+	{"-10", "-10", 16, -16, true},
+	{"+10", "10", 16, 16, true},
+	{"0x10", "16", 0, 16, true},
+	{in: "0x10", base: 16, ok: false},
+	{"-0x10", "-16", 0, -16, true},
+	{"+0x10", "16", 0, 16, true},
+	{"00", "0", 0, 0, true},
+	{"0", "0", 8, 0, true},
+	{"07", "7", 0, 7, true},
+	{"7", "7", 8, 7, true},
+	{"023", "19", 0, 19, true},
+	{"23", "23", 8, 19, true},
+	{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+	{"0b0", "0", 0, 0, true},
+	{"-111", "-111", 2, -7, true},
+	{"-0b111", "-7", 0, -7, true},
+	{"0b1001010111", "599", 0, 0x257, true},
+	{"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+	switch base {
+	case 2:
+		return "%b"
+	case 8:
+		return "%o"
+	case 16:
+		return "%x"
+	}
+	return "%d"
+}
+
+func TestGetString(t *testing.T) {
+	z := new(Int)
+	for i, test := range stringTests {
+		if !test.ok {
+			continue
+		}
+		z.SetInt64(test.val)
+
+		if test.base == 10 {
+			s := z.String()
+			if s != test.out {
+				t.Errorf("#%da got %s; want %s", i, s, test.out)
+			}
+		}
+
+		s := fmt.Sprintf(format(test.base), z)
+		if s != test.out {
+			t.Errorf("#%db got %s; want %s", i, s, test.out)
+		}
+	}
+}
+
+func TestSetString(t *testing.T) {
+	tmp := new(Int)
+	for i, test := range stringTests {
+		// initialize to a non-zero value so that issues with parsing
+		// 0 are detected
+		tmp.SetInt64(1234567890)
+		n1, ok1 := new(Int).SetString(test.in, test.base)
+		n2, ok2 := tmp.SetString(test.in, test.base)
+		expected := NewInt(test.val)
+		if ok1 != test.ok || ok2 != test.ok {
+			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+			continue
+		}
+		if !ok1 {
+			if n1 != nil {
+				t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+			}
+			continue
+		}
+		if !ok2 {
+			if n2 != nil {
+				t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+			}
+			continue
+		}
+
+		if ok1 && !isNormalized(n1) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+		}
+		if ok2 && !isNormalized(n2) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+		}
+
+		if n1.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+		}
+		if n2.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+		}
+	}
+}
+
+var formatTests = []struct {
+	input  string
+	format string
+	output string
+}{
+	{"<nil>", "%x", "<nil>"},
+	{"<nil>", "%#x", "<nil>"},
+	{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+	{"10", "%b", "1010"},
+	{"10", "%o", "12"},
+	{"10", "%d", "10"},
+	{"10", "%v", "10"},
+	{"10", "%x", "a"},
+	{"10", "%X", "A"},
+	{"-10", "%X", "-A"},
+	{"10", "%y", "%!y(big.Int=10)"},
+	{"-10", "%y", "%!y(big.Int=-10)"},
+
+	{"10", "%#b", "1010"},
+	{"10", "%#o", "012"},
+	{"10", "%#d", "10"},
+	{"10", "%#v", "10"},
+	{"10", "%#x", "0xa"},
+	{"10", "%#X", "0XA"},
+	{"-10", "%#X", "-0XA"},
+	{"10", "%#y", "%!y(big.Int=10)"},
+	{"-10", "%#y", "%!y(big.Int=-10)"},
+
+	{"1234", "%d", "1234"},
+	{"1234", "%3d", "1234"},
+	{"1234", "%4d", "1234"},
+	{"-1234", "%d", "-1234"},
+	{"1234", "% 5d", " 1234"},
+	{"1234", "%+5d", "+1234"},
+	{"1234", "%-5d", "1234 "},
+	{"1234", "%x", "4d2"},
+	{"1234", "%X", "4D2"},
+	{"-1234", "%3x", "-4d2"},
+	{"-1234", "%4x", "-4d2"},
+	{"-1234", "%5x", " -4d2"},
+	{"-1234", "%-5x", "-4d2 "},
+	{"1234", "%03d", "1234"},
+	{"1234", "%04d", "1234"},
+	{"1234", "%05d", "01234"},
+	{"1234", "%06d", "001234"},
+	{"-1234", "%06d", "-01234"},
+	{"1234", "%+06d", "+01234"},
+	{"1234", "% 06d", " 01234"},
+	{"1234", "%-6d", "1234  "},
+	{"1234", "%-06d", "1234  "},
+	{"-1234", "%-06d", "-1234 "},
+
+	{"1234", "%.3d", "1234"},
+	{"1234", "%.4d", "1234"},
+	{"1234", "%.5d", "01234"},
+	{"1234", "%.6d", "001234"},
+	{"-1234", "%.3d", "-1234"},
+	{"-1234", "%.4d", "-1234"},
+	{"-1234", "%.5d", "-01234"},
+	{"-1234", "%.6d", "-001234"},
+
+	{"1234", "%8.3d", "    1234"},
+	{"1234", "%8.4d", "    1234"},
+	{"1234", "%8.5d", "   01234"},
+	{"1234", "%8.6d", "  001234"},
+	{"-1234", "%8.3d", "   -1234"},
+	{"-1234", "%8.4d", "   -1234"},
+	{"-1234", "%8.5d", "  -01234"},
+	{"-1234", "%8.6d", " -001234"},
+
+	{"1234", "%+8.3d", "   +1234"},
+	{"1234", "%+8.4d", "   +1234"},
+	{"1234", "%+8.5d", "  +01234"},
+	{"1234", "%+8.6d", " +001234"},
+	{"-1234", "%+8.3d", "   -1234"},
+	{"-1234", "%+8.4d", "   -1234"},
+	{"-1234", "%+8.5d", "  -01234"},
+	{"-1234", "%+8.6d", " -001234"},
+
+	{"1234", "% 8.3d", "    1234"},
+	{"1234", "% 8.4d", "    1234"},
+	{"1234", "% 8.5d", "   01234"},
+	{"1234", "% 8.6d", "  001234"},
+	{"-1234", "% 8.3d", "   -1234"},
+	{"-1234", "% 8.4d", "   -1234"},
+	{"-1234", "% 8.5d", "  -01234"},
+	{"-1234", "% 8.6d", " -001234"},
+
+	{"1234", "%.3x", "4d2"},
+	{"1234", "%.4x", "04d2"},
+	{"1234", "%.5x", "004d2"},
+	{"1234", "%.6x", "0004d2"},
+	{"-1234", "%.3x", "-4d2"},
+	{"-1234", "%.4x", "-04d2"},
+	{"-1234", "%.5x", "-004d2"},
+	{"-1234", "%.6x", "-0004d2"},
+
+	{"1234", "%8.3x", "     4d2"},
+	{"1234", "%8.4x", "    04d2"},
+	{"1234", "%8.5x", "   004d2"},
+	{"1234", "%8.6x", "  0004d2"},
+	{"-1234", "%8.3x", "    -4d2"},
+	{"-1234", "%8.4x", "   -04d2"},
+	{"-1234", "%8.5x", "  -004d2"},
+	{"-1234", "%8.6x", " -0004d2"},
+
+	{"1234", "%+8.3x", "    +4d2"},
+	{"1234", "%+8.4x", "   +04d2"},
+	{"1234", "%+8.5x", "  +004d2"},
+	{"1234", "%+8.6x", " +0004d2"},
+	{"-1234", "%+8.3x", "    -4d2"},
+	{"-1234", "%+8.4x", "   -04d2"},
+	{"-1234", "%+8.5x", "  -004d2"},
+	{"-1234", "%+8.6x", " -0004d2"},
+
+	{"1234", "% 8.3x", "     4d2"},
+	{"1234", "% 8.4x", "    04d2"},
+	{"1234", "% 8.5x", "   004d2"},
+	{"1234", "% 8.6x", "  0004d2"},
+	{"1234", "% 8.7x", " 00004d2"},
+	{"1234", "% 8.8x", " 000004d2"},
+	{"-1234", "% 8.3x", "    -4d2"},
+	{"-1234", "% 8.4x", "   -04d2"},
+	{"-1234", "% 8.5x", "  -004d2"},
+	{"-1234", "% 8.6x", " -0004d2"},
+	{"-1234", "% 8.7x", "-00004d2"},
+	{"-1234", "% 8.8x", "-000004d2"},
+
+	{"1234", "%-8.3d", "1234    "},
+	{"1234", "%-8.4d", "1234    "},
+	{"1234", "%-8.5d", "01234   "},
+	{"1234", "%-8.6d", "001234  "},
+	{"1234", "%-8.7d", "0001234 "},
+	{"1234", "%-8.8d", "00001234"},
+	{"-1234", "%-8.3d", "-1234   "},
+	{"-1234", "%-8.4d", "-1234   "},
+	{"-1234", "%-8.5d", "-01234  "},
+	{"-1234", "%-8.6d", "-001234 "},
+	{"-1234", "%-8.7d", "-0001234"},
+	{"-1234", "%-8.8d", "-00001234"},
+
+	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+	{"0", "%.d", ""},
+	{"0", "%.0d", ""},
+	{"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+	for i, test := range formatTests {
+		var x *Int
+		if test.input != "<nil>" {
+			var ok bool
+			x, ok = new(Int).SetString(test.input, 0)
+			if !ok {
+				t.Errorf("#%d failed reading input %s", i, test.input)
+			}
+		}
+		output := fmt.Sprintf(test.format, x)
+		if output != test.output {
+			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+		}
+	}
+}
+
+var scanTests = []struct {
+	input     string
+	format    string
+	output    string
+	remaining int
+}{
+	{"1010", "%b", "10", 0},
+	{"0b1010", "%v", "10", 0},
+	{"12", "%o", "10", 0},
+	{"012", "%v", "10", 0},
+	{"10", "%d", "10", 0},
+	{"10", "%v", "10", 0},
+	{"a", "%x", "10", 0},
+	{"0xa", "%v", "10", 0},
+	{"A", "%X", "10", 0},
+	{"-A", "%X", "-10", 0},
+	{"+0b1011001", "%v", "89", 0},
+	{"0xA", "%v", "10", 0},
+	{"0 ", "%v", "0", 1},
+	{"2+3", "%v", "2", 2},
+	{"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range scanTests {
+		x := new(Int)
+		buf.Reset()
+		buf.WriteString(test.input)
+		if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+			t.Errorf("#%d error: %s", i, err)
+		}
+		if x.String() != test.output {
+			t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+		}
+		if buf.Len() != test.remaining {
+			t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/nat.go b/src/cmd/internal/gc/big/nat.go
new file mode 100644
index 0000000..2a279d1
--- /dev/null
+++ b/src/cmd/internal/gc/big/nat.go
@@ -0,0 +1,1155 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package big implements multi-precision arithmetic (big numbers).
+// The following numeric types are supported:
+//
+//   Int    signed integers
+//   Rat    rational numbers
+//   Float  floating-point numbers
+//
+// Methods are typically of the form:
+//
+//   func (z *T) Unary(x *T) *T        // z = op x
+//   func (z *T) Binary(x, y *T) *T    // z = x op y
+//   func (x *T) M() T1                // v = x.M()
+//
+// with T one of Int, Rat, or Float. For unary and binary operations, the
+// result is the receiver (usually named z in that case); if it is one of
+// the operands x or y it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned. Methods
+// returning a result other than *Int, *Rat, or *Float take an operand as
+// the receiver (usually named x in that case).
+//
+package big
+
+// This file contains operations on unsigned multi-precision integers.
+// These are the building blocks for the operations on signed integers
+// and rationals.
+
+import "math/rand"
+
+// An unsigned integer x of the form
+//
+//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
+//
+// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
+// with the digits x[i] as the slice elements.
+//
+// A number is normalized if the slice contains no leading 0 digits.
+// During arithmetic operations, denormalized values may occur but are
+// always normalized before returning the final result. The normalized
+// representation of 0 is the empty or nil slice (length = 0).
+//
+type nat []Word
+
+var (
+	natOne = nat{1}
+	natTwo = nat{2}
+	natTen = nat{10}
+)
+
+func (z nat) clear() {
+	for i := range z {
+		z[i] = 0
+	}
+}
+
+func (z nat) norm() nat {
+	i := len(z)
+	for i > 0 && z[i-1] == 0 {
+		i--
+	}
+	return z[0:i]
+}
+
+func (z nat) make(n int) nat {
+	if n <= cap(z) {
+		return z[:n] // reuse z
+	}
+	// Choosing a good value for e has significant performance impact
+	// because it increases the chance that a value can be reused.
+	const e = 4 // extra capacity
+	return make(nat, n, n+e)
+}
+
+func (z nat) setWord(x Word) nat {
+	if x == 0 {
+		return z[:0]
+	}
+	z = z.make(1)
+	z[0] = x
+	return z
+}
+
+func (z nat) setUint64(x uint64) nat {
+	// single-digit values
+	if w := Word(x); uint64(w) == x {
+		return z.setWord(w)
+	}
+
+	// compute number of words n required to represent x
+	n := 0
+	for t := x; t > 0; t >>= _W {
+		n++
+	}
+
+	// split x into n words
+	z = z.make(n)
+	for i := range z {
+		z[i] = Word(x & _M)
+		x >>= _W
+	}
+
+	return z
+}
+
+func (z nat) set(x nat) nat {
+	z = z.make(len(x))
+	copy(z, x)
+	return z
+}
+
+func (z nat) add(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		return z.add(y, x)
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return z[:0]
+	case n == 0:
+		// result is x
+		return z.set(x)
+	}
+	// m > 0
+
+	z = z.make(m + 1)
+	c := addVV(z[0:n], x, y)
+	if m > n {
+		c = addVW(z[n:m], x[n:], c)
+	}
+	z[m] = c
+
+	return z.norm()
+}
+
+func (z nat) sub(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		panic("underflow")
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return z[:0]
+	case n == 0:
+		// result is x
+		return z.set(x)
+	}
+	// m > 0
+
+	z = z.make(m)
+	c := subVV(z[0:n], x, y)
+	if m > n {
+		c = subVW(z[n:], x[n:], c)
+	}
+	if c != 0 {
+		panic("underflow")
+	}
+
+	return z.norm()
+}
+
+func (x nat) cmp(y nat) (r int) {
+	m := len(x)
+	n := len(y)
+	if m != n || m == 0 {
+		switch {
+		case m < n:
+			r = -1
+		case m > n:
+			r = 1
+		}
+		return
+	}
+
+	i := m - 1
+	for i > 0 && x[i] == y[i] {
+		i--
+	}
+
+	switch {
+	case x[i] < y[i]:
+		r = -1
+	case x[i] > y[i]:
+		r = 1
+	}
+	return
+}
+
+func (z nat) mulAddWW(x nat, y, r Word) nat {
+	m := len(x)
+	if m == 0 || y == 0 {
+		return z.setWord(r) // result is r
+	}
+	// m > 0
+
+	z = z.make(m + 1)
+	z[m] = mulAddVWW(z[0:m], x, y, r)
+
+	return z.norm()
+}
+
+// basicMul multiplies x and y and leaves the result in z.
+// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
+func basicMul(z, x, y nat) {
+	z[0 : len(x)+len(y)].clear() // initialize z
+	for i, d := range y {
+		if d != 0 {
+			z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d)
+		}
+	}
+}
+
+// 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) {
+	if c := addVV(z[0:n], z, x); c != 0 {
+		addVW(z[n:n+n>>1], z[n:], c)
+	}
+}
+
+// Like karatsubaAdd, but does subtract.
+func karatsubaSub(z, x nat, n int) {
+	if c := subVV(z[0:n], z, x); c != 0 {
+		subVW(z[n:n+n>>1], z[n:], c)
+	}
+}
+
+// Operands that are shorter than karatsubaThreshold are multiplied using
+// "grade school" multiplication; for longer operands the Karatsuba algorithm
+// is used.
+var karatsubaThreshold int = 40 // computed by calibrate.go
+
+// karatsuba multiplies x and y and leaves the result in z.
+// Both x and y must have the same length n and n must be a
+// power of 2. The result vector z must have len(z) >= 6*n.
+// The (non-normalized) result is placed in z[0 : 2*n].
+func karatsuba(z, x, y nat) {
+	n := len(y)
+
+	// Switch to basic multiplication if numbers are odd or small.
+	// (n is always even if karatsubaThreshold is even, but be
+	// conservative)
+	if n&1 != 0 || n < karatsubaThreshold || n < 2 {
+		basicMul(z, x, y)
+		return
+	}
+	// n&1 == 0 && n >= karatsubaThreshold && n >= 2
+
+	// Karatsuba multiplication is based on the observation that
+	// for two numbers x and y with:
+	//
+	//   x = x1*b + x0
+	//   y = y1*b + y0
+	//
+	// the product x*y can be obtained with 3 products z2, z1, z0
+	// instead of 4:
+	//
+	//   x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0
+	//       =    z2*b*b +              z1*b +    z0
+	//
+	// with:
+	//
+	//   xd = x1 - x0
+	//   yd = y0 - y1
+	//
+	//   z1 =      xd*yd                    + z2 + z0
+	//      = (x1-x0)*(y0 - y1)             + z2 + z0
+	//      = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z2 + z0
+	//      = x1*y0 -    z2 -    z0 + x0*y1 + z2 + z0
+	//      = x1*y0                 + x0*y1
+
+	// split x, y into "digits"
+	n2 := n >> 1              // n2 >= 1
+	x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0
+	y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0
+
+	// z is used for the result and temporary storage:
+	//
+	//   6*n     5*n     4*n     3*n     2*n     1*n     0*n
+	// z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ]
+	//
+	// For each recursive call of karatsuba, an unused slice of
+	// z is passed in that has (at least) half the length of the
+	// caller's z.
+
+	// compute z0 and z2 with the result "in place" in z
+	karatsuba(z, x0, y0)     // z0 = x0*y0
+	karatsuba(z[n:], x1, y1) // z2 = x1*y1
+
+	// compute xd (or the negative value if underflow occurs)
+	s := 1 // sign of product xd*yd
+	xd := z[2*n : 2*n+n2]
+	if subVV(xd, x1, x0) != 0 { // x1-x0
+		s = -s
+		subVV(xd, x0, x1) // x0-x1
+	}
+
+	// compute yd (or the negative value if underflow occurs)
+	yd := z[2*n+n2 : 3*n]
+	if subVV(yd, y0, y1) != 0 { // y0-y1
+		s = -s
+		subVV(yd, y1, y0) // y1-y0
+	}
+
+	// p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0
+	// p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0
+	p := z[n*3:]
+	karatsuba(p, xd, yd)
+
+	// save original z2:z0
+	// (ok to use upper half of z since we're done recursing)
+	r := z[n*4:]
+	copy(r, z[:n*2])
+
+	// add up all partial products
+	//
+	//   2*n     n     0
+	// z = [ z2  | z0  ]
+	//   +    [ z0  ]
+	//   +    [ z2  ]
+	//   +    [  p  ]
+	//
+	karatsubaAdd(z[n2:], r, n)
+	karatsubaAdd(z[n2:], r[n:], n)
+	if s > 0 {
+		karatsubaAdd(z[n2:], p, n)
+	} else {
+		karatsubaSub(z[n2:], p, n)
+	}
+}
+
+// alias reports whether x and y share the same base array.
+func alias(x, y nat) bool {
+	return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
+}
+
+// addAt implements z += x<<(_W*i); z must be long enough.
+// (we don't use nat.add because we need z to stay the same
+// slice, and we don't need to normalize z after each addition)
+func addAt(z, x nat, i int) {
+	if n := len(x); n > 0 {
+		if c := addVV(z[i:i+n], z[i:], x); c != 0 {
+			j := i + n
+			if j < len(z) {
+				addVW(z[j:], z[j:], c)
+			}
+		}
+	}
+}
+
+func max(x, y int) int {
+	if x > y {
+		return x
+	}
+	return y
+}
+
+// karatsubaLen computes an approximation to the maximum k <= n such that
+// k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
+// result is the largest number that can be divided repeatedly by 2 before
+// becoming about the value of karatsubaThreshold.
+func karatsubaLen(n int) int {
+	i := uint(0)
+	for n > karatsubaThreshold {
+		n >>= 1
+		i++
+	}
+	return n << i
+}
+
+func (z nat) mul(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		return z.mul(y, x)
+	case m == 0 || n == 0:
+		return z[:0]
+	case n == 1:
+		return z.mulAddWW(x, y[0], 0)
+	}
+	// m >= n > 1
+
+	// determine if z can be reused
+	if alias(z, x) || alias(z, y) {
+		z = nil // z is an alias for x or y - cannot reuse
+	}
+
+	// use basic multiplication if the numbers are small
+	if n < karatsubaThreshold {
+		z = z.make(m + n)
+		basicMul(z, x, y)
+		return z.norm()
+	}
+	// m >= n && n >= karatsubaThreshold && n >= 2
+
+	// determine Karatsuba length k such that
+	//
+	//   x = xh*b + x0  (0 <= x0 < b)
+	//   y = yh*b + y0  (0 <= y0 < b)
+	//   b = 1<<(_W*k)  ("base" of digits xi, yi)
+	//
+	k := karatsubaLen(n)
+	// k <= n
+
+	// multiply x0 and y0 via Karatsuba
+	x0 := x[0:k]              // x0 is not normalized
+	y0 := y[0:k]              // y0 is not normalized
+	z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y
+	karatsuba(z, x0, y0)
+	z = z[0 : m+n]  // z has final length but may be incomplete
+	z[2*k:].clear() // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m)
+
+	// If xh != 0 or yh != 0, add the missing terms to z. For
+	//
+	//   xh = xi*b^i + ... + x2*b^2 + x1*b (0 <= xi < b)
+	//   yh =                         y1*b (0 <= y1 < b)
+	//
+	// the missing terms are
+	//
+	//   x0*y1*b and xi*y0*b^i, xi*y1*b^(i+1) for i > 0
+	//
+	// since all the yi for i > 1 are 0 by choice of k: If any of them
+	// were > 0, then yh >= b^2 and thus y >= b^2. Then k' = k*2 would
+	// be a larger valid threshold contradicting the assumption about k.
+	//
+	if k < n || m != n {
+		var t nat
+
+		// add x0*y1*b
+		x0 := x0.norm()
+		y1 := y[k:]       // y1 is normalized because y is
+		t = t.mul(x0, y1) // update t so we don't lose t's underlying array
+		addAt(z, t, k)
+
+		// add xi*y0<<i, xi*y1*b<<(i+k)
+		y0 := y0.norm()
+		for i := k; i < len(x); i += k {
+			xi := x[i:]
+			if len(xi) > k {
+				xi = xi[:k]
+			}
+			xi = xi.norm()
+			t = t.mul(xi, y0)
+			addAt(z, t, i)
+			t = t.mul(xi, y1)
+			addAt(z, t, i+k)
+		}
+	}
+
+	return z.norm()
+}
+
+// mulRange computes the product of all the unsigned integers in the
+// range [a, b] inclusively. If a > b (empty range), the result is 1.
+func (z nat) mulRange(a, b uint64) nat {
+	switch {
+	case a == 0:
+		// cut long ranges short (optimization)
+		return z.setUint64(0)
+	case a > b:
+		return z.setUint64(1)
+	case a == b:
+		return z.setUint64(a)
+	case a+1 == b:
+		return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
+	}
+	m := (a + b) / 2
+	return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
+}
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+	m := len(x)
+	switch {
+	case y == 0:
+		panic("division by zero")
+	case y == 1:
+		q = z.set(x) // result is x
+		return
+	case m == 0:
+		q = z[:0] // result is 0
+		return
+	}
+	// m > 0
+	z = z.make(m)
+	r = divWVW(z, 0, x, y)
+	q = z.norm()
+	return
+}
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+	if len(v) == 0 {
+		panic("division by zero")
+	}
+
+	if u.cmp(v) < 0 {
+		q = z[:0]
+		r = z2.set(u)
+		return
+	}
+
+	if len(v) == 1 {
+		var r2 Word
+		q, r2 = z.divW(u, v[0])
+		r = z2.setWord(r2)
+		return
+	}
+
+	q, r = z.divLarge(z2, u, v)
+	return
+}
+
+// q = (uIn-r)/v, with 0 <= r < y
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+//    len(v) >= 2
+//    len(uIn) >= len(v)
+func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
+	n := len(v)
+	m := len(uIn) - n
+
+	// determine if z can be reused
+	// TODO(gri) should find a better solution - this if statement
+	//           is very costly (see e.g. time pidigits -s -n 10000)
+	if alias(z, uIn) || alias(z, v) {
+		z = nil // z is an alias for uIn or v - cannot reuse
+	}
+	q = z.make(m + 1)
+
+	qhatv := make(nat, n+1)
+	if alias(u, uIn) || alias(u, v) {
+		u = nil // u is an alias for uIn or v - cannot reuse
+	}
+	u = u.make(len(uIn) + 1)
+	u.clear() // TODO(gri) no need to clear if we allocated a new u
+
+	// D1.
+	shift := leadingZeros(v[n-1])
+	if shift > 0 {
+		// do not modify v, it may be used by another goroutine simultaneously
+		v1 := make(nat, n)
+		shlVU(v1, v, shift)
+		v = v1
+	}
+	u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
+
+	// D2.
+	for j := m; j >= 0; j-- {
+		// D3.
+		qhat := Word(_M)
+		if u[j+n] != v[n-1] {
+			var rhat Word
+			qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+
+			// x1 | x2 = q̂v_{n-2}
+			x1, x2 := mulWW(qhat, v[n-2])
+			// test if q̂v_{n-2} > br̂ + u_{j+n-2}
+			for greaterThan(x1, x2, rhat, u[j+n-2]) {
+				qhat--
+				prevRhat := rhat
+				rhat += v[n-1]
+				// v[n-1] >= 0, so this tests for overflow.
+				if rhat < prevRhat {
+					break
+				}
+				x1, x2 = mulWW(qhat, v[n-2])
+			}
+		}
+
+		// D4.
+		qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+
+		c := subVV(u[j:j+len(qhatv)], u[j:], qhatv)
+		if c != 0 {
+			c := addVV(u[j:j+n], u[j:], v)
+			u[j+n] += c
+			qhat--
+		}
+
+		q[j] = qhat
+	}
+
+	q = q.norm()
+	shrVU(u, u, shift)
+	r = u.norm()
+
+	return q, r
+}
+
+// Length of x in bits. x must be normalized.
+func (x nat) bitLen() int {
+	if i := len(x) - 1; i >= 0 {
+		return i*_W + bitLen(x[i])
+	}
+	return 0
+}
+
+const deBruijn32 = 0x077CB531
+
+var deBruijn32Lookup = []byte{
+	0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
+}
+
+const deBruijn64 = 0x03f79d71b4ca8b09
+
+var deBruijn64Lookup = []byte{
+	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+// trailingZeroBits returns the number of consecutive least significant zero
+// bits of x.
+func trailingZeroBits(x Word) uint {
+	// x & -x leaves only the right-most bit set in the word. Let k be the
+	// index of that bit. Since only a single bit is set, the value is two
+	// to the power of k. Multiplying by a power of two is equivalent to
+	// left shifting, in this case by k bits.  The de Bruijn constant is
+	// such that all six bit, consecutive substrings are distinct.
+	// Therefore, if we have a left shifted version of this constant we can
+	// find by how many bits it was shifted by looking at which six bit
+	// substring ended up at the top of the word.
+	// (Knuth, volume 4, section 7.3.1)
+	switch _W {
+	case 32:
+		return uint(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
+	case 64:
+		return uint(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
+	default:
+		panic("unknown word size")
+	}
+}
+
+// trailingZeroBits returns the number of consecutive least significant zero
+// bits of x.
+func (x nat) trailingZeroBits() uint {
+	if len(x) == 0 {
+		return 0
+	}
+	var i uint
+	for x[i] == 0 {
+		i++
+	}
+	// x[i] != 0
+	return i*_W + trailingZeroBits(x[i])
+}
+
+// z = x << s
+func (z nat) shl(x nat, s uint) nat {
+	m := len(x)
+	if m == 0 {
+		return z[:0]
+	}
+	// m > 0
+
+	n := m + int(s/_W)
+	z = z.make(n + 1)
+	z[n] = shlVU(z[n-m:n], x, s%_W)
+	z[0 : n-m].clear()
+
+	return z.norm()
+}
+
+// z = x >> s
+func (z nat) shr(x nat, s uint) nat {
+	m := len(x)
+	n := m - int(s/_W)
+	if n <= 0 {
+		return z[:0]
+	}
+	// n > 0
+
+	z = z.make(n)
+	shrVU(z, x[m-n:], s%_W)
+
+	return z.norm()
+}
+
+func (z nat) setBit(x nat, i uint, b uint) nat {
+	j := int(i / _W)
+	m := Word(1) << (i % _W)
+	n := len(x)
+	switch b {
+	case 0:
+		z = z.make(n)
+		copy(z, x)
+		if j >= n {
+			// no need to grow
+			return z
+		}
+		z[j] &^= m
+		return z.norm()
+	case 1:
+		if j >= n {
+			z = z.make(j + 1)
+			z[n:].clear()
+		} else {
+			z = z.make(n)
+		}
+		copy(z, x)
+		z[j] |= m
+		// no need to normalize
+		return z
+	}
+	panic("set bit is not 0 or 1")
+}
+
+// bit returns the value of the i'th bit, with lsb == bit 0.
+func (x nat) bit(i uint) uint {
+	j := i / _W
+	if j >= uint(len(x)) {
+		return 0
+	}
+	// 0 <= j < len(x)
+	return uint(x[j] >> (i % _W) & 1)
+}
+
+// sticky returns 1 if there's a 1 bit within the
+// i least significant bits, otherwise it returns 0.
+func (x nat) sticky(i uint) uint {
+	j := i / _W
+	if j >= uint(len(x)) {
+		if len(x) == 0 {
+			return 0
+		}
+		return 1
+	}
+	// 0 <= j < len(x)
+	for _, x := range x[:j] {
+		if x != 0 {
+			return 1
+		}
+	}
+	if x[j]<<(_W-i%_W) != 0 {
+		return 1
+	}
+	return 0
+}
+
+func (z nat) and(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	if m > n {
+		m = n
+	}
+	// m <= n
+
+	z = z.make(m)
+	for i := 0; i < m; i++ {
+		z[i] = x[i] & y[i]
+	}
+
+	return z.norm()
+}
+
+func (z nat) andNot(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	if n > m {
+		n = m
+	}
+	// m >= n
+
+	z = z.make(m)
+	for i := 0; i < n; i++ {
+		z[i] = x[i] &^ y[i]
+	}
+	copy(z[n:m], x[n:m])
+
+	return z.norm()
+}
+
+func (z nat) or(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	s := x
+	if m < n {
+		n, m = m, n
+		s = y
+	}
+	// m >= n
+
+	z = z.make(m)
+	for i := 0; i < n; i++ {
+		z[i] = x[i] | y[i]
+	}
+	copy(z[n:m], s[n:m])
+
+	return z.norm()
+}
+
+func (z nat) xor(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	s := x
+	if m < n {
+		n, m = m, n
+		s = y
+	}
+	// m >= n
+
+	z = z.make(m)
+	for i := 0; i < n; i++ {
+		z[i] = x[i] ^ y[i]
+	}
+	copy(z[n:m], s[n:m])
+
+	return z.norm()
+}
+
+// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool {
+	return x1 > y1 || x1 == y1 && x2 > y2
+}
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+	// TODO(agl): we don't actually need to store the q value.
+	var q nat
+	q = q.make(len(x))
+	return divWVW(q, 0, x, d)
+}
+
+// random creates a random integer in [0..limit), using the space in z if
+// possible. n is the bit length of limit.
+func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+	if alias(z, limit) {
+		z = nil // z is an alias for limit - cannot reuse
+	}
+	z = z.make(len(limit))
+
+	bitLengthOfMSW := uint(n % _W)
+	if bitLengthOfMSW == 0 {
+		bitLengthOfMSW = _W
+	}
+	mask := Word((1 << bitLengthOfMSW) - 1)
+
+	for {
+		switch _W {
+		case 32:
+			for i := range z {
+				z[i] = Word(rand.Uint32())
+			}
+		case 64:
+			for i := range z {
+				z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
+			}
+		default:
+			panic("unknown word size")
+		}
+		z[len(limit)-1] &= mask
+		if z.cmp(limit) < 0 {
+			break
+		}
+	}
+
+	return z.norm()
+}
+
+// If m != 0 (i.e., len(m) != 0), expNN sets z to x**y mod m;
+// otherwise it sets z to x**y. The result is the value of z.
+func (z nat) expNN(x, y, m nat) nat {
+	if alias(z, x) || alias(z, y) {
+		// We cannot allow in-place modification of x or y.
+		z = nil
+	}
+
+	// x**y mod 1 == 0
+	if len(m) == 1 && m[0] == 1 {
+		return z.setWord(0)
+	}
+	// m == 0 || m > 1
+
+	// x**0 == 1
+	if len(y) == 0 {
+		return z.setWord(1)
+	}
+	// y > 0
+
+	if len(m) != 0 {
+		// We likely end up being as long as the modulus.
+		z = z.make(len(m))
+	}
+	z = z.set(x)
+
+	// If the base is non-trivial and the exponent is large, we use
+	// 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.
+	if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+		return z.expNNWindowed(x, y, m)
+	}
+
+	v := y[len(y)-1] // v > 0 because y is normalized and y > 0
+	shift := leadingZeros(v) + 1
+	v <<= shift
+	var q nat
+
+	const mask = 1 << (_W - 1)
+
+	// We walk through the bits of the exponent one by one. Each time we
+	// see a bit, we square, thus doubling the power. If the bit is a one,
+	// we also multiply by x, thus adding one to the power.
+
+	w := _W - int(shift)
+	// zz and r are used to avoid allocating in mul and div as
+	// otherwise the arguments would alias.
+	var zz, r nat
+	for j := 0; j < w; j++ {
+		zz = zz.mul(z, z)
+		zz, z = z, zz
+
+		if v&mask != 0 {
+			zz = zz.mul(z, x)
+			zz, z = z, zz
+		}
+
+		if len(m) != 0 {
+			zz, r = zz.div(r, z, m)
+			zz, r, q, z = q, z, zz, r
+		}
+
+		v <<= 1
+	}
+
+	for i := len(y) - 2; i >= 0; i-- {
+		v = y[i]
+
+		for j := 0; j < _W; j++ {
+			zz = zz.mul(z, z)
+			zz, z = z, zz
+
+			if v&mask != 0 {
+				zz = zz.mul(z, x)
+				zz, z = z, zz
+			}
+
+			if len(m) != 0 {
+				zz, r = zz.div(r, z, m)
+				zz, r, q, z = q, z, zz, r
+			}
+
+			v <<= 1
+		}
+	}
+
+	return z.norm()
+}
+
+// expNNWindowed calculates x**y mod m using a fixed, 4-bit window.
+func (z nat) expNNWindowed(x, y, m nat) nat {
+	// zz and r are used to avoid allocating in mul and div as otherwise
+	// the arguments would alias.
+	var zz, r nat
+
+	const n = 4
+	// powers[i] contains x^i.
+	var powers [1 << n]nat
+	powers[0] = natOne
+	powers[1] = x
+	for i := 2; i < 1<<n; i += 2 {
+		p2, p, p1 := &powers[i/2], &powers[i], &powers[i+1]
+		*p = p.mul(*p2, *p2)
+		zz, r = zz.div(r, *p, m)
+		*p, r = r, *p
+		*p1 = p1.mul(*p, x)
+		zz, r = zz.div(r, *p1, m)
+		*p1, r = r, *p1
+	}
+
+	z = z.setWord(1)
+
+	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 {
+				// Unrolled loop for significant performance
+				// gain.  Use go test -bench=".*" in crypto/rsa
+				// to check performance before making changes.
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+			}
+
+			zz = zz.mul(z, powers[yi>>(_W-n)])
+			zz, z = z, zz
+			zz, r = zz.div(r, z, m)
+			z, r = r, z
+
+			yi <<= n
+		}
+	}
+
+	return z.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.
+func (n nat) probablyPrime(reps int) bool {
+	if len(n) == 0 {
+		return false
+	}
+
+	if len(n) == 1 {
+		if n[0] < 2 {
+			return false
+		}
+
+		if n[0]%2 == 0 {
+			return n[0] == 2
+		}
+
+		// We have to exclude these cases because we reject all
+		// multiples of these numbers below.
+		switch n[0] {
+		case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
+			return true
+		}
+	}
+
+	if n[0]&1 == 0 {
+		return false // n is even
+	}
+
+	const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
+	const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
+
+	var r Word
+	switch _W {
+	case 32:
+		r = n.modW(primesProduct32)
+	case 64:
+		r = n.modW(primesProduct64 & _M)
+	default:
+		panic("Unknown word size")
+	}
+
+	if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
+		r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
+		return false
+	}
+
+	if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
+		r%43 == 0 || r%47 == 0 || r%53 == 0) {
+		return false
+	}
+
+	nm1 := nat(nil).sub(n, natOne)
+	// determine q, k such that nm1 = q << k
+	k := nm1.trailingZeroBits()
+	q := nat(nil).shr(nm1, k)
+
+	nm3 := nat(nil).sub(nm1, natTwo)
+	rand := rand.New(rand.NewSource(int64(n[0])))
+
+	var x, y, quotient nat
+	nm3Len := nm3.bitLen()
+
+NextRandom:
+	for i := 0; i < reps; i++ {
+		x = x.random(rand, nm3, nm3Len)
+		x = x.add(x, natTwo)
+		y = y.expNN(x, q, n)
+		if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+			continue
+		}
+		for j := uint(1); j < k; j++ {
+			y = y.mul(y, y)
+			quotient, y = quotient.div(y, y, n)
+			if y.cmp(nm1) == 0 {
+				continue NextRandom
+			}
+			if y.cmp(natOne) == 0 {
+				return false
+			}
+		}
+		return false
+	}
+
+	return true
+}
+
+// bytes writes the value of z into buf using big-endian encoding.
+// len(buf) must be >= len(z)*_S. The value of z is encoded in the
+// slice buf[i:]. The number i of unused bytes at the beginning of
+// buf is returned as result.
+func (z nat) bytes(buf []byte) (i int) {
+	i = len(buf)
+	for _, d := range z {
+		for j := 0; j < _S; j++ {
+			i--
+			buf[i] = byte(d)
+			d >>= 8
+		}
+	}
+
+	for i < len(buf) && buf[i] == 0 {
+		i++
+	}
+
+	return
+}
+
+// setBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z nat) setBytes(buf []byte) nat {
+	z = z.make((len(buf) + _S - 1) / _S)
+
+	k := 0
+	s := uint(0)
+	var d Word
+	for i := len(buf); i > 0; i-- {
+		d |= Word(buf[i-1]) << s
+		if s += 8; s == _S*8 {
+			z[k] = d
+			k++
+			s = 0
+			d = 0
+		}
+	}
+	if k < len(z) {
+		z[k] = d
+	}
+
+	return z.norm()
+}
diff --git a/src/cmd/internal/gc/big/nat_test.go b/src/cmd/internal/gc/big/nat_test.go
new file mode 100644
index 0000000..b25a89f
--- /dev/null
+++ b/src/cmd/internal/gc/big/nat_test.go
@@ -0,0 +1,518 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+	"runtime"
+	"strings"
+	"testing"
+)
+
+var cmpTests = []struct {
+	x, y nat
+	r    int
+}{
+	{nil, nil, 0},
+	{nil, nat(nil), 0},
+	{nat(nil), nil, 0},
+	{nat(nil), nat(nil), 0},
+	{nat{0}, nat{0}, 0},
+	{nat{0}, nat{1}, -1},
+	{nat{1}, nat{0}, 1},
+	{nat{1}, nat{1}, 0},
+	{nat{0, _M}, nat{1}, 1},
+	{nat{1}, nat{0, _M}, -1},
+	{nat{1, _M}, nat{0, _M}, 1},
+	{nat{0, _M}, nat{1, _M}, -1},
+	{nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
+	{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
+}
+
+func TestCmp(t *testing.T) {
+	for i, a := range cmpTests {
+		r := a.x.cmp(a.y)
+		if r != a.r {
+			t.Errorf("#%d got r = %v; want %v", i, r, a.r)
+		}
+	}
+}
+
+type funNN func(z, x, y nat) nat
+type argNN struct {
+	z, x, y nat
+}
+
+var sumNN = []argNN{
+	{},
+	{nat{1}, nil, nat{1}},
+	{nat{1111111110}, nat{123456789}, nat{987654321}},
+	{nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
+	{nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
+	{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
+}
+
+var prodNN = []argNN{
+	{},
+	{nil, nil, nil},
+	{nil, nat{991}, nil},
+	{nat{991}, nat{991}, nat{1}},
+	{nat{991 * 991}, nat{991}, nat{991}},
+	{nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
+	{nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
+	{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
+	// 3^100 * 3^28 = 3^128
+	{
+		natFromString("11790184577738583171520872861412518665678211592275841109096961"),
+		natFromString("515377520732011331036461129765621272702107522001"),
+		natFromString("22876792454961"),
+	},
+	// z = 111....1 (70000 digits)
+	// x = 10^(99*700) + ... + 10^1400 + 10^700 + 1
+	// y = 111....1 (700 digits, larger than Karatsuba threshold on 32-bit and 64-bit)
+	{
+		natFromString(strings.Repeat("1", 70000)),
+		natFromString("1" + strings.Repeat(strings.Repeat("0", 699)+"1", 99)),
+		natFromString(strings.Repeat("1", 700)),
+	},
+	// z = 111....1 (20000 digits)
+	// x = 10^10000 + 1
+	// y = 111....1 (10000 digits)
+	{
+		natFromString(strings.Repeat("1", 20000)),
+		natFromString("1" + strings.Repeat("0", 9999) + "1"),
+		natFromString(strings.Repeat("1", 10000)),
+	},
+}
+
+func natFromString(s string) nat {
+	x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func TestSet(t *testing.T) {
+	for _, a := range sumNN {
+		z := nat(nil).set(a.z)
+		if z.cmp(a.z) != 0 {
+			t.Errorf("got z = %v; want %v", z, a.z)
+		}
+	}
+}
+
+func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
+	z := f(nil, a.x, a.y)
+	if z.cmp(a.z) != 0 {
+		t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
+	}
+}
+
+func TestFunNN(t *testing.T) {
+	for _, a := range sumNN {
+		arg := a
+		testFunNN(t, "add", nat.add, arg)
+
+		arg = argNN{a.z, a.y, a.x}
+		testFunNN(t, "add symmetric", nat.add, arg)
+
+		arg = argNN{a.x, a.z, a.y}
+		testFunNN(t, "sub", nat.sub, arg)
+
+		arg = argNN{a.y, a.z, a.x}
+		testFunNN(t, "sub symmetric", nat.sub, arg)
+	}
+
+	for _, a := range prodNN {
+		arg := a
+		testFunNN(t, "mul", nat.mul, arg)
+
+		arg = argNN{a.z, a.y, a.x}
+		testFunNN(t, "mul symmetric", nat.mul, arg)
+	}
+}
+
+var mulRangesN = []struct {
+	a, b uint64
+	prod string
+}{
+	{0, 0, "0"},
+	{1, 1, "1"},
+	{1, 2, "2"},
+	{1, 3, "6"},
+	{10, 10, "10"},
+	{0, 100, "0"},
+	{0, 1e9, "0"},
+	{1, 0, "1"},                    // empty range
+	{100, 1, "1"},                  // empty range
+	{1, 10, "3628800"},             // 10!
+	{1, 20, "2432902008176640000"}, // 20!
+	{1, 100,
+		"933262154439441526816992388562667004907159682643816214685929" +
+			"638952175999932299156089414639761565182862536979208272237582" +
+			"51185210916864000000000000000000000000", // 100!
+	},
+}
+
+func TestMulRangeN(t *testing.T) {
+	for i, r := range mulRangesN {
+		prod := nat(nil).mulRange(r.a, r.b).decimalString()
+		if prod != r.prod {
+			t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
+		}
+	}
+}
+
+// allocBytes returns the number of bytes allocated by invoking f.
+func allocBytes(f func()) uint64 {
+	var stats runtime.MemStats
+	runtime.ReadMemStats(&stats)
+	t := stats.TotalAlloc
+	f()
+	runtime.ReadMemStats(&stats)
+	return stats.TotalAlloc - t
+}
+
+// TestMulUnbalanced tests that multiplying numbers of different lengths
+// does not cause deep recursion and in turn allocate too much memory.
+// Test case for issue 3807.
+func TestMulUnbalanced(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	x := rndNat(50000)
+	y := rndNat(40)
+	allocSize := allocBytes(func() {
+		nat(nil).mul(x, y)
+	})
+	inputSize := uint64(len(x)+len(y)) * _S
+	if ratio := allocSize / uint64(inputSize); ratio > 10 {
+		t.Errorf("multiplication uses too much memory (%d > %d times the size of inputs)", allocSize, ratio)
+	}
+}
+
+func rndNat(n int) nat {
+	return nat(rndV(n)).norm()
+}
+
+func BenchmarkMul(b *testing.B) {
+	mulx := rndNat(1e4)
+	muly := rndNat(1e4)
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		var z nat
+		z.mul(mulx, muly)
+	}
+}
+
+func TestLeadingZeros(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)
+		}
+		x >>= 1
+	}
+}
+
+type shiftTest struct {
+	in    nat
+	shift uint
+	out   nat
+}
+
+var leftShiftTests = []shiftTest{
+	{nil, 0, nil},
+	{nil, 1, nil},
+	{natOne, 0, natOne},
+	{natOne, 1, natTwo},
+	{nat{1 << (_W - 1)}, 1, nat{0}},
+	{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
+}
+
+func TestShiftLeft(t *testing.T) {
+	for i, test := range leftShiftTests {
+		var z nat
+		z = z.shl(test.in, test.shift)
+		for j, d := range test.out {
+			if j >= len(z) || z[j] != d {
+				t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+				break
+			}
+		}
+	}
+}
+
+var rightShiftTests = []shiftTest{
+	{nil, 0, nil},
+	{nil, 1, nil},
+	{natOne, 0, natOne},
+	{natOne, 1, nil},
+	{natTwo, 1, natOne},
+	{nat{0, 1}, 1, nat{1 << (_W - 1)}},
+	{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
+}
+
+func TestShiftRight(t *testing.T) {
+	for i, test := range rightShiftTests {
+		var z nat
+		z = z.shr(test.in, test.shift)
+		for j, d := range test.out {
+			if j >= len(z) || z[j] != d {
+				t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+				break
+			}
+		}
+	}
+}
+
+type modWTest struct {
+	in       string
+	dividend string
+	out      string
+}
+
+var modWTests32 = []modWTest{
+	{"23492635982634928349238759823742", "252341", "220170"},
+}
+
+var modWTests64 = []modWTest{
+	{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
+}
+
+func runModWTests(t *testing.T, tests []modWTest) {
+	for i, test := range tests {
+		in, _ := new(Int).SetString(test.in, 10)
+		d, _ := new(Int).SetString(test.dividend, 10)
+		out, _ := new(Int).SetString(test.out, 10)
+
+		r := in.abs.modW(d.abs[0])
+		if r != out.abs[0] {
+			t.Errorf("#%d failed: got %d want %s", i, r, out)
+		}
+	}
+}
+
+func TestModW(t *testing.T) {
+	if _W >= 32 {
+		runModWTests(t, modWTests32)
+	}
+	if _W >= 64 {
+		runModWTests(t, modWTests64)
+	}
+}
+
+func TestTrailingZeroBits(t *testing.T) {
+	// test 0 case explicitly
+	if n := trailingZeroBits(0); n != 0 {
+		t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
+	}
+
+	x := Word(1)
+	for i := uint(0); i < _W; i++ {
+		n := trailingZeroBits(x)
+		if n != i {
+			t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
+		}
+		x <<= 1
+	}
+
+	// test 0 case explicitly
+	if n := nat(nil).trailingZeroBits(); n != 0 {
+		t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
+	}
+
+	y := nat(nil).set(natOne)
+	for i := uint(0); i <= 3*_W; i++ {
+		n := y.trailingZeroBits()
+		if n != i {
+			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
+		}
+		y = y.shl(y, 1)
+	}
+}
+
+var expNNTests = []struct {
+	x, y, m string
+	out     string
+}{
+	{"0", "0", "0", "1"},
+	{"0", "0", "1", "0"},
+	{"1", "1", "1", "0"},
+	{"2", "1", "1", "0"},
+	{"2", "2", "1", "0"},
+	{"10", "100000000000", "1", "0"},
+	{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+	{"0x8000000000000000", "2", "6719", "4944"},
+	{"0x8000000000000000", "3", "6719", "5447"},
+	{"0x8000000000000000", "1000", "6719", "1603"},
+	{"0x8000000000000000", "1000000", "6719", "3199"},
+	{
+		"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+		"298472983472983471903246121093472394872319615612417471234712061",
+		"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+		"23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+	},
+}
+
+func TestExpNN(t *testing.T) {
+	for i, test := range expNNTests {
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		out := natFromString(test.out)
+
+		var m nat
+		if len(test.m) > 0 {
+			m = natFromString(test.m)
+		}
+
+		z := nat(nil).expNN(x, y, m)
+		if z.cmp(out) != 0 {
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+		}
+	}
+}
+
+func ExpHelper(b *testing.B, x, y Word) {
+	var z nat
+	for i := 0; i < b.N; i++ {
+		z.expWW(x, y)
+	}
+}
+
+func BenchmarkExp3Power0x10(b *testing.B)     { ExpHelper(b, 3, 0x10) }
+func BenchmarkExp3Power0x40(b *testing.B)     { ExpHelper(b, 3, 0x40) }
+func BenchmarkExp3Power0x100(b *testing.B)    { ExpHelper(b, 3, 0x100) }
+func BenchmarkExp3Power0x400(b *testing.B)    { ExpHelper(b, 3, 0x400) }
+func BenchmarkExp3Power0x1000(b *testing.B)   { ExpHelper(b, 3, 0x1000) }
+func BenchmarkExp3Power0x4000(b *testing.B)   { ExpHelper(b, 3, 0x4000) }
+func BenchmarkExp3Power0x10000(b *testing.B)  { ExpHelper(b, 3, 0x10000) }
+func BenchmarkExp3Power0x40000(b *testing.B)  { ExpHelper(b, 3, 0x40000) }
+func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
+func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
+
+func fibo(n int) nat {
+	switch n {
+	case 0:
+		return nil
+	case 1:
+		return nat{1}
+	}
+	f0 := fibo(0)
+	f1 := fibo(1)
+	var f2 nat
+	for i := 1; i < n; i++ {
+		f2 = f2.add(f0, f1)
+		f0, f1, f2 = f1, f2, f0
+	}
+	return f1
+}
+
+var fiboNums = []string{
+	"0",
+	"55",
+	"6765",
+	"832040",
+	"102334155",
+	"12586269025",
+	"1548008755920",
+	"190392490709135",
+	"23416728348467685",
+	"2880067194370816120",
+	"354224848179261915075",
+}
+
+func TestFibo(t *testing.T) {
+	for i, want := range fiboNums {
+		n := i * 10
+		got := fibo(n).decimalString()
+		if got != want {
+			t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
+		}
+	}
+}
+
+func BenchmarkFibo(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		fibo(1e0)
+		fibo(1e1)
+		fibo(1e2)
+		fibo(1e3)
+		fibo(1e4)
+		fibo(1e5)
+	}
+}
+
+var bitTests = []struct {
+	x    string
+	i    uint
+	want uint
+}{
+	{"0", 0, 0},
+	{"0", 1, 0},
+	{"0", 1000, 0},
+
+	{"0x1", 0, 1},
+	{"0x10", 0, 0},
+	{"0x10", 3, 0},
+	{"0x10", 4, 1},
+	{"0x10", 5, 0},
+
+	{"0x8000000000000000", 62, 0},
+	{"0x8000000000000000", 63, 1},
+	{"0x8000000000000000", 64, 0},
+
+	{"0x3" + strings.Repeat("0", 32), 127, 0},
+	{"0x3" + strings.Repeat("0", 32), 128, 1},
+	{"0x3" + strings.Repeat("0", 32), 129, 1},
+	{"0x3" + strings.Repeat("0", 32), 130, 0},
+}
+
+func TestBit(t *testing.T) {
+	for i, test := range bitTests {
+		x := natFromString(test.x)
+		if got := x.bit(test.i); got != test.want {
+			t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+		}
+	}
+}
+
+var stickyTests = []struct {
+	x    string
+	i    uint
+	want uint
+}{
+	{"0", 0, 0},
+	{"0", 1, 0},
+	{"0", 1000, 0},
+
+	{"0x1", 0, 0},
+	{"0x1", 1, 1},
+
+	{"0x1350", 0, 0},
+	{"0x1350", 4, 0},
+	{"0x1350", 5, 1},
+
+	{"0x8000000000000000", 63, 0},
+	{"0x8000000000000000", 64, 1},
+
+	{"0x1" + strings.Repeat("0", 100), 400, 0},
+	{"0x1" + strings.Repeat("0", 100), 401, 1},
+}
+
+func TestSticky(t *testing.T) {
+	for i, test := range stickyTests {
+		x := natFromString(test.x)
+		if got := x.sticky(test.i); got != test.want {
+			t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+		}
+		if test.want == 1 {
+			// all subsequent i's should also return 1
+			for d := uint(1); d <= 3; d++ {
+				if got := x.sticky(test.i + d); got != 1 {
+					t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/natconv.go b/src/cmd/internal/gc/big/natconv.go
new file mode 100644
index 0000000..022dcfe
--- /dev/null
+++ b/src/cmd/internal/gc/big/natconv.go
@@ -0,0 +1,495 @@
+// 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.
+
+// This file implements nat-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"sync"
+)
+
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1
+
+// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
+// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
+// In other words, at most n digits in base b fit into a Word.
+// TODO(gri) replace this with a table, generated at build time.
+func maxPow(b Word) (p Word, n int) {
+	p, n = b, 1 // assuming b <= _M
+	for max := _M / b; p <= max; {
+		// p == b**n && p <= max
+		p *= b
+		n++
+	}
+	// p == b**n && p <= _M
+	return
+}
+
+// pow returns x**n for n > 0, and 1 otherwise.
+func pow(x Word, n int) (p Word) {
+	// n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
+	// thus x**n == product of x**(2**i) for all i where bi == 1
+	// (Russian Peasant Method for exponentiation)
+	p = 1
+	for n > 0 {
+		if n&1 != 0 {
+			p *= x
+		}
+		x *= x
+		n >>= 1
+	}
+	return
+}
+
+// scan scans the number corresponding to the longest possible prefix
+// from r representing an unsigned number in a given conversion base.
+// It returns the corresponding natural number res, the actual base b,
+// a digit count, and a read or syntax error err, if any.
+//
+//	number   = [ prefix ] mantissa .
+//	prefix   = "0" [ "x" | "X" | "b" | "B" ] .
+//      mantissa = digits | digits "." [ digits ] | "." digits .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// Unless fracOk is set, the base argument must be 0 or a value between
+// 2 and MaxBase. If fracOk is set, the base argument must be one of
+// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
+// time panic.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
+// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
+// the selected base is 10 and no prefix is accepted.
+//
+// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
+// stands for a zero digit), and a period followed by a fractional part
+// is permitted. The result value is computed as if there were no period
+// present; and the count value is used to determine the fractional part.
+//
+// A result digit count > 0 corresponds to the number of (non-prefix) digits
+// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
+// is set, only), and -count is the number of fractional digits found.
+// In this case, the actual value of the scanned number is res * b**count.
+//
+func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
+	// reject illegal bases
+	baseOk := base == 0 ||
+		!fracOk && 2 <= base && base <= MaxBase ||
+		fracOk && (base == 2 || base == 10 || base == 16)
+	if !baseOk {
+		panic(fmt.Sprintf("illegal number base %d", base))
+	}
+
+	// one char look-ahead
+	ch, err := r.ReadByte()
+	if err != nil {
+		return
+	}
+
+	// determine actual base
+	b = base
+	if base == 0 {
+		// actual base is 10 unless there's a base prefix
+		b = 10
+		if ch == '0' {
+			count = 1
+			switch ch, err = r.ReadByte(); err {
+			case nil:
+				// possibly one of 0x, 0X, 0b, 0B
+				if !fracOk {
+					b = 8
+				}
+				switch ch {
+				case 'x', 'X':
+					b = 16
+				case 'b', 'B':
+					b = 2
+				}
+				switch b {
+				case 16, 2:
+					count = 0 // prefix is not counted
+					if ch, err = r.ReadByte(); err != nil {
+						// io.EOF is also an error in this case
+						return
+					}
+				case 8:
+					count = 0 // prefix is not counted
+				}
+			case io.EOF:
+				// input is "0"
+				res = z[:0]
+				err = nil
+				return
+			default:
+				// read error
+				return
+			}
+		}
+	}
+
+	// convert string
+	// Algorithm: Collect digits in groups of at most n digits in di
+	// and then use mulAddWW for every such group to add them to the
+	// result.
+	z = z[:0]
+	b1 := Word(b)
+	bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
+	di := Word(0)       // 0 <= di < b1**i < bn
+	i := 0              // 0 <= i < n
+	dp := -1            // position of decimal point
+	for {
+		if fracOk && ch == '.' {
+			fracOk = false
+			dp = count
+			// advance
+			if ch, err = r.ReadByte(); err != nil {
+				if err == io.EOF {
+					err = nil
+					break
+				}
+				return
+			}
+		}
+
+		// convert rune into digit value d1
+		var d1 Word
+		switch {
+		case '0' <= ch && ch <= '9':
+			d1 = Word(ch - '0')
+		case 'a' <= ch && ch <= 'z':
+			d1 = Word(ch - 'a' + 10)
+		case 'A' <= ch && ch <= 'Z':
+			d1 = Word(ch - 'A' + 10)
+		default:
+			d1 = MaxBase + 1
+		}
+		if d1 >= b1 {
+			r.UnreadByte() // ch does not belong to number anymore
+			break
+		}
+		count++
+
+		// collect d1 in di
+		di = di*b1 + d1
+		i++
+
+		// if di is "full", add it to the result
+		if i == n {
+			z = z.mulAddWW(z, bn, di)
+			di = 0
+			i = 0
+		}
+
+		// advance
+		if ch, err = r.ReadByte(); err != nil {
+			if err == io.EOF {
+				err = nil
+				break
+			}
+			return
+		}
+	}
+
+	if count == 0 {
+		// no digits found
+		switch {
+		case base == 0 && b == 8:
+			// there was only the octal prefix 0 (possibly followed by digits > 7);
+			// count as one digit and return base 10, not 8
+			count = 1
+			b = 10
+		case base != 0 || b != 8:
+			// there was neither a mantissa digit nor the octal prefix 0
+			err = errors.New("syntax error scanning number")
+		}
+		return
+	}
+	// count > 0
+
+	// add remaining digits to result
+	if i > 0 {
+		z = z.mulAddWW(z, pow(b1, i), di)
+	}
+	res = z.norm()
+
+	// adjust for fraction, if any
+	if dp >= 0 {
+		// 0 <= dp <= count > 0
+		count = dp - count
+	}
+
+	return
+}
+
+// Character sets for string conversion.
+const (
+	lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+	uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+	return x.string(lowercaseDigits[:10])
+}
+
+// hexString returns a hexadecimal representation of x.
+// It calls x.string with the charset "0123456789abcdef".
+func (x nat) hexString() string {
+	return x.string(lowercaseDigits[:16])
+}
+
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2 and <= 256.
+func (x nat) string(charset string) string {
+	b := Word(len(charset))
+
+	// special cases
+	switch {
+	case b < 2 || b > 256:
+		panic("invalid character set length")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
+	s := make([]byte, i)
+
+	// convert power of two and non power of two bases separately
+	if b == b&-b {
+		// shift is base-b digit size in bits
+		shift := trailingZeroBits(b) // shift > 0 because b >= 2
+		mask := Word(1)<<shift - 1
+		w := x[0]
+		nbits := uint(_W) // number of unprocessed bits in w
+
+		// convert less-significant words
+		for k := 1; k < len(x); k++ {
+			// convert full digits
+			for nbits >= shift {
+				i--
+				s[i] = charset[w&mask]
+				w >>= shift
+				nbits -= shift
+			}
+
+			// convert any partial leading digit and advance to next word
+			if nbits == 0 {
+				// no partial digit remaining, just advance
+				w = x[k]
+				nbits = _W
+			} else {
+				// partial digit in current (k-1) and next (k) word
+				w |= x[k] << nbits
+				i--
+				s[i] = charset[w&mask]
+
+				// advance
+				w = x[k] >> (shift - nbits)
+				nbits = _W - (shift - nbits)
+			}
+		}
+
+		// convert digits of most-significant word (omit leading zeros)
+		for nbits >= 0 && w != 0 {
+			i--
+			s[i] = charset[w&mask]
+			w >>= shift
+			nbits -= shift
+		}
+
+	} else {
+		bb, ndigits := maxPow(Word(b))
+
+		// construct table of successive squares of bb*leafSize to use in subdivisions
+		// result (table != nil) <=> (len(x) > leafSize > 0)
+		table := divisors(len(x), b, ndigits, bb)
+
+		// preserve x, create local copy for use by convertWords
+		q := nat(nil).set(x)
+
+		// convert q to string s in base b
+		q.convertWords(s, charset, b, ndigits, bb, table)
+
+		// strip leading zeros
+		// (x != 0; thus s must contain at least one non-zero digit
+		// and the loop will terminate)
+		i = 0
+		for zero := charset[0]; s[i] == zero; {
+			i++
+		}
+	}
+
+	return string(s[i:])
+}
+
+// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
+// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
+// repeated nat/Word division.
+//
+// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
+// Recursive conversion divides q by its approximate square root, yielding two parts, each half
+// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
+// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
+// is made better by splitting the subblocks recursively. Best is to split blocks until one more
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
+// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
+// specific hardware.
+//
+func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+	// split larger blocks recursively
+	if table != nil {
+		// len(q) > leafSize > 0
+		var r nat
+		index := len(table) - 1
+		for len(q) > leafSize {
+			// find divisor close to sqrt(q) if possible, but in any case < q
+			maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
+			minLength := maxLength >> 1 // ~= log2 sqrt(q)
+			for index > 0 && table[index-1].nbits > minLength {
+				index-- // desired
+			}
+			if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+				index--
+				if index < 0 {
+					panic("internal inconsistency")
+				}
+			}
+
+			// split q into the two digit number (q'*bbb + r) to form independent subblocks
+			q, r = q.div(r, q, table[index].bbb)
+
+			// convert subblocks and collect results in s[:h] and s[h:]
+			h := len(s) - table[index].ndigits
+			r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
+			s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+		}
+	}
+
+	// having split any large blocks now process the remaining (small) block iteratively
+	i := len(s)
+	var r Word
+	if b == 10 {
+		// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				// avoid % computation since r%10 == r - int(r/10)*10;
+				// this appears to be faster for BenchmarkString10000Base10
+				// and smaller strings (but a bit slower for larger ones)
+				t := r / 10
+				s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+				r = t
+			}
+		}
+	} else {
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				s[i] = charset[r%b]
+				r /= b
+			}
+		}
+	}
+
+	// prepend high-order zeroes
+	zero := charset[0]
+	for i > 0 { // while need more leading zeroes
+		i--
+		s[i] = zero
+	}
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
+// Benchmark and configure leafSize using: go test -bench="Leaf"
+//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+	bbb     nat // divisor
+	nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+	ndigits int // digit length of divisor in terms of output base digits
+}
+
+var cacheBase10 struct {
+	sync.Mutex
+	table [64]divisor // cached divisors for base 10
+}
+
+// expWW computes x**y
+func (z nat) expWW(x, y Word) nat {
+	return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
+}
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+	// only compute table when recursive conversion is enabled and x is large
+	if leafSize == 0 || m <= leafSize {
+		return nil
+	}
+
+	// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+	k := 1
+	for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
+		k++
+	}
+
+	// reuse and extend existing table of divisors or create new table as appropriate
+	var table []divisor // for b == 10, table overlaps with cacheBase10.table
+	if b == 10 {
+		cacheBase10.Lock()
+		table = cacheBase10.table[0:k] // reuse old table for this conversion
+	} else {
+		table = make([]divisor, k) // create new table for this conversion
+	}
+
+	// extend table
+	if table[k-1].ndigits == 0 {
+		// add new entries as needed
+		var larger nat
+		for i := 0; i < k; i++ {
+			if table[i].ndigits == 0 {
+				if i == 0 {
+					table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
+					table[0].ndigits = ndigits * leafSize
+				} else {
+					table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+					table[i].ndigits = 2 * table[i-1].ndigits
+				}
+
+				// optimization: exploit aggregated extra bits in macro blocks
+				larger = nat(nil).set(table[i].bbb)
+				for mulAddVWW(larger, larger, b, 0) == 0 {
+					table[i].bbb = table[i].bbb.set(larger)
+					table[i].ndigits++
+				}
+
+				table[i].nbits = table[i].bbb.bitLen()
+			}
+		}
+	}
+
+	if b == 10 {
+		cacheBase10.Unlock()
+	}
+
+	return table
+}
diff --git a/src/cmd/internal/gc/big/natconv_test.go b/src/cmd/internal/gc/big/natconv_test.go
new file mode 100644
index 0000000..f321fbc
--- /dev/null
+++ b/src/cmd/internal/gc/big/natconv_test.go
@@ -0,0 +1,425 @@
+// 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 big
+
+import (
+	"io"
+	"strings"
+	"testing"
+)
+
+func toString(x nat, charset string) string {
+	base := len(charset)
+
+	// special cases
+	switch {
+	case base < 2:
+		panic("illegal base")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+	s := make([]byte, i)
+
+	// don't destroy x
+	q := nat(nil).set(x)
+
+	// convert
+	for len(q) > 0 {
+		i--
+		var r Word
+		q, r = q.divW(q, Word(base))
+		s[i] = charset[r]
+	}
+
+	return string(s[i:])
+}
+
+var strTests = []struct {
+	x nat    // nat value to be converted
+	c string // conversion charset
+	s string // expected result
+}{
+	{nil, "01", "0"},
+	{nat{1}, "01", "1"},
+	{nat{0xc5}, "01", "11000101"},
+	{nat{03271}, lowercaseDigits[:8], "3271"},
+	{nat{10}, lowercaseDigits[:10], "10"},
+	{nat{1234567890}, uppercaseDigits[:10], "1234567890"},
+	{nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
+	{nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
+	{nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
+	{nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
+}
+
+func TestString(t *testing.T) {
+	// test invalid character set explicitly
+	var panicStr string
+	func() {
+		defer func() {
+			panicStr = recover().(string)
+		}()
+		natOne.string("0")
+	}()
+	if panicStr != "invalid character set length" {
+		t.Errorf("expected panic for invalid character set")
+	}
+
+	for _, a := range strTests {
+		s := a.x.string(a.c)
+		if s != a.s {
+			t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+		}
+
+		x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false)
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != len(a.c) {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+		}
+		if err != nil {
+			t.Errorf("scan%+v\n\tgot error = %s", a, err)
+		}
+	}
+}
+
+var natScanTests = []struct {
+	s     string // string to be scanned
+	base  int    // input base
+	frac  bool   // fraction ok
+	x     nat    // expected nat
+	b     int    // expected base
+	count int    // expected digit count
+	ok    bool   // expected success
+	next  rune   // next character (or 0, if at EOF)
+}{
+	// error: no mantissa
+	{},
+	{s: "?"},
+	{base: 10},
+	{base: 36},
+	{s: "?", base: 10},
+	{s: "0x"},
+	{s: "345", base: 2},
+
+	// error: incorrect use of decimal point
+	{s: ".0"},
+	{s: ".0", base: 10},
+	{s: ".", base: 0},
+	{s: "0x.0"},
+
+	// no errors
+	{"0", 0, false, nil, 10, 1, true, 0},
+	{"0", 10, false, nil, 10, 1, true, 0},
+	{"0", 36, false, nil, 36, 1, true, 0},
+	{"1", 0, false, nat{1}, 10, 1, true, 0},
+	{"1", 10, false, nat{1}, 10, 1, true, 0},
+	{"0 ", 0, false, nil, 10, 1, true, ' '},
+	{"08", 0, false, nil, 10, 1, true, '8'},
+	{"08", 10, false, nat{8}, 10, 2, true, 0},
+	{"018", 0, false, nat{1}, 8, 1, true, '8'},
+	{"0b1", 0, false, nat{1}, 2, 1, true, 0},
+	{"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0},
+	{"03271", 0, false, nat{03271}, 8, 4, true, 0},
+	{"10ab", 0, false, nat{10}, 10, 2, true, 'a'},
+	{"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0},
+	{"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0},
+	{"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'},
+	{"0x", 16, false, nil, 16, 1, true, 'x'},
+	{"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+	{"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+
+	// no errors, decimal point
+	{"0.", 0, false, nil, 10, 1, true, '.'},
+	{"0.", 10, true, nil, 10, 0, true, 0},
+	{"0.1.2", 10, true, nat{1}, 10, -1, true, '.'},
+	{".000", 10, true, nil, 10, -3, true, 0},
+	{"12.3", 10, true, nat{123}, 10, -1, true, 0},
+	{"012.345", 10, true, nat{12345}, 10, -3, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+	for _, a := range natScanTests {
+		r := strings.NewReader(a.s)
+		x, b, count, err := nat(nil).scan(r, a.base, a.frac)
+		if err == nil && !a.ok {
+			t.Errorf("scan%+v\n\texpected error", a)
+		}
+		if err != nil {
+			if a.ok {
+				t.Errorf("scan%+v\n\tgot error = %s", a, err)
+			}
+			continue
+		}
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != a.b {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+		}
+		if count != a.count {
+			t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count)
+		}
+		next, _, err := r.ReadRune()
+		if err == io.EOF {
+			next = 0
+			err = nil
+		}
+		if err == nil && next != a.next {
+			t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
+		}
+	}
+}
+
+var pi = "3" +
+	"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+	"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+	"28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+	"96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+	"31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+	"60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+	"22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+	"29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+	"81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+	"21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+	"55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+	"63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+	"75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+	"45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+	"34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+	"16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+	"04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+	"26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+	"99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+	"53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+	"68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+	"13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+	"88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+	"79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+	"68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+	"21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+	"06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+	"14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+	"21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+	"05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+	"23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+	"90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+	"31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+	"20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+	"97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+	"44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+	"44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+	"85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+	"58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+	"27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+	"09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+	"79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+	"06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+	"91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+	"94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+	"78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+	"24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+	"59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+	"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+	"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+	"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+	var x nat
+	z, _, _, err := x.scan(strings.NewReader(pi), 10, false)
+	if err != nil {
+		t.Errorf("scanning pi: %s", err)
+	}
+	if s := z.decimalString(); s != pi {
+		t.Errorf("scanning pi: got %s", s)
+	}
+}
+
+func TestScanPiParallel(t *testing.T) {
+	const n = 2
+	c := make(chan int)
+	for i := 0; i < n; i++ {
+		go func() {
+			TestScanPi(t)
+			c <- 0
+		}()
+	}
+	for i := 0; i < n; i++ {
+		<-c
+	}
+}
+
+func BenchmarkScanPi(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x nat
+		x.scan(strings.NewReader(pi), 10, false)
+	}
+}
+
+func BenchmarkStringPiParallel(b *testing.B) {
+	var x nat
+	x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
+	if x.decimalString() != pi {
+		panic("benchmark incorrect: conversion failed")
+	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			x.decimalString()
+		}
+	})
+}
+
+func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
+
+func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
+
+func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
+
+func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
+
+func ScanHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+
+	var s string
+	s = z.string(lowercaseDigits[:base])
+	if t := toString(z, lowercaseDigits[:base]); t != s {
+		b.Fatalf("scanning: got %s; want %s", s, t)
+	}
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		z.scan(strings.NewReader(s), base, false)
+	}
+}
+
+func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
+
+func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
+
+func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
+
+func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
+
+func StringHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+	z.string(lowercaseDigits[:base]) // warm divisor cache
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		_ = z.string(lowercaseDigits[:base])
+	}
+}
+
+func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+	b.StopTimer()
+	originalLeafSize := leafSize
+	resetTable(cacheBase10.table[:])
+	leafSize = size
+	b.StartTimer()
+
+	for d := 1; d <= 10000; d *= 10 {
+		b.StopTimer()
+		var z nat
+		z = z.expWW(base, Word(d))           // build target number
+		_ = z.string(lowercaseDigits[:base]) // warm divisor cache
+		b.StartTimer()
+
+		for i := 0; i < b.N; i++ {
+			_ = z.string(lowercaseDigits[:base])
+		}
+	}
+
+	b.StopTimer()
+	resetTable(cacheBase10.table[:])
+	leafSize = originalLeafSize
+	b.StartTimer()
+}
+
+func resetTable(table []divisor) {
+	if table != nil && table[0].bbb != nil {
+		for i := 0; i < len(table); i++ {
+			table[i].bbb = nil
+			table[i].nbits = 0
+			table[i].ndigits = 0
+		}
+	}
+}
+
+func TestStringPowers(t *testing.T) {
+	var b, p Word
+	for b = 2; b <= 16; b++ {
+		for p = 0; p <= 512; p++ {
+			x := nat(nil).expWW(b, p)
+			xs := x.string(lowercaseDigits[:b])
+			xs2 := toString(x, lowercaseDigits[:b])
+			if xs != xs2 {
+				t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+			}
+		}
+		if b >= 3 && testing.Short() {
+			break
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/rat.go b/src/cmd/internal/gc/big/rat.go
new file mode 100644
index 0000000..fb16f18
--- /dev/null
+++ b/src/cmd/internal/gc/big/rat.go
@@ -0,0 +1,570 @@
+// 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.
+
+// This file implements multi-precision rational numbers.
+
+package big
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"math"
+)
+
+// A Rat represents a quotient a/b of arbitrary precision.
+// The zero value for a Rat represents the value 0.
+type Rat struct {
+	// To make zero values for Rat work w/o initialization,
+	// a zero value of b (len(b) == 0) acts like b == 1.
+	// a.neg determines the sign of the Rat, b.neg is ignored.
+	a, b Int
+}
+
+// NewRat creates a new Rat with numerator a and denominator b.
+func NewRat(a, b int64) *Rat {
+	return new(Rat).SetFrac64(a, b)
+}
+
+// SetFloat64 sets z to exactly f and returns z.
+// If f is not finite, SetFloat returns nil.
+func (z *Rat) SetFloat64(f float64) *Rat {
+	const expMask = 1<<11 - 1
+	bits := math.Float64bits(f)
+	mantissa := bits & (1<<52 - 1)
+	exp := int((bits >> 52) & expMask)
+	switch exp {
+	case expMask: // non-finite
+		return nil
+	case 0: // denormal
+		exp -= 1022
+	default: // normal
+		mantissa |= 1 << 52
+		exp -= 1023
+	}
+
+	shift := 52 - exp
+
+	// Optimization (?): partially pre-normalise.
+	for mantissa&1 == 0 && shift > 0 {
+		mantissa >>= 1
+		shift--
+	}
+
+	z.a.SetUint64(mantissa)
+	z.a.neg = f < 0
+	z.b.Set(intOne)
+	if shift > 0 {
+		z.b.Lsh(&z.b, uint(shift))
+	} else {
+		z.a.Lsh(&z.a, uint(-shift))
+	}
+	return z.norm()
+}
+
+// quotToFloat32 returns the non-negative float32 value
+// nearest to the quotient a/b, using round-to-even in
+// halfway cases.  It does not mutate its arguments.
+// Preconditions: b is non-zero; a and b have no common factors.
+func quotToFloat32(a, b nat) (f float32, exact bool) {
+	const (
+		// float size in bits
+		Fsize = 32
+
+		// mantissa
+		Msize  = 23
+		Msize1 = Msize + 1 // incl. implicit 1
+		Msize2 = Msize1 + 1
+
+		// exponent
+		Esize = Fsize - Msize1
+		Ebias = 1<<(Esize-1) - 1
+		Emin  = 1 - Ebias
+		Emax  = Ebias
+	)
+
+	// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
+	alen := a.bitLen()
+	if alen == 0 {
+		return 0, true
+	}
+	blen := b.bitLen()
+	if blen == 0 {
+		panic("division by zero")
+	}
+
+	// 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
+	// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
+	// This is 2 or 3 more than the float32 mantissa field width of Msize:
+	// - the optional extra bit is shifted away in step 3 below.
+	// - the high-order 1 is omitted in "normal" representation;
+	// - the low-order 1 will be used during rounding then discarded.
+	exp := alen - blen
+	var a2, b2 nat
+	a2 = a2.set(a)
+	b2 = b2.set(b)
+	if shift := Msize2 - exp; shift > 0 {
+		a2 = a2.shl(a2, uint(shift))
+	} else if shift < 0 {
+		b2 = b2.shl(b2, uint(-shift))
+	}
+
+	// 2. Compute quotient and remainder (q, r).  NB: due to the
+	// extra shift, the low-order bit of q is logically the
+	// high-order bit of r.
+	var q nat
+	q, r := q.div(a2, a2, b2) // (recycle a2)
+	mantissa := low32(q)
+	haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
+
+	// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
+	// (in effect---we accomplish this incrementally).
+	if mantissa>>Msize2 == 1 {
+		if mantissa&1 == 1 {
+			haveRem = true
+		}
+		mantissa >>= 1
+		exp++
+	}
+	if mantissa>>Msize1 != 1 {
+		panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
+	}
+
+	// 4. Rounding.
+	if Emin-Msize <= exp && exp <= Emin {
+		// Denormal case; lose 'shift' bits of precision.
+		shift := uint(Emin - (exp - 1)) // [1..Esize1)
+		lostbits := mantissa & (1<<shift - 1)
+		haveRem = haveRem || lostbits != 0
+		mantissa >>= shift
+		exp = 2 - Ebias // == exp + shift
+	}
+	// Round q using round-half-to-even.
+	exact = !haveRem
+	if mantissa&1 != 0 {
+		exact = false
+		if haveRem || mantissa&2 != 0 {
+			if mantissa++; mantissa >= 1<<Msize2 {
+				// Complete rollover 11...1 => 100...0, so shift is safe
+				mantissa >>= 1
+				exp++
+			}
+		}
+	}
+	mantissa >>= 1 // discard rounding bit.  Mantissa now scaled by 1<<Msize1.
+
+	f = float32(math.Ldexp(float64(mantissa), exp-Msize1))
+	if math.IsInf(float64(f), 0) {
+		exact = false
+	}
+	return
+}
+
+// quotToFloat64 returns the non-negative float64 value
+// nearest to the quotient a/b, using round-to-even in
+// halfway cases.  It does not mutate its arguments.
+// Preconditions: b is non-zero; a and b have no common factors.
+func quotToFloat64(a, b nat) (f float64, exact bool) {
+	const (
+		// float size in bits
+		Fsize = 64
+
+		// mantissa
+		Msize  = 52
+		Msize1 = Msize + 1 // incl. implicit 1
+		Msize2 = Msize1 + 1
+
+		// exponent
+		Esize = Fsize - Msize1
+		Ebias = 1<<(Esize-1) - 1
+		Emin  = 1 - Ebias
+		Emax  = Ebias
+	)
+
+	// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
+	alen := a.bitLen()
+	if alen == 0 {
+		return 0, true
+	}
+	blen := b.bitLen()
+	if blen == 0 {
+		panic("division by zero")
+	}
+
+	// 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
+	// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
+	// This is 2 or 3 more than the float64 mantissa field width of Msize:
+	// - the optional extra bit is shifted away in step 3 below.
+	// - the high-order 1 is omitted in "normal" representation;
+	// - the low-order 1 will be used during rounding then discarded.
+	exp := alen - blen
+	var a2, b2 nat
+	a2 = a2.set(a)
+	b2 = b2.set(b)
+	if shift := Msize2 - exp; shift > 0 {
+		a2 = a2.shl(a2, uint(shift))
+	} else if shift < 0 {
+		b2 = b2.shl(b2, uint(-shift))
+	}
+
+	// 2. Compute quotient and remainder (q, r).  NB: due to the
+	// extra shift, the low-order bit of q is logically the
+	// high-order bit of r.
+	var q nat
+	q, r := q.div(a2, a2, b2) // (recycle a2)
+	mantissa := low64(q)
+	haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
+
+	// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
+	// (in effect---we accomplish this incrementally).
+	if mantissa>>Msize2 == 1 {
+		if mantissa&1 == 1 {
+			haveRem = true
+		}
+		mantissa >>= 1
+		exp++
+	}
+	if mantissa>>Msize1 != 1 {
+		panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
+	}
+
+	// 4. Rounding.
+	if Emin-Msize <= exp && exp <= Emin {
+		// Denormal case; lose 'shift' bits of precision.
+		shift := uint(Emin - (exp - 1)) // [1..Esize1)
+		lostbits := mantissa & (1<<shift - 1)
+		haveRem = haveRem || lostbits != 0
+		mantissa >>= shift
+		exp = 2 - Ebias // == exp + shift
+	}
+	// Round q using round-half-to-even.
+	exact = !haveRem
+	if mantissa&1 != 0 {
+		exact = false
+		if haveRem || mantissa&2 != 0 {
+			if mantissa++; mantissa >= 1<<Msize2 {
+				// Complete rollover 11...1 => 100...0, so shift is safe
+				mantissa >>= 1
+				exp++
+			}
+		}
+	}
+	mantissa >>= 1 // discard rounding bit.  Mantissa now scaled by 1<<Msize1.
+
+	f = math.Ldexp(float64(mantissa), exp-Msize1)
+	if math.IsInf(f, 0) {
+		exact = false
+	}
+	return
+}
+
+// Float32 returns the nearest float32 value for x and a bool indicating
+// whether f represents x exactly. If the magnitude of x is too large to
+// be represented by a float32, f is an infinity and exact is false.
+// The sign of f always matches the sign of x, even if f == 0.
+func (x *Rat) Float32() (f float32, exact bool) {
+	b := x.b.abs
+	if len(b) == 0 {
+		b = b.set(natOne) // materialize denominator
+	}
+	f, exact = quotToFloat32(x.a.abs, b)
+	if x.a.neg {
+		f = -f
+	}
+	return
+}
+
+// Float64 returns the nearest float64 value for x and a bool indicating
+// whether f represents x exactly. If the magnitude of x is too large to
+// be represented by a float64, f is an infinity and exact is false.
+// The sign of f always matches the sign of x, even if f == 0.
+func (x *Rat) Float64() (f float64, exact bool) {
+	b := x.b.abs
+	if len(b) == 0 {
+		b = b.set(natOne) // materialize denominator
+	}
+	f, exact = quotToFloat64(x.a.abs, b)
+	if x.a.neg {
+		f = -f
+	}
+	return
+}
+
+// SetFrac sets z to a/b and returns z.
+func (z *Rat) SetFrac(a, b *Int) *Rat {
+	z.a.neg = a.neg != b.neg
+	babs := b.abs
+	if len(babs) == 0 {
+		panic("division by zero")
+	}
+	if &z.a == b || alias(z.a.abs, babs) {
+		babs = nat(nil).set(babs) // make a copy
+	}
+	z.a.abs = z.a.abs.set(a.abs)
+	z.b.abs = z.b.abs.set(babs)
+	return z.norm()
+}
+
+// SetFrac64 sets z to a/b and returns z.
+func (z *Rat) SetFrac64(a, b int64) *Rat {
+	z.a.SetInt64(a)
+	if b == 0 {
+		panic("division by zero")
+	}
+	if b < 0 {
+		b = -b
+		z.a.neg = !z.a.neg
+	}
+	z.b.abs = z.b.abs.setUint64(uint64(b))
+	return z.norm()
+}
+
+// SetInt sets z to x (by making a copy of x) and returns z.
+func (z *Rat) SetInt(x *Int) *Rat {
+	z.a.Set(x)
+	z.b.abs = z.b.abs[:0]
+	return z
+}
+
+// SetInt64 sets z to x and returns z.
+func (z *Rat) SetInt64(x int64) *Rat {
+	z.a.SetInt64(x)
+	z.b.abs = z.b.abs[:0]
+	return z
+}
+
+// Set sets z to x (by making a copy of x) and returns z.
+func (z *Rat) Set(x *Rat) *Rat {
+	if z != x {
+		z.a.Set(&x.a)
+		z.b.Set(&x.b)
+	}
+	return z
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+	z.Set(x)
+	z.a.neg = false
+	return z
+}
+
+// Neg sets z to -x and returns z.
+func (z *Rat) Neg(x *Rat) *Rat {
+	z.Set(x)
+	z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
+	return z
+}
+
+// Inv sets z to 1/x and returns z.
+func (z *Rat) Inv(x *Rat) *Rat {
+	if len(x.a.abs) == 0 {
+		panic("division by zero")
+	}
+	z.Set(x)
+	a := z.b.abs
+	if len(a) == 0 {
+		a = a.set(natOne) // materialize numerator
+	}
+	b := z.a.abs
+	if b.cmp(natOne) == 0 {
+		b = b[:0] // normalize denominator
+	}
+	z.a.abs, z.b.abs = a, b // sign doesn't change
+	return z
+}
+
+// Sign returns:
+//
+//	-1 if x <  0
+//	 0 if x == 0
+//	+1 if x >  0
+//
+func (x *Rat) Sign() int {
+	return x.a.Sign()
+}
+
+// IsInt reports whether the denominator of x is 1.
+func (x *Rat) IsInt() bool {
+	return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0
+}
+
+// Num returns the numerator of x; it may be <= 0.
+// The result is a reference to x's numerator; it
+// may change if a new value is assigned to x, and vice versa.
+// The sign of the numerator corresponds to the sign of x.
+func (x *Rat) Num() *Int {
+	return &x.a
+}
+
+// Denom returns the denominator of x; it is always > 0.
+// The result is a reference to x's denominator; it
+// may change if a new value is assigned to x, and vice versa.
+func (x *Rat) Denom() *Int {
+	x.b.neg = false // the result is always >= 0
+	if len(x.b.abs) == 0 {
+		x.b.abs = x.b.abs.set(natOne) // materialize denominator
+	}
+	return &x.b
+}
+
+func (z *Rat) norm() *Rat {
+	switch {
+	case len(z.a.abs) == 0:
+		// z == 0 - normalize sign and denominator
+		z.a.neg = false
+		z.b.abs = z.b.abs[:0]
+	case len(z.b.abs) == 0:
+		// z is normalized int - nothing to do
+	case z.b.abs.cmp(natOne) == 0:
+		// z is int - normalize denominator
+		z.b.abs = z.b.abs[:0]
+	default:
+		neg := z.a.neg
+		z.a.neg = false
+		z.b.neg = false
+		if f := NewInt(0).binaryGCD(&z.a, &z.b); f.Cmp(intOne) != 0 {
+			z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs)
+			z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
+			if z.b.abs.cmp(natOne) == 0 {
+				// z is int - normalize denominator
+				z.b.abs = z.b.abs[:0]
+			}
+		}
+		z.a.neg = neg
+	}
+	return z
+}
+
+// mulDenom sets z to the denominator product x*y (by taking into
+// account that 0 values for x or y must be interpreted as 1) and
+// returns z.
+func mulDenom(z, x, y nat) nat {
+	switch {
+	case len(x) == 0:
+		return z.set(y)
+	case len(y) == 0:
+		return z.set(x)
+	}
+	return z.mul(x, y)
+}
+
+// scaleDenom computes x*f.
+// If f == 0 (zero value of denominator), the result is (a copy of) x.
+func scaleDenom(x *Int, f nat) *Int {
+	var z Int
+	if len(f) == 0 {
+		return z.Set(x)
+	}
+	z.abs = z.abs.mul(x.abs, f)
+	z.neg = x.neg
+	return &z
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y
+//   +1 if x >  y
+//
+func (x *Rat) Cmp(y *Rat) int {
+	return scaleDenom(&x.a, y.b.abs).Cmp(scaleDenom(&y.a, x.b.abs))
+}
+
+// Add sets z to the sum x+y and returns z.
+func (z *Rat) Add(x, y *Rat) *Rat {
+	a1 := scaleDenom(&x.a, y.b.abs)
+	a2 := scaleDenom(&y.a, x.b.abs)
+	z.a.Add(a1, a2)
+	z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
+	return z.norm()
+}
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Rat) Sub(x, y *Rat) *Rat {
+	a1 := scaleDenom(&x.a, y.b.abs)
+	a2 := scaleDenom(&y.a, x.b.abs)
+	z.a.Sub(a1, a2)
+	z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
+	return z.norm()
+}
+
+// Mul sets z to the product x*y and returns z.
+func (z *Rat) Mul(x, y *Rat) *Rat {
+	z.a.Mul(&x.a, &y.a)
+	z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
+	return z.norm()
+}
+
+// Quo sets z to the quotient x/y and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+func (z *Rat) Quo(x, y *Rat) *Rat {
+	if len(y.a.abs) == 0 {
+		panic("division by zero")
+	}
+	a := scaleDenom(&x.a, y.b.abs)
+	b := scaleDenom(&y.a, x.b.abs)
+	z.a.abs = a.abs
+	z.b.abs = b.abs
+	z.a.neg = a.neg != b.neg
+	return z.norm()
+}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Rat) GobEncode() ([]byte, error) {
+	if x == nil {
+		return nil, nil
+	}
+	buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+	i := x.b.abs.bytes(buf)
+	j := x.a.abs.bytes(buf[:i])
+	n := i - j
+	if int(uint32(n)) != n {
+		// this should never happen
+		return nil, errors.New("Rat.GobEncode: numerator too large")
+	}
+	binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+	j -= 1 + 4
+	b := ratGobVersion << 1 // make space for sign bit
+	if x.a.neg {
+		b |= 1
+	}
+	buf[j] = b
+	return buf[j:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) error {
+	if len(buf) == 0 {
+		// Other side sent a nil or default value.
+		*z = Rat{}
+		return nil
+	}
+	b := buf[0]
+	if b>>1 != ratGobVersion {
+		return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
+	}
+	const j = 1 + 4
+	i := j + binary.BigEndian.Uint32(buf[j-4:j])
+	z.a.neg = b&1 != 0
+	z.a.abs = z.a.abs.setBytes(buf[j:i])
+	z.b.abs = z.b.abs.setBytes(buf[i:])
+	return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (r *Rat) MarshalText() (text []byte, err error) {
+	return []byte(r.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (r *Rat) UnmarshalText(text []byte) error {
+	if _, ok := r.SetString(string(text)); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+	}
+	return nil
+}
diff --git a/src/cmd/internal/gc/big/rat_test.go b/src/cmd/internal/gc/big/rat_test.go
new file mode 100644
index 0000000..012d0c4
--- /dev/null
+++ b/src/cmd/internal/gc/big/rat_test.go
@@ -0,0 +1,736 @@
+// 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.
+
+package big
+
+import (
+	"bytes"
+	"encoding/gob"
+	"encoding/json"
+	"encoding/xml"
+	"math"
+	"testing"
+)
+
+func TestZeroRat(t *testing.T) {
+	var x, y, z Rat
+	y.SetFrac64(0, 42)
+
+	if x.Cmp(&y) != 0 {
+		t.Errorf("x and y should be both equal and zero")
+	}
+
+	if s := x.String(); s != "0/1" {
+		t.Errorf("got x = %s, want 0/1", s)
+	}
+
+	if s := x.RatString(); s != "0" {
+		t.Errorf("got x = %s, want 0", s)
+	}
+
+	z.Add(&x, &y)
+	if s := z.RatString(); s != "0" {
+		t.Errorf("got x+y = %s, want 0", s)
+	}
+
+	z.Sub(&x, &y)
+	if s := z.RatString(); s != "0" {
+		t.Errorf("got x-y = %s, want 0", s)
+	}
+
+	z.Mul(&x, &y)
+	if s := z.RatString(); s != "0" {
+		t.Errorf("got x*y = %s, want 0", s)
+	}
+
+	// check for division by zero
+	defer func() {
+		if s := recover(); s == nil || s.(string) != "division by zero" {
+			panic(s)
+		}
+	}()
+	z.Quo(&x, &y)
+}
+
+func TestRatSign(t *testing.T) {
+	zero := NewRat(0, 1)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		s := x.Sign()
+		e := x.Cmp(zero)
+		if s != e {
+			t.Errorf("got %d; want %d for z = %v", s, e, &x)
+		}
+	}
+}
+
+var ratCmpTests = []struct {
+	rat1, rat2 string
+	out        int
+}{
+	{"0", "0/1", 0},
+	{"1/1", "1", 0},
+	{"-1", "-2/2", 0},
+	{"1", "0", 1},
+	{"0/1", "1/1", -1},
+	{"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
+	{"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
+	{"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
+	{"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
+}
+
+func TestRatCmp(t *testing.T) {
+	for i, test := range ratCmpTests {
+		x, _ := new(Rat).SetString(test.rat1)
+		y, _ := new(Rat).SetString(test.rat2)
+
+		out := x.Cmp(y)
+		if out != test.out {
+			t.Errorf("#%d got out = %v; want %v", i, out, test.out)
+		}
+	}
+}
+
+func TestIsInt(t *testing.T) {
+	one := NewInt(1)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		i := x.IsInt()
+		e := x.Denom().Cmp(one) == 0
+		if i != e {
+			t.Errorf("got IsInt(%v) == %v; want %v", x, i, e)
+		}
+	}
+}
+
+func TestRatAbs(t *testing.T) {
+	zero := new(Rat)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		e := new(Rat).Set(x)
+		if e.Cmp(zero) < 0 {
+			e.Sub(zero, e)
+		}
+		z := new(Rat).Abs(x)
+		if z.Cmp(e) != 0 {
+			t.Errorf("got Abs(%v) = %v; want %v", x, z, e)
+		}
+	}
+}
+
+func TestRatNeg(t *testing.T) {
+	zero := new(Rat)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		e := new(Rat).Sub(zero, x)
+		z := new(Rat).Neg(x)
+		if z.Cmp(e) != 0 {
+			t.Errorf("got Neg(%v) = %v; want %v", x, z, e)
+		}
+	}
+}
+
+func TestRatInv(t *testing.T) {
+	zero := new(Rat)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		if x.Cmp(zero) == 0 {
+			continue // avoid division by zero
+		}
+		e := new(Rat).SetFrac(x.Denom(), x.Num())
+		z := new(Rat).Inv(x)
+		if z.Cmp(e) != 0 {
+			t.Errorf("got Inv(%v) = %v; want %v", x, z, e)
+		}
+	}
+}
+
+type ratBinFun func(z, x, y *Rat) *Rat
+type ratBinArg struct {
+	x, y, z string
+}
+
+func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
+	x, _ := new(Rat).SetString(a.x)
+	y, _ := new(Rat).SetString(a.y)
+	z, _ := new(Rat).SetString(a.z)
+	out := f(new(Rat), x, y)
+
+	if out.Cmp(z) != 0 {
+		t.Errorf("%s #%d got %s want %s", name, i, out, z)
+	}
+}
+
+var ratBinTests = []struct {
+	x, y      string
+	sum, prod string
+}{
+	{"0", "0", "0", "0"},
+	{"0", "1", "1", "0"},
+	{"-1", "0", "-1", "0"},
+	{"-1", "1", "0", "-1"},
+	{"1", "1", "2", "1"},
+	{"1/2", "1/2", "1", "1/4"},
+	{"1/4", "1/3", "7/12", "1/12"},
+	{"2/5", "-14/3", "-64/15", "-28/15"},
+	{"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
+	{"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
+	{"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
+	{"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
+	{"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
+	{"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
+	{"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
+	{"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
+	{"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
+	{"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
+}
+
+func TestRatBin(t *testing.T) {
+	for i, test := range ratBinTests {
+		arg := ratBinArg{test.x, test.y, test.sum}
+		testRatBin(t, i, "Add", (*Rat).Add, arg)
+
+		arg = ratBinArg{test.y, test.x, test.sum}
+		testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
+
+		arg = ratBinArg{test.sum, test.x, test.y}
+		testRatBin(t, i, "Sub", (*Rat).Sub, arg)
+
+		arg = ratBinArg{test.sum, test.y, test.x}
+		testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
+
+		arg = ratBinArg{test.x, test.y, test.prod}
+		testRatBin(t, i, "Mul", (*Rat).Mul, arg)
+
+		arg = ratBinArg{test.y, test.x, test.prod}
+		testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
+
+		if test.x != "0" {
+			arg = ratBinArg{test.prod, test.x, test.y}
+			testRatBin(t, i, "Quo", (*Rat).Quo, arg)
+		}
+
+		if test.y != "0" {
+			arg = ratBinArg{test.prod, test.y, test.x}
+			testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
+		}
+	}
+}
+
+func TestIssue820(t *testing.T) {
+	x := NewRat(3, 1)
+	y := NewRat(2, 1)
+	z := y.Quo(x, y)
+	q := NewRat(3, 2)
+	if z.Cmp(q) != 0 {
+		t.Errorf("got %s want %s", z, q)
+	}
+
+	y = NewRat(3, 1)
+	x = NewRat(2, 1)
+	z = y.Quo(x, y)
+	q = NewRat(2, 3)
+	if z.Cmp(q) != 0 {
+		t.Errorf("got %s want %s", z, q)
+	}
+
+	x = NewRat(3, 1)
+	z = x.Quo(x, x)
+	q = NewRat(3, 3)
+	if z.Cmp(q) != 0 {
+		t.Errorf("got %s want %s", z, q)
+	}
+}
+
+var setFrac64Tests = []struct {
+	a, b int64
+	out  string
+}{
+	{0, 1, "0"},
+	{0, -1, "0"},
+	{1, 1, "1"},
+	{-1, 1, "-1"},
+	{1, -1, "-1"},
+	{-1, -1, "1"},
+	{-9223372036854775808, -9223372036854775808, "1"},
+}
+
+func TestRatSetFrac64Rat(t *testing.T) {
+	for i, test := range setFrac64Tests {
+		x := new(Rat).SetFrac64(test.a, test.b)
+		if x.RatString() != test.out {
+			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+		}
+	}
+}
+
+func TestRatGobEncoding(t *testing.T) {
+	var medium bytes.Buffer
+	enc := gob.NewEncoder(&medium)
+	dec := gob.NewDecoder(&medium)
+	for _, test := range encodingTests {
+		medium.Reset() // empty buffer for each test case (in case of failures)
+		var tx Rat
+		tx.SetString(test + ".14159265")
+		if err := enc.Encode(&tx); err != nil {
+			t.Errorf("encoding of %s failed: %s", &tx, err)
+		}
+		var rx Rat
+		if err := dec.Decode(&rx); err != nil {
+			t.Errorf("decoding of %s failed: %s", &tx, err)
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilRatInSlice(t *testing.T) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	dec := gob.NewDecoder(buf)
+
+	var in = make([]*Rat, 1)
+	err := enc.Encode(&in)
+	if err != nil {
+		t.Errorf("gob encode failed: %q", err)
+	}
+	var out []*Rat
+	err = dec.Decode(&out)
+	if err != nil {
+		t.Fatalf("gob decode failed: %q", err)
+	}
+	if len(out) != 1 {
+		t.Fatalf("wrong len; want 1 got %d", len(out))
+	}
+	var zero Rat
+	if out[0].Cmp(&zero) != 0 {
+		t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
+	}
+}
+
+var ratNums = []string{
+	"-141592653589793238462643383279502884197169399375105820974944592307816406286",
+	"-1415926535897932384626433832795028841971",
+	"-141592653589793",
+	"-1",
+	"0",
+	"1",
+	"141592653589793",
+	"1415926535897932384626433832795028841971",
+	"141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+	"1",
+	"718281828459045",
+	"7182818284590452353602874713526624977572",
+	"718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+	for _, num := range ratNums {
+		for _, denom := range ratDenoms {
+			var tx Rat
+			tx.SetString(num + "/" + denom)
+			b, err := json.Marshal(&tx)
+			if err != nil {
+				t.Errorf("marshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Rat
+			if err := json.Unmarshal(b, &rx); err != nil {
+				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			if rx.Cmp(&tx) != 0 {
+				t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+			}
+		}
+	}
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+	for _, num := range ratNums {
+		for _, denom := range ratDenoms {
+			var tx Rat
+			tx.SetString(num + "/" + denom)
+			b, err := xml.Marshal(&tx)
+			if err != nil {
+				t.Errorf("marshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Rat
+			if err := xml.Unmarshal(b, &rx); err != nil {
+				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			if rx.Cmp(&tx) != 0 {
+				t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+			}
+		}
+	}
+}
+
+func TestIssue2379(t *testing.T) {
+	// 1) no aliasing
+	q := NewRat(3, 2)
+	x := new(Rat)
+	x.SetFrac(NewInt(3), NewInt(2))
+	if x.Cmp(q) != 0 {
+		t.Errorf("1) got %s want %s", x, q)
+	}
+
+	// 2) aliasing of numerator
+	x = NewRat(2, 3)
+	x.SetFrac(NewInt(3), x.Num())
+	if x.Cmp(q) != 0 {
+		t.Errorf("2) got %s want %s", x, q)
+	}
+
+	// 3) aliasing of denominator
+	x = NewRat(2, 3)
+	x.SetFrac(x.Denom(), NewInt(2))
+	if x.Cmp(q) != 0 {
+		t.Errorf("3) got %s want %s", x, q)
+	}
+
+	// 4) aliasing of numerator and denominator
+	x = NewRat(2, 3)
+	x.SetFrac(x.Denom(), x.Num())
+	if x.Cmp(q) != 0 {
+		t.Errorf("4) got %s want %s", x, q)
+	}
+
+	// 5) numerator and denominator are the same
+	q = NewRat(1, 1)
+	x = new(Rat)
+	n := NewInt(7)
+	x.SetFrac(n, n)
+	if x.Cmp(q) != 0 {
+		t.Errorf("5) got %s want %s", x, q)
+	}
+}
+
+func TestIssue3521(t *testing.T) {
+	a := new(Int)
+	b := new(Int)
+	a.SetString("64375784358435883458348587", 0)
+	b.SetString("4789759874531", 0)
+
+	// 0) a raw zero value has 1 as denominator
+	zero := new(Rat)
+	one := NewInt(1)
+	if zero.Denom().Cmp(one) != 0 {
+		t.Errorf("0) got %s want %s", zero.Denom(), one)
+	}
+
+	// 1a) a zero value remains zero independent of denominator
+	x := new(Rat)
+	x.Denom().Set(new(Int).Neg(b))
+	if x.Cmp(zero) != 0 {
+		t.Errorf("1a) got %s want %s", x, zero)
+	}
+
+	// 1b) a zero value may have a denominator != 0 and != 1
+	x.Num().Set(a)
+	qab := new(Rat).SetFrac(a, b)
+	if x.Cmp(qab) != 0 {
+		t.Errorf("1b) got %s want %s", x, qab)
+	}
+
+	// 2a) an integral value becomes a fraction depending on denominator
+	x.SetFrac64(10, 2)
+	x.Denom().SetInt64(3)
+	q53 := NewRat(5, 3)
+	if x.Cmp(q53) != 0 {
+		t.Errorf("2a) got %s want %s", x, q53)
+	}
+
+	// 2b) an integral value becomes a fraction depending on denominator
+	x = NewRat(10, 2)
+	x.Denom().SetInt64(3)
+	if x.Cmp(q53) != 0 {
+		t.Errorf("2b) got %s want %s", x, q53)
+	}
+
+	// 3) changing the numerator/denominator of a Rat changes the Rat
+	x.SetFrac(a, b)
+	a = x.Num()
+	b = x.Denom()
+	a.SetInt64(5)
+	b.SetInt64(3)
+	if x.Cmp(q53) != 0 {
+		t.Errorf("3) got %s want %s", x, q53)
+	}
+}
+
+func TestFloat32Distribution(t *testing.T) {
+	// Generate a distribution of (sign, mantissa, exp) values
+	// broader than the float32 range, and check Rat.Float32()
+	// always picks the closest float32 approximation.
+	var add = []int64{
+		0,
+		1,
+		3,
+		5,
+		7,
+		9,
+		11,
+	}
+	var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
+	if testing.Short() {
+		winc, einc = 5, 15 // quick test (~60ms on x86-64)
+	}
+
+	for _, sign := range "+-" {
+		for _, a := range add {
+			for wid := uint64(0); wid < 30; wid += winc {
+				b := 1<<wid + a
+				if sign == '-' {
+					b = -b
+				}
+				for exp := -150; exp < 150; exp += einc {
+					num, den := NewInt(b), NewInt(1)
+					if exp > 0 {
+						num.Lsh(num, uint(exp))
+					} else {
+						den.Lsh(den, uint(-exp))
+					}
+					r := new(Rat).SetFrac(num, den)
+					f, _ := r.Float32()
+
+					if !checkIsBestApprox32(t, f, r) {
+						// Append context information.
+						t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
+							b, exp, f, f, math.Ldexp(float64(b), exp), r)
+					}
+
+					checkNonLossyRoundtrip32(t, f)
+				}
+			}
+		}
+	}
+}
+
+func TestFloat64Distribution(t *testing.T) {
+	// Generate a distribution of (sign, mantissa, exp) values
+	// broader than the float64 range, and check Rat.Float64()
+	// always picks the closest float64 approximation.
+	var add = []int64{
+		0,
+		1,
+		3,
+		5,
+		7,
+		9,
+		11,
+	}
+	var winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
+	if testing.Short() {
+		winc, einc = 10, 500 // quick test (~12ms on x86-64)
+	}
+
+	for _, sign := range "+-" {
+		for _, a := range add {
+			for wid := uint64(0); wid < 60; wid += winc {
+				b := 1<<wid + a
+				if sign == '-' {
+					b = -b
+				}
+				for exp := -1100; exp < 1100; exp += einc {
+					num, den := NewInt(b), NewInt(1)
+					if exp > 0 {
+						num.Lsh(num, uint(exp))
+					} else {
+						den.Lsh(den, uint(-exp))
+					}
+					r := new(Rat).SetFrac(num, den)
+					f, _ := r.Float64()
+
+					if !checkIsBestApprox64(t, f, r) {
+						// Append context information.
+						t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
+							b, exp, f, f, math.Ldexp(float64(b), exp), r)
+					}
+
+					checkNonLossyRoundtrip64(t, f)
+				}
+			}
+		}
+	}
+}
+
+// TestSetFloat64NonFinite checks that SetFloat64 of a non-finite value
+// returns nil.
+func TestSetFloat64NonFinite(t *testing.T) {
+	for _, f := range []float64{math.NaN(), math.Inf(+1), math.Inf(-1)} {
+		var r Rat
+		if r2 := r.SetFloat64(f); r2 != nil {
+			t.Errorf("SetFloat64(%g) was %v, want nil", f, r2)
+		}
+	}
+}
+
+// checkNonLossyRoundtrip32 checks that a float->Rat->float roundtrip is
+// non-lossy for finite f.
+func checkNonLossyRoundtrip32(t *testing.T, f float32) {
+	if !isFinite(float64(f)) {
+		return
+	}
+	r := new(Rat).SetFloat64(float64(f))
+	if r == nil {
+		t.Errorf("Rat.SetFloat64(float64(%g) (%b)) == nil", f, f)
+		return
+	}
+	f2, exact := r.Float32()
+	if f != f2 || !exact {
+		t.Errorf("Rat.SetFloat64(float64(%g)).Float32() = %g (%b), %v, want %g (%b), %v; delta = %b",
+			f, f2, f2, exact, f, f, true, f2-f)
+	}
+}
+
+// checkNonLossyRoundtrip64 checks that a float->Rat->float roundtrip is
+// non-lossy for finite f.
+func checkNonLossyRoundtrip64(t *testing.T, f float64) {
+	if !isFinite(f) {
+		return
+	}
+	r := new(Rat).SetFloat64(f)
+	if r == nil {
+		t.Errorf("Rat.SetFloat64(%g (%b)) == nil", f, f)
+		return
+	}
+	f2, exact := r.Float64()
+	if f != f2 || !exact {
+		t.Errorf("Rat.SetFloat64(%g).Float64() = %g (%b), %v, want %g (%b), %v; delta = %b",
+			f, f2, f2, exact, f, f, true, f2-f)
+	}
+}
+
+// delta returns the absolute difference between r and f.
+func delta(r *Rat, f float64) *Rat {
+	d := new(Rat).Sub(r, new(Rat).SetFloat64(f))
+	return d.Abs(d)
+}
+
+// checkIsBestApprox32 checks that f is the best possible float32
+// approximation of r.
+// Returns true on success.
+func checkIsBestApprox32(t *testing.T, f float32, r *Rat) bool {
+	if math.Abs(float64(f)) >= math.MaxFloat32 {
+		// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat32).
+		// But we have tests for these special cases.
+		return true
+	}
+
+	// r must be strictly between f0 and f1, the floats bracketing f.
+	f0 := math.Nextafter32(f, float32(math.Inf(-1)))
+	f1 := math.Nextafter32(f, float32(math.Inf(+1)))
+
+	// For f to be correct, r must be closer to f than to f0 or f1.
+	df := delta(r, float64(f))
+	df0 := delta(r, float64(f0))
+	df1 := delta(r, float64(f1))
+	if df.Cmp(df0) > 0 {
+		t.Errorf("Rat(%v).Float32() = %g (%b), but previous float32 %g (%b) is closer", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) > 0 {
+		t.Errorf("Rat(%v).Float32() = %g (%b), but next float32 %g (%b) is closer", r, f, f, f1, f1)
+		return false
+	}
+	if df.Cmp(df0) == 0 && !isEven32(f) {
+		t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) == 0 && !isEven32(f) {
+		t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
+		return false
+	}
+	return true
+}
+
+// checkIsBestApprox64 checks that f is the best possible float64
+// approximation of r.
+// Returns true on success.
+func checkIsBestApprox64(t *testing.T, f float64, r *Rat) bool {
+	if math.Abs(f) >= math.MaxFloat64 {
+		// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat64).
+		// But we have tests for these special cases.
+		return true
+	}
+
+	// r must be strictly between f0 and f1, the floats bracketing f.
+	f0 := math.Nextafter(f, math.Inf(-1))
+	f1 := math.Nextafter(f, math.Inf(+1))
+
+	// For f to be correct, r must be closer to f than to f0 or f1.
+	df := delta(r, f)
+	df0 := delta(r, f0)
+	df1 := delta(r, f1)
+	if df.Cmp(df0) > 0 {
+		t.Errorf("Rat(%v).Float64() = %g (%b), but previous float64 %g (%b) is closer", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) > 0 {
+		t.Errorf("Rat(%v).Float64() = %g (%b), but next float64 %g (%b) is closer", r, f, f, f1, f1)
+		return false
+	}
+	if df.Cmp(df0) == 0 && !isEven64(f) {
+		t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) == 0 && !isEven64(f) {
+		t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
+		return false
+	}
+	return true
+}
+
+func isEven32(f float32) bool { return math.Float32bits(f)&1 == 0 }
+func isEven64(f float64) bool { return math.Float64bits(f)&1 == 0 }
+
+func TestIsFinite(t *testing.T) {
+	finites := []float64{
+		1.0 / 3,
+		4891559871276714924261e+222,
+		math.MaxFloat64,
+		math.SmallestNonzeroFloat64,
+		-math.MaxFloat64,
+		-math.SmallestNonzeroFloat64,
+	}
+	for _, f := range finites {
+		if !isFinite(f) {
+			t.Errorf("!IsFinite(%g (%b))", f, f)
+		}
+	}
+	nonfinites := []float64{
+		math.NaN(),
+		math.Inf(-1),
+		math.Inf(+1),
+	}
+	for _, f := range nonfinites {
+		if isFinite(f) {
+			t.Errorf("IsFinite(%g, (%b))", f, f)
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/ratconv.go b/src/cmd/internal/gc/big/ratconv.go
new file mode 100644
index 0000000..778077b
--- /dev/null
+++ b/src/cmd/internal/gc/big/ratconv.go
@@ -0,0 +1,251 @@
+// 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.
+
+// This file implements rat-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+func ratTok(ch rune) bool {
+	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
+	tok, err := s.Token(true, ratTok)
+	if err != nil {
+		return err
+	}
+	if strings.IndexRune("efgEFGv", ch) < 0 {
+		return errors.New("Rat.Scan: invalid verb")
+	}
+	if _, ok := z.SetString(string(tok)); !ok {
+		return errors.New("Rat.Scan: invalid syntax")
+	}
+	return nil
+}
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of
+// z is undefined but the returned value is nil.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+	if len(s) == 0 {
+		return nil, false
+	}
+	// len(s) > 0
+
+	// parse fraction a/b, if any
+	if sep := strings.Index(s, "/"); sep >= 0 {
+		if _, ok := z.a.SetString(s[:sep], 0); !ok {
+			return nil, false
+		}
+		s = s[sep+1:]
+		var err error
+		if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
+			return nil, false
+		}
+		if len(z.b.abs) == 0 {
+			return nil, false
+		}
+		return z.norm(), true
+	}
+
+	// parse floating-point number
+	r := strings.NewReader(s)
+
+	// sign
+	neg, err := scanSign(r)
+	if err != nil {
+		return nil, false
+	}
+
+	// mantissa
+	var ecorr int
+	z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
+	if err != nil {
+		return nil, false
+	}
+
+	// exponent
+	var exp int64
+	exp, _, err = scanExponent(r, false)
+	if err != nil {
+		return nil, false
+	}
+
+	// there should be no unread characters left
+	if _, err = r.ReadByte(); err != io.EOF {
+		return nil, false
+	}
+
+	// correct exponent
+	if ecorr < 0 {
+		exp += int64(ecorr)
+	}
+
+	// compute exponent power
+	expabs := exp
+	if expabs < 0 {
+		expabs = -expabs
+	}
+	powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
+
+	// complete fraction
+	if exp < 0 {
+		z.b.abs = powTen
+		z.norm()
+	} else {
+		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+		z.b.abs = z.b.abs[:0]
+	}
+
+	z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
+
+	return z, true
+}
+
+// scanExponent scans the longest possible prefix of r representing a decimal
+// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
+// exponent base (10 or 2), or a read or syntax error, if any.
+//
+//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//	sign     = "+" | "-" .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" .
+//
+// A binary exponent is only permitted if binExpOk is set.
+func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
+	base = 10
+
+	var ch byte
+	if ch, err = r.ReadByte(); err != nil {
+		if err == io.EOF {
+			err = nil // no exponent; same as e0
+		}
+		return
+	}
+
+	switch ch {
+	case 'e', 'E':
+		// ok
+	case 'p':
+		if binExpOk {
+			base = 2
+			break // ok
+		}
+		fallthrough // binary exponent not permitted
+	default:
+		r.UnreadByte()
+		return // no exponent; same as e0
+	}
+
+	var neg bool
+	if neg, err = scanSign(r); err != nil {
+		return
+	}
+
+	var digits []byte
+	if neg {
+		digits = append(digits, '-')
+	}
+
+	// no need to use nat.scan for exponent digits
+	// since we only care about int64 values - the
+	// from-scratch scan is easy enough and faster
+	for i := 0; ; i++ {
+		if ch, err = r.ReadByte(); err != nil {
+			if err != io.EOF || i == 0 {
+				return
+			}
+			err = nil
+			break // i > 0
+		}
+		if ch < '0' || '9' < ch {
+			if i == 0 {
+				r.UnreadByte()
+				err = fmt.Errorf("invalid exponent (missing digits)")
+				return
+			}
+			break // i > 0
+		}
+		digits = append(digits, byte(ch))
+	}
+	// i > 0 => we have at least one digit
+
+	exp, err = strconv.ParseInt(string(digits), 10, 64)
+	return
+}
+
+// String returns a string representation of x in the form "a/b" (even if b == 1).
+func (x *Rat) String() string {
+	s := "/1"
+	if len(x.b.abs) != 0 {
+		s = "/" + x.b.abs.decimalString()
+	}
+	return x.a.String() + s
+}
+
+// RatString returns a string representation of x in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (x *Rat) RatString() string {
+	if x.IsInt() {
+		return x.a.String()
+	}
+	return x.String()
+}
+
+// FloatString returns a string representation of x in decimal form with prec
+// digits of precision after the decimal point and the last digit rounded.
+func (x *Rat) FloatString(prec int) string {
+	if x.IsInt() {
+		s := x.a.String()
+		if prec > 0 {
+			s += "." + strings.Repeat("0", prec)
+		}
+		return s
+	}
+	// x.b.abs != 0
+
+	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
+
+	p := natOne
+	if prec > 0 {
+		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
+	}
+
+	r = r.mul(r, p)
+	r, r2 := r.div(nat(nil), r, x.b.abs)
+
+	// see if we need to round up
+	r2 = r2.add(r2, r2)
+	if x.b.abs.cmp(r2) <= 0 {
+		r = r.add(r, natOne)
+		if r.cmp(p) >= 0 {
+			q = nat(nil).add(q, natOne)
+			r = nat(nil).sub(r, p)
+		}
+	}
+
+	s := q.decimalString()
+	if x.a.neg {
+		s = "-" + s
+	}
+
+	if prec > 0 {
+		rs := r.decimalString()
+		leadingZeros := prec - len(rs)
+		s += "." + strings.Repeat("0", leadingZeros) + rs
+	}
+
+	return s
+}
diff --git a/src/cmd/internal/gc/big/ratconv_test.go b/src/cmd/internal/gc/big/ratconv_test.go
new file mode 100644
index 0000000..16b3a19
--- /dev/null
+++ b/src/cmd/internal/gc/big/ratconv_test.go
@@ -0,0 +1,451 @@
+// 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 big
+
+import (
+	"bytes"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+type StringTest struct {
+	in, out string
+	ok      bool
+}
+
+var setStringTests = []StringTest{
+	{"0", "0", true},
+	{"-0", "0", true},
+	{"1", "1", true},
+	{"-1", "-1", true},
+	{"1.", "1", true},
+	{"1e0", "1", true},
+	{"1.e1", "10", true},
+	{in: "1e"},
+	{in: "1.e"},
+	{in: "1e+14e-5"},
+	{in: "1e4.5"},
+	{in: "r"},
+	{in: "a/b"},
+	{in: "a.b"},
+	{"-0.1", "-1/10", true},
+	{"-.1", "-1/10", true},
+	{"2/4", "1/2", true},
+	{".25", "1/4", true},
+	{"-1/5", "-1/5", true},
+	{"8129567.7690E14", "812956776900000000000", true},
+	{"78189e+4", "781890000", true},
+	{"553019.8935e+8", "55301989350000", true},
+	{"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+	{"9877861857500000E-7", "3951144743/4", true},
+	{"2169378.417e-3", "2169378417/1000000", true},
+	{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+	{"53/70893980658822810696", "53/70893980658822810696", true},
+	{"106/141787961317645621392", "53/70893980658822810696", true},
+	{"204211327800791583.81095", "4084226556015831676219/20000", true},
+	{in: "1/0"},
+}
+
+// These are not supported by fmt.Fscanf.
+var setStringTests2 = []StringTest{
+	{"0x10", "16", true},
+	{"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
+	{"-010.", "-10", true},
+	{"0x10/0x20", "1/2", true},
+	{"0b1000/3", "8/3", true},
+	// TODO(gri) add more tests
+}
+
+func TestRatSetString(t *testing.T) {
+	var tests []StringTest
+	tests = append(tests, setStringTests...)
+	tests = append(tests, setStringTests2...)
+
+	for i, test := range tests {
+		x, ok := new(Rat).SetString(test.in)
+
+		if ok {
+			if !test.ok {
+				t.Errorf("#%d SetString(%q) expected failure", i, test.in)
+			} else if x.RatString() != test.out {
+				t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
+			}
+		} else if x != nil {
+			t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
+		}
+	}
+}
+
+func TestRatScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range setStringTests {
+		x := new(Rat)
+		buf.Reset()
+		buf.WriteString(test.in)
+
+		_, err := fmt.Fscanf(&buf, "%v", x)
+		if err == nil != test.ok {
+			if test.ok {
+				t.Errorf("#%d (%s) error: %s", i, test.in, err)
+			} else {
+				t.Errorf("#%d (%s) expected error", i, test.in)
+			}
+			continue
+		}
+		if err == nil && x.RatString() != test.out {
+			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+		}
+	}
+}
+
+var floatStringTests = []struct {
+	in   string
+	prec int
+	out  string
+}{
+	{"0", 0, "0"},
+	{"0", 4, "0.0000"},
+	{"1", 0, "1"},
+	{"1", 2, "1.00"},
+	{"-1", 0, "-1"},
+	{".25", 2, "0.25"},
+	{".25", 1, "0.3"},
+	{".25", 3, "0.250"},
+	{"-1/3", 3, "-0.333"},
+	{"-2/3", 4, "-0.6667"},
+	{"0.96", 1, "1.0"},
+	{"0.999", 2, "1.00"},
+	{"0.9", 0, "1"},
+	{".25", -1, "0"},
+	{".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+	for i, test := range floatStringTests {
+		x, _ := new(Rat).SetString(test.in)
+
+		if x.FloatString(test.prec) != test.out {
+			t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+		}
+	}
+}
+
+// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// to be skipped in --test.short mode.  (The threshold is about 500us.)
+var float64inputs = []string{
+	// Constants plundered from strconv/testfp.txt.
+
+	// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+	"5e+125",
+	"69e+267",
+	"999e-026",
+	"7861e-034",
+	"75569e-254",
+	"928609e-261",
+	"9210917e+080",
+	"84863171e+114",
+	"653777767e+273",
+	"5232604057e-298",
+	"27235667517e-109",
+	"653532977297e-123",
+	"3142213164987e-294",
+	"46202199371337e-072",
+	"231010996856685e-073",
+	"9324754620109615e+212",
+	"78459735791271921e+049",
+	"272104041512242479e+200",
+	"6802601037806061975e+198",
+	"20505426358836677347e-221",
+	"836168422905420598437e-234",
+	"4891559871276714924261e+222",
+
+	// Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+	"9e-265",
+	"85e-037",
+	"623e+100",
+	"3571e+263",
+	"81661e+153",
+	"920657e-023",
+	"4603285e-024",
+	"87575437e-309",
+	"245540327e+122",
+	"6138508175e+120",
+	"83356057653e+193",
+	"619534293513e+124",
+	"2335141086879e+218",
+	"36167929443327e-159",
+	"609610927149051e-255",
+	"3743626360493413e-165",
+	"94080055902682397e-242",
+	"899810892172646163e+283",
+	"7120190517612959703e+120",
+	"25188282901709339043e-252",
+	"308984926168550152811e-052",
+	"6372891218502368041059e+064",
+
+	// Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+	"5e-20",
+	"67e+14",
+	"985e+15",
+	"7693e-42",
+	"55895e-16",
+	"996622e-44",
+	"7038531e-32",
+	"60419369e-46",
+	"702990899e-20",
+	"6930161142e-48",
+	"25933168707e+13",
+	"596428896559e+20",
+
+	// Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+	"3e-23",
+	"57e+18",
+	"789e-35",
+	"2539e-18",
+	"76173e+28",
+	"887745e-11",
+	"5382571e-37",
+	"82381273e-35",
+	"750486563e-38",
+	"3752432815e-39",
+	"75224575729e-45",
+	"459926601011e+15",
+
+	// Constants plundered from strconv/atof_test.go.
+
+	"0",
+	"1",
+	"+1",
+	"1e23",
+	"1E23",
+	"100000000000000000000000",
+	"1e-100",
+	"123456700",
+	"99999999999999974834176",
+	"100000000000000000000001",
+	"100000000000000008388608",
+	"100000000000000016777215",
+	"100000000000000016777216",
+	"-1",
+	"-0.1",
+	"-0", // NB: exception made for this input
+	"1e-20",
+	"625e-3",
+
+	// largest float64
+	"1.7976931348623157e308",
+	"-1.7976931348623157e308",
+	// next float64 - too large
+	"1.7976931348623159e308",
+	"-1.7976931348623159e308",
+	// the border is ...158079
+	// borderline - okay
+	"1.7976931348623158e308",
+	"-1.7976931348623158e308",
+	// borderline - too large
+	"1.797693134862315808e308",
+	"-1.797693134862315808e308",
+
+	// a little too large
+	"1e308",
+	"2e308",
+	"1e309",
+
+	// way too large
+	"1e310",
+	"-1e310",
+	"1e400",
+	"-1e400",
+	"long:1e400000",
+	"long:-1e400000",
+
+	// denormalized
+	"1e-305",
+	"1e-306",
+	"1e-307",
+	"1e-308",
+	"1e-309",
+	"1e-310",
+	"1e-322",
+	// smallest denormal
+	"5e-324",
+	"4e-324",
+	"3e-324",
+	// too small
+	"2e-324",
+	// way too small
+	"1e-350",
+	"long:1e-400000",
+	// way too small, negative
+	"-1e-350",
+	"long:-1e-400000",
+
+	// try to overflow exponent
+	// [Disabled: too slow and memory-hungry with rationals.]
+	// "1e-4294967296",
+	// "1e+4294967296",
+	// "1e-18446744073709551616",
+	// "1e+18446744073709551616",
+
+	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+	"2.2250738585072012e-308",
+	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+	"2.2250738585072011e-308",
+
+	// A very large number (initially wrongly parsed by the fast algorithm).
+	"4.630813248087435e+307",
+
+	// A different kind of very large number.
+	"22.222222222222222",
+	"long:2." + strings.Repeat("2", 4000) + "e+1",
+
+	// Exactly halfway between 1 and math.Nextafter(1, 2).
+	// Round to even (down).
+	"1.00000000000000011102230246251565404236316680908203125",
+	// Slightly lower; still round down.
+	"1.00000000000000011102230246251565404236316680908203124",
+	// Slightly higher; round up.
+	"1.00000000000000011102230246251565404236316680908203126",
+	// Slightly higher, but you have to read all the way to the end.
+	"long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
+
+	// Smallest denormal, 2^(-1022-52)
+	"4.940656458412465441765687928682213723651e-324",
+	// Half of smallest denormal, 2^(-1022-53)
+	"2.470328229206232720882843964341106861825e-324",
+	// A little more than the exact half of smallest denormal
+	// 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
+	"2.470328302827751011111470718709768633275e-324",
+	// The exact halfway between smallest normal and largest denormal:
+	// 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
+	"2.225073858507201136057409796709131975935e-308",
+
+	"1152921504606846975",  //   1<<60 - 1
+	"-1152921504606846975", // -(1<<60 - 1)
+	"1152921504606846977",  //   1<<60 + 1
+	"-1152921504606846977", // -(1<<60 + 1)
+
+	"1/3",
+}
+
+// isFinite reports whether f represents a finite rational value.
+// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
+func isFinite(f float64) bool {
+	return math.Abs(f) <= math.MaxFloat64
+}
+
+func TestFloat32SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float32()
+
+		// 1. Check string -> Rat -> float32 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e64, _ := strconv.ParseFloat(input, 32)
+			e := float32(e64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float32bits(e) == math.Float32bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(float64(f)) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox32(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip32(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
+
+func TestFloat64SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float64()
+
+		// 1. Check string -> Rat -> float64 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e, _ := strconv.ParseFloat(input, 64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float64bits(e) == math.Float64bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(f) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox64(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip64(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
diff --git a/src/cmd/internal/gc/big/roundingmode_string.go b/src/cmd/internal/gc/big/roundingmode_string.go
new file mode 100644
index 0000000..05024b8
--- /dev/null
+++ b/src/cmd/internal/gc/big/roundingmode_string.go
@@ -0,0 +1,16 @@
+// generated by stringer -type=RoundingMode; DO NOT EDIT
+
+package big
+
+import "fmt"
+
+const _RoundingMode_name = "ToNearestEvenToNearestAwayToZeroAwayFromZeroToNegativeInfToPositiveInf"
+
+var _RoundingMode_index = [...]uint8{0, 13, 26, 32, 44, 57, 70}
+
+func (i RoundingMode) String() string {
+	if i+1 >= RoundingMode(len(_RoundingMode_index)) {
+		return fmt.Sprintf("RoundingMode(%d)", i)
+	}
+	return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
+}
diff --git a/src/cmd/internal/gc/big/vendor.bash b/src/cmd/internal/gc/big/vendor.bash
new file mode 100755
index 0000000..84aa750
--- /dev/null
+++ b/src/cmd/internal/gc/big/vendor.bash
@@ -0,0 +1,25 @@
+#!/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.
+
+# Run this script to obtain an up-to-date vendored version of math/big.
+
+BIGDIR=../../../../math/big
+
+# Start from scratch.
+rm *.go
+
+# We don't want any assembly files.
+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
+rm arith_decl_pure.go
+
+# gofmt to clean up after sed
+gofmt -w .
+
+# Test that it works
+go test -short
diff --git a/src/cmd/internal/gc/builtin.go b/src/cmd/internal/gc/builtin.go
index 13ee7d7..6bdf78c 100644
--- a/src/cmd/internal/gc/builtin.go
+++ b/src/cmd/internal/gc/builtin.go
@@ -87,35 +87,36 @@
 	"func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" +
 	"func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" +
 	"func @\"\".closechan (@\"\".hchan·1 any)\n" +
+	"var @\"\".writeBarrierEnabled bool\n" +
 	"func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
 	"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
 	"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
 	"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
-	"func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
-	"func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
 	"func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" +
 	"func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n" +
 	"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" +
diff --git a/src/cmd/internal/gc/builtin/runtime.go b/src/cmd/internal/gc/builtin/runtime.go
index 0cf1fb2..179a4dd 100644
--- a/src/cmd/internal/gc/builtin/runtime.go
+++ b/src/cmd/internal/gc/builtin/runtime.go
@@ -108,7 +108,8 @@
 func chansend1(chanType *byte, hchan chan<- any, elem *any)
 func closechan(hchan any)
 
-// *byte is really *runtime.Type
+var writeBarrierEnabled bool
+
 func writebarrierptr(dst *any, src any)
 func writebarrierstring(dst *any, src any)
 func writebarrierslice(dst *any, src any)
@@ -118,32 +119,33 @@
 // which is the maximum alignment on NaCl amd64p32
 // (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
 // The bitmap in the name tells which words being copied are pointers.
-func writebarrierfat01(dst *any, _ *byte, src any)
-func writebarrierfat10(dst *any, _ *byte, src any)
-func writebarrierfat11(dst *any, _ *byte, src any)
-func writebarrierfat001(dst *any, _ *byte, src any)
-func writebarrierfat010(dst *any, _ *byte, src any)
-func writebarrierfat011(dst *any, _ *byte, src any)
-func writebarrierfat100(dst *any, _ *byte, src any)
-func writebarrierfat101(dst *any, _ *byte, src any)
-func writebarrierfat110(dst *any, _ *byte, src any)
-func writebarrierfat111(dst *any, _ *byte, src any)
-func writebarrierfat0001(dst *any, _ *byte, src any)
-func writebarrierfat0010(dst *any, _ *byte, src any)
-func writebarrierfat0011(dst *any, _ *byte, src any)
-func writebarrierfat0100(dst *any, _ *byte, src any)
-func writebarrierfat0101(dst *any, _ *byte, src any)
-func writebarrierfat0110(dst *any, _ *byte, src any)
-func writebarrierfat0111(dst *any, _ *byte, src any)
-func writebarrierfat1000(dst *any, _ *byte, src any)
-func writebarrierfat1001(dst *any, _ *byte, src any)
-func writebarrierfat1010(dst *any, _ *byte, src any)
-func writebarrierfat1011(dst *any, _ *byte, src any)
-func writebarrierfat1100(dst *any, _ *byte, src any)
-func writebarrierfat1101(dst *any, _ *byte, src any)
-func writebarrierfat1110(dst *any, _ *byte, src any)
-func writebarrierfat1111(dst *any, _ *byte, src any)
+func writebarrierfat01(dst *any, _ uintptr, src any)
+func writebarrierfat10(dst *any, _ uintptr, src any)
+func writebarrierfat11(dst *any, _ uintptr, src any)
+func writebarrierfat001(dst *any, _ uintptr, src any)
+func writebarrierfat010(dst *any, _ uintptr, src any)
+func writebarrierfat011(dst *any, _ uintptr, src any)
+func writebarrierfat100(dst *any, _ uintptr, src any)
+func writebarrierfat101(dst *any, _ uintptr, src any)
+func writebarrierfat110(dst *any, _ uintptr, src any)
+func writebarrierfat111(dst *any, _ uintptr, src any)
+func writebarrierfat0001(dst *any, _ uintptr, src any)
+func writebarrierfat0010(dst *any, _ uintptr, src any)
+func writebarrierfat0011(dst *any, _ uintptr, src any)
+func writebarrierfat0100(dst *any, _ uintptr, src any)
+func writebarrierfat0101(dst *any, _ uintptr, src any)
+func writebarrierfat0110(dst *any, _ uintptr, src any)
+func writebarrierfat0111(dst *any, _ uintptr, src any)
+func writebarrierfat1000(dst *any, _ uintptr, src any)
+func writebarrierfat1001(dst *any, _ uintptr, src any)
+func writebarrierfat1010(dst *any, _ uintptr, src any)
+func writebarrierfat1011(dst *any, _ uintptr, src any)
+func writebarrierfat1100(dst *any, _ uintptr, src any)
+func writebarrierfat1101(dst *any, _ uintptr, src any)
+func writebarrierfat1110(dst *any, _ uintptr, src any)
+func writebarrierfat1111(dst *any, _ uintptr, src any)
 
+// *byte is really *runtime.Type
 func typedmemmove(typ *byte, dst *any, src *any)
 func typedslicecopy(typ *byte, dst any, src any) int
 
diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go
index b3524c2..501cdcb 100644
--- a/src/cmd/internal/gc/cgen.go
+++ b/src/cmd/internal/gc/cgen.go
@@ -13,11 +13,20 @@
  * generate:
  *	res = n;
  * simplifies and calls Thearch.Gmove.
+ * if wb is true, need to emit write barriers.
  */
-func Cgen(n *Node, res *Node) {
+func Cgen(n, res *Node) {
+	cgen_wb(n, res, false)
+}
+
+func cgen_wb(n, res *Node, wb bool) {
 	if Debug['g'] != 0 {
-		Dump("\ncgen-n", n)
-		Dump("cgen-res", res)
+		op := "cgen"
+		if wb {
+			op = "cgen_wb"
+		}
+		Dump("\n"+op+"-n", n)
+		Dump(op+"-res", res)
 	}
 
 	if n == nil || n.Type == nil {
@@ -34,29 +43,29 @@
 
 	switch n.Op {
 	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
-		if res.Op != ONAME || res.Addable == 0 {
+		if res.Op != ONAME || !res.Addable || wb {
 			var n1 Node
 			Tempname(&n1, n.Type)
 			Cgen_slice(n, &n1)
-			Cgen(&n1, res)
+			cgen_wb(&n1, res, wb)
 		} else {
 			Cgen_slice(n, res)
 		}
 		return
 
 	case OEFACE:
-		if res.Op != ONAME || res.Addable == 0 {
+		if res.Op != ONAME || !res.Addable || wb {
 			var n1 Node
 			Tempname(&n1, n.Type)
 			Cgen_eface(n, &n1)
-			Cgen(&n1, res)
+			cgen_wb(&n1, res, wb)
 		} else {
 			Cgen_eface(n, res)
 		}
 		return
 
 	case ODOTTYPE:
-		cgen_dottype(n, res, nil)
+		cgen_dottype(n, res, nil, wb)
 		return
 	}
 
@@ -68,26 +77,26 @@
 			var n1 Node
 			Tempname(&n1, n.Type)
 			Cgen(n, &n1)
-			Cgen(&n1, res)
+			cgen_wb(&n1, res, wb)
 			return
 		}
 	}
 
 	if Isfat(n.Type) {
 		if n.Type.Width < 0 {
-			Fatal("forgot to compute width for %v", Tconv(n.Type, 0))
+			Fatal("forgot to compute width for %v", n.Type)
 		}
-		sgen(n, res, n.Type.Width)
+		sgen_wb(n, res, n.Type.Width, wb)
 		return
 	}
 
-	if res.Addable == 0 {
+	if !res.Addable {
 		if n.Ullman > res.Ullman {
 			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
 				var n1 Node
 				Tempname(&n1, n.Type)
 				Cgen(n, &n1)
-				Cgen(&n1, res)
+				cgen_wb(&n1, res, wb)
 				return
 			}
 
@@ -100,70 +109,67 @@
 				Fatal("loop in cgen")
 			}
 
-			Cgen(&n1, res)
+			cgen_wb(&n1, res, wb)
 			Regfree(&n1)
 			return
 		}
 
 		var f int
-		if res.Ullman >= UINF {
-			goto gen
-		}
+		if res.Ullman < UINF {
+			if Complexop(n, res) {
+				Complexgen(n, res)
+				return
+			}
 
-		if Complexop(n, res) {
-			Complexgen(n, res)
-			return
-		}
+			f = 1 // gen thru register
+			switch n.Op {
+			case OLITERAL:
+				if Smallintconst(n) {
+					f = 0
+				}
 
-		f = 1 // gen thru register
-		switch n.Op {
-		case OLITERAL:
-			if Smallintconst(n) {
+			case OREGISTER:
 				f = 0
 			}
 
-		case OREGISTER:
-			f = 0
-		}
-
-		if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
-			a := Thearch.Optoas(OAS, res.Type)
-			var addr obj.Addr
-			if Thearch.Sudoaddable(a, res, &addr) {
-				var p1 *obj.Prog
-				if f != 0 {
-					var n2 Node
-					Regalloc(&n2, res.Type, nil)
-					Cgen(n, &n2)
-					p1 = Thearch.Gins(a, &n2, nil)
-					Regfree(&n2)
-				} else {
-					p1 = Thearch.Gins(a, n, nil)
+			if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 && !wb {
+				a := Thearch.Optoas(OAS, res.Type)
+				var addr obj.Addr
+				if Thearch.Sudoaddable(a, res, &addr) {
+					var p1 *obj.Prog
+					if f != 0 {
+						var n2 Node
+						Regalloc(&n2, res.Type, nil)
+						Cgen(n, &n2)
+						p1 = Thearch.Gins(a, &n2, nil)
+						Regfree(&n2)
+					} else {
+						p1 = Thearch.Gins(a, n, nil)
+					}
+					p1.To = addr
+					if Debug['g'] != 0 {
+						fmt.Printf("%v [ignore previous line]\n", p1)
+					}
+					Thearch.Sudoclean()
+					return
 				}
-				p1.To = addr
-				if Debug['g'] != 0 {
-					fmt.Printf("%v [ignore previous line]\n", p1)
-				}
-				Thearch.Sudoclean()
-				return
 			}
 		}
 
-	gen:
 		if Ctxt.Arch.Thechar == '8' {
 			// no registers to speak of
 			var n1, n2 Node
 			Tempname(&n1, n.Type)
 			Cgen(n, &n1)
 			Igen(res, &n2, nil)
-			Thearch.Gmove(&n1, &n2)
+			cgen_wb(&n1, &n2, wb)
 			Regfree(&n2)
 			return
 		}
 
 		var n1 Node
 		Igen(res, &n1, nil)
-		Cgen(n, &n1)
+		cgen_wb(n, &n1, wb)
 		Regfree(&n1)
 		return
 	}
@@ -186,9 +192,25 @@
 		n.Addable = n.Left.Addable
 	}
 
+	if wb {
+		if int(Simtype[res.Type.Etype]) != Tptr {
+			Fatal("cgen_wb of type %v", res.Type)
+		}
+		if n.Ullman >= UINF {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen(n, &n1)
+			n = &n1
+		}
+		cgen_wbptr(n, res)
+		return
+	}
+
+	// Write barrier now handled. Code below this line can ignore wb.
+
 	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
 		// if both are addressable, move
-		if n.Addable != 0 && res.Addable != 0 {
+		if n.Addable && res.Addable {
 			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] {
 				Thearch.Gmove(n, res)
 			} else {
@@ -203,7 +225,7 @@
 		}
 
 		// if both are not addressable, use a temporary.
-		if n.Addable == 0 && res.Addable == 0 {
+		if !n.Addable && !res.Addable {
 			// could use regalloc here sometimes,
 			// but have to check for ullman >= UINF.
 			var n1 Node
@@ -215,7 +237,7 @@
 
 		// if result is not addressable directly but n is,
 		// compute its address and then store via the address.
-		if res.Addable == 0 {
+		if !res.Addable {
 			var n1 Node
 			Igen(res, &n1, nil)
 			Cgen(n, &n1)
@@ -229,14 +251,14 @@
 		return
 	}
 
-	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable != 0 {
+	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
 		Thearch.Gmove(n, res)
 		return
 	}
 
 	if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
 		// if both are addressable, move
-		if n.Addable != 0 {
+		if n.Addable {
 			if n.Op == OREGISTER || res.Op == OREGISTER {
 				Thearch.Gmove(n, res)
 			} else {
@@ -345,25 +367,12 @@
 		Dump("cgen-res", res)
 		Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
 
-		// these call bgen to get a bool value
-	case OOROR,
-		OANDAND,
-		OEQ,
-		ONE,
-		OLT,
-		OLE,
-		OGE,
-		OGT,
+	case OOROR, OANDAND,
+		OEQ, ONE,
+		OLT, OLE,
+		OGE, OGT,
 		ONOT:
-		p1 := Gbranch(obj.AJMP, nil, 0)
-
-		p2 := Pc
-		Thearch.Gmove(Nodbool(true), res)
-		p3 := Gbranch(obj.AJMP, nil, 0)
-		Patch(p1, Pc)
-		Bgen(n, true, 0, p2)
-		Thearch.Gmove(Nodbool(false), res)
-		Patch(p3, Pc)
+		Bvgen(n, res, true)
 		return
 
 	case OPLUS:
@@ -409,6 +418,19 @@
 		cgen_norm(n, &n1, res)
 		return
 
+	case OSQRT:
+		var n1 Node
+		Regalloc(&n1, nl.Type, res)
+		Cgen(n.Left, &n1)
+		Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1)
+		Thearch.Gmove(&n1, res)
+		Regfree(&n1)
+		return
+
+	case OGETG:
+		Thearch.Getg(res)
+		return
+
 		// symmetric binary
 	case OAND,
 		OOR,
@@ -449,7 +471,7 @@
 		var n1 Node
 		var n2 Node
 		if Ctxt.Arch.Thechar == '5' {
-			if nl.Addable != 0 && !Is64(nl.Type) {
+			if nl.Addable && !Is64(nl.Type) {
 				Regalloc(&n1, nl.Type, res)
 				Thearch.Gmove(nl, &n1)
 			} else {
@@ -765,6 +787,103 @@
 	cgen_norm(n, &n1, res)
 }
 
+var sys_wbptr *Node
+
+func cgen_wbptr(n, res *Node) {
+	if Debug_wb > 0 {
+		Warn("write barrier")
+	}
+
+	var dst, src Node
+	Igen(res, &dst, nil)
+	if n.Op == OREGISTER {
+		src = *n
+		Regrealloc(&src)
+	} else {
+		Cgenr(n, &src, nil)
+	}
+
+	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)
+	Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
+	pjmp := Gbranch(obj.AJMP, nil, 0)
+	Patch(pbr, Pc)
+	var adst Node
+	Agenr(&dst, &adst, &dst)
+	p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &adst, nil)
+	a := &p.To
+	a.Type = obj.TYPE_MEM
+	a.Reg = int16(Thearch.REGSP)
+	a.Offset = 0
+	if HasLinkRegister() {
+		a.Offset += int64(Widthptr)
+	}
+	p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
+	p2.To = p.To
+	p2.To.Offset += int64(Widthptr)
+	Regfree(&adst)
+	if sys_wbptr == nil {
+		sys_wbptr = writebarrierfn("writebarrierptr", Types[Tptr], Types[Tptr])
+	}
+	Ginscall(sys_wbptr, 0)
+	Patch(pjmp, Pc)
+
+	Regfree(&dst)
+	Regfree(&src)
+}
+
+func cgen_wbfat(n, res *Node) {
+	if Debug_wb > 0 {
+		Warn("write barrier")
+	}
+	needType := true
+	funcName := "typedmemmove"
+	var dst, src Node
+	if n.Ullman >= res.Ullman {
+		Agenr(n, &src, nil)
+		Agenr(res, &dst, nil)
+	} else {
+		Agenr(res, &dst, nil)
+		Agenr(n, &src, nil)
+	}
+	p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil)
+	a := &p.To
+	a.Type = obj.TYPE_MEM
+	a.Reg = int16(Thearch.REGSP)
+	a.Offset = 0
+	if HasLinkRegister() {
+		a.Offset += int64(Widthptr)
+	}
+	if needType {
+		a.Offset += int64(Widthptr)
+	}
+	p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
+	p2.To = p.To
+	p2.To.Offset += int64(Widthptr)
+	Regfree(&dst)
+	if needType {
+		src.Type = Types[Tptr]
+		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), &src)
+		p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
+		p3.To = p2.To
+		p3.To.Offset -= 2 * int64(Widthptr)
+	}
+	Regfree(&src)
+	Ginscall(writebarrierfn(funcName, Types[Tptr], Types[Tptr]), 0)
+}
+
 // cgen_norm moves n1 to res, truncating to expected type if necessary.
 // n1 is a register, and cgen_norm frees it.
 func cgen_norm(n, n1, res *Node) {
@@ -786,10 +905,10 @@
 func Mgen(n *Node, n1 *Node, rg *Node) {
 	n1.Op = OEMPTY
 
-	if n.Addable != 0 {
+	if n.Addable {
 		*n1 = *n
 		if n1.Op == OREGISTER || n1.Op == OINDREG {
-			reg[n.Val.U.Reg-int16(Thearch.REGMIN)]++
+			reg[n.Reg-int16(Thearch.REGMIN)]++
 		}
 		return
 	}
@@ -823,7 +942,7 @@
 		Fatal("cgenr on fat node")
 	}
 
-	if n.Addable != 0 {
+	if n.Addable {
 		Regalloc(a, n.Type, res)
 		Thearch.Gmove(n, a)
 		return
@@ -882,7 +1001,7 @@
 			bounded := Debug['B'] != 0 || n.Bounded
 			var n1 Node
 			var n3 Node
-			if nr.Addable != 0 {
+			if nr.Addable {
 				var tmp Node
 				if !Isconst(nr, CTINT) {
 					Tempname(&tmp, Types[TINT32])
@@ -895,7 +1014,7 @@
 					Regalloc(&n1, tmp.Type, nil)
 					Thearch.Gmove(&tmp, &n1)
 				}
-			} else if nl.Addable != 0 {
+			} else if nl.Addable {
 				if !Isconst(nr, CTINT) {
 					var tmp Node
 					Tempname(&tmp, Types[TINT32])
@@ -1013,12 +1132,18 @@
 			} else if w == 1 {
 				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
 			} else {
-				Regalloc(&n4, Types[TUINT32], nil)
-				Nodconst(&n1, Types[TUINT32], int64(w))
-				Thearch.Gmove(&n1, &n4)
-				Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
+				if w&(w-1) == 0 {
+					// Power of 2.  Use shift.
+					Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
+				} else {
+					// Not a power of 2.  Use multiply.
+					Regalloc(&n4, Types[TUINT32], nil)
+					Nodconst(&n1, Types[TUINT32], int64(w))
+					Thearch.Gmove(&n1, &n4)
+					Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
+					Regfree(&n4)
+				}
 				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
-				Regfree(&n4)
 			}
 			*a = n3
 			Regfree(&n2)
@@ -1031,7 +1156,7 @@
 			var n3 Node
 			var tmp Node
 			var n1 Node
-			if nr.Addable != 0 {
+			if nr.Addable {
 				// Generate &nl first, and move nr into register.
 				if !Isconst(nl, CTSTR) {
 					Igen(nl, &n3, res)
@@ -1041,7 +1166,7 @@
 					Regalloc(&n1, tmp.Type, nil)
 					Thearch.Gmove(&tmp, &n1)
 				}
-			} else if nl.Addable != 0 {
+			} else if nl.Addable {
 				// Generate nr first, and move &nl into register.
 				if !Isconst(nr, CTINT) {
 					p2 = Thearch.Igenindex(nr, &tmp, bounded)
@@ -1173,8 +1298,13 @@
 			} else if w == 1 {
 				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
 			} else {
-				Nodconst(&tmp, Types[TUINT32], int64(w))
-				Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &tmp, &n2)
+				if w&(w-1) == 0 {
+					// Power of 2.  Use shift.
+					Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
+				} else {
+					// Not a power of 2.  Use multiply.
+					Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT32]), int64(w), &n2)
+				}
 				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
 			}
 
@@ -1192,10 +1322,10 @@
 		var nlen Node
 		var tmp Node
 		var n1 Node
-		if nr.Addable != 0 {
+		if nr.Addable {
 			goto irad
 		}
-		if nl.Addable != 0 {
+		if nl.Addable {
 			Cgenr(nr, &n1, nil)
 			if !Isconst(nl, CTSTR) {
 				if Isfixedarray(nl.Type) {
@@ -1224,7 +1354,7 @@
 			if Isfixedarray(nl.Type) {
 				Agenr(nl, &n3, res)
 			} else {
-				if nl.Addable == 0 {
+				if !nl.Addable {
 					if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet.
 						Regfree(res)
 					}
@@ -1366,7 +1496,13 @@
 		} else if w == 1 {
 			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
 		} else {
-			Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
+			if w&(w-1) == 0 {
+				// Power of 2.  Use shift.
+				Thearch.Ginscon(Thearch.Optoas(OLSH, t), int64(log2(w)), &n2)
+			} else {
+				// Not a power of 2.  Use multiply.
+				Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
+			}
 			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
 		}
 
@@ -1383,6 +1519,15 @@
 	}
 }
 
+// log2 returns the logarithm base 2 of n.  n must be a power of 2.
+func log2(n uint64) int {
+	x := 0
+	for n>>uint(x) != 1 {
+		x++
+	}
+	return x
+}
+
 /*
  * generate:
  *	res = &n;
@@ -1423,7 +1568,18 @@
 		return
 	}
 
-	if n.Addable != 0 {
+	if n.Op == OINDREG && n.Xoffset == 0 {
+		// Generate MOVW R0, R1 instead of MOVW $0(R0), R1.
+		// This allows better move propagation in the back ends
+		// (and maybe it helps the processor).
+		n1 := *n
+		n1.Op = OREGISTER
+		n1.Type = res.Type
+		Thearch.Gmove(&n1, res)
+		return
+	}
+
+	if n.Addable {
 		if n.Op == OREGISTER {
 			Fatal("agen OREGISTER")
 		}
@@ -1544,8 +1700,8 @@
 	case OINDREG:
 		// Increase the refcount of the register so that igen's caller
 		// has to call Regfree.
-		if n.Val.U.Reg != int16(Thearch.REGSP) {
-			reg[n.Val.U.Reg-int16(Thearch.REGMIN)]++
+		if n.Reg != int16(Thearch.REGSP) {
+			reg[n.Reg-int16(Thearch.REGMIN)]++
 		}
 		*a = *n
 		return
@@ -1582,8 +1738,8 @@
 		fp := Structfirst(&flist, Getoutarg(n.Left.Type))
 		*a = Node{}
 		a.Op = OINDREG
-		a.Val.U.Reg = int16(Thearch.REGSP)
-		a.Addable = 1
+		a.Reg = int16(Thearch.REGSP)
+		a.Addable = true
 		a.Xoffset = fp.Width
 		if HasLinkRegister() {
 			a.Xoffset += int64(Ctxt.Arch.Ptrsize)
@@ -1626,22 +1782,67 @@
 	a.Type = n.Type
 }
 
-/*
- * generate:
- *	if(n == true) goto to;
- */
-func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
-	if Debug['g'] != 0 {
-		Dump("\nbgen", n)
+// Bgen generates code for branches:
+//
+// 	if n == wantTrue {
+// 		goto to
+// 	}
+func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) {
+	bgenx(n, nil, wantTrue, likely, to)
+}
+
+// Bvgen generates code for calculating boolean values:
+// 	res = n == wantTrue
+func Bvgen(n, res *Node, wantTrue bool) {
+	if Thearch.Ginsboolval == nil {
+		// Direct value generation not implemented for this architecture.
+		// Implement using jumps.
+		bvgenjump(n, res, wantTrue, true)
+		return
 	}
+	bgenx(n, res, wantTrue, 0, nil)
+}
+
+// bvgenjump implements boolean value generation using jumps:
+// 	if n == wantTrue {
+// 		res = 1
+// 	} else {
+// 		res = 0
+// 	}
+// geninit controls whether n's Ninit is generated.
+func bvgenjump(n, res *Node, wantTrue, geninit bool) {
+	init := n.Ninit
+	if !geninit {
+		n.Ninit = nil
+	}
+	p1 := Gbranch(obj.AJMP, nil, 0)
+	p2 := Pc
+	Thearch.Gmove(Nodbool(true), res)
+	p3 := Gbranch(obj.AJMP, nil, 0)
+	Patch(p1, Pc)
+	Bgen(n, wantTrue, 0, p2)
+	Thearch.Gmove(Nodbool(false), res)
+	Patch(p3, Pc)
+	n.Ninit = init
+}
+
+// bgenx is the backend for Bgen and Bvgen.
+// If res is nil, it generates a branch.
+// Otherwise, it generates a boolean value.
+func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
+	if Debug['g'] != 0 {
+		fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to)
+		Dump("n", n)
+		Dump("res", res)
+	}
+
+	genval := res != nil
 
 	if n == nil {
 		n = Nodbool(true)
 	}
 
-	if n.Ninit != nil {
-		Genlist(n.Ninit)
-	}
+	Genlist(n.Ninit)
 
 	if n.Type == nil {
 		Convlit(&n, Types[TBOOL])
@@ -1650,306 +1851,367 @@
 		}
 	}
 
-	et := int(n.Type.Etype)
-	if et != TBOOL {
-		Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0))
-		Patch(Thearch.Gins(obj.AEND, nil, nil), to)
-		return
+	if n.Type.Etype != TBOOL {
+		Fatal("bgen: bad type %v for %v", n.Type, Oconv(int(n.Op), 0))
 	}
 
 	for n.Op == OCONVNOP {
 		n = n.Left
-		if n.Ninit != nil {
-			Genlist(n.Ninit)
-		}
+		Genlist(n.Ninit)
 	}
 
 	if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
-		Thearch.Bgen_float(n, bool2int(true_), likely, to)
+		if genval {
+			bvgenjump(n, res, wantTrue, false)
+			return
+		}
+		Thearch.Bgen_float(n, wantTrue, likely, to)
 		return
 	}
 
-	var nl *Node
-	var nr *Node
 	switch n.Op {
 	default:
-		goto def
+		if genval {
+			Cgen(n, res)
+			if !wantTrue {
+				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
+			}
+			return
+		}
 
-		// need to ask if it is bool?
+		var tmp Node
+		Regalloc(&tmp, n.Type, nil)
+		Cgen(n, &tmp)
+		bgenNonZero(&tmp, nil, wantTrue, likely, to)
+		Regfree(&tmp)
+		return
+
+	case ONAME:
+		if genval {
+			// 5g, 7g, and 9g might need a temporary or other help here,
+			// but they don't support direct generation of a bool value yet.
+			// We can fix that as we go.
+			switch Ctxt.Arch.Thechar {
+			case '5', '7', '9':
+				Fatal("genval 5g, 7g, 9g ONAMES not fully implemented")
+			}
+			Cgen(n, res)
+			if !wantTrue {
+				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
+			}
+			return
+		}
+
+		if n.Addable && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
+			// no need for a temporary
+			bgenNonZero(n, nil, wantTrue, likely, to)
+			return
+		}
+		var tmp Node
+		Regalloc(&tmp, n.Type, nil)
+		Cgen(n, &tmp)
+		bgenNonZero(&tmp, nil, wantTrue, likely, to)
+		Regfree(&tmp)
+		return
+
 	case OLITERAL:
-		if !true_ == (n.Val.U.Bval == 0) {
+		// n is a constant.
+		if !Isconst(n, CTBOOL) {
+			Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong))
+		}
+		if genval {
+			Cgen(Nodbool(wantTrue == n.Val.U.Bval), res)
+			return
+		}
+		// If n == wantTrue, jump; otherwise do nothing.
+		if wantTrue == n.Val.U.Bval {
 			Patch(Gbranch(obj.AJMP, nil, likely), to)
 		}
 		return
 
-	case ONAME:
-		if n.Addable == 0 || Ctxt.Arch.Thechar == '5' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
-			goto def
-		}
-		var n1 Node
-		Nodconst(&n1, n.Type, 0)
-		Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &n1)
-		a := Thearch.Optoas(ONE, n.Type)
-		if !true_ {
-			a = Thearch.Optoas(OEQ, n.Type)
-		}
-		Patch(Gbranch(a, n.Type, likely), to)
-		return
-
 	case OANDAND, OOROR:
-		if (n.Op == OANDAND) == true_ {
+		and := (n.Op == OANDAND) == wantTrue
+		if genval {
+			p1 := Gbranch(obj.AJMP, nil, 0)
+			p2 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p2, Pc)
+			Cgen(Nodbool(!and), res)
+			p3 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, Pc)
+			Bgen(n.Left, wantTrue != and, 0, p2)
+			Bvgen(n.Right, res, wantTrue)
+			Patch(p3, Pc)
+			return
+		}
+
+		if and {
 			p1 := Gbranch(obj.AJMP, nil, 0)
 			p2 := Gbranch(obj.AJMP, nil, 0)
 			Patch(p1, Pc)
-			Bgen(n.Left, !true_, -likely, p2)
-			Bgen(n.Right, !true_, -likely, p2)
+			Bgen(n.Left, !wantTrue, -likely, p2)
+			Bgen(n.Right, !wantTrue, -likely, p2)
 			p1 = Gbranch(obj.AJMP, nil, 0)
 			Patch(p1, to)
 			Patch(p2, Pc)
 		} else {
-			Bgen(n.Left, true_, likely, to)
-			Bgen(n.Right, true_, likely, to)
+			Bgen(n.Left, wantTrue, likely, to)
+			Bgen(n.Right, wantTrue, likely, to)
 		}
+		return
 
+	case ONOT: // unary
+		if n.Left == nil || n.Left.Type == nil {
+			return
+		}
+		bgenx(n.Left, res, !wantTrue, likely, to)
 		return
 
 	case OEQ, ONE, OLT, OGT, OLE, OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			return
-		}
-		fallthrough
-
-	case ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
+		if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil {
 			return
 		}
 	}
 
-	switch n.Op {
-	case ONOT:
-		Bgen(nl, !true_, likely, to)
-		return
+	// n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE
+	nl := n.Left
+	nr := n.Right
+	a := int(n.Op)
 
-	case OEQ, ONE, OLT, OGT, OLE, OGE:
-		a := int(n.Op)
-		if !true_ {
-			if Isfloat[nr.Type.Etype] {
-				// brcom is not valid on floats when NaN is involved.
-				p1 := Gbranch(obj.AJMP, nil, 0)
-				p2 := Gbranch(obj.AJMP, nil, 0)
-				Patch(p1, Pc)
-				ll := n.Ninit // avoid re-genning ninit
-				n.Ninit = nil
-				Bgen(n, true, -likely, p2)
+	if !wantTrue {
+		if Isfloat[nr.Type.Etype] {
+			// Brcom is not valid on floats when NaN is involved.
+			ll := n.Ninit // avoid re-genning Ninit
+			n.Ninit = nil
+			if genval {
+				bgenx(n, res, true, likely, to)
+				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res
 				n.Ninit = ll
-				Patch(Gbranch(obj.AJMP, nil, 0), to)
-				Patch(p2, Pc)
 				return
 			}
-
-			a = Brcom(a)
-			true_ = !true_
+			p1 := Gbranch(obj.AJMP, nil, 0)
+			p2 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, Pc)
+			bgenx(n, res, true, -likely, p2)
+			Patch(Gbranch(obj.AJMP, nil, 0), to)
+			Patch(p2, Pc)
+			n.Ninit = ll
+			return
 		}
 
-		// make simplest on right
-		if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
-			a = Brrev(a)
-			r := nl
-			nl = nr
-			nr = r
-		}
+		a = Brcom(a)
+	}
+	wantTrue = true
 
-		if Isslice(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
+	// make simplest on right
+	if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
+		a = Brrev(a)
+		nl, nr = nr, nl
+	}
+
+	if Isslice(nl.Type) || Isinter(nl.Type) {
+		// front end should only leave cmp to literal nil
+		if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
+			if Isslice(nl.Type) {
 				Yyerror("illegal slice comparison")
-				break
-			}
-
-			a = Thearch.Optoas(a, Types[Tptr])
-			var n1 Node
-			Igen(nl, &n1, nil)
-			n1.Xoffset += int64(Array_array)
-			n1.Type = Types[Tptr]
-			var n2 Node
-			Regalloc(&n2, Types[Tptr], &n1)
-			Cgen(&n1, &n2)
-			Regfree(&n1)
-			var tmp Node
-			Nodconst(&tmp, Types[Tptr], 0)
-			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
-			Patch(Gbranch(a, Types[Tptr], likely), to)
-			Regfree(&n2)
-			break
-		}
-
-		if Isinter(nl.Type) {
-			// front end should only leave cmp to literal nil
-			if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
+			} else {
 				Yyerror("illegal interface comparison")
-				break
 			}
-
-			a = Thearch.Optoas(a, Types[Tptr])
-			var n1 Node
-			Igen(nl, &n1, nil)
-			n1.Type = Types[Tptr]
-			var n2 Node
-			Regalloc(&n2, Types[Tptr], &n1)
-			Cgen(&n1, &n2)
-			Regfree(&n1)
-			var tmp Node
-			Nodconst(&tmp, Types[Tptr], 0)
-			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
-			Patch(Gbranch(a, Types[Tptr], likely), to)
-			Regfree(&n2)
-			break
+			return
 		}
 
-		if Iscomplex[nl.Type.Etype] {
-			Complexbool(a, nl, nr, true_, likely, to)
-			break
+		var ptr Node
+		Igen(nl, &ptr, nil)
+		if Isslice(nl.Type) {
+			ptr.Xoffset += int64(Array_array)
 		}
+		ptr.Type = Types[Tptr]
+		var tmp Node
+		Regalloc(&tmp, ptr.Type, &ptr)
+		Cgen(&ptr, &tmp)
+		Regfree(&ptr)
+		bgenNonZero(&tmp, res, a == OEQ != wantTrue, likely, to)
+		Regfree(&tmp)
+		return
+	}
 
-		if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
-			if nl.Addable == 0 || Isconst(nl, CTINT) {
-				var n1 Node
-				Tempname(&n1, nl.Type)
-				Cgen(nl, &n1)
-				nl = &n1
-			}
+	if Iscomplex[nl.Type.Etype] {
+		complexbool(a, nl, nr, res, wantTrue, likely, to)
+		return
+	}
 
-			if nr.Addable == 0 {
-				var n2 Node
-				Tempname(&n2, nr.Type)
-				Cgen(nr, &n2)
-				nr = &n2
-			}
-
-			Thearch.Cmp64(nl, nr, a, likely, to)
-			break
+	if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+		if genval {
+			// TODO: Teach Cmp64 to generate boolean values and remove this.
+			bvgenjump(n, res, wantTrue, false)
+			return
 		}
+		if !nl.Addable || Isconst(nl, CTINT) {
+			nl = CgenTemp(nl)
+		}
+		if !nr.Addable {
+			nr = CgenTemp(nr)
+		}
+		Thearch.Cmp64(nl, nr, a, likely, to)
+		return
+	}
 
+	if nr.Ullman >= UINF {
 		var n1 Node
+		Regalloc(&n1, nl.Type, nil)
+		Cgen(nl, &n1)
+
+		var tmp Node
+		Tempname(&tmp, nl.Type)
+		Thearch.Gmove(&n1, &tmp)
+		Regfree(&n1)
+
 		var n2 Node
-		if nr.Ullman >= UINF {
-			Regalloc(&n1, nl.Type, nil)
-			Cgen(nl, &n1)
+		Regalloc(&n2, nr.Type, nil)
+		Cgen(nr, &n2)
+		Regfree(&n2)
 
-			var tmp Node
-			Tempname(&tmp, nl.Type)
-			Thearch.Gmove(&n1, &tmp)
-			Regfree(&n1)
-
-			Regalloc(&n2, nr.Type, nil)
-			Cgen(nr, &n2)
-
-			Regalloc(&n1, nl.Type, nil)
-			Cgen(&tmp, &n1)
-
-			goto cmp
-		}
-
-		if nl.Addable == 0 && Ctxt.Arch.Thechar == '8' {
+		Regalloc(&n1, nl.Type, nil)
+		Cgen(&tmp, &n1)
+		Regfree(&n1)
+	} else {
+		var n1 Node
+		if !nl.Addable && Ctxt.Arch.Thechar == '8' {
 			Tempname(&n1, nl.Type)
 		} else {
 			Regalloc(&n1, nl.Type, nil)
+			defer Regfree(&n1)
 		}
 		Cgen(nl, &n1)
 		nl = &n1
 
 		if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
 			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
-			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
-			if n1.Op == OREGISTER {
-				Regfree(&n1)
-			}
-			break
+			bins(nr.Type, res, a, likely, to)
+			return
 		}
 
-		if nr.Addable == 0 && Ctxt.Arch.Thechar == '8' {
-			var tmp Node
-			Tempname(&tmp, nr.Type)
-			Cgen(nr, &tmp)
-			nr = &tmp
+		if !nr.Addable && Ctxt.Arch.Thechar == '8' {
+			nr = CgenTemp(nr)
 		}
 
+		var n2 Node
 		Regalloc(&n2, nr.Type, nil)
 		Cgen(nr, &n2)
 		nr = &n2
+		Regfree(&n2)
+	}
 
-	cmp:
-		l, r := nl, nr
-		// On x86, only < and <= work right with NaN; reverse if needed
-		if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
-			l, r = r, l
-			a = Brrev(a)
-		}
+	l, r := nl, nr
 
-		Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
+	// On x86, only < and <= work right with NaN; reverse if needed
+	if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
+		l, r = r, l
+		a = Brrev(a)
+	}
 
-		if Ctxt.Arch.Thechar == '6' && Isfloat[nr.Type.Etype] && (n.Op == OEQ || n.Op == ONE) {
-			if n.Op == OEQ {
-				// neither NE nor P
-				p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
-				p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
-				Patch(Gbranch(obj.AJMP, nil, 0), to)
-				Patch(p1, Pc)
-				Patch(p2, Pc)
-			} else {
-				// either NE or P
-				Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
-				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
+	// Do the comparison.
+	Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
+
+	// Handle floating point special cases.
+	// Note that 8g has Bgen_float and is handled above.
+	if Isfloat[nl.Type.Etype] {
+		switch Ctxt.Arch.Thechar {
+		case '5':
+			if genval {
+				Fatal("genval 5g Isfloat special cases not implemented")
 			}
-		} else if Ctxt.Arch.Thechar == '5' && Isfloat[nl.Type.Etype] {
-			if n.Op == ONE {
+			switch n.Op {
+			case ONE:
 				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
 				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
-			} else {
+			default:
 				p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
 				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
 				Patch(p, Pc)
 			}
-		} else if (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') && Isfloat[nl.Type.Etype] && (a == OLE || a == OGE) {
-			// On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
-			if a == OLE {
-				a = OLT
-			} else {
-				a = OGT
+			return
+		case '6':
+			switch n.Op {
+			case OEQ:
+				// neither NE nor P
+				if genval {
+					var reg Node
+					Regalloc(&reg, Types[TBOOL], nil)
+					Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), &reg)
+					Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res)
+					Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), &reg, res)
+					Regfree(&reg)
+				} else {
+					p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
+					p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
+					Patch(Gbranch(obj.AJMP, nil, 0), to)
+					Patch(p1, Pc)
+					Patch(p2, Pc)
+				}
+				return
+			case ONE:
+				// either NE or P
+				if genval {
+					var reg Node
+					Regalloc(&reg, Types[TBOOL], nil)
+					Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), &reg)
+					Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res)
+					Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), &reg, res)
+					Regfree(&reg)
+				} else {
+					Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
+					Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
+				}
+				return
 			}
-			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
-			Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
-		} else {
-			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
-		}
-		if n1.Op == OREGISTER {
-			Regfree(&n1)
-		}
-		if n2.Op == OREGISTER {
-			Regfree(&n2)
+		case '7', '9':
+			if genval {
+				Fatal("genval 7g, 9g Isfloat special cases not implemented")
+			}
+			switch n.Op {
+			// On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
+			// TODO(josh): Convert a <= b to b > a instead?
+			case OLE, OGE:
+				if a == OLE {
+					a = OLT
+				} else {
+					a = OGT
+				}
+				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+				Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
+				return
+			}
 		}
 	}
 
-	return
+	// Not a special case. Insert the conditional jump or value gen.
+	bins(nr.Type, res, a, likely, to)
+}
 
-def:
+func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	// TODO: Optimize on systems that can compare to zero easily.
-	var n1 Node
-	Regalloc(&n1, n.Type, nil)
-	Cgen(n, &n1)
-	var n2 Node
-	Nodconst(&n2, n.Type, 0)
-	Thearch.Gins(Thearch.Optoas(OCMP, n.Type), &n1, &n2)
-	a := Thearch.Optoas(ONE, n.Type)
-	if !true_ {
-		a = Thearch.Optoas(OEQ, n.Type)
+	a := ONE
+	if !wantTrue {
+		a = OEQ
 	}
-	Patch(Gbranch(a, n.Type, likely), to)
-	Regfree(&n1)
-	return
+	var zero Node
+	Nodconst(&zero, n.Type, 0)
+	Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero)
+	bins(n.Type, res, a, likely, to)
+}
+
+// bins inserts an instruction to handle the result of a compare.
+// If res is non-nil, it inserts appropriate value generation instructions.
+// If res is nil, it inserts a branch to to.
+func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) {
+	a = Thearch.Optoas(a, typ)
+	if res != nil {
+		// value gen
+		Thearch.Ginsboolval(a, res)
+	} else {
+		// jump
+		Patch(Gbranch(a, typ, likely), to)
+	}
 }
 
 /*
@@ -2012,10 +2274,15 @@
 /*
  * block copy:
  *	memmove(&ns, &n, w);
+ * if wb is true, needs write barrier.
  */
-func sgen(n *Node, ns *Node, w int64) {
+func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
 	if Debug['g'] != 0 {
-		fmt.Printf("\nsgen w=%d\n", w)
+		op := "sgen"
+		if wb {
+			op = "sgen-wb"
+		}
+		fmt.Printf("\n%s w=%d\n", op, w)
 		Dump("r", n)
 		Dump("res", ns)
 	}
@@ -2039,7 +2306,7 @@
 	}
 
 	// Avoid taking the address for simple enough types.
-	if Componentgen(n, ns) {
+	if componentgen_wb(n, ns, wb) {
 		return
 	}
 
@@ -2057,19 +2324,33 @@
 	osrc := stkof(n)
 	odst := stkof(ns)
 
-	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
+	if odst != -1000 {
+		// on stack, write barrier not needed after all
+		wb = false
+	}
+
+	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -1000 {
 		// osrc and odst both on stack, and at least one is in
 		// an unknown position.  Could generate code to test
 		// for forward/backward copy, but instead just copy
 		// to a temporary location first.
+		//
+		// OR: write barrier needed and source is on stack.
+		// Invoking the write barrier will use the stack to prepare its call.
+		// Copy to temporary.
 		var tmp Node
 		Tempname(&tmp, n.Type)
-		sgen(n, &tmp, w)
-		sgen(&tmp, ns, w)
+		sgen_wb(n, &tmp, w, false)
+		sgen_wb(&tmp, ns, w, wb)
 		return
 	}
 
-	Thearch.Stackcopy(n, ns, osrc, odst, w)
+	if wb {
+		cgen_wbfat(n, ns)
+		return
+	}
+
+	Thearch.Blockcopy(n, ns, osrc, odst, w)
 }
 
 /*
@@ -2136,12 +2417,12 @@
 
 		// size of arguments at 0(SP)
 		stk.Op = OINDREG
-		stk.Val.U.Reg = int16(Thearch.REGSP)
+		stk.Reg = int16(Thearch.REGSP)
 		stk.Xoffset = 0
 		if HasLinkRegister() {
 			stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
 		}
-		Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk)
+		Thearch.Ginscon(Thearch.Optoas(OAS, Types[TINT32]), int64(Argsize(f.Type)), &stk)
 
 		// FuncVal* at 8(SP)
 		stk.Xoffset = int64(Widthptr)
@@ -2190,7 +2471,7 @@
 
 	i = i.Left // interface
 
-	if i.Addable == 0 {
+	if !i.Addable {
 		var tmpi Node
 		Tempname(&tmpi, i.Type)
 		Cgen(i, &tmpi)
@@ -2295,7 +2576,7 @@
 	}
 
 	// call direct
-	n.Left.Method = 1
+	n.Left.Method = true
 
 	Ginscall(n.Left, proc)
 }
@@ -2324,8 +2605,8 @@
 
 	var nod Node
 	nod.Op = OINDREG
-	nod.Val.U.Reg = int16(Thearch.REGSP)
-	nod.Addable = 1
+	nod.Reg = int16(Thearch.REGSP)
+	nod.Addable = true
 
 	nod.Xoffset = fp.Width
 	if HasLinkRegister() {
@@ -2354,8 +2635,8 @@
 
 	var nod1 Node
 	nod1.Op = OINDREG
-	nod1.Val.U.Reg = int16(Thearch.REGSP)
-	nod1.Addable = 1
+	nod1.Reg = int16(Thearch.REGSP)
+	nod1.Addable = true
 	nod1.Xoffset = fp.Width
 	if HasLinkRegister() {
 		nod1.Xoffset += int64(Ctxt.Arch.Ptrsize)
@@ -2547,7 +2828,7 @@
 	if n.Op != OINDREG {
 		return
 	}
-	if n.Val.U.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
+	if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
 		return
 	}
 	if n.Xoffset != int64(int32(n.Xoffset)) {
diff --git a/src/cmd/internal/gc/closure.go b/src/cmd/internal/gc/closure.go
index a5364fc..8d5fd5a 100644
--- a/src/cmd/internal/gc/closure.go
+++ b/src/cmd/internal/gc/closure.go
@@ -269,7 +269,7 @@
 			if v.Byval {
 				how = "value"
 			}
-			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", Sconv(name, 0), how, Sconv(v.Sym, 0), 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.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
 		}
 
 		typecheck(&outer, Erv)
@@ -517,7 +517,7 @@
 		basetype = basetype.Type
 	}
 	if basetype.Etype != TINTER && basetype.Sym == nil {
-		Fatal("missing base type for %v", Tconv(rcvrtype, 0))
+		Fatal("missing base type for %v", rcvrtype)
 	}
 
 	var spkg *Pkg
@@ -599,7 +599,7 @@
 	ptr := Nod(ONAME, nil, nil)
 	ptr.Sym = Lookup("rcvr")
 	ptr.Class = PAUTO
-	ptr.Addable = 1
+	ptr.Addable = true
 	ptr.Ullman = 1
 	ptr.Used = true
 	ptr.Curfn = xfunc
diff --git a/src/cmd/internal/gc/const.go b/src/cmd/internal/gc/const.go
index 6842c84..ad29158 100644
--- a/src/cmd/internal/gc/const.go
+++ b/src/cmd/internal/gc/const.go
@@ -23,8 +23,8 @@
 	v.U.Fval = oldv
 	overflow(v, t)
 
-	fv := new(Mpflt)
-	*fv = *oldv
+	fv := newMpflt()
+	mpmovefltflt(fv, oldv)
 
 	// convert large precision literal floating
 	// into limited precision (float64 or float32)
@@ -103,7 +103,7 @@
 			n.Val = toint(n.Val)
 		}
 		if t != nil && !Isint[t.Etype] {
-			Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (shift of type %v)", n, t)
 			t = nil
 		}
 
@@ -255,7 +255,7 @@
 bad:
 	if n.Diag == 0 {
 		if t.Broke == 0 {
-			Yyerror("cannot convert %v to type %v", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("cannot convert %v to type %v", n, t)
 		}
 		n.Diag = 1
 	}
@@ -276,7 +276,7 @@
 		v.U.Xval = i
 
 	case CTFLT:
-		f := new(Mpflt)
+		f := newMpflt()
 		mpmovefltflt(f, v.U.Fval)
 		v.U.Fval = f
 
@@ -313,13 +313,13 @@
 func toflt(v Val) Val {
 	switch v.Ctype {
 	case CTINT, CTRUNE:
-		f := new(Mpflt)
+		f := newMpflt()
 		Mpmovefixflt(f, v.U.Xval)
 		v.Ctype = CTFLT
 		v.U.Fval = f
 
 	case CTCPLX:
-		f := new(Mpflt)
+		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))
@@ -363,7 +363,7 @@
 	switch v.Ctype {
 	case CTINT, CTRUNE:
 		if !Isint[t.Etype] {
-			Fatal("overflow: %v integer constant", Tconv(t, 0))
+			Fatal("overflow: %v integer constant", t)
 		}
 		if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 {
 			return true
@@ -371,7 +371,7 @@
 
 	case CTFLT:
 		if !Isfloat[t.Etype] {
-			Fatal("overflow: %v floating-point constant", Tconv(t, 0))
+			Fatal("overflow: %v floating-point constant", t)
 		}
 		if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 {
 			return true
@@ -379,7 +379,7 @@
 
 	case CTCPLX:
 		if !Iscomplex[t.Etype] {
-			Fatal("overflow: %v complex constant", Tconv(t, 0))
+			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 {
 			return true
@@ -402,13 +402,13 @@
 
 	switch v.Ctype {
 	case CTINT, CTRUNE:
-		Yyerror("constant %v overflows %v", Bconv(v.U.Xval, 0), Tconv(t, 0))
+		Yyerror("constant %v overflows %v", v.U.Xval, t)
 
 	case CTFLT:
-		Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), Tconv(t, 0))
+		Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t)
 
 	case CTCPLX:
-		Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), Tconv(t, 0))
+		Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t)
 	}
 }
 
@@ -577,7 +577,7 @@
 		switch uint32(n.Op)<<16 | uint32(v.Ctype) {
 		default:
 			if n.Diag == 0 {
-				Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), Tconv(nl.Type, 0))
+				Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), nl.Type)
 				n.Diag = 1
 			}
 
@@ -650,7 +650,7 @@
 			mpnegflt(&v.U.Cval.Imag)
 
 		case ONOT<<16 | CTBOOL:
-			if v.U.Bval == 0 {
+			if !v.U.Bval {
 				goto settrue
 			}
 			goto setfalse
@@ -744,7 +744,7 @@
 		if (v.Ctype == 0 || rv.Ctype == 0) && nerrors > 0 {
 			return
 		}
-		Fatal("constant type mismatch %v(%d) %v(%d)", Tconv(nl.Type, 0), v.Ctype, Tconv(nr.Type, 0), rv.Ctype)
+		Fatal("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype, nr.Type, rv.Ctype)
 	}
 
 	// run op
@@ -990,13 +990,13 @@
 		goto setfalse
 
 	case OOROR<<16 | CTBOOL:
-		if v.U.Bval != 0 || rv.U.Bval != 0 {
+		if v.U.Bval || rv.U.Bval {
 			goto settrue
 		}
 		goto setfalse
 
 	case OANDAND<<16 | CTBOOL:
-		if v.U.Bval != 0 && rv.U.Bval != 0 {
+		if v.U.Bval && rv.U.Bval {
 			goto settrue
 		}
 		goto setfalse
@@ -1051,7 +1051,7 @@
 
 illegal:
 	if n.Diag == 0 {
-		Yyerror("illegal constant expression: %v %v %v", Tconv(nl.Type, 0), Oconv(int(n.Op), 0), Tconv(nr.Type, 0))
+		Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(int(n.Op), 0), nr.Type)
 		n.Diag = 1
 	}
 
@@ -1135,7 +1135,6 @@
 		} else {
 			return k2
 		}
-		fallthrough
 
 	case OREAL, OIMAG:
 		return CTFLT
@@ -1205,7 +1204,7 @@
 			break
 		}
 
-		Yyerror("defaultlit: unknown literal: %v", Nconv(n, 0))
+		Yyerror("defaultlit: unknown literal: %v", n)
 
 	case CTxxx:
 		Fatal("defaultlit: idealkind is CTxxx: %v", Nconv(n, obj.FmtSign))
@@ -1418,7 +1417,7 @@
 			i = Mpgetfix(val.U.Xval)
 
 		case CTBOOL:
-			i = int64(val.U.Bval)
+			i = int64(obj.Bool2int(val.U.Bval))
 
 		case CTNIL:
 			i = 0
@@ -1432,7 +1431,7 @@
 	if Isfloat[tt] {
 		con.Val = toflt(con.Val)
 		if con.Val.Ctype != CTFLT {
-			Fatal("convconst ctype=%d %v", con.Val.Ctype, Tconv(t, 0))
+			Fatal("convconst ctype=%d %v", con.Val.Ctype, t)
 		}
 		if tt == TFLOAT32 {
 			con.Val.U.Fval = truncfltlit(con.Val.U.Fval, t)
diff --git a/src/cmd/internal/gc/cplx.go b/src/cmd/internal/gc/cplx.go
index fe4c38c..cf48c92 100644
--- a/src/cmd/internal/gc/cplx.go
+++ b/src/cmd/internal/gc/cplx.go
@@ -6,10 +6,6 @@
 
 import "cmd/internal/obj"
 
-func CASE(a int, b int) int {
-	return a<<16 | b
-}
-
 func overlap_cplx(f *Node, t *Node) bool {
 	// check whether f and t could be overlapping stack references.
 	// not exact, because it's hard to check for the stack register
@@ -18,72 +14,73 @@
 	return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset
 }
 
-func Complexbool(op int, nl *Node, nr *Node, true_ bool, likely int, to *obj.Prog) {
-	var tnl Node
-
+func complexbool(op int, nl, nr, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	// make both sides addable in ullman order
 	if nr != nil {
-		if nl.Ullman > nr.Ullman && nl.Addable == 0 {
-			Tempname(&tnl, nl.Type)
-			Cgen(nl, &tnl)
-			nl = &tnl
+		if nl.Ullman > nr.Ullman && !nl.Addable {
+			nl = CgenTemp(nl)
 		}
 
-		if nr.Addable == 0 {
-			var tnr Node
-			Tempname(&tnr, nr.Type)
-			Cgen(nr, &tnr)
-			nr = &tnr
+		if !nr.Addable {
+			nr = CgenTemp(nr)
 		}
 	}
-
-	if nl.Addable == 0 {
-		Tempname(&tnl, nl.Type)
-		Cgen(nl, &tnl)
-		nl = &tnl
+	if !nl.Addable {
+		nl = CgenTemp(nl)
 	}
 
+	// Break nl and nr into real and imaginary components.
+	var lreal, limag, rreal, rimag Node
+	subnode(&lreal, &limag, nl)
+	subnode(&rreal, &rimag, nr)
+
 	// build tree
-	// real(l) == real(r) && imag(l) == imag(r)
-
-	var n2 Node
-	var n1 Node
-	subnode(&n1, &n2, nl)
-
-	var n3 Node
-	var n4 Node
-	subnode(&n3, &n4, nr)
-
-	var na Node
-	na.Op = OANDAND
-	var nb Node
-	na.Left = &nb
-	var nc Node
-	na.Right = &nc
-	na.Type = Types[TBOOL]
-
-	nb = Node{}
-	nb.Op = OEQ
-	nb.Left = &n1
-	nb.Right = &n3
-	nb.Type = Types[TBOOL]
-
-	nc = Node{}
-	nc.Op = OEQ
-	nc.Left = &n2
-	nc.Right = &n4
-	nc.Type = Types[TBOOL]
-
-	if op == ONE {
-		true_ = !true_
+	// if branching:
+	// 	real(l) == real(r) && imag(l) == imag(r)
+	// if generating a value, use a branch-free version:
+	// 	real(l) == real(r) & imag(l) == imag(r)
+	realeq := Node{
+		Op:    OEQ,
+		Left:  &lreal,
+		Right: &rreal,
+		Type:  Types[TBOOL],
+	}
+	imageq := Node{
+		Op:    OEQ,
+		Left:  &limag,
+		Right: &rimag,
+		Type:  Types[TBOOL],
+	}
+	and := Node{
+		Op:    OANDAND,
+		Left:  &realeq,
+		Right: &imageq,
+		Type:  Types[TBOOL],
 	}
 
-	Bgen(&na, true_, likely, to)
+	if res != nil {
+		// generating a value
+		and.Op = OAND
+		if op == ONE {
+			and.Op = OOR
+			realeq.Op = ONE
+			imageq.Op = ONE
+		}
+		Bvgen(&and, res, true)
+		return
+	}
+
+	// generating a branch
+	if op == ONE {
+		wantTrue = !wantTrue
+	}
+
+	Bgen(&and, wantTrue, likely, to)
 }
 
 // break addable nc-complex into nr-real and ni-imaginary
 func subnode(nr *Node, ni *Node, nc *Node) {
-	if nc.Addable == 0 {
+	if !nc.Addable {
 		Fatal("subnode not addable")
 	}
 
@@ -227,14 +224,14 @@
 func nodfconst(n *Node, t *Type, fval *Mpflt) {
 	*n = Node{}
 	n.Op = OLITERAL
-	n.Addable = 1
+	n.Addable = true
 	ullmancalc(n)
 	n.Val.U.Fval = fval
 	n.Val.Ctype = CTFLT
 	n.Type = t
 
 	if !Isfloat[t.Etype] {
-		Fatal("nodfconst: bad type %v", Tconv(t, 0))
+		Fatal("nodfconst: bad type %v", t)
 	}
 }
 
@@ -291,7 +288,7 @@
 		Dump("complexmove-t", t)
 	}
 
-	if t.Addable == 0 {
+	if !t.Addable {
 		Fatal("complexmove: to not addable")
 	}
 
@@ -299,7 +296,7 @@
 	tt := Simsimtype(t.Type)
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		Fatal("complexmove: unknown conversion: %v -> %v\n", Tconv(f.Type, 0), Tconv(t.Type, 0))
+		Fatal("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
 
 		// complex to complex move/convert.
 	// make f addable.
@@ -308,7 +305,7 @@
 		TCOMPLEX64<<16 | TCOMPLEX128,
 		TCOMPLEX128<<16 | TCOMPLEX64,
 		TCOMPLEX128<<16 | TCOMPLEX128:
-		if f.Addable == 0 || overlap_cplx(f, t) {
+		if !f.Addable || overlap_cplx(f, t) {
 			var tmp Node
 			Tempname(&tmp, f.Type)
 			Complexmove(f, &tmp)
@@ -340,7 +337,7 @@
 	// pick off float/complex opcodes
 	switch n.Op {
 	case OCOMPLEX:
-		if res.Addable != 0 {
+		if res.Addable {
 			var n1 Node
 			var n2 Node
 			subnode(&n1, &n2, res)
@@ -354,7 +351,7 @@
 
 	case OREAL, OIMAG:
 		nl := n.Left
-		if nl.Addable == 0 {
+		if !nl.Addable {
 			var tmp Node
 			Tempname(&tmp, nl.Type)
 			Complexgen(nl, &tmp)
@@ -380,7 +377,7 @@
 	tr := Simsimtype(n.Type)
 	tr = cplxsubtype(tr)
 	if tl != tr {
-		if n.Addable == 0 {
+		if !n.Addable {
 			var n1 Node
 			Tempname(&n1, n.Type)
 			Complexmove(n, &n1)
@@ -391,7 +388,7 @@
 		return
 	}
 
-	if res.Addable == 0 {
+	if !res.Addable {
 		var n1 Node
 		Igen(res, &n1, nil)
 		Cgen(n, &n1)
@@ -399,7 +396,7 @@
 		return
 	}
 
-	if n.Addable != 0 {
+	if n.Addable {
 		Complexmove(n, res)
 		return
 	}
@@ -444,13 +441,13 @@
 	// make both sides addable in ullman order
 	var tnl Node
 	if nr != nil {
-		if nl.Ullman > nr.Ullman && nl.Addable == 0 {
+		if nl.Ullman > nr.Ullman && !nl.Addable {
 			Tempname(&tnl, nl.Type)
 			Cgen(nl, &tnl)
 			nl = &tnl
 		}
 
-		if nr.Addable == 0 {
+		if !nr.Addable {
 			var tnr Node
 			Tempname(&tnr, nr.Type)
 			Cgen(nr, &tnr)
@@ -458,7 +455,7 @@
 		}
 	}
 
-	if nl.Addable == 0 {
+	if !nl.Addable {
 		Tempname(&tnl, nl.Type)
 		Cgen(nl, &tnl)
 		nl = &tnl
diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go
index 846ec7d..08d2469 100644
--- a/src/cmd/internal/gc/dcl.go
+++ b/src/cmd/internal/gc/dcl.go
@@ -46,7 +46,7 @@
 	d := push()
 	dcopy(d, s)
 	if dflag() {
-		fmt.Printf("\t%v push %v %p\n", Ctxt.Line(int(lineno)), Sconv(s, 0), s.Def)
+		fmt.Printf("\t%v push %v %p\n", Ctxt.Line(int(lineno)), s, s.Def)
 	}
 	return d
 }
@@ -68,7 +68,7 @@
 		dcopy(s, d)
 		d.Lastlineno = int32(lno)
 		if dflag() {
-			fmt.Printf("\t%v pop %v %p\n", Ctxt.Line(int(lineno)), Sconv(s, 0), s.Def)
+			fmt.Printf("\t%v pop %v %p\n", Ctxt.Line(int(lineno)), s, s.Def)
 		}
 	}
 
@@ -114,7 +114,7 @@
 
 		fmt.Printf(" '%s'", d.Name)
 		s = Pkglookup(d.Name, d.Pkg)
-		fmt.Printf(" %v\n", Sconv(s, 0))
+		fmt.Printf(" %v\n", s)
 	}
 }
 
@@ -139,7 +139,7 @@
 			tmp = s.Pkg.Path
 		}
 		pkgstr := tmp
-		Yyerror("%v redeclared %s\n"+"\tprevious declaration during import %q", Sconv(s, 0), where, pkgstr)
+		Yyerror("%v redeclared %s\n"+"\tprevious declaration during import %q", s, where, pkgstr)
 	} else {
 		line1 := parserline()
 		line2 := int(s.Lastlineno)
@@ -153,7 +153,7 @@
 			line1 = int(s.Lastlineno)
 		}
 
-		yyerrorl(int(line1), "%v redeclared %s\n"+"\tprevious declaration at %v", Sconv(s, 0), where, Ctxt.Line(line2))
+		yyerrorl(int(line1), "%v redeclared %s\n"+"\tprevious declaration at %v", s, where, Ctxt.Line(line2))
 	}
 }
 
@@ -165,7 +165,7 @@
 
 var declare_typegen int
 
-func declare(n *Node, ctxt int) {
+func declare(n *Node, ctxt uint8) {
 	if ctxt == PDISCARD {
 		return
 	}
@@ -179,7 +179,7 @@
 
 	// kludgy: typecheckok means we're past parsing.  Eg genwrapper may declare out of package names later.
 	if importpkg == nil && typecheckok == 0 && s.Pkg != localpkg {
-		Yyerror("cannot declare name %v", Sconv(s, 0))
+		Yyerror("cannot declare name %v", s)
 	}
 
 	if ctxt == PEXTERN && s.Name == "init" {
@@ -190,7 +190,7 @@
 	if ctxt == PEXTERN {
 		externdcl = list(externdcl, n)
 		if dflag() {
-			fmt.Printf("\t%v global decl %v %p\n", Ctxt.Line(int(lineno)), Sconv(s, 0), n)
+			fmt.Printf("\t%v global decl %v %p\n", Ctxt.Line(int(lineno)), s, n)
 		}
 	} else {
 		if Curfn == nil && ctxt == PAUTO {
@@ -232,9 +232,9 @@
 	autoexport(n, ctxt)
 }
 
-func addvar(n *Node, t *Type, ctxt int) {
+func addvar(n *Node, t *Type, ctxt uint8) {
 	if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
-		Fatal("addvar: n=%v t=%v nil", Nconv(n, 0), Tconv(t, 0))
+		Fatal("addvar: n=%v t=%v nil", n, t)
 	}
 
 	n.Op = ONAME
@@ -367,7 +367,7 @@
 	n := Nod(ONAME, nil, nil)
 	n.Sym = s
 	n.Type = nil
-	n.Addable = 1
+	n.Addable = true
 	n.Ullman = 1
 	n.Xoffset = 0
 	return n
@@ -438,7 +438,7 @@
 			c.Class = PPARAMREF
 			c.Isddd = n.Isddd
 			c.Defn = n
-			c.Addable = 0
+			c.Addable = false
 			c.Ullman = 2
 			c.Funcdepth = Funcdepth
 			c.Outer = n.Closure
@@ -487,13 +487,13 @@
 			continue
 		}
 		if !colasname(n) {
-			yyerrorl(int(defn.Lineno), "non-name %v on left side of :=", Nconv(n, 0))
+			yyerrorl(int(defn.Lineno), "non-name %v on left side of :=", n)
 			nerr++
 			continue
 		}
 
 		if n.Sym.Flags&SymUniq == 0 {
-			yyerrorl(int(defn.Lineno), "%v repeated on left side of :=", Sconv(n.Sym, 0))
+			yyerrorl(int(defn.Lineno), "%v repeated on left side of :=", n.Sym)
 			n.Diag++
 			nerr++
 			continue
@@ -521,7 +521,7 @@
 	as := Nod(OAS2, nil, nil)
 	as.List = left
 	as.Rlist = right
-	as.Colas = 1
+	as.Colas = true
 	as.Lineno = lno
 	colasdefn(left, as)
 
@@ -695,7 +695,7 @@
  */
 func funcargs2(t *Type) {
 	if t.Etype != TFUNC {
-		Fatal("funcargs2 %v", Tconv(t, 0))
+		Fatal("funcargs2 %v", t)
 	}
 
 	if t.Thistuple != 0 {
@@ -803,7 +803,7 @@
 	lineno = n.Lineno
 
 	if n.Op != ODCLFIELD {
-		Fatal("structfield: oops %v\n", Nconv(n, 0))
+		Fatal("structfield: oops %v\n", n)
 	}
 
 	f := typ(TFIELD)
@@ -836,7 +836,6 @@
 		Yyerror("field annotation must be string")
 		fallthrough
 
-		// fallthrough
 	case CTxxx:
 		f.Note = nil
 	}
@@ -934,7 +933,7 @@
 	lineno = n.Lineno
 
 	if n.Op != ODCLFIELD {
-		Fatal("interfacefield: oops %v\n", Nconv(n, 0))
+		Fatal("interfacefield: oops %v\n", n)
 	}
 
 	if n.Val.Ctype != CTxxx {
@@ -974,11 +973,11 @@
 					break
 
 				case TFORW:
-					Yyerror("interface type loop involving %v", Tconv(n.Type, 0))
+					Yyerror("interface type loop involving %v", n.Type)
 					f.Broke = 1
 
 				default:
-					Yyerror("interface contains embedded non-interface %v", Tconv(n.Type, 0))
+					Yyerror("interface contains embedded non-interface %v", n.Type)
 					f.Broke = 1
 				}
 			}
@@ -1301,7 +1300,7 @@
 	return s
 
 bad:
-	Yyerror("illegal receiver type: %v", Tconv(t0, 0))
+	Yyerror("illegal receiver type: %v", t0)
 	return nil
 }
 
@@ -1326,9 +1325,9 @@
 
 	var p string
 	if star != "" {
-		p = fmt.Sprintf("(%s%v).%v", star, Sconv(t.Sym, 0), Sconv(n.Sym, 0))
+		p = fmt.Sprintf("(%s%v).%v", star, t.Sym, n.Sym)
 	} else {
-		p = fmt.Sprintf("%v.%v", Sconv(t.Sym, 0), Sconv(n.Sym, 0))
+		p = fmt.Sprintf("%v.%v", t.Sym, n.Sym)
 	}
 
 	if exportname(t.Sym.Name) {
@@ -1367,7 +1366,7 @@
 		if t != nil {
 			if Isptr[t.Etype] {
 				if t.Sym != nil {
-					Yyerror("invalid receiver type %v (%v is a pointer type)", Tconv(pa, 0), Tconv(t, 0))
+					Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
 					return
 				}
 
@@ -1378,24 +1377,24 @@
 				return
 			}
 			if t.Sym == nil {
-				Yyerror("invalid receiver type %v (%v is an unnamed type)", Tconv(pa, 0), Tconv(t, 0))
+				Yyerror("invalid receiver type %v (%v is an unnamed type)", pa, t)
 				return
 			}
 
 			if Isptr[t.Etype] {
-				Yyerror("invalid receiver type %v (%v is a pointer type)", Tconv(pa, 0), Tconv(t, 0))
+				Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
 				return
 			}
 
 			if t.Etype == TINTER {
-				Yyerror("invalid receiver type %v (%v is an interface type)", Tconv(pa, 0), Tconv(t, 0))
+				Yyerror("invalid receiver type %v (%v is an interface type)", pa, t)
 				return
 			}
 		}
 
 		// Should have picked off all the reasons above,
 		// but just in case, fall back to generic error.
-		Yyerror("invalid receiver type %v (%v / %v)", Tconv(pa, 0), Tconv(pa, obj.FmtLong), Tconv(t, obj.FmtLong))
+		Yyerror("invalid receiver type %v (%v / %v)", pa, Tconv(pa, obj.FmtLong), Tconv(t, obj.FmtLong))
 
 		return
 	}
@@ -1404,7 +1403,7 @@
 	if pa.Etype == TSTRUCT {
 		for f := pa.Type; f != nil; f = f.Down {
 			if f.Sym == sf {
-				Yyerror("type %v has both field and method named %v", Tconv(pa, 0), Sconv(sf, 0))
+				Yyerror("type %v has both field and method named %v", pa, sf)
 				return
 			}
 		}
@@ -1412,7 +1411,7 @@
 
 	if local && !pa.Local {
 		// defining method on non-local type.
-		Yyerror("cannot define new methods on non-local type %v", Tconv(pa, 0))
+		Yyerror("cannot define new methods on non-local type %v", pa)
 
 		return
 	}
@@ -1430,7 +1429,7 @@
 			continue
 		}
 		if !Eqtype(t, f.Type) {
-			Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", Tconv(pa, 0), Sconv(sf, 0), Tconv(f.Type, 0), Tconv(t, 0))
+			Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", pa, sf, f.Type, t)
 		}
 		return
 	}
@@ -1466,7 +1465,7 @@
 	checkwidth(n.Type)
 
 	if Curfn != nil {
-		Fatal("funccompile %v inside %v", Sconv(n.Nname.Sym, 0), Sconv(Curfn.Nname.Sym, 0))
+		Fatal("funccompile %v inside %v", n.Nname.Sym, Curfn.Nname.Sym)
 	}
 
 	Stksize = 0
diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/internal/gc/esc.go
index bcd3a83..c816fea 100644
--- a/src/cmd/internal/gc/esc.go
+++ b/src/cmd/internal/gc/esc.go
@@ -205,6 +205,171 @@
 	EscFuncTagged
 )
 
+// There appear to be some loops in the escape graph, causing
+// arbitrary recursion into deeper and deeper levels.
+// Cut this off safely by making minLevel sticky: once you
+// get that deep, you cannot go down any further but you also
+// cannot go up any further. This is a conservative fix.
+// Making minLevel smaller (more negative) would handle more
+// complex chains of indirections followed by address-of operations,
+// at the cost of repeating the traversal once for each additional
+// allowed level when a loop is encountered. Using -2 suffices to
+// pass all the tests we have written so far, which we assume matches
+// the level of complexity we want the escape analysis code to handle.
+const (
+	MinLevel = -2
+)
+
+// A Level encodes the reference state and context applied to
+// (stack, heap) allocated memory.
+//
+// value is the overall sum of *(1) and &(-1) operations encountered
+// along a path from a destination (sink, return value) to a source
+// (allocation, parameter).
+//
+// suffixValue is the maximum-copy-started-suffix-level applied to a sink.
+// For example:
+// sink = x.left.left --> level=2, x is dereferenced twice and does not escape to sink.
+// sink = &Node{x} --> level=-1, x is accessible from sink via one "address of"
+// sink = &Node{&Node{x}} --> level=-2, x is accessible from sink via two "address of"
+// sink = &Node{&Node{x.left}} --> level=-1, but x is NOT accessible from sink because it was indirected and then copied.
+// (The copy operations are sometimes implicit in the source code; in this case,
+// value of x.left was copied into a field of a newly allocated Node)
+//
+// There's one of these for each Node, and the integer values
+// rarely exceed even what can be stored in 4 bits, never mind 8.
+type Level struct {
+	value, suffixValue int8
+}
+
+func (l Level) int() int {
+	return int(l.value)
+}
+
+func levelFrom(i int) Level {
+	if i <= MinLevel {
+		return Level{value: MinLevel}
+	}
+	return Level{value: int8(i)}
+}
+
+func satInc8(x int8) int8 {
+	if x == 127 {
+		return 127
+	}
+	return x + 1
+}
+
+func satAdd8(x, y int8) int8 {
+	z := x + y
+	if x^y < 0 || x^z >= 0 {
+		return z
+	}
+	if x < 0 {
+		return -128
+	}
+	return 127
+}
+
+func min8(a, b int8) int8 {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+func max8(a, b int8) int8 {
+	if a > b {
+		return a
+	}
+	return b
+}
+
+// inc returns the level l + 1, representing the effect of an indirect (*) operation.
+func (l Level) inc() Level {
+	if l.value <= MinLevel {
+		return Level{value: MinLevel}
+	}
+	return Level{value: satInc8(l.value), suffixValue: satInc8(l.suffixValue)}
+}
+
+// dec returns the level l - 1, representing the effect of an address-of (&) operation.
+func (l Level) dec() Level {
+	if l.value <= MinLevel {
+		return Level{value: MinLevel}
+	}
+	return Level{value: l.value - 1, suffixValue: l.suffixValue - 1}
+}
+
+// copy returns the level for a copy of a value with level l.
+func (l Level) copy() Level {
+	return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)}
+}
+
+func (l1 Level) min(l2 Level) Level {
+	return Level{
+		value:       min8(l1.value, l2.value),
+		suffixValue: min8(l1.suffixValue, l2.suffixValue)}
+}
+
+// guaranteedDereference returns the number of dereferences
+// applied to a pointer before addresses are taken/generated.
+// This is the maximum level computed from path suffixes starting
+// with copies where paths flow from destination to source.
+func (l Level) guaranteedDereference() int {
+	return int(l.suffixValue)
+}
+
+// Escape constants are numbered in order of increasing "escapiness"
+// to help make inferences be monotonic.  With the exception of
+// EscNever which is sticky, eX < eY means that eY is more exposed
+// than eX, and hence replaces it in a conservative analysis.
+const (
+	EscUnknown = iota
+	EscNone    // Does not escape to heap, result, or parameters.
+	EscReturn  // Is returned or reachable from returned.
+	EscScope   // Allocated in an inner loop scope, assigned to an outer loop scope,
+	// which allows the construction of non-escaping but arbitrarily large linked
+	// data structures (i.e., not eligible for allocation in a fixed-size stack frame).
+	EscHeap           // Reachable from the heap
+	EscNever          // By construction will not escape.
+	EscBits           = 3
+	EscMask           = (1 << EscBits) - 1
+	EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap
+	EscReturnBits     = EscBits + 1
+	// Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3
+)
+
+// escMax returns the maximum of an existing escape value
+// (and its additional parameter flow flags) and a new escape type.
+func escMax(e, etype uint16) uint16 {
+	if e&EscMask >= EscScope {
+		// normalize
+		if e&^EscMask != 0 {
+			Fatal("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask)
+		}
+	}
+	if e&EscMask > etype {
+		return e
+	}
+	if etype == EscNone || etype == EscReturn {
+		return (e &^ EscMask) | etype
+	}
+	return etype
+}
+
+// For each input parameter to a function, the escapeReturnEncoding describes
+// how the parameter may leak to the function's outputs.  This is currently the
+// "level" of the leak where level is 0 or larger (negative level means stored into
+// something whose address is returned -- but that implies stored into the heap,
+// hence EscHeap, which means that the details are not currently relevant. )
+const (
+	bitsPerOutputInTag = 3                                         // For each output, the number of bits for a tag
+	bitsMaskForTag     = uint16(1<<bitsPerOutputInTag) - 1         // The bit mask to extract a single tag.
+	outputsPerTag      = (16 - EscReturnBits) / bitsPerOutputInTag // The number of outputs that can be tagged.
+	maxEncodedLevel    = int(bitsMaskForTag - 1)                   // The largest level that can be stored in a tag.
+)
+
 type EscState struct {
 	// Fake node that all
 	//   - return values and output variables
@@ -213,13 +378,6 @@
 	// flow to.
 	theSink Node
 
-	// If an analyzed function is recorded to return
-	// pieces obtained via indirection from a parameter,
-	// and later there is a call f(x) to that function,
-	// we create a link funcParam <- x to record that fact.
-	// The funcParam node is handled specially in escflood.
-	funcParam Node
-
 	dsts      *NodeList // all dst nodes
 	loopdepth int       // for detecting nested loop scopes
 	pdepth    int       // for debug printing in recursions.
@@ -229,42 +387,6 @@
 	recursive bool      // recursive function or group of mutually recursive functions.
 }
 
-var tags [16]*string
-
-// mktag returns the string representation for an escape analysis tag.
-func mktag(mask int) *string {
-	switch mask & EscMask {
-	case EscNone, EscReturn:
-		break
-
-	default:
-		Fatal("escape mktag")
-	}
-
-	mask >>= EscBits
-
-	if mask < len(tags) && tags[mask] != nil {
-		return tags[mask]
-	}
-
-	s := fmt.Sprintf("esc:0x%x", mask)
-	if mask < len(tags) {
-		tags[mask] = &s
-	}
-	return &s
-}
-
-func parsetag(note *string) int {
-	if note == nil || !strings.HasPrefix(*note, "esc:") {
-		return EscUnknown
-	}
-	em := atoi((*note)[4:])
-	if em == 0 {
-		return EscNone
-	}
-	return EscReturn | em<<EscBits
-}
-
 func escAnalyze(all *NodeList, recursive bool) {
 	var es EscState
 	e := &es
@@ -275,12 +397,6 @@
 	e.theSink.Escloopdepth = -1
 	e.recursive = recursive
 
-	e.funcParam.Op = ONAME
-	e.funcParam.Orig = &e.funcParam
-	e.funcParam.Class = PAUTO
-	e.funcParam.Sym = Lookup(".param")
-	e.funcParam.Escloopdepth = 10000000
-
 	for l := all; l != nil; l = l.Next {
 		if l.N.Op == ODCLFUNC {
 			l.N.Esc = EscFuncPlanned
@@ -318,7 +434,7 @@
 				} else {
 					tmp = nil
 				}
-				Warnl(int(l.N.Lineno), "%v %v does not escape", Sconv(tmp, 0), Nconv(l.N, obj.FmtShort))
+				Warnl(int(l.N.Lineno), "%v %v does not escape", tmp, Nconv(l.N, obj.FmtShort))
 			}
 		}
 	}
@@ -328,7 +444,7 @@
 	//	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
 
 	if func_.Esc != 1 {
-		Fatal("repeat escfunc %v", Nconv(func_.Nname, 0))
+		Fatal("repeat escfunc %v", func_.Nname)
 	}
 	func_.Esc = EscFuncStarted
 
@@ -483,7 +599,7 @@
 		} else {
 			tmp = nil
 		}
-		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, Sconv(tmp, 0), Nconv(n, 0))
+		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, tmp, n)
 	}
 
 	switch n.Op {
@@ -496,11 +612,11 @@
 	case OLABEL:
 		if n.Left.Sym.Label == &nonlooping {
 			if Debug['m'] > 1 {
-				fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), Nconv(n, 0))
+				fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), n)
 			}
 		} else if n.Left.Sym.Label == &looping {
 			if Debug['m'] > 1 {
-				fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), Nconv(n, 0))
+				fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), n)
 			}
 			e.loopdepth++
 		}
@@ -537,7 +653,7 @@
 	// This assignment is a no-op for escape analysis,
 	// it does not store any new pointers into b that were not already there.
 	// However, without this special case b will escape, because we assign to OIND/ODOTPTR.
-	case OAS, OASOP:
+	case OAS, OASOP, OASWB:
 		if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference
 			(n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation
 			(n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference
@@ -560,7 +676,7 @@
 				} else {
 					tmp = nil
 				}
-				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", Sconv(tmp, 0), Nconv(n.Left, obj.FmtShort))
+				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", tmp, Nconv(n.Left, obj.FmtShort))
 			}
 
 			break
@@ -729,7 +845,6 @@
 		}
 		fallthrough
 
-		// fallthrough
 	case OMAKECHAN,
 		OMAKEMAP,
 		OMAKESLICE,
@@ -800,7 +915,10 @@
 		} else {
 			tmp = nil
 		}
-		fmt.Printf("%v:[%d] %v escassign: %v(%v) = %v(%v)\n", Ctxt.Line(int(lineno)), e.loopdepth, Sconv(tmp, 0), Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort))
+		fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
+			Ctxt.Line(int(lineno)), e.loopdepth, tmp,
+			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))
 	}
 
 	setlineno(dst)
@@ -874,13 +992,21 @@
 		OSTRARRAYBYTE,
 		OADDSTR,
 		ONEW,
-		OCLOSURE,
 		OCALLPART,
 		ORUNESTR,
 		OCONVIFACE:
 		escflows(e, dst, src)
 
-		// Flowing multiple returns to a single dst happens when
+	case OCLOSURE:
+		// OCLOSURE is lowered to OPTRLIT,
+		// insert OADDR to account for the additional indirection.
+		a := Nod(OADDR, src, nil)
+		a.Lineno = src.Lineno
+		a.Escloopdepth = src.Escloopdepth
+		a.Type = Ptrto(src.Type)
+		escflows(e, dst, a)
+
+	// Flowing multiple returns to a single dst happens when
 	// analyzing "go f(g())": here g() flows to sink (issue 4529).
 	case OCALLMETH, OCALLFUNC, OCALLINTER:
 		for ll := src.Escretval; ll != nil; ll = ll.Next {
@@ -895,7 +1021,6 @@
 		fallthrough
 
 		// Conversions, field access, slice all preserve the input value.
-	// fallthrough
 	case OCONV,
 		OCONVNOP,
 		ODOTMETH,
@@ -947,9 +1072,110 @@
 	lineno = int32(lno)
 }
 
-func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) int {
+// Common case for escapes is 16 bits 000000000xxxEEEE
+// where commonest cases for xxx encoding in-to-out pointer
+//  flow are 000, 001, 010, 011  and EEEE is computed Esc bits.
+// Note width of xxx depends on value of constant
+// bitsPerOutputInTag -- expect 2 or 3, so in practice the
+// tag cache array is 64 or 128 long.  Some entries will
+// never be populated.
+var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
+
+// mktag returns the string representation for an escape analysis tag.
+func mktag(mask int) *string {
+	switch mask & EscMask {
+	case EscNone, EscReturn:
+		break
+
+	default:
+		Fatal("escape mktag")
+	}
+
+	if mask < len(tags) && tags[mask] != "" {
+		return &tags[mask]
+	}
+
+	s := fmt.Sprintf("esc:0x%x", mask)
+	if mask < len(tags) {
+		tags[mask] = s
+	}
+	return &s
+}
+
+// parsetag decodes an escape analysis tag and returns the esc value.
+func parsetag(note *string) uint16 {
+	if note == nil || !strings.HasPrefix(*note, "esc:") {
+		return EscUnknown
+	}
+	em := uint16(atoi((*note)[4:]))
+	if em == 0 {
+		return EscNone
+	}
+	return em
+}
+
+// describeEscape returns a string describing the escape tag.
+// The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation
+// or a description of parameter flow, which takes the form of an optional "contentToHeap"
+// indicating that the content of this parameter is leaked to the heap, followed by a sequence
+// of level encodings separated by spaces, one for each parameter, where _ means no flow,
+// = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow.
+// e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences)
+// escapes to the heap, the parameter does not leak to the first output, but does leak directly
+// to the second output (and if there are more than two outputs, there is no flow to those.)
+func describeEscape(em uint16) string {
+	var s string
+	if em&EscMask == EscUnknown {
+		s = "EscUnknown"
+	}
+	if em&EscMask == EscNone {
+		s = "EscNone"
+	}
+	if em&EscMask == EscHeap {
+		s = "EscHeap"
+	}
+	if em&EscMask == EscReturn {
+		s = "EscReturn"
+	}
+	if em&EscMask == EscScope {
+		s = "EscScope"
+	}
+	if em&EscContentEscapes != 0 {
+		if s != "" {
+			s += " "
+		}
+		s += "contentToHeap"
+	}
+	for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag {
+		// See encoding description above
+		if s != "" {
+			s += " "
+		}
+		switch embits := em & bitsMaskForTag; embits {
+		case 0:
+			s += "_"
+		case 1:
+			s += "="
+		default:
+			for i := uint16(0); i < embits-1; i++ {
+				s += "*"
+			}
+		}
+
+	}
+	return s
+}
+
+// escassignfromtag models the input-to-output assignment flow of one of a function
+// calls arguments, where the flow is encoded in "note".
+func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 {
 	em := parsetag(note)
 
+	if Debug['m'] > 2 {
+		fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n",
+			Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em))
+	}
+
 	if em == EscUnknown {
 		escassign(e, &e.theSink, src)
 		return em
@@ -960,17 +1186,30 @@
 	}
 
 	// If content inside parameter (reached via indirection)
-	// escapes back to results, mark as such.
+	// escapes to heap, mark as such.
 	if em&EscContentEscapes != 0 {
-		escassign(e, &e.funcParam, src)
+		escassign(e, &e.theSink, addDereference(src))
 	}
 
 	em0 := em
-	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>1, dsts.Next {
-		if em&1 != 0 {
-			escassign(e, dsts.N, src)
+	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next {
+		// Prefer the lowest-level path to the reference (for escape purposes).
+		// Two-bit encoding (for example. 1, 3, and 4 bits are other options)
+		//  01 = 0-level
+		//  10 = 1-level, (content escapes),
+		//  11 = 2-level, (content of content escapes),
+		embits := em & bitsMaskForTag
+		if embits > 0 {
+			n := src
+			for i := uint16(0); i < embits-1; i++ {
+				n = addDereference(n) // encode level>0 as indirections
+			}
+			escassign(e, dsts.N, n)
 		}
 	}
+	// If there are too many outputs to fit in the tag,
+	// that is handled at the encoding end as EscHeap,
+	// so there is no need to check here.
 
 	if em != 0 && dsts == nil {
 		Fatal("corrupt esc tag %q or messed up escretval list\n", note)
@@ -978,6 +1217,58 @@
 	return em0
 }
 
+// addDereference constructs a suitable OIND note applied to src.
+// Because this is for purposes of escape accounting, not execution,
+// some semantically dubious node combinations are (currently) possible.
+func addDereference(n *Node) *Node {
+	ind := Nod(OIND, n, nil)
+	ind.Escloopdepth = n.Escloopdepth
+	ind.Lineno = n.Lineno
+	t := n.Type
+	if Istype(t, Tptr) {
+		// This should model our own sloppy use of OIND to encode
+		// decreasing levels of indirection; i.e., "indirecting" an array
+		// might yield the type of an element.  To be enhanced...
+		t = t.Type
+	}
+	ind.Type = t
+	return ind
+}
+
+// escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter.
+// Levels greater than maxEncodedLevel are replaced with maxEncodedLevel.
+// If the encoding cannot describe the modified input level and output number, then EscHeap is returned.
+func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
+	// Flow+level is encoded in two bits.
+	// 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel
+	// 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful.
+	if level.int() <= 0 && level.guaranteedDereference() > 0 {
+		return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content.
+	}
+	if level.int() < 0 {
+		return EscHeap
+	}
+	if level.int() > maxEncodedLevel {
+		// Cannot encode larger values than maxEncodedLevel.
+		level = levelFrom(maxEncodedLevel)
+	}
+	encoded := uint16(level.int() + 1)
+
+	shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits)
+	old := (e >> shift) & bitsMaskForTag
+	if old == 0 || encoded != 0 && encoded < old {
+		old = encoded
+	}
+
+	encodedFlow := old << shift
+	if (encodedFlow>>shift)&bitsMaskForTag != old {
+		// Encoding failure defaults to heap.
+		return EscHeap
+	}
+
+	return (e &^ (bitsMaskForTag << shift)) | encodedFlow
+}
+
 // 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
@@ -1016,7 +1307,12 @@
 		}
 	}
 
-	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Defn != nil && fn.Defn.Nbody != nil && fn.Ntype != nil && fn.Defn.Esc < EscFuncTagged {
+	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
+		fn.Defn != nil && fn.Defn.Nbody != nil && fn.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))
+		}
+
 		// function in same mutually recursive group.  Incorporate into flow graph.
 		//		print("esc local fn: %N\n", fn->ntype);
 		if fn.Defn.Esc == EscFuncUnknown || n.Escretval != nil {
@@ -1061,6 +1357,9 @@
 
 		// "..." arguments are untracked
 		for ; ll != nil; ll = ll.Next {
+			if Debug['m'] > 2 {
+				fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+			}
 			escassign(e, &e.theSink, ll.N)
 		}
 
@@ -1072,6 +1371,10 @@
 		Fatal("esc already decorated call %v\n", Nconv(n, obj.FmtSign))
 	}
 
+	if Debug['m'] > 2 {
+		fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
+	}
+
 	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
 	i := 0
 
@@ -1079,7 +1382,7 @@
 	var buf string
 	for t := getoutargx(fntype).Type; t != nil; t = t.Down {
 		src = Nod(ONAME, nil, nil)
-		buf = fmt.Sprintf(".dum%d", i)
+		buf = fmt.Sprintf(".out%d", i)
 		i++
 		src.Sym = Lookup(buf)
 		src.Type = t.Type
@@ -1156,10 +1459,14 @@
 	// "..." arguments are untracked
 	for ; ll != nil; ll = ll.Next {
 		escassign(e, &e.theSink, ll.N)
+		if Debug['m'] > 2 {
+			fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+		}
 	}
 }
 
-// Store the link src->dst in dst, throwing out some quick wins.
+// escflows records the link src->dst in dst, throwing out some quick wins,
+// and also ensuring that dst is noted as a flow destination.
 func escflows(e *EscState, dst *Node, src *Node) {
 	if dst == nil || src == nil || dst == src {
 		return
@@ -1209,36 +1516,36 @@
 		} else {
 			tmp = nil
 		}
-		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), Sconv(tmp, 0), dst.Escloopdepth)
+		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), tmp, dst.Escloopdepth)
 	}
 
 	for l := dst.Escflowsrc; l != nil; l = l.Next {
 		walkgen++
-		escwalk(e, 0, dst, l.N)
+		escwalk(e, levelFrom(0), dst, l.N)
 	}
 }
 
-// There appear to be some loops in the escape graph, causing
-// arbitrary recursion into deeper and deeper levels.
-// Cut this off safely by making minLevel sticky: once you
-// get that deep, you cannot go down any further but you also
-// cannot go up any further. This is a conservative fix.
-// Making minLevel smaller (more negative) would handle more
-// complex chains of indirections followed by address-of operations,
-// at the cost of repeating the traversal once for each additional
-// allowed level when a loop is encountered. Using -2 suffices to
-// pass all the tests we have written so far, which we assume matches
-// the level of complexity we want the escape analysis code to handle.
-const (
-	MinLevel = -2
-)
+// funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function.
+func funcOutputAndInput(dst, src *Node) bool {
+	// Note if dst is marked as escaping, then "returned" is too weak.
+	return dst.Op == ONAME && dst.Class == PPARAMOUT &&
+		src.Op == ONAME && src.Class == PPARAM && src.Curfn == dst.Curfn
+}
 
-func escwalk(e *EscState, level int, dst *Node, src *Node) {
-	if src.Walkgen == walkgen && src.Esclevel <= int32(level) {
-		return
+func escwalk(e *EscState, level Level, dst *Node, src *Node) {
+
+	if src.Walkgen == walkgen {
+		// Esclevels are vectors, do not compare as integers,
+		// and must use "min" of old and new to guarantee
+		// convergence.
+		level = level.min(src.Esclevel)
+		if level == src.Esclevel {
+			return
+		}
 	}
+
 	src.Walkgen = walkgen
-	src.Esclevel = int32(level)
+	src.Esclevel = level
 
 	if Debug['m'] > 1 {
 		var tmp *Sym
@@ -1247,48 +1554,70 @@
 		} else {
 			tmp = nil
 		}
-		fmt.Printf("escwalk: level:%d depth:%d %.*s %v(%v) scope:%v[%d]\n", level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Sconv(tmp, 0), src.Escloopdepth)
+		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)
 	}
 
 	e.pdepth++
 
 	// Input parameter flowing to output parameter?
 	var leaks bool
-	if dst.Op == ONAME && dst.Class == PPARAMOUT && dst.Vargen <= 20 {
-		if src.Op == ONAME && src.Class == PPARAM && src.Curfn == dst.Curfn && src.Esc != EscScope && src.Esc != EscHeap {
-			if level == 0 {
-				if Debug['m'] != 0 {
-					Warnl(int(src.Lineno), "leaking param: %v to result %v", Nconv(src, obj.FmtShort), Sconv(dst.Sym, 0))
-				}
-				if src.Esc&EscMask != EscReturn {
-					src.Esc = EscReturn
-				}
-				src.Esc |= 1 << uint((dst.Vargen-1)+EscReturnBits)
-				goto recurse
-			} else if level > 0 {
-				if Debug['m'] != 0 {
-					Warnl(int(src.Lineno), "%v leaking param %v content to result %v", Nconv(src.Curfn.Nname, 0), Nconv(src, obj.FmtShort), Sconv(dst.Sym, 0))
-				}
-				if src.Esc&EscMask != EscReturn {
-					src.Esc = EscReturn
-				}
-				src.Esc |= EscContentEscapes
-				goto recurse
+	if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap {
+		// This case handles:
+		// 1. return in
+		// 2. return &in
+		// 3. tmp := in; return &tmp
+		// 4. return *in
+		if Debug['m'] != 0 {
+			if Debug['m'] == 1 {
+				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int())
+			} else {
+				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level)
 			}
 		}
+		if src.Esc&EscMask != EscReturn {
+			src.Esc = EscReturn | src.Esc&EscContentEscapes
+		}
+		src.Esc = escNoteOutputParamFlow(src.Esc, dst.Vargen, level)
+		goto recurse
+	}
+
+	// If parameter content escapes to heap, set EscContentEscapes
+	// Note minor confusion around escape from pointer-to-struct vs escape from struct
+	if dst.Esc == EscHeap &&
+		src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope &&
+		level.int() > 0 {
+		src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
+		if Debug['m'] != 0 {
+			Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort))
+		}
 	}
 
-	// The second clause is for values pointed at by an object passed to a call
-	// that returns something reached via indirect from the object.
-	// We don't know which result it is or how many indirects, so we treat it as leaking.
-	leaks = level <= 0 && dst.Escloopdepth < src.Escloopdepth || level < 0 && dst == &e.funcParam && haspointers(src.Type)
+	leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dst.Escloopdepth < src.Escloopdepth
 
 	switch src.Op {
 	case ONAME:
-		if src.Class == PPARAM && (leaks || dst.Escloopdepth < 0) && src.Esc != EscHeap {
-			src.Esc = EscScope
-			if Debug['m'] != 0 {
-				Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort))
+		if src.Class == PPARAM && (leaks || dst.Escloopdepth < 0) && src.Esc&EscMask < EscScope {
+			if level.guaranteedDereference() > 0 {
+				src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
+				if Debug['m'] != 0 {
+					if Debug['m'] == 1 {
+						Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort))
+					} else {
+						Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v",
+							Nconv(src, obj.FmtShort), level, dst.Escloopdepth, src.Escloopdepth, Nconv(dst, obj.FmtShort))
+					}
+				}
+			} else {
+				src.Esc = EscScope
+				if Debug['m'] != 0 {
+					if Debug['m'] == 1 {
+						Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort))
+					} else {
+						Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v",
+							Nconv(src, obj.FmtShort), level, dst.Escloopdepth, src.Escloopdepth, Nconv(dst, obj.FmtShort))
+					}
+				}
 			}
 		}
 
@@ -1306,15 +1635,23 @@
 			src.Esc = EscHeap
 			addrescapes(src.Left)
 			if Debug['m'] != 0 {
-				Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort))
+				p := src
+				if p.Left.Op == OCLOSURE {
+					p = p.Left // merely to satisfy error messages in tests
+				}
+				if Debug['m'] > 1 {
+					Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v",
+						Nconv(p, obj.FmtShort), level, dst.Escloopdepth, src.Escloopdepth)
+				} else {
+					Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort))
+				}
 			}
 		}
 
-		newlevel := level
-		if level > MinLevel {
-			newlevel--
-		}
-		escwalk(e, newlevel, dst, src.Left)
+		escwalk(e, level.dec(), dst, src.Left)
+
+	case OAPPEND:
+		escwalk(e, level, dst, src.List.N)
 
 	case OARRAYLIT:
 		if Isfixedarray(src.Type) {
@@ -1322,7 +1659,6 @@
 		}
 		fallthrough
 
-		// fall through
 	case ODDDARG,
 		OMAKECHAN,
 		OMAKEMAP,
@@ -1360,17 +1696,27 @@
 		}
 		fallthrough
 
-		// fall through
 	case ODOTPTR, OINDEXMAP, OIND:
-		newlevel := level
+		escwalk(e, level.inc(), dst, src.Left)
 
-		if level > MinLevel {
-			newlevel++
+	// In this case a link went directly to a call, but should really go
+	// to the dummy .outN outputs that were created for the call that
+	// themselves link to the inputs with levels adjusted.
+	// See e.g. #10466
+	// This can only happen with functions returning a single result.
+	case OCALLMETH, OCALLFUNC, OCALLINTER:
+		if src.Escretval != nil {
+			if Debug['m'] > 1 {
+				fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n",
+					Ctxt.Line(int(lineno)), e.loopdepth,
+					Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(src.Escretval.N, obj.FmtShort))
+			}
+			src = src.Escretval.N
 		}
-		escwalk(e, newlevel, dst, src.Left)
 	}
 
 recurse:
+	level = level.copy()
 	for ll := src.Escflowsrc; ll != nil; ll = ll.Next {
 		escwalk(e, level, dst, ll.N)
 	}
@@ -1399,7 +1745,7 @@
 	Curfn = func_
 
 	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-		if ll.N.Op != ONAME || ll.N.Class != PPARAM {
+		if ll.N.Op != ONAME {
 			continue
 		}
 
diff --git a/src/cmd/internal/gc/export.go b/src/cmd/internal/gc/export.go
index f950889..1efc815 100644
--- a/src/cmd/internal/gc/export.go
+++ b/src/cmd/internal/gc/export.go
@@ -21,7 +21,7 @@
 	}
 	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
 		if n.Sym.Flags&SymPackage != 0 {
-			Yyerror("export/package mismatch: %v", Sconv(n.Sym, 0))
+			Yyerror("export/package mismatch: %v", n.Sym)
 		}
 		return
 	}
@@ -29,7 +29,7 @@
 	n.Sym.Flags |= SymExport
 
 	if Debug['E'] != 0 {
-		fmt.Printf("export symbol %v\n", Sconv(n.Sym, 0))
+		fmt.Printf("export symbol %v\n", n.Sym)
 	}
 	exportlist = list(exportlist, n)
 }
@@ -57,7 +57,7 @@
 	return sym.Pkg == localpkg && exportname(sym.Name)
 }
 
-func autoexport(n *Node, ctxt int) {
+func autoexport(n *Node, ctxt uint8) {
 	if n == nil || n.Sym == nil {
 		return
 	}
@@ -119,11 +119,10 @@
 			}
 			fallthrough
 
-			// fallthrough
 		case PEXTERN:
 			if n.Sym != nil && !exportedsym(n.Sym) {
 				if Debug['E'] != 0 {
-					fmt.Printf("reexport name %v\n", Sconv(n.Sym, 0))
+					fmt.Printf("reexport name %v\n", n.Sym)
 				}
 				exportlist = list(exportlist, n)
 			}
@@ -139,7 +138,7 @@
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 				if Debug['E'] != 0 {
-					fmt.Printf("reexport type %v from declaration\n", Sconv(t.Sym, 0))
+					fmt.Printf("reexport type %v from declaration\n", t.Sym)
 				}
 				exportlist = list(exportlist, t.Sym.Def)
 			}
@@ -153,18 +152,17 @@
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 				if Debug['E'] != 0 {
-					fmt.Printf("reexport literal type %v\n", Sconv(t.Sym, 0))
+					fmt.Printf("reexport literal type %v\n", t.Sym)
 				}
 				exportlist = list(exportlist, t.Sym.Def)
 			}
 		}
 		fallthrough
 
-		// fallthrough
 	case OTYPE:
 		if n.Sym != nil && !exportedsym(n.Sym) {
 			if Debug['E'] != 0 {
-				fmt.Printf("reexport literal/type %v\n", Sconv(n.Sym, 0))
+				fmt.Printf("reexport literal/type %v\n", n.Sym)
 			}
 			exportlist = list(exportlist, n)
 		}
@@ -193,7 +191,7 @@
 		}
 		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 			if Debug['E'] != 0 {
-				fmt.Printf("reexport type for expression %v\n", Sconv(t.Sym, 0))
+				fmt.Printf("reexport type for expression %v\n", t.Sym)
 			}
 			exportlist = list(exportlist, t.Sym.Def)
 		}
@@ -214,7 +212,7 @@
 	n := s.Def
 	typecheck(&n, Erv)
 	if n == nil || n.Op != OLITERAL {
-		Fatal("dumpexportconst: oconst nil: %v", Sconv(s, 0))
+		Fatal("dumpexportconst: oconst nil: %v", s)
 	}
 
 	t := n.Type // may or may not be specified
@@ -231,7 +229,7 @@
 	n := s.Def
 	typecheck(&n, Erv|Ecall)
 	if n == nil || n.Type == nil {
-		Yyerror("variable exported but not defined: %v", Sconv(s, 0))
+		Yyerror("variable exported but not defined: %v", s)
 		return
 	}
 
@@ -337,7 +335,7 @@
 	s.Flags |= SymExported
 
 	if s.Def == nil {
-		Yyerror("unknown export symbol: %v", Sconv(s, 0))
+		Yyerror("unknown export symbol: %v", s)
 		return
 	}
 
@@ -346,14 +344,14 @@
 
 	switch s.Def.Op {
 	default:
-		Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), Sconv(s, 0))
+		Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), s)
 
 	case OLITERAL:
 		dumpexportconst(s)
 
 	case OTYPE:
 		if s.Def.Type.Etype == TFORW {
-			Yyerror("export of incomplete type %v", Sconv(s, 0))
+			Yyerror("export of incomplete type %v", s)
 		} else {
 			dumpexporttype(s.Def.Type)
 		}
@@ -424,7 +422,7 @@
 	}
 
 	if s.Def.Type == nil {
-		Yyerror("pkgtype %v", Sconv(s, 0))
+		Yyerror("pkgtype %v", s)
 	}
 	return s.Def.Type
 }
@@ -477,7 +475,7 @@
 	declare(n, PEXTERN)
 
 	if Debug['E'] != 0 {
-		fmt.Printf("import const %v\n", Sconv(s, 0))
+		fmt.Printf("import const %v\n", s)
 	}
 }
 
@@ -487,7 +485,7 @@
 		if Eqtype(t, s.Def.Type) {
 			return
 		}
-		Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", Sconv(s, 0), Tconv(s.Def.Type, 0), s.Importdef.Path, Tconv(t, 0), importpkg.Path)
+		Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
 	}
 
 	n := newname(s)
@@ -496,7 +494,7 @@
 	declare(n, PEXTERN)
 
 	if Debug['E'] != 0 {
-		fmt.Printf("import var %v %v\n", Sconv(s, 0), Tconv(t, obj.FmtLong))
+		fmt.Printf("import var %v %v\n", s, Tconv(t, obj.FmtLong))
 	}
 }
 
@@ -517,11 +515,11 @@
 		declare(n, PEXTERN)
 		checkwidth(pt)
 	} else if !Eqtype(pt.Orig, t) {
-		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", Sconv(pt.Sym, 0), Tconv(pt, obj.FmtLong), pt.Sym.Importdef.Path, Tconv(t, obj.FmtLong), importpkg.Path)
+		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, obj.FmtLong), pt.Sym.Importdef.Path, Tconv(t, obj.FmtLong), importpkg.Path)
 	}
 
 	if Debug['E'] != 0 {
-		fmt.Printf("import type %v %v\n", Tconv(pt, 0), Tconv(t, obj.FmtLong))
+		fmt.Printf("import type %v %v\n", pt, Tconv(t, obj.FmtLong))
 	}
 }
 
diff --git a/src/cmd/internal/gc/fmt.go b/src/cmd/internal/gc/fmt.go
index e5b9e56..1a991a0 100644
--- a/src/cmd/internal/gc/fmt.go
+++ b/src/cmd/internal/gc/fmt.go
@@ -168,7 +168,7 @@
 
 // Fmt "%O":  Node opcodes
 func Oconv(o int, flag int) string {
-	if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode != FDbg {
+	if (flag&obj.FmtSharp != 0) || fmtmode != FDbg {
 		if o >= 0 && o < len(goopnames) && goopnames[o] != "" {
 			return goopnames[o]
 		}
@@ -201,8 +201,8 @@
 		fmt.Fprintf(&buf, " u(%d)", n.Ullman)
 	}
 
-	if c == 0 && n.Addable != 0 {
-		fmt.Fprintf(&buf, " a(%d)", n.Addable)
+	if c == 0 && n.Addable {
+		fmt.Fprintf(&buf, " a(%v)", n.Addable)
 	}
 
 	if c == 0 && n.Vargen != 0 {
@@ -229,8 +229,8 @@
 		}
 	}
 
-	if n.Colas != 0 {
-		fmt.Fprintf(&buf, " colas(%d)", n.Colas)
+	if n.Colas {
+		fmt.Fprintf(&buf, " colas(%v)", n.Colas)
 	}
 
 	if n.Funcdepth != 0 {
@@ -301,7 +301,7 @@
 func Vconv(v *Val, flag int) string {
 	switch v.Ctype {
 	case CTINT:
-		if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
+		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
 			return Bconv(v.U.Xval, obj.FmtSharp)
 		}
 		return Bconv(v.U.Xval, 0)
@@ -317,17 +317,17 @@
 		if 0 <= x && x <= utf8.MaxRune {
 			return fmt.Sprintf("'\\U%08x'", uint64(x))
 		}
-		return fmt.Sprintf("('\\x00' + %v)", Bconv(v.U.Xval, 0))
+		return fmt.Sprintf("('\\x00' + %v)", v.U.Xval)
 
 	case CTFLT:
-		if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
+		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
 			return Fconv(v.U.Fval, 0)
 		}
 		return Fconv(v.U.Fval, obj.FmtSharp)
 
 	case CTCPLX:
-		if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
-			return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, 0), Fconv(&v.U.Cval.Imag, 0))
+		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
+			return fmt.Sprintf("(%v+%vi)", &v.U.Cval.Real, &v.U.Cval.Imag)
 		}
 		if mpcmpfltc(&v.U.Cval.Real, 0) == 0 {
 			return fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp))
@@ -344,7 +344,7 @@
 		return strconv.Quote(v.U.Sval)
 
 	case CTBOOL:
-		if v.U.Bval != 0 {
+		if v.U.Bval {
 			return "true"
 		}
 		return "false"
@@ -406,7 +406,7 @@
 
 // Fmt "%S": syms
 func symfmt(s *Sym, flag int) string {
-	if s.Pkg != nil && flag&obj.FmtShort == 0 /*untyped*/ {
+	if s.Pkg != nil && flag&obj.FmtShort == 0 {
 		switch fmtmode {
 		case FErr: // This is for the user
 			if s.Pkg == localpkg {
@@ -438,7 +438,7 @@
 		}
 	}
 
-	if flag&obj.FmtByte != 0 /*untyped*/ {
+	if flag&obj.FmtByte != 0 {
 		// FmtByte (hh) implies FmtShort (h)
 		// skip leading "type." in method name
 		p := s.Name
@@ -499,25 +499,24 @@
 	}
 
 	// Unless the 'l' flag was specified, if the type has a name, just print that name.
-	if flag&obj.FmtLong == 0 /*untyped*/ && t.Sym != nil && t.Etype != TFIELD && t != Types[t.Etype] {
+	if flag&obj.FmtLong == 0 && t.Sym != nil && t.Etype != TFIELD && t != Types[t.Etype] {
 		switch fmtmode {
 		case FTypeId:
-			if flag&obj.FmtShort != 0 /*untyped*/ {
+			if flag&obj.FmtShort != 0 {
 				if t.Vargen != 0 {
 					return fmt.Sprintf("%v·%d", Sconv(t.Sym, obj.FmtShort), t.Vargen)
 				}
 				return Sconv(t.Sym, obj.FmtShort)
 			}
 
-			if flag&obj.FmtUnsigned != 0 /*untyped*/ {
+			if flag&obj.FmtUnsigned != 0 {
 				return Sconv(t.Sym, obj.FmtUnsigned)
 			}
 			fallthrough
 
-			// fallthrough
 		case FExp:
 			if t.Sym.Pkg == localpkg && t.Vargen != 0 {
-				return fmt.Sprintf("%v·%d", Sconv(t.Sym, 0), t.Vargen)
+				return fmt.Sprintf("%v·%d", t.Sym, t.Vargen)
 			}
 		}
 
@@ -541,36 +540,36 @@
 
 	switch t.Etype {
 	case TPTR32, TPTR64:
-		if fmtmode == FTypeId && (flag&obj.FmtShort != 0 /*untyped*/) {
+		if fmtmode == FTypeId && (flag&obj.FmtShort != 0) {
 			return fmt.Sprintf("*%v", Tconv(t.Type, obj.FmtShort))
 		}
-		return fmt.Sprintf("*%v", Tconv(t.Type, 0))
+		return fmt.Sprintf("*%v", t.Type)
 
 	case TARRAY:
 		if t.Bound >= 0 {
-			return fmt.Sprintf("[%d]%v", t.Bound, Tconv(t.Type, 0))
+			return fmt.Sprintf("[%d]%v", t.Bound, t.Type)
 		}
 		if t.Bound == -100 {
-			return fmt.Sprintf("[...]%v", Tconv(t.Type, 0))
+			return fmt.Sprintf("[...]%v", t.Type)
 		}
-		return fmt.Sprintf("[]%v", Tconv(t.Type, 0))
+		return fmt.Sprintf("[]%v", t.Type)
 
 	case TCHAN:
 		switch t.Chan {
 		case Crecv:
-			return fmt.Sprintf("<-chan %v", Tconv(t.Type, 0))
+			return fmt.Sprintf("<-chan %v", t.Type)
 
 		case Csend:
-			return fmt.Sprintf("chan<- %v", Tconv(t.Type, 0))
+			return fmt.Sprintf("chan<- %v", t.Type)
 		}
 
 		if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
-			return fmt.Sprintf("chan (%v)", Tconv(t.Type, 0))
+			return fmt.Sprintf("chan (%v)", t.Type)
 		}
-		return fmt.Sprintf("chan %v", Tconv(t.Type, 0))
+		return fmt.Sprintf("chan %v", t.Type)
 
 	case TMAP:
-		return fmt.Sprintf("map[%v]%v", Tconv(t.Down, 0), Tconv(t.Type, 0))
+		return fmt.Sprintf("map[%v]%v", t.Down, t.Type)
 
 	case TINTER:
 		var buf bytes.Buffer
@@ -630,15 +629,15 @@
 			// Format the bucket struct for map[x]y as map.bucket[x]y.
 			// This avoids a recursive print that generates very long names.
 			if t.Map.Bucket == t {
-				return fmt.Sprintf("map.bucket[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
+				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type)
 			}
 
 			if t.Map.Hmap == t {
-				return fmt.Sprintf("map.hdr[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
+				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
 			}
 
 			if t.Map.Hiter == t {
-				return fmt.Sprintf("map.iter[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
+				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
 			}
 
 			Yyerror("unknown internal map type")
@@ -681,7 +680,7 @@
 
 	case TFIELD:
 		var name string
-		if flag&obj.FmtShort == 0 /*untyped*/ {
+		if flag&obj.FmtShort == 0 {
 			s := t.Sym
 
 			// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
@@ -741,7 +740,7 @@
 
 	case TFORW:
 		if t.Sym != nil {
-			return fmt.Sprintf("undefined %v", Sconv(t.Sym, 0))
+			return fmt.Sprintf("undefined %v", t.Sym)
 		}
 		return "undefined"
 
@@ -757,7 +756,7 @@
 	}
 
 	// Don't know how to handle - fall back to detailed prints.
-	return fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), Sconv(t.Sym, 0), Tconv(t.Type, 0))
+	return fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), t.Sym, t.Type)
 }
 
 // Statements which may be rendered with a simplestmt as init.
@@ -792,7 +791,7 @@
 	}
 
 	if complexinit {
-		f += fmt.Sprintf(" %v; ", Hconv(n.Ninit, 0))
+		f += fmt.Sprintf(" %v; ", n.Ninit)
 	}
 
 	switch n.Op {
@@ -800,16 +799,16 @@
 		if fmtmode == FExp {
 			switch n.Left.Class &^ PHEAP {
 			case PPARAM, PPARAMOUT, PAUTO:
-				f += fmt.Sprintf("var %v %v", Nconv(n.Left, 0), Tconv(n.Left.Type, 0))
+				f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
 				goto ret
 			}
 		}
 
-		f += fmt.Sprintf("var %v %v", Sconv(n.Left.Sym, 0), Tconv(n.Left.Type, 0))
+		f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type)
 
 	case ODCLFIELD:
 		if n.Left != nil {
-			f += fmt.Sprintf("%v %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
+			f += fmt.Sprintf("%v %v", n.Left, n.Right)
 		} else {
 			f += Nconv(n.Right, 0)
 		}
@@ -817,37 +816,36 @@
 		// Don't export "v = <N>" initializing statements, hope they're always
 	// preceded by the DCL which will be re-parsed and typecheck to reproduce
 	// the "v = <N>" again.
-	case OAS:
+	case OAS, OASWB:
 		if fmtmode == FExp && n.Right == nil {
 			break
 		}
 
-		if n.Colas != 0 && !complexinit {
-			f += fmt.Sprintf("%v := %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
+		if n.Colas && !complexinit {
+			f += fmt.Sprintf("%v := %v", n.Left, n.Right)
 		} else {
-			f += fmt.Sprintf("%v = %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
+			f += fmt.Sprintf("%v = %v", n.Left, n.Right)
 		}
 
 	case OASOP:
 		if n.Implicit {
 			if n.Etype == OADD {
-				f += fmt.Sprintf("%v++", Nconv(n.Left, 0))
+				f += fmt.Sprintf("%v++", n.Left)
 			} else {
-				f += fmt.Sprintf("%v--", Nconv(n.Left, 0))
+				f += fmt.Sprintf("%v--", n.Left)
 			}
 			break
 		}
 
-		f += fmt.Sprintf("%v %v= %v", Nconv(n.Left, 0), Oconv(int(n.Etype), obj.FmtSharp), Nconv(n.Right, 0))
+		f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(int(n.Etype), obj.FmtSharp), n.Right)
 
 	case OAS2:
-		if n.Colas != 0 && !complexinit {
+		if n.Colas && !complexinit {
 			f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
 			break
 		}
 		fallthrough
 
-		// fallthrough
 	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
 		f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
 
@@ -855,22 +853,22 @@
 		f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma))
 
 	case ORETJMP:
-		f += fmt.Sprintf("retjmp %v", Sconv(n.Sym, 0))
+		f += fmt.Sprintf("retjmp %v", n.Sym)
 
 	case OPROC:
-		f += fmt.Sprintf("go %v", Nconv(n.Left, 0))
+		f += fmt.Sprintf("go %v", n.Left)
 
 	case ODEFER:
-		f += fmt.Sprintf("defer %v", Nconv(n.Left, 0))
+		f += fmt.Sprintf("defer %v", n.Left)
 
 	case OIF:
 		if simpleinit {
-			f += fmt.Sprintf("if %v; %v { %v }", Nconv(n.Ninit.N, 0), Nconv(n.Ntest, 0), Hconv(n.Nbody, 0))
+			f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.N, n.Ntest, n.Nbody)
 		} else {
-			f += fmt.Sprintf("if %v { %v }", Nconv(n.Ntest, 0), Hconv(n.Nbody, 0))
+			f += fmt.Sprintf("if %v { %v }", n.Ntest, n.Nbody)
 		}
 		if n.Nelse != nil {
-			f += fmt.Sprintf(" else { %v }", Hconv(n.Nelse, 0))
+			f += fmt.Sprintf(" else { %v }", n.Nelse)
 		}
 
 	case OFOR:
@@ -881,22 +879,22 @@
 
 		f += "for"
 		if simpleinit {
-			f += fmt.Sprintf(" %v;", Nconv(n.Ninit.N, 0))
+			f += fmt.Sprintf(" %v;", n.Ninit.N)
 		} else if n.Nincr != nil {
 			f += " ;"
 		}
 
 		if n.Ntest != nil {
-			f += fmt.Sprintf(" %v", Nconv(n.Ntest, 0))
+			f += fmt.Sprintf(" %v", n.Ntest)
 		}
 
 		if n.Nincr != nil {
-			f += fmt.Sprintf("; %v", Nconv(n.Nincr, 0))
+			f += fmt.Sprintf("; %v", n.Nincr)
 		} else if simpleinit {
 			f += ";"
 		}
 
-		f += fmt.Sprintf(" { %v }", Hconv(n.Nbody, 0))
+		f += fmt.Sprintf(" { %v }", n.Nbody)
 
 	case ORANGE:
 		if fmtmode == FErr {
@@ -905,11 +903,11 @@
 		}
 
 		if n.List == nil {
-			f += fmt.Sprintf("for range %v { %v }", Nconv(n.Right, 0), Hconv(n.Nbody, 0))
+			f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody)
 			break
 		}
 
-		f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), Nconv(n.Right, 0), Hconv(n.Nbody, 0))
+		f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), n.Right, n.Nbody)
 
 	case OSELECT, OSWITCH:
 		if fmtmode == FErr {
@@ -919,19 +917,19 @@
 
 		f += Oconv(int(n.Op), obj.FmtSharp)
 		if simpleinit {
-			f += fmt.Sprintf(" %v;", Nconv(n.Ninit.N, 0))
+			f += fmt.Sprintf(" %v;", n.Ninit.N)
 		}
 		if n.Ntest != nil {
 			f += Nconv(n.Ntest, 0)
 		}
 
-		f += fmt.Sprintf(" { %v }", Hconv(n.List, 0))
+		f += fmt.Sprintf(" { %v }", n.List)
 
 	case OCASE, OXCASE:
 		if n.List != nil {
-			f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), Hconv(n.Nbody, 0))
+			f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), n.Nbody)
 		} else {
-			f += fmt.Sprintf("default: %v", Hconv(n.Nbody, 0))
+			f += fmt.Sprintf("default: %v", n.Nbody)
 		}
 
 	case OBREAK,
@@ -940,7 +938,7 @@
 		OFALL,
 		OXFALL:
 		if n.Left != nil {
-			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0))
+			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), n.Left)
 		} else {
 			f += Oconv(int(n.Op), obj.FmtSharp)
 		}
@@ -949,7 +947,7 @@
 		break
 
 	case OLABEL:
-		f += fmt.Sprintf("%v: ", Nconv(n.Left, 0))
+		f += fmt.Sprintf("%v: ", n.Left)
 	}
 
 ret:
@@ -976,6 +974,7 @@
 	OCONV:         8,
 	OCOPY:         8,
 	ODELETE:       8,
+	OGETG:         8,
 	OLEN:          8,
 	OLITERAL:      8,
 	OMAKESLICE:    8,
@@ -1088,18 +1087,18 @@
 	}
 
 	if prec > nprec {
-		return fmt.Sprintf("(%v)", Nconv(n, 0))
+		return fmt.Sprintf("(%v)", n)
 	}
 
 	switch n.Op {
 	case OPAREN:
-		return fmt.Sprintf("(%v)", Nconv(n.Left, 0))
+		return fmt.Sprintf("(%v)", n.Left)
 
 	case ODDDARG:
 		return "... argument"
 
 	case OREGISTER:
-		return obj.Rconv(int(n.Val.U.Reg))
+		return obj.Rconv(int(n.Reg))
 
 	case OLITERAL: // this is a bit of a mess
 		if fmtmode == FErr {
@@ -1117,9 +1116,9 @@
 			// Need parens when type begins with what might
 			// be misinterpreted as a unary operator: * or <-.
 			if Isptr[n.Type.Etype] || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
-				return fmt.Sprintf("(%v)(%v)", Tconv(n.Type, 0), Vconv(&n.Val, 0))
+				return fmt.Sprintf("(%v)(%v)", n.Type, Vconv(&n.Val, 0))
 			} else {
-				return fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Vconv(&n.Val, 0))
+				return fmt.Sprintf("%v(%v)", n.Type, Vconv(&n.Val, 0))
 			}
 		}
 
@@ -1132,7 +1131,7 @@
 			return "_"
 		}
 		if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Vargen > 0 {
-			return fmt.Sprintf("%v·%d", Sconv(n.Sym, 0), n.Vargen)
+			return fmt.Sprintf("%v·%d", n.Sym, n.Vargen)
 		}
 
 		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
@@ -1140,9 +1139,9 @@
 		// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
 		if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
 			if Isptr[n.Left.Type.Etype] {
-				return fmt.Sprintf("(%v).%v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
+				return fmt.Sprintf("(%v).%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
 			} else {
-				return fmt.Sprintf("%v.%v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
+				return fmt.Sprintf("%v.%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
 			}
 		}
 		fallthrough
@@ -1159,31 +1158,30 @@
 
 	case OTARRAY:
 		if n.Left != nil {
-			return fmt.Sprintf("[]%v", Nconv(n.Left, 0))
+			return fmt.Sprintf("[]%v", n.Left)
 		}
 		var f string
-		f += fmt.Sprintf("[]%v", Nconv(n.Right, 0))
+		f += fmt.Sprintf("[]%v", n.Right)
 		return f // happens before typecheck
 
 	case OTMAP:
-		return fmt.Sprintf("map[%v]%v", Nconv(n.Left, 0), Nconv(n.Right, 0))
+		return fmt.Sprintf("map[%v]%v", n.Left, n.Right)
 
 	case OTCHAN:
 		switch n.Etype {
 		case Crecv:
-			return fmt.Sprintf("<-chan %v", Nconv(n.Left, 0))
+			return fmt.Sprintf("<-chan %v", n.Left)
 
 		case Csend:
-			return fmt.Sprintf("chan<- %v", Nconv(n.Left, 0))
+			return fmt.Sprintf("chan<- %v", n.Left)
 
 		default:
 			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
-				return fmt.Sprintf("chan (%v)", Nconv(n.Left, 0))
+				return fmt.Sprintf("chan (%v)", n.Left)
 			} else {
-				return fmt.Sprintf("chan %v", Nconv(n.Left, 0))
+				return fmt.Sprintf("chan %v", n.Left)
 			}
 		}
-		fallthrough
 
 	case OTSTRUCT:
 		return "<struct>"
@@ -1199,18 +1197,18 @@
 			return "func literal"
 		}
 		if n.Nbody != nil {
-			return fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Nbody, 0))
+			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
 		}
-		return fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Closure.Nbody, 0))
+		return fmt.Sprintf("%v { %v }", n.Type, n.Closure.Nbody)
 
 	case OCOMPLIT:
 		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
 		if fmtmode == FErr {
 			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
 				if ptrlit {
-					return fmt.Sprintf("&%v literal", Tconv(n.Right.Type.Type, 0))
+					return fmt.Sprintf("&%v literal", n.Right.Type.Type)
 				} else {
-					return fmt.Sprintf("%v literal", Tconv(n.Right.Type, 0))
+					return fmt.Sprintf("%v literal", n.Right.Type)
 				}
 			}
 
@@ -1219,16 +1217,16 @@
 
 		if fmtmode == FExp && ptrlit {
 			// typecheck has overwritten OIND by OTYPE with pointer type.
-			return fmt.Sprintf("(&%v{ %v })", Tconv(n.Right.Type.Type, 0), Hconv(n.List, obj.FmtComma))
+			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Type, Hconv(n.List, obj.FmtComma))
 		}
 
-		return fmt.Sprintf("(%v{ %v })", Nconv(n.Right, 0), Hconv(n.List, obj.FmtComma))
+		return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, obj.FmtComma))
 
 	case OPTRLIT:
 		if fmtmode == FExp && n.Left.Implicit {
 			return Nconv(n.Left, 0)
 		}
-		return fmt.Sprintf("&%v", Nconv(n.Left, 0))
+		return fmt.Sprintf("&%v", n.Left)
 
 	case OSTRUCTLIT:
 		if fmtmode == FExp { // requires special handling of field names
@@ -1236,10 +1234,10 @@
 			if n.Implicit {
 				f += "{"
 			} else {
-				f += fmt.Sprintf("(%v{", Tconv(n.Type, 0))
+				f += fmt.Sprintf("(%v{", n.Type)
 			}
 			for l := n.List; l != nil; l = l.Next {
-				f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), Nconv(l.N.Right, 0))
+				f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), l.N.Right)
 
 				if l.Next != nil {
 					f += ","
@@ -1257,32 +1255,30 @@
 		}
 		fallthrough
 
-		// fallthrough
-
 	case OARRAYLIT, OMAPLIT:
 		if fmtmode == FErr {
-			return fmt.Sprintf("%v literal", Tconv(n.Type, 0))
+			return fmt.Sprintf("%v literal", n.Type)
 		}
 		if fmtmode == FExp && n.Implicit {
 			return fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma))
 		}
-		return fmt.Sprintf("(%v{ %v })", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
+		return fmt.Sprintf("(%v{ %v })", n.Type, Hconv(n.List, obj.FmtComma))
 
 	case OKEY:
 		if n.Left != nil && n.Right != nil {
 			if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD {
 				// requires special handling of field names
-				return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), Nconv(n.Right, 0))
+				return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), n.Right)
 			} else {
-				return fmt.Sprintf("%v:%v", Nconv(n.Left, 0), Nconv(n.Right, 0))
+				return fmt.Sprintf("%v:%v", n.Left, n.Right)
 			}
 		}
 
 		if n.Left == nil && n.Right != nil {
-			return fmt.Sprintf(":%v", Nconv(n.Right, 0))
+			return fmt.Sprintf(":%v", n.Right)
 		}
 		if n.Left != nil && n.Right == nil {
-			return fmt.Sprintf("%v:", Nconv(n.Left, 0))
+			return fmt.Sprintf("%v:", n.Left)
 		}
 		return ":"
 
@@ -1305,10 +1301,10 @@
 		var f string
 		f += exprfmt(n.Left, nprec)
 		if n.Right != nil {
-			f += fmt.Sprintf(".(%v)", Nconv(n.Right, 0))
+			f += fmt.Sprintf(".(%v)", n.Right)
 			return f
 		}
-		f += fmt.Sprintf(".(%v)", Tconv(n.Type, 0))
+		f += fmt.Sprintf(".(%v)", n.Type)
 		return f
 
 	case OINDEX,
@@ -1320,11 +1316,11 @@
 		OSLICE3ARR:
 		var f string
 		f += exprfmt(n.Left, nprec)
-		f += fmt.Sprintf("[%v]", Nconv(n.Right, 0))
+		f += fmt.Sprintf("[%v]", n.Right)
 		return f
 
 	case OCOPY, OCOMPLEX:
-		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0), Nconv(n.Right, 0))
+		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), n.Left, n.Right)
 
 	case OCONV,
 		OCONVIFACE,
@@ -1335,12 +1331,12 @@
 		OSTRARRAYRUNE,
 		ORUNESTR:
 		if n.Type == nil || n.Type.Sym == nil {
-			return fmt.Sprintf("(%v)(%v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
+			return fmt.Sprintf("(%v)(%v)", n.Type, n.Left)
 		}
 		if n.Left != nil {
-			return fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
+			return fmt.Sprintf("%v(%v)", n.Type, n.Left)
 		}
-		return fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
+		return fmt.Sprintf("%v(%v)", n.Type, Hconv(n.List, obj.FmtComma))
 
 	case OREAL,
 		OIMAG,
@@ -1356,14 +1352,14 @@
 		OPRINT,
 		OPRINTN:
 		if n.Left != nil {
-			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0))
+			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), n.Left)
 		}
 		if n.Isddd {
 			return fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
 		}
 		return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
 
-	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
+	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
 		var f string
 		f += exprfmt(n.Left, nprec)
 		if n.Isddd {
@@ -1375,15 +1371,15 @@
 
 	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
 		if n.List != nil { // pre-typecheck
-			return fmt.Sprintf("make(%v, %v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
+			return fmt.Sprintf("make(%v, %v)", n.Type, Hconv(n.List, obj.FmtComma))
 		}
 		if n.Right != nil {
-			return fmt.Sprintf("make(%v, %v, %v)", Tconv(n.Type, 0), Nconv(n.Left, 0), Nconv(n.Right, 0))
+			return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right)
 		}
 		if n.Left != nil && (n.Op == OMAKESLICE || !isideal(n.Left.Type)) {
-			return fmt.Sprintf("make(%v, %v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
+			return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
 		}
-		return fmt.Sprintf("make(%v)", Tconv(n.Type, 0))
+		return fmt.Sprintf("make(%v)", n.Type)
 
 		// Unary
 	case OPLUS,
@@ -1462,11 +1458,11 @@
 		n = n.Orig
 	}
 
-	if flag&obj.FmtLong != 0 /*untyped*/ && t != nil {
+	if flag&obj.FmtLong != 0 && t != nil {
 		if t.Etype == TNIL {
 			return "nil"
 		} else {
-			return fmt.Sprintf("%v (type %v)", Nconv(n, 0), Tconv(t, 0))
+			return fmt.Sprintf("%v (type %v)", n, t)
 		}
 	}
 
@@ -1493,7 +1489,7 @@
 		return ""
 	}
 
-	recur := flag&obj.FmtShort == 0 /*untyped*/
+	recur := flag&obj.FmtShort == 0
 
 	var buf bytes.Buffer
 	if recur {
@@ -1504,7 +1500,7 @@
 		}
 
 		if n.Ninit != nil {
-			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), Hconv(n.Ninit, 0))
+			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), n.Ninit)
 			indent(&buf)
 		}
 	}
@@ -1514,39 +1510,39 @@
 		fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
 
 	case OREGISTER, OINDREG:
-		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Val.U.Reg)), Jconv(n, 0))
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Reg)), Jconv(n, 0))
 
 	case OLITERAL:
 		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Vconv(&n.Val, 0), Jconv(n, 0))
 
 	case ONAME, ONONAME:
 		if n.Sym != nil {
-			fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0))
+			fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0))
 		} else {
 			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
 		}
 		if recur && n.Type == nil && n.Ntype != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype)
 		}
 
 	case OASOP:
 		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
 
 	case OTYPE:
-		fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0), Tconv(n.Type, 0))
+		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 {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype)
 		}
 	}
 
 	if n.Sym != nil && n.Op != ONAME {
-		fmt.Fprintf(&buf, " %v G%d", Sconv(n.Sym, 0), n.Vargen)
+		fmt.Fprintf(&buf, " %v G%d", n.Sym, n.Vargen)
 	}
 
 	if n.Type != nil {
-		fmt.Fprintf(&buf, " %v", Tconv(n.Type, 0))
+		fmt.Fprintf(&buf, " %v", n.Type)
 	}
 
 	if recur {
@@ -1558,42 +1554,46 @@
 		}
 		if n.List != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), Hconv(n.List, 0))
+			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), n.List)
 		}
 
 		if n.Rlist != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), Hconv(n.Rlist, 0))
+			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist)
 		}
 
 		if n.Ntest != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-test%v", Oconv(int(n.Op), 0), Nconv(n.Ntest, 0))
+			fmt.Fprintf(&buf, "%v-test%v", Oconv(int(n.Op), 0), n.Ntest)
 		}
 
 		if n.Nbody != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), Hconv(n.Nbody, 0))
+			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody)
 		}
 
 		if n.Nelse != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-else%v", Oconv(int(n.Op), 0), Hconv(n.Nelse, 0))
+			fmt.Fprintf(&buf, "%v-else%v", Oconv(int(n.Op), 0), n.Nelse)
 		}
 
 		if n.Nincr != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-incr%v", Oconv(int(n.Op), 0), Nconv(n.Nincr, 0))
+			fmt.Fprintf(&buf, "%v-incr%v", Oconv(int(n.Op), 0), n.Nincr)
 		}
 	}
 
 	return buf.String()
 }
 
+func (s *Sym) String() string {
+	return Sconv(s, 0)
+}
+
 // Fmt "%S": syms
 // Flags:  "%hS" suppresses qualifying with package
 func Sconv(s *Sym, flag int) string {
-	if flag&obj.FmtLong != 0 /*untyped*/ {
+	if flag&obj.FmtLong != 0 {
 		panic("linksymfmt")
 	}
 
@@ -1615,6 +1615,10 @@
 	return str
 }
 
+func (t *Type) String() string {
+	return Tconv(t, 0)
+}
+
 // Fmt "%T": types.
 // Flags: 'l' print definition, not name
 //	  'h' omit 'func' and receiver from function types, short type names
@@ -1653,6 +1657,10 @@
 	return str
 }
 
+func (n *Node) String() string {
+	return Nconv(n, 0)
+}
+
 // Fmt '%N': Nodes.
 // Flags: 'l' suffix with "(type %T)" where possible
 //	  '+h' in debug mode, don't recurse, no multiline output
@@ -1684,6 +1692,10 @@
 	return str
 }
 
+func (l *NodeList) String() string {
+	return Hconv(l, 0)
+}
+
 // Fmt '%H': NodeList.
 // Flags: all those of %N plus ',': separate with comma's instead of semicolons.
 func Hconv(l *NodeList, flag int) string {
@@ -1698,7 +1710,7 @@
 	sep := "; "
 	if fmtmode == FDbg {
 		sep = "\n"
-	} else if flag&obj.FmtComma != 0 /*untyped*/ {
+	} else if flag&obj.FmtComma != 0 {
 		sep = ", "
 	}
 
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go
index caae2f1..e6af897 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/internal/gc/gen.go
@@ -23,11 +23,10 @@
 	return n
 }
 
-/*
- * the address of n has been taken and might be used after
- * the current function returns.  mark any local vars
- * as needing to move to the heap.
- */
+// addrescapes tags node n as having had its address taken
+// by "increasing" the "value" of n.Esc to EscHeap.
+// Storage is allocated as necessary to allow the address
+// to be taken.
 func addrescapes(n *Node) {
 	switch n.Op {
 	// probably a type error already.
@@ -50,7 +49,7 @@
 		case PPARAMREF:
 			addrescapes(n.Defn)
 
-			// if func param, need separate temporary
+		// if func param, need separate temporary
 		// to hold heap pointer.
 		// the function type has already been checked
 		// (we're in the function body)
@@ -61,19 +60,17 @@
 			n.Stackparam = Nod(OPARAM, n, nil)
 
 			n.Stackparam.Type = n.Type
-			n.Stackparam.Addable = 1
+			n.Stackparam.Addable = true
 			if n.Xoffset == BADWIDTH {
 				Fatal("addrescapes before param assignment")
 			}
 			n.Stackparam.Xoffset = n.Xoffset
 			fallthrough
 
-			// fallthrough
-
 		case PAUTO:
 			n.Class |= PHEAP
 
-			n.Addable = 0
+			n.Addable = false
 			n.Ullman = 2
 			n.Xoffset = 0
 
@@ -82,12 +79,12 @@
 
 			Curfn = n.Curfn
 			n.Heapaddr = temp(Ptrto(n.Type))
-			buf := fmt.Sprintf("&%v", Sconv(n.Sym, 0))
+			buf := fmt.Sprintf("&%v", n.Sym)
 			n.Heapaddr.Sym = Lookup(buf)
 			n.Heapaddr.Orig.Sym = n.Heapaddr.Sym
 			n.Esc = EscHeap
 			if Debug['m'] != 0 {
-				fmt.Printf("%v: moved to heap: %v\n", n.Line(), Nconv(n, 0))
+				fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
 			}
 			Curfn = oldfn
 		}
@@ -95,12 +92,12 @@
 	case OIND, ODOTPTR:
 		break
 
-		// ODOTPTR has already been introduced,
+	// ODOTPTR has already been introduced,
 	// so these are the non-pointer ODOT and OINDEX.
 	// In &x[0], if x is a slice, then x does not
 	// escape--the pointer inside x does, but that
 	// is always a heap pointer anyway.
-	case ODOT, OINDEX:
+	case ODOT, OINDEX, OPAREN, OCONVNOP:
 		if !Isslice(n.Left.Type) {
 			addrescapes(n.Left)
 		}
@@ -133,7 +130,7 @@
 
 	if n.Op == OLABEL {
 		if lab.Def != nil {
-			Yyerror("label %v already defined at %v", Sconv(s, 0), lab.Def.Line())
+			Yyerror("label %v already defined at %v", s, lab.Def.Line())
 		} else {
 			lab.Def = n
 		}
@@ -192,9 +189,9 @@
 		}
 
 		if block != nil {
-			Yyerror("goto %v jumps into block starting at %v", Sconv(from.Left.Sym, 0), Ctxt.Line(int(block.Lastlineno)))
+			Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
 		} else {
-			Yyerror("goto %v jumps over declaration of %v at %v", Sconv(from.Left.Sym, 0), Sconv(dcl, 0), Ctxt.Line(int(dcl.Lastlineno)))
+			Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
 		}
 		lineno = int32(lno)
 	}
@@ -260,7 +257,7 @@
 		return
 	}
 	if compiling_runtime != 0 {
-		Yyerror("%v escapes to heap, not allowed in runtime.", Nconv(n, 0))
+		Yyerror("%v escapes to heap, not allowed in runtime.", n)
 	}
 	if n.Alloc == nil {
 		n.Alloc = callnew(n.Type)
@@ -332,7 +329,7 @@
 	var z Node
 	z.Op = OLITERAL
 	z.Type = n.Type
-	z.Addable = 1
+	z.Addable = true
 
 	switch Simtype[n.Type.Etype] {
 	case TCOMPLEX64, TCOMPLEX128:
@@ -365,7 +362,7 @@
 		Mpmovecfix(z.Val.U.Xval, 0)
 
 	default:
-		Fatal("clearslim called on type %v", Tconv(n.Type, 0))
+		Fatal("clearslim called on type %v", n.Type)
 	}
 
 	ullmancalc(&z)
@@ -405,7 +402,7 @@
  * n.Left is x
  * n.Type is T
  */
-func cgen_dottype(n *Node, res, resok *Node) {
+func cgen_dottype(n *Node, res, resok *Node, wb bool) {
 	if Debug_typeassert > 0 {
 		Warn("type assertion inlined")
 	}
@@ -443,16 +440,17 @@
 	Cgen(typename(n.Type), &r2)
 	Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
 	p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
+	Regfree(&r2) // not needed for success path; reclaimed on one failure path
 	iface.Xoffset += int64(Widthptr)
 	Cgen(&iface, &r1)
 	Regfree(&iface)
 
 	if resok == nil {
 		r1.Type = res.Type
-		Cgen(&r1, res)
+		cgen_wb(&r1, res, wb)
 		q := Gbranch(obj.AJMP, nil, 0)
 		Patch(p, Pc)
-
+		Regrealloc(&r2) // reclaim from above, for this failure path
 		fn := syslook("panicdottype", 0)
 		dowidth(fn.Type)
 		call := Nod(OCALLFUNC, fn, nil)
@@ -469,10 +467,9 @@
 		// This half is handling the res, resok = x.(T) case,
 		// which is called from gen, not cgen, and is consequently fussier
 		// about blank assignments. We have to avoid calling cgen for those.
-		Regfree(&r2)
 		r1.Type = res.Type
 		if !isblank(res) {
-			Cgen(&r1, res)
+			cgen_wb(&r1, res, wb)
 		}
 		Regfree(&r1)
 		if !isblank(resok) {
@@ -749,7 +746,7 @@
 	s.Def = n
 	n.Type = t
 	n.Class = PAUTO
-	n.Addable = 1
+	n.Addable = true
 	n.Ullman = 1
 	n.Esc = EscNever
 	n.Curfn = Curfn
@@ -850,13 +847,13 @@
 		if n.Left != nil {
 			lab := n.Left.Sym.Label
 			if lab == nil {
-				Yyerror("break label not defined: %v", Sconv(n.Left.Sym, 0))
+				Yyerror("break label not defined: %v", n.Left.Sym)
 				break
 			}
 
 			lab.Used = 1
 			if lab.Breakpc == nil {
-				Yyerror("invalid break label %v", Sconv(n.Left.Sym, 0))
+				Yyerror("invalid break label %v", n.Left.Sym)
 				break
 			}
 
@@ -875,13 +872,13 @@
 		if n.Left != nil {
 			lab := n.Left.Sym.Label
 			if lab == nil {
-				Yyerror("continue label not defined: %v", Sconv(n.Left.Sym, 0))
+				Yyerror("continue label not defined: %v", n.Left.Sym)
 				break
 			}
 
 			lab.Used = 1
 			if lab.Continpc == nil {
-				Yyerror("invalid continue label %v", Sconv(n.Left.Sym, 0))
+				Yyerror("invalid continue label %v", n.Left.Sym)
 				break
 			}
 
@@ -981,8 +978,11 @@
 		}
 		Cgen_as(n.Left, n.Right)
 
+	case OASWB:
+		Cgen_as_wb(n.Left, n.Right, true)
+
 	case OAS2DOTTYPE:
-		cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N)
+		cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false)
 
 	case OCALLMETH:
 		cgen_callmeth(n, 0)
@@ -1002,6 +1002,13 @@
 	case ORETURN, ORETJMP:
 		cgen_ret(n)
 
+	// Function calls turned into compiler intrinsics.
+	// At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
+	case OGETG:
+		// nothing
+	case OSQRT:
+		cgen_discard(n.Left)
+
 	case OCHECKNIL:
 		Cgen_checknil(n.Left)
 
@@ -1018,10 +1025,18 @@
 	lineno = lno
 }
 
-func Cgen_as(nl *Node, nr *Node) {
+func Cgen_as(nl, nr *Node) {
+	Cgen_as_wb(nl, nr, false)
+}
+
+func Cgen_as_wb(nl, nr *Node, wb bool) {
 	if Debug['g'] != 0 {
-		Dump("cgen_as", nl)
-		Dump("cgen_as = ", nr)
+		op := "cgen_as"
+		if wb {
+			op = "cgen_as_wb"
+		}
+		Dump(op, nl)
+		Dump(op+" = ", nr)
 	}
 
 	for nr != nil && nr.Op == OCONVNOP {
@@ -1060,7 +1075,7 @@
 		return
 	}
 
-	Cgen(nr, nl)
+	cgen_wb(nr, nl, wb)
 }
 
 func cgen_callmeth(n *Node, proc int) {
@@ -1084,24 +1099,32 @@
 	cgen_call(&n2, proc)
 }
 
+// CgenTemp creates a temporary node, assigns n to it, and returns it.
+func CgenTemp(n *Node) *Node {
+	var tmp Node
+	Tempname(&tmp, n.Type)
+	Cgen(n, &tmp)
+	return &tmp
+}
+
 func checklabels() {
 	var l *NodeList
 
 	for lab := labellist; lab != nil; lab = lab.Link {
 		if lab.Def == nil {
 			for l = lab.Use; l != nil; l = l.Next {
-				yyerrorl(int(l.N.Lineno), "label %v not defined", Sconv(lab.Sym, 0))
+				yyerrorl(int(l.N.Lineno), "label %v not defined", lab.Sym)
 			}
 			continue
 		}
 
 		if lab.Use == nil && lab.Used == 0 {
-			yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", Sconv(lab.Sym, 0))
+			yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym)
 			continue
 		}
 
 		if lab.Gotopc != nil {
-			Fatal("label %v never resolved", Sconv(lab.Sym, 0))
+			Fatal("label %v never resolved", lab.Sym)
 		}
 		for l = lab.Use; l != nil; l = l.Next {
 			checkgoto(l.N, lab.Def)
@@ -1109,277 +1132,267 @@
 	}
 }
 
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func Componentgen(nr *Node, nl *Node) bool {
+// Componentgen copies a composite value by moving its individual components.
+// Slices, strings and interfaces are supported. Small structs or arrays with
+// elements of basic type are also supported.
+// nr is nil when assigning a zero value.
+func Componentgen(nr, nl *Node) bool {
+	return componentgen_wb(nr, nl, false)
+}
+
+// componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
+func componentgen_wb(nr, nl *Node, wb bool) bool {
+	// Don't generate any code for complete copy of a variable into itself.
+	// It's useless, and the VARDEF will incorrectly mark the old value as dead.
+	// (This check assumes that the arguments passed to componentgen did not
+	// themselves come from Igen, or else we could have Op==ONAME but
+	// with a Type and Xoffset describing an individual field, not the entire
+	// variable.)
+	if nl.Op == ONAME && nl == nr {
+		return true
+	}
+
+	// Count number of moves required to move components.
+	// If using write barrier, can only emit one pointer.
+	// TODO(rsc): Allow more pointers, for reflect.Value.
+	const maxMoves = 8
+	n := 0
+	numPtr := 0
+	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
+		n++
+		if int(Simtype[t.Etype]) == Tptr && t != itable {
+			numPtr++
+		}
+		return n <= maxMoves && (!wb || numPtr <= 1)
+	})
+	if n > maxMoves || wb && numPtr > 1 {
+		return false
+	}
+
+	// Must call emitVardef after evaluating rhs but before writing to lhs.
+	emitVardef := func() {
+		// Emit vardef if needed.
+		if nl.Op == ONAME {
+			switch nl.Type.Etype {
+			case TARRAY, TSTRING, TINTER, TSTRUCT:
+				Gvardef(nl)
+			}
+		}
+	}
+
+	isConstString := Isconst(nr, CTSTR)
+
+	if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
+		return false
+	}
+
 	var nodl Node
-	var nodr Node
-
-	freel := 0
-	freer := 0
-
-	var isConstString bool
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if Isfat(t.Type) && !Isslice(t) {
-				goto no
-			}
-			if t.Etype != TFIELD {
-				Fatal("componentgen: not a TFIELD: %v", Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case TSTRING, TINTER:
-		break
-	}
-
-	isConstString = Isconst(nr, CTSTR)
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) && !isConstString {
-			goto no
-		}
-		Igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) && !isConstString {
-			Igen(nr, &nodr, nil)
-			freer = 1
-		}
+	if cadable(nl) {
+		nodl = *nl
 	} else {
+		if nr != nil && !cadable(nr) && !isConstString {
+			return false
+		}
+		if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
+			Igen(nl, &nodl, nil)
+			defer Regfree(&nodl)
+		}
+	}
+	lbase := nodl.Xoffset
+
+	// Special case: zeroing.
+	var nodr Node
+	if nr == nil {
 		// When zeroing, prepare a register containing zero.
-		var tmp Node
-		Nodconst(&tmp, nl.Type, 0)
-
-		Regalloc(&nodr, Types[TUINT], nil)
-		Thearch.Gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == ONAME && nr.Op == ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case TARRAY:
-		if nl.Op == ONAME {
-			Gvardef(nl)
-		}
-		t := nl.Type
-		if !Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					Clearslim(&nodl)
-				} else {
-					Thearch.Gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
+		// TODO(rsc): Check that this is actually generating the best code.
+		if Thearch.REGZERO != 0 {
+			// cpu has a dedicated zero register
+			Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
+		} else {
+			// no dedicated zero register
+			var zero Node
+			Nodconst(&zero, nl.Type, 0)
+			Regalloc(&nodr, Types[TUINT], nil)
+			Thearch.Gmove(&zero, &nodr)
+			defer Regfree(&nodr)
 		}
 
-		// componentgen for slices.
-		nodl.Xoffset += int64(Array_array)
-
-		nodl.Type = Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
-		nodl.Type = Types[Simtype[TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(Array_cap) - int64(Array_nel)
-		nodl.Type = Types[Simtype[TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(Array_cap) - int64(Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		goto yes
-
-	case TSTRING:
-		if nl.Op == ONAME {
-			Gvardef(nl)
-		}
-		nodl.Xoffset += int64(Array_array)
-		nodl.Type = Ptrto(Types[TUINT8])
-
-		if isConstString {
-			Regalloc(&nodr, Types[Tptr], nil)
-			p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
-			Datastring(nr.Val.U.Sval, &p.From)
-			p.From.Type = obj.TYPE_ADDR
-			Regfree(&nodr)
-		} else if nr != nil {
-			nodr.Xoffset += int64(Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
-		nodl.Type = Types[Simtype[TUINT]]
-
-		if isConstString {
-			Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval)))
-		} else if nr != nil {
-			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		goto yes
-
-	case TINTER:
-		if nl.Op == ONAME {
-			Gvardef(nl)
-		}
-		nodl.Xoffset += int64(Array_array)
-		nodl.Type = Ptrto(Types[TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
-		nodl.Type = Ptrto(Types[TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		Thearch.Gmove(&nodr, &nodl)
-
-		goto yes
-
-	case TSTRUCT:
-		if nl.Op == ONAME {
-			Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
+		emitVardef()
+		visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
+			nodl.Type = t
+			nodl.Xoffset = lbase + offset
+			nodr.Type = t
+			if Isfloat[t.Etype] {
+				// TODO(rsc): Cache zero register like we do for integers?
 				Clearslim(&nodl)
 			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
 				Thearch.Gmove(&nodr, &nodl)
 			}
+			return true
+		})
+		return true
+	}
+
+	// Special case: assignment of string constant.
+	if isConstString {
+		emitVardef()
+
+		// base
+		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)
+		p.From.Type = obj.TYPE_ADDR
+		Thearch.Gmove(&nodr, &nodl)
+		Regfree(&nodr)
+
+		// length
+		nodl.Type = Types[Simtype[TUINT]]
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval)))
+		Thearch.Gmove(&nodr, &nodl)
+		return true
+	}
+
+	// General case: copy nl = nr.
+	nodr = *nr
+	if !cadable(nr) {
+		if nr.Ullman >= UINF && nodl.Op == OINDREG {
+			Fatal("miscompile")
 		}
+		Igen(nr, &nodr, nil)
+		defer Regfree(&nodr)
+	}
+	rbase := nodr.Xoffset
 
-		goto yes
+	if nodl.Op == 0 {
+		Igen(nl, &nodl, nil)
+		defer Regfree(&nodl)
+		lbase = nodl.Xoffset
 	}
 
-no:
-	if freer != 0 {
-		Regfree(&nodr)
-	}
-	if freel != 0 {
-		Regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		Regfree(&nodr)
-	}
-	if freel != 0 {
-		Regfree(&nodl)
+	emitVardef()
+	var (
+		ptrType   *Type
+		ptrOffset int64
+	)
+	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
+		if wb && int(Simtype[t.Etype]) == Tptr && t != itable {
+			if ptrType != nil {
+				Fatal("componentgen_wb %v", Tconv(nl.Type, 0))
+			}
+			ptrType = t
+			ptrOffset = offset
+			return true
+		}
+		nodl.Type = t
+		nodl.Xoffset = lbase + offset
+		nodr.Type = t
+		nodr.Xoffset = rbase + offset
+		Thearch.Gmove(&nodr, &nodl)
+		return true
+	})
+	if ptrType != nil {
+		nodl.Type = ptrType
+		nodl.Xoffset = lbase + ptrOffset
+		nodr.Type = ptrType
+		nodr.Xoffset = rbase + ptrOffset
+		cgen_wbptr(&nodr, &nodl)
 	}
 	return true
 }
 
-func cadable(n *Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
+// visitComponents walks the individual components of the type t,
+// walking into array elements, struct fields, the real and imaginary
+// parts of complex numbers, and on 32-bit systems the high and
+// low halves of 64-bit integers.
+// It calls f for each such component, passing the component (aka element)
+// type and memory offset, assuming t starts at startOffset.
+// If f ever returns false, visitComponents returns false without any more
+// calls to f. Otherwise visitComponents returns true.
+func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
+	switch t.Etype {
+	case TINT64:
+		if Widthreg == 8 {
+			break
+		}
+		// NOTE: Assuming little endian (signed top half at offset 4).
+		// We don't have any 32-bit big-endian systems.
+		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
+			Fatal("unknown 32-bit architecture")
+		}
+		return f(Types[TUINT32], startOffset) &&
+			f(Types[TINT32], startOffset+4)
 
-	switch n.Op {
-	case ONAME:
+	case TUINT64:
+		if Widthreg == 8 {
+			break
+		}
+		return f(Types[TUINT32], startOffset) &&
+			f(Types[TUINT32], startOffset+4)
+
+	case TCOMPLEX64:
+		return f(Types[TFLOAT32], startOffset) &&
+			f(Types[TFLOAT32], startOffset+4)
+
+	case TCOMPLEX128:
+		return f(Types[TFLOAT64], startOffset) &&
+			f(Types[TFLOAT64], startOffset+8)
+
+	case TINTER:
+		return f(itable, startOffset) &&
+			f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
+		return true
+
+	case TSTRING:
+		return f(Ptrto(Types[TUINT8]), startOffset) &&
+			f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
+
+	case TARRAY:
+		if Isslice(t) {
+			return f(Ptrto(t.Type), startOffset+int64(Array_array)) &&
+				f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
+				f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
+		}
+
+		// Short-circuit [1e6]struct{}.
+		if t.Type.Width == 0 {
+			return true
+		}
+
+		for i := int64(0); i < t.Bound; i++ {
+			if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
+				return false
+			}
+		}
+		return true
+
+	case TSTRUCT:
+		if t.Type != nil && t.Type.Width != 0 {
+			// NOTE(rsc): If this happens, the right thing to do is to say
+			//	startOffset -= t.Type.Width
+			// but I want to see if it does.
+			// The old version of componentgen handled this,
+			// in code introduced in CL 6932045 to fix issue #4518.
+			// But the test case in issue 4518 does not trigger this anymore,
+			// so maybe this complication is no longer needed.
+			Fatal("struct not at offset 0")
+		}
+
+		for field := t.Type; field != nil; field = field.Down {
+			if field.Etype != TFIELD {
+				Fatal("bad struct")
+			}
+			if !visitComponents(field.Type, startOffset+field.Width, f) {
+				return false
+			}
+		}
 		return true
 	}
+	return f(t, startOffset)
+}
 
-	return false
+func cadable(n *Node) bool {
+	// Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
+	return n.Addable && n.Op == ONAME
 }
diff --git a/src/cmd/internal/gc/go.errors b/src/cmd/internal/gc/go.errors
new file mode 100644
index 0000000..8370a20
--- /dev/null
+++ b/src/cmd/internal/gc/go.errors
@@ -0,0 +1,81 @@
+// 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/go.go b/src/cmd/internal/gc/go.go
index a6e525a..71bce0b 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -6,8 +6,8 @@
 
 import (
 	"bytes"
+	"cmd/internal/gc/big"
 	"cmd/internal/obj"
-	"math/big"
 )
 
 // avoid <ctype.h>
@@ -57,13 +57,11 @@
 )
 
 const (
-	Mpscale = 29         // safely smaller than bits in a long
-	Mpprec  = 16         // Mpscale*Mpprec is max number of bits
-	Mpnorm  = Mpprec - 1 // significant words in a normalized float
-	Mpbase  = 1 << Mpscale
-	Mpsign  = Mpbase >> 1
-	Mpmask  = Mpbase - 1
-	Mpdebug = 0
+	// Maximum size in bits for Mpints before signalling
+	// overflow and also mantissa precision for Mpflts.
+	Mpprec = 512
+	// Turn on for constant arithmetic debugging output.
+	Mpdebug = false
 )
 
 // Mpint represents an integer constant.
@@ -72,19 +70,12 @@
 	Ovf bool // set if Val overflowed compiler limit (sticky)
 }
 
-// Mpfix is the original (old) representation of an integer constant.
-// Still needed for Mpflt.
-type Mpfix struct {
-	A   [Mpprec]int
-	Neg uint8
-	Ovf uint8
-}
-
+// Mpflt represents a floating-point constant.
 type Mpflt struct {
-	Val Mpfix
-	Exp int16
+	Val big.Float
 }
 
+// Mpcplx represents a complex constant.
 type Mpcplx struct {
 	Real Mpflt
 	Imag Mpflt
@@ -93,8 +84,7 @@
 type Val struct {
 	Ctype int16
 	U     struct {
-		Reg  int16   // OREGISTER
-		Bval int16   // bool value CTBOOL
+		Bval bool    // bool value CTBOOL
 		Xval *Mpint  // int CTINT, rune CTRUNE
 		Fval *Mpflt  // float CTFLT
 		Cval *Mpcplx // float CTCPLX
@@ -214,7 +204,6 @@
 
 type InitEntry struct {
 	Xoffset int64 // struct, array only
-	Key     *Node // map only
 	Expr    *Node // bytes of run-time computed expressions
 }
 
@@ -226,19 +215,6 @@
 }
 
 const (
-	EscUnknown = iota
-	EscHeap
-	EscScope
-	EscNone
-	EscReturn
-	EscNever
-	EscBits           = 3
-	EscMask           = (1 << EscBits) - 1
-	EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to some returned result
-	EscReturnBits     = EscBits + 1
-)
-
-const (
 	SymExport   = 1 << 0 // to be exported
 	SymPackage  = 1 << 1
 	SymExported = 1 << 2 // already written out by export
@@ -254,8 +230,6 @@
 	Done  int
 	Tfunc *Type
 	T     *Type
-	An    **Node
-	N     *Node
 }
 
 const (
@@ -333,7 +307,7 @@
 
 // declaration context
 const (
-	Pxxx      = iota
+	Pxxx      = uint8(iota)
 	PEXTERN   // global variable
 	PAUTO     // local variables
 	PPARAM    // input arguments
@@ -343,7 +317,7 @@
 
 	PDISCARD // discard during parse of duplicate import
 
-	PHEAP = 1 << 7 // an extra bit to identify an escaped variable
+	PHEAP = uint8(1 << 7) // an extra bit to identify an escaped variable
 )
 
 const (
@@ -510,8 +484,6 @@
 
 var racepkg *Pkg // package runtime/race
 
-var stringpkg *Pkg // fake package for C strings
-
 var typepkg *Pkg // fake package for runtime type info (headers)
 
 var typelinkpkg *Pkg // fake package for runtime type info (data)
@@ -522,8 +494,6 @@
 
 var trackpkg *Pkg // fake package for field tracking
 
-var rawpkg *Pkg // fake package for raw symbol names
-
 var Tptr int // either TPTR32 or TPTR64
 
 var myimportpath string
@@ -594,7 +564,7 @@
 
 var funcsyms *NodeList
 
-var dclcontext int // PEXTERN/PAUTO
+var dclcontext uint8 // PEXTERN/PAUTO
 
 var incannedimport int
 
@@ -632,8 +602,6 @@
 
 var nblank *Node
 
-var Use_sse bool // should we generate SSE2 instructions for 386 targets
-
 var hunk string
 
 var nhunk int32
@@ -684,8 +652,6 @@
 
 var Pc *obj.Prog
 
-var firstpc *obj.Prog
-
 var nodfp *Node
 
 var Disable_checknil int
@@ -789,6 +755,7 @@
 	REGRETURN    int // AX
 	REGMIN       int
 	REGMAX       int
+	REGZERO      int // architectural zero register, if available
 	FREGMIN      int
 	FREGMAX      int
 	MAXWIDTH     int64
@@ -796,8 +763,8 @@
 
 	AddIndex     func(*Node, int64, *Node) bool // optional
 	Betypeinit   func()
-	Bgen_float   func(*Node, int, int, *obj.Prog) // optional
-	Cgen64       func(*Node, *Node)               // only on 32-bit systems
+	Bgen_float   func(*Node, bool, int, *obj.Prog) // optional
+	Cgen64       func(*Node, *Node)                // only on 32-bit systems
 	Cgenindex    func(*Node, *Node, bool) *obj.Prog
 	Cgen_bmul    func(int, *Node, *Node, *Node) bool
 	Cgen_float   func(*Node, *Node) // optional
@@ -809,7 +776,15 @@
 	Dodiv        func(int, *Node, *Node, *Node)
 	Excise       func(*Flow)
 	Expandchecks func(*obj.Prog)
+	Getg         func(*Node)
 	Gins         func(int, *Node, *Node) *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)
 	Ginscon      func(int, int64, *Node)
 	Ginsnop      func()
 	Gmove        func(*Node, *Node)
@@ -821,7 +796,7 @@
 	Sameaddr     func(*obj.Addr, *obj.Addr) bool
 	Smallindir   func(*obj.Addr, *obj.Addr) bool
 	Stackaddr    func(*obj.Addr) bool
-	Stackcopy    func(*Node, *Node, int64, int64, int64)
+	Blockcopy    func(*Node, *Node, int64, int64, int64)
 	Sudoaddable  func(int, *Node, *obj.Addr) bool
 	Sudoclean    func()
 	Excludedregs func() uint64
@@ -832,6 +807,7 @@
 	Optoas       func(int, *Type) int
 	Doregbits    func(int) uint64
 	Regnames     func(*int) []string
+	Use387       bool // should 8g use 387 FP instructions instead of sse2.
 }
 
 var pcloc int32
diff --git a/src/cmd/internal/gc/go.y b/src/cmd/internal/gc/go.y
index 62d2556..f1904b0 100644
--- a/src/cmd/internal/gc/go.y
+++ b/src/cmd/internal/gc/go.y
@@ -449,7 +449,7 @@
 			if $1.Next != nil {
 				Yyerror("argument count mismatch: %d = %d", count($1), 1);
 			} else if ($1.N.Op != ONAME && $1.N.Op != OTYPE && $1.N.Op != ONONAME) || isblank($1.N) {
-				Yyerror("invalid variable name %s in type switch", Nconv($1.N, 0));
+				Yyerror("invalid variable name %s in type switch", $1.N);
 			} else {
 				$$.Left = dclname($1.N.Sym);
 			}  // it's a colas, so must not re-use an oldname.
@@ -618,7 +618,7 @@
 	{
 		$$ = Nod(ORANGE, nil, $4);
 		$$.List = $1;
-		$$.Colas = 1;
+		$$.Colas = true;
 		colasdefn($1, $$);
 	}
 |	LRANGE expr
@@ -631,7 +631,7 @@
 	osimple_stmt ';' osimple_stmt ';' osimple_stmt
 	{
 		// init ; test ; incr
-		if $5 != nil && $5.Colas != 0 {
+		if $5 != nil && $5.Colas {
 			Yyerror("cannot declare in the for-increment");
 		}
 		$$ = Nod(OFOR, nil, nil);
@@ -1419,7 +1419,7 @@
 				dclcontext = PDISCARD;  // since we skip funchdr below
 				break;
 			}
-			Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0));
+			Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", s, s.Def.Type, t);
 		}
 
 		$$ = newfuncname(s);
@@ -1634,7 +1634,7 @@
 		var pkg *Pkg
 
 		if $1.Def == nil || $1.Def.Op != OPACK {
-			Yyerror("%v is not a package", Sconv($1, 0));
+			Yyerror("%v is not a package", $1);
 			pkg = localpkg;
 		} else {
 			$1.Def.Used = true;
@@ -2188,7 +2188,7 @@
 	{
 		$$ = oldname(Pkglookup($1.Name, builtinpkg));
 		if $$.Op != OLITERAL {
-			Yyerror("bad constant %v", Sconv($$.Sym, 0));
+			Yyerror("bad constant %v", $$.Sym);
 		}
 	}
 
@@ -2240,7 +2240,6 @@
 	}
 
 %%
-
 func fixlbrace(lbr int) {
 	// If the opening brace was an LBODY,
 	// set up for another one now that we're done.
@@ -2249,4 +2248,3 @@
 		loophack = 1
 	}
 }
-
diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go
index 499c216..53b3f6c 100644
--- a/src/cmd/internal/gc/gsubr.go
+++ b/src/cmd/internal/gc/gsubr.go
@@ -75,7 +75,7 @@
 	if b.Op != OREGISTER {
 		return false
 	}
-	if a.Val.U.Reg != b.Val.U.Reg {
+	if a.Reg != b.Reg {
 		return false
 	}
 	return true
@@ -87,7 +87,7 @@
 	p.To.Val = nil
 	if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' {
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(bool2int(likely > 0))
+		p.From.Offset = int64(obj.Bool2int(likely > 0))
 	}
 
 	return p
@@ -133,9 +133,9 @@
 
 	*n = Node{}
 	n.Op = OREGISTER
-	n.Addable = 1
+	n.Addable = true
 	ullmancalc(n)
-	n.Val.U.Reg = int16(r)
+	n.Reg = int16(r)
 	n.Type = t
 }
 
@@ -218,11 +218,15 @@
 	}
 }
 
-func ggloblsym(s *Sym, width int32, flags int8) {
+func ggloblsym(s *Sym, width int32, flags int16) {
 	p := Thearch.Gins(obj.AGLOBL, nil, nil)
 	p.From.Type = obj.TYPE_MEM
 	p.From.Name = obj.NAME_EXTERN
 	p.From.Sym = Linksym(s)
+	if flags&obj.LOCAL != 0 {
+		p.From.Sym.Local = true
+		flags &= ^obj.LOCAL
+	}
 	p.To.Type = obj.TYPE_CONST
 	p.To.Offset = int64(width)
 	p.From3.Offset = int64(flags)
@@ -304,7 +308,7 @@
 
 	case OREGISTER:
 		a.Type = obj.TYPE_REG
-		a.Reg = n.Val.U.Reg
+		a.Reg = n.Reg
 		a.Sym = nil
 		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
 			a.Width = 0
@@ -312,7 +316,7 @@
 
 	case OINDREG:
 		a.Type = obj.TYPE_MEM
-		a.Reg = n.Val.U.Reg
+		a.Reg = n.Reg
 		a.Sym = Linksym(n.Sym)
 		a.Offset = n.Xoffset
 		if a.Offset != int64(int32(a.Offset)) {
@@ -361,7 +365,7 @@
 		if s == nil {
 			s = Lookup(".noname")
 		}
-		if n.Method != 0 {
+		if n.Method {
 			if n.Type != nil {
 				if n.Type.Sym != nil {
 					if n.Type.Sym.Pkg != nil {
@@ -374,7 +378,7 @@
 		a.Type = obj.TYPE_MEM
 		switch n.Class {
 		default:
-			Fatal("naddr: ONAME class %v %d\n", Sconv(n.Sym, 0), n.Class)
+			Fatal("naddr: ONAME class %v %d\n", n.Sym, n.Class)
 
 		case PEXTERN:
 			a.Name = obj.NAME_EXTERN
@@ -417,7 +421,7 @@
 		case CTBOOL:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
-			a.Offset = int64(n.Val.U.Bval)
+			a.Offset = int64(obj.Bool2int(n.Val.U.Bval))
 
 		case CTNIL:
 			a.Sym = nil
@@ -466,9 +470,6 @@
 			break // len(nil)
 		}
 		a.Etype = Simtype[TUINT]
-		if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
-			a.Etype = Simtype[TINT]
-		}
 		a.Offset += int64(Array_nel)
 		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
@@ -482,9 +483,6 @@
 			break // cap(nil)
 		}
 		a.Etype = Simtype[TUINT]
-		if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
-			a.Etype = Simtype[TINT]
-		}
 		a.Offset += int64(Array_cap)
 		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
@@ -517,15 +515,15 @@
 			Fatal("nodarg: bad struct")
 		}
 		if first.Width == BADWIDTH {
-			Fatal("nodarg: offset not computed for %v", Tconv(t, 0))
+			Fatal("nodarg: offset not computed for %v", t)
 		}
 		n.Xoffset = first.Width
-		n.Addable = 1
+		n.Addable = true
 		goto fp
 	}
 
 	if t.Etype != TFIELD {
-		Fatal("nodarg: not field %v", Tconv(t, 0))
+		Fatal("nodarg: not field %v", t)
 	}
 
 	if fp == 1 {
@@ -543,10 +541,10 @@
 	n.Sym = t.Sym
 
 	if t.Width == BADWIDTH {
-		Fatal("nodarg: offset not computed for %v", Tconv(t, 0))
+		Fatal("nodarg: offset not computed for %v", t)
 	}
 	n.Xoffset = t.Width
-	n.Addable = 1
+	n.Addable = true
 	n.Orig = t.Nname
 
 	// Rewrite argument named _ to __,
@@ -561,7 +559,7 @@
 	case 0: // output arg
 		n.Op = OINDREG
 
-		n.Val.U.Reg = int16(Thearch.REGSP)
+		n.Reg = int16(Thearch.REGSP)
 		if HasLinkRegister() {
 			n.Xoffset += int64(Ctxt.Arch.Ptrsize)
 		}
@@ -669,11 +667,11 @@
 Switch:
 	switch et {
 	default:
-		Fatal("regalloc: unknown type %v", Tconv(t, 0))
+		Fatal("regalloc: unknown type %v", t)
 
 	case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL:
 		if o != nil && o.Op == OREGISTER {
-			i = int(o.Val.U.Reg)
+			i = int(o.Reg)
 			if Thearch.REGMIN <= i && i <= Thearch.REGMAX {
 				break Switch
 			}
@@ -688,12 +686,12 @@
 		Fatal("out of fixed registers")
 
 	case TFLOAT32, TFLOAT64:
-		if Thearch.Thechar == '8' && !Use_sse {
+		if Thearch.Use387 {
 			i = Thearch.FREGMIN // x86.REG_F0
 			break Switch
 		}
 		if o != nil && o.Op == OREGISTER {
-			i = int(o.Val.U.Reg)
+			i = int(o.Reg)
 			if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX {
 				break Switch
 			}
@@ -732,7 +730,7 @@
 	if n.Op != OREGISTER && n.Op != OINDREG {
 		Fatal("regfree: not a register")
 	}
-	i := int(n.Val.U.Reg)
+	i := int(n.Reg)
 	if i == Thearch.REGSP {
 		return
 	}
@@ -773,7 +771,7 @@
 	if n.Op != OREGISTER && n.Op != OINDREG {
 		Fatal("regrealloc: not a register")
 	}
-	i := int(n.Val.U.Reg)
+	i := int(n.Reg)
 	if i == Thearch.REGSP {
 		return
 	}
diff --git a/src/cmd/internal/gc/init.go b/src/cmd/internal/gc/init.go
index b3a6a00..b5d1e50 100644
--- a/src/cmd/internal/gc/init.go
+++ b/src/cmd/internal/gc/init.go
@@ -57,7 +57,7 @@
 		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
 			break
 
-		case OAS:
+		case OAS, OASWB:
 			if isblank(l.N.Left) && candiscard(l.N.Right) {
 				break
 			}
diff --git a/src/cmd/internal/gc/inl.go b/src/cmd/internal/gc/inl.go
index 7ba94b5..dd2087d 100644
--- a/src/cmd/internal/gc/inl.go
+++ b/src/cmd/internal/gc/inl.go
@@ -54,7 +54,7 @@
 			rcvr = rcvr.Type
 		}
 		if rcvr.Sym == nil {
-			Fatal("receiver with no sym: [%v] %v  (%v)", Sconv(fn.Sym, 0), Nconv(fn, obj.FmtLong), Tconv(rcvr, 0))
+			Fatal("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, obj.FmtLong), rcvr)
 		}
 		return rcvr.Sym.Pkg
 	}
@@ -79,7 +79,7 @@
 	}
 
 	if Debug['m'] > 2 {
-		fmt.Printf("typecheck import [%v] %v { %v }\n", Sconv(fn.Sym, 0), Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
+		fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
 	}
 
 	save_safemode := safemode
@@ -100,7 +100,7 @@
 // fn and ->nbody will already have been typechecked.
 func caninl(fn *Node) {
 	if fn.Op != ODCLFUNC {
-		Fatal("caninl %v", Nconv(fn, 0))
+		Fatal("caninl %v", fn)
 	}
 	if fn.Nname == nil {
 		Fatal("caninl no nname %v", Nconv(fn, obj.FmtSign))
@@ -112,7 +112,7 @@
 	}
 
 	if fn.Typecheck == 0 {
-		Fatal("caninl on non-typechecked function %v", Nconv(fn, 0))
+		Fatal("caninl on non-typechecked function %v", fn)
 	}
 
 	// can't handle ... args yet
@@ -124,6 +124,16 @@
 		}
 	}
 
+	// Runtime package must not be race instrumented.
+	// Racewalk skips runtime package. However, some runtime code can be
+	// inlined into other packages and instrumented there. To avoid this,
+	// we disable inlining of runtime functions in race mode.
+	// The example that we observed is inlining of LockOSThread,
+	// which lead to false race reports on m contents.
+	if flag_race != 0 && myimportpath == "runtime" {
+		return
+	}
+
 	const maxBudget = 80
 	budget := maxBudget // allowed hairyness
 	if ishairylist(fn.Nbody, &budget) || budget < 0 {
@@ -145,7 +155,7 @@
 	if Debug['m'] > 1 {
 		fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Nname.Func.Inl, obj.FmtSharp))
 	} else if Debug['m'] != 0 {
-		fmt.Printf("%v: can inline %v\n", fn.Line(), Nconv(fn.Nname, 0))
+		fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Nname)
 	}
 
 	Curfn = savefn
@@ -390,7 +400,6 @@
 		}
 		fallthrough
 
-		// fallthrough
 	default:
 		for l := n.List; l != nil; l = l.Next {
 			if l.N.Op == OINLCALL {
@@ -411,7 +420,6 @@
 		}
 		fallthrough
 
-		// fallthrough
 	default:
 		for l := n.Rlist; l != nil; l = l.Next {
 			if l.N.Op == OINLCALL {
@@ -504,7 +512,7 @@
 func tinlvar(t *Type) *Node {
 	if t.Nname != nil && !isblank(t.Nname) {
 		if t.Nname.Inlvar == nil {
-			Fatal("missing inlvar for %v\n", Nconv(t.Nname, 0))
+			Fatal("missing inlvar for %v\n", t.Nname)
 		}
 		return t.Nname.Inlvar
 	}
@@ -537,9 +545,9 @@
 
 	// Bingo, we have a function node, and it has an inlineable body
 	if Debug['m'] > 1 {
-		fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), Sconv(fn.Sym, 0), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Inl, obj.FmtSharp))
+		fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Inl, obj.FmtSharp))
 	} else if Debug['m'] != 0 {
-		fmt.Printf("%v: inlining call to %v\n", n.Line(), Nconv(fn, 0))
+		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
 	}
 
 	if Debug['m'] > 2 {
@@ -604,7 +612,7 @@
 		t := getthisx(fn.Type).Type
 
 		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil {
-			Fatal("missing inlvar for %v\n", Nconv(t.Nname, 0))
+			Fatal("missing inlvar for %v\n", t.Nname)
 		}
 		if n.Left.Left == nil {
 			Fatal("method call without receiver: %v", Nconv(n, obj.FmtSign))
@@ -673,7 +681,7 @@
 		t := getthisx(fn.Type).Type
 
 		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil {
-			Fatal("missing inlvar for %v\n", Nconv(t.Nname, 0))
+			Fatal("missing inlvar for %v\n", t.Nname)
 		}
 		if t == nil {
 			Fatal("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go
index cc25929..4bbda95 100644
--- a/src/cmd/internal/gc/lex.go
+++ b/src/cmd/internal/gc/lex.go
@@ -3,6 +3,7 @@
 // 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
@@ -22,8 +23,6 @@
 	"unicode/utf8"
 )
 
-var yychar_lex int
-
 var yyprev int
 
 var yylast int
@@ -36,6 +35,8 @@
 
 var goroot string
 
+var Debug_wb int
+
 // Debug arguments.
 // These can be specified with the -d flag, as in "-d nil"
 // to set the debug_checknil variable. In general the list passed
@@ -47,6 +48,7 @@
 	{"nil", &Debug_checknil},          // print information about nil checks
 	{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
 	{"disablenil", &Disable_checknil}, // disable nil checks
+	{"wb", &Debug_wb},                 // print information about write barriers
 }
 
 // Our own isdigit, isspace, isalpha, isalnum that take care
@@ -182,9 +184,9 @@
 	obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
 	obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
 	obj.Flagcount("B", "disable bounds checking", &Debug['B'])
-	obj.Flagstr("D", "path: set relative path for local imports", &localimport)
+	obj.Flagstr("D", "set relative `path` for local imports", &localimport)
 	obj.Flagcount("E", "debug symbol export", &Debug['E'])
-	obj.Flagfn1("I", "dir: add dir to import search path", addidir)
+	obj.Flagfn1("I", "add `directory` to import search path", addidir)
 	obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
 	obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
 	obj.Flagcount("M", "debug move generation", &Debug['M'])
@@ -194,27 +196,27 @@
 	obj.Flagcount("S", "print assembly listing", &Debug['S'])
 	obj.Flagfn0("V", "print compiler version", doversion)
 	obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
-	obj.Flagstr("asmhdr", "file: write assembly header to named file", &asmhdr)
+	obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
 	obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
-	obj.Flagstr("d", "list: print debug information about items in list", &debugstr)
+	obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
 	obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
 	obj.Flagcount("f", "debug stack frames", &Debug['f'])
 	obj.Flagcount("g", "debug code generation", &Debug['g'])
 	obj.Flagcount("h", "halt on error", &Debug['h'])
 	obj.Flagcount("i", "debug line number stack", &Debug['i'])
-	obj.Flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix)
+	obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
 	obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
 	obj.Flagcount("l", "disable inlining", &Debug['l'])
 	obj.Flagcount("live", "debug liveness analysis", &debuglive)
 	obj.Flagcount("m", "print optimization decisions", &Debug['m'])
 	obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
-	obj.Flagstr("o", "obj: set output file", &outfile)
-	obj.Flagstr("p", "path: set expected package import path", &myimportpath)
+	obj.Flagstr("o", "write output to `file`", &outfile)
+	obj.Flagstr("p", "set expected package import `path`", &myimportpath)
 	obj.Flagcount("pack", "write package file instead of object file", &writearchive)
 	obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
 	obj.Flagcount("race", "enable race detector", &flag_race)
 	obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
-	obj.Flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &Ctxt.Trimpath)
+	obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
 	obj.Flagcount("u", "reject unsafe code", &safemode)
 	obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
 	obj.Flagcount("w", "debug type checking", &Debug['w'])
@@ -223,15 +225,23 @@
 	obj.Flagcount("x", "debug lexer", &Debug['x'])
 	obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
 	var flag_shared int
+	var flag_dynlink bool
 	if Thearch.Thechar == '6' {
 		obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
 		obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
+		flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
 	}
-
-	obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
-	obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
+	obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
+	obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
+	obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
 	obj.Flagparse(usage)
+
+	if flag_dynlink {
+		flag_shared = 1
+	}
 	Ctxt.Flag_shared = int32(flag_shared)
+	Ctxt.Flag_dynlink = flag_dynlink
+
 	Ctxt.Debugasm = int32(Debug['S'])
 	Ctxt.Debugvlog = int32(Debug['v'])
 
@@ -248,24 +258,29 @@
 
 	// parse -d argument
 	if debugstr != "" {
-		var j int
-		f := strings.Split(debugstr, ",")
-		for i := range f {
-			if f[i] == "" {
+	Split:
+		for _, name := range strings.Split(debugstr, ",") {
+			if name == "" {
 				continue
 			}
-			for j = 0; j < len(debugtab); j++ {
-				if debugtab[j].name == f[i] {
-					if debugtab[j].val != nil {
-						*debugtab[j].val = 1
+			val := 1
+			if i := strings.Index(name, "="); i >= 0 {
+				var err error
+				val, err = strconv.Atoi(name[i+1:])
+				if err != nil {
+					log.Fatalf("invalid debug value %v", name)
+				}
+				name = name[:i]
+			}
+			for _, t := range debugtab {
+				if t.name == name {
+					if t.val != nil {
+						*t.val = val
+						continue Split
 					}
-					break
 				}
 			}
-
-			if j >= len(debugtab) {
-				log.Fatalf("unknown debug information -d '%s'\n", f[i])
-			}
+			log.Fatalf("unknown debug key -d %s\n", name)
 		}
 	}
 
@@ -277,17 +292,6 @@
 		Debug['l'] = 1 - Debug['l']
 	}
 
-	if Thearch.Thechar == '8' {
-		switch v := obj.Getgo386(); v {
-		case "387":
-			Use_sse = false
-		case "sse2":
-			Use_sse = true
-		default:
-			log.Fatalf("unsupported setting GO386=%s", v)
-		}
-	}
-
 	Thearch.Betypeinit()
 	if Widthptr == 0 {
 		Fatal("betypeinit failed")
@@ -1385,7 +1389,7 @@
 	}
 
 	if Debug['x'] != 0 {
-		fmt.Printf("lex: %s %s\n", Sconv(s, 0), lexname(int(s.Lexical)))
+		fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical)))
 	}
 	yylval.sym = s
 	return int32(s.Lexical)
@@ -1454,7 +1458,7 @@
 	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.Ovf != 0 {
+	if yylval.val.U.Cval.Imag.Val.IsInf() {
 		Yyerror("overflow in imaginary constant")
 		Mpmovecflt(&yylval.val.U.Cval.Real, 0.0)
 	}
@@ -1471,9 +1475,9 @@
 	ungetc(c)
 
 	str = lexbuf.String()
-	yylval.val.U.Fval = new(Mpflt)
+	yylval.val.U.Fval = newMpflt()
 	mpatoflt(yylval.val.U.Fval, str)
-	if yylval.val.U.Fval.Val.Ovf != 0 {
+	if yylval.val.U.Fval.Val.IsInf() {
 		Yyerror("overflow in float constant")
 		Mpmovecflt(yylval.val.U.Fval, 0.0)
 	}
@@ -1793,11 +1797,6 @@
 
 type yy struct{}
 
-var yymsg []struct {
-	yystate, yychar int
-	msg             string
-}
-
 func (yy) Lex(v *yySymType) int {
 	return int(yylex(v))
 }
@@ -1866,20 +1865,21 @@
 			curio.cp = curio.cp[1:]
 		}
 	} else {
-		var c1 int
-		var c2 int
 	loop:
 		c = obj.Bgetc(curio.bin)
 		if c == 0xef {
-			c1 = obj.Bgetc(curio.bin)
-			c2 = obj.Bgetc(curio.bin)
-			if c1 == 0xbb && c2 == 0xbf {
+			buf, err := curio.bin.Peek(2)
+			if err != nil {
+				log.Fatalf("getc: peeking: %v", err)
+			}
+			if buf[0] == 0xbb && buf[1] == 0xbf {
 				yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
+
+				// consume BOM bytes
+				obj.Bgetc(curio.bin)
+				obj.Bgetc(curio.bin)
 				goto loop
 			}
-
-			obj.Bungetc(curio.bin)
-			obj.Bungetc(curio.bin)
 		}
 	}
 
@@ -2078,369 +2078,67 @@
 	etype   int
 	op      int
 }{
-	/*	name		lexical		etype		op
-	 */
 	/* basic types */
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"int8", LNAME, TINT8, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"int16", LNAME, TINT16, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"int32", LNAME, TINT32, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"int64", LNAME, TINT64, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"uint8", LNAME, TUINT8, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"uint16", LNAME, TUINT16, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"uint32", LNAME, TUINT32, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"uint64", LNAME, TUINT64, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"float32", LNAME, TFLOAT32, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"float64", LNAME, TFLOAT64, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"complex64", LNAME, TCOMPLEX64, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"complex128", LNAME, TCOMPLEX128, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"bool", LNAME, TBOOL, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"string", LNAME, TSTRING, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"any", LNAME, TANY, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"break", LBREAK, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"case", LCASE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"chan", LCHAN, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"const", LCONST, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"continue", LCONTINUE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"default", LDEFAULT, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"else", LELSE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"defer", LDEFER, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"fallthrough", LFALL, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"for", LFOR, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"func", LFUNC, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"go", LGO, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"goto", LGOTO, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"if", LIF, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"import", LIMPORT, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"interface", LINTERFACE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"map", LMAP, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"package", LPACKAGE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"range", LRANGE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"return", LRETURN, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"select", LSELECT, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"struct", LSTRUCT, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"switch", LSWITCH, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"type", LTYPE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"var", LVAR, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"append", LNAME, Txxx, OAPPEND},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"cap", LNAME, Txxx, OCAP},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"close", LNAME, Txxx, OCLOSE},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"complex", LNAME, Txxx, OCOMPLEX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"copy", LNAME, Txxx, OCOPY},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"delete", LNAME, Txxx, ODELETE},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"imag", LNAME, Txxx, OIMAG},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"len", LNAME, Txxx, OLEN},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"make", LNAME, Txxx, OMAKE},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"new", LNAME, Txxx, ONEW},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"panic", LNAME, Txxx, OPANIC},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"print", LNAME, Txxx, OPRINT},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"println", LNAME, Txxx, OPRINTN},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"real", LNAME, Txxx, OREAL},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"recover", LNAME, Txxx, ORECOVER},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"notwithstanding", LIGNORE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"thetruthofthematter", LIGNORE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"despiteallobjections", LIGNORE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"whereas", LIGNORE, Txxx, OXXX},
-	struct {
-		name    string
-		lexical int
-		etype   int
-		op      int
-	}{"insofaras", LIGNORE, Txxx, OXXX},
+	{"int8", LNAME, TINT8, OXXX},
+	{"int16", LNAME, TINT16, OXXX},
+	{"int32", LNAME, TINT32, OXXX},
+	{"int64", LNAME, TINT64, OXXX},
+	{"uint8", LNAME, TUINT8, OXXX},
+	{"uint16", LNAME, TUINT16, OXXX},
+	{"uint32", LNAME, TUINT32, OXXX},
+	{"uint64", LNAME, TUINT64, OXXX},
+	{"float32", LNAME, TFLOAT32, OXXX},
+	{"float64", LNAME, TFLOAT64, OXXX},
+	{"complex64", LNAME, TCOMPLEX64, OXXX},
+	{"complex128", LNAME, TCOMPLEX128, OXXX},
+	{"bool", LNAME, TBOOL, OXXX},
+	{"string", LNAME, TSTRING, OXXX},
+	{"any", LNAME, TANY, OXXX},
+	{"break", LBREAK, Txxx, OXXX},
+	{"case", LCASE, Txxx, OXXX},
+	{"chan", LCHAN, Txxx, OXXX},
+	{"const", LCONST, Txxx, OXXX},
+	{"continue", LCONTINUE, Txxx, OXXX},
+	{"default", LDEFAULT, Txxx, OXXX},
+	{"else", LELSE, Txxx, OXXX},
+	{"defer", LDEFER, Txxx, OXXX},
+	{"fallthrough", LFALL, Txxx, OXXX},
+	{"for", LFOR, Txxx, OXXX},
+	{"func", LFUNC, Txxx, OXXX},
+	{"go", LGO, Txxx, OXXX},
+	{"goto", LGOTO, Txxx, OXXX},
+	{"if", LIF, Txxx, OXXX},
+	{"import", LIMPORT, Txxx, OXXX},
+	{"interface", LINTERFACE, Txxx, OXXX},
+	{"map", LMAP, Txxx, OXXX},
+	{"package", LPACKAGE, Txxx, OXXX},
+	{"range", LRANGE, Txxx, OXXX},
+	{"return", LRETURN, Txxx, OXXX},
+	{"select", LSELECT, Txxx, OXXX},
+	{"struct", LSTRUCT, Txxx, OXXX},
+	{"switch", LSWITCH, Txxx, OXXX},
+	{"type", LTYPE, Txxx, OXXX},
+	{"var", LVAR, Txxx, OXXX},
+	{"append", LNAME, Txxx, OAPPEND},
+	{"cap", LNAME, Txxx, OCAP},
+	{"close", LNAME, Txxx, OCLOSE},
+	{"complex", LNAME, Txxx, OCOMPLEX},
+	{"copy", LNAME, Txxx, OCOPY},
+	{"delete", LNAME, Txxx, ODELETE},
+	{"imag", LNAME, Txxx, OIMAG},
+	{"len", LNAME, Txxx, OLEN},
+	{"make", LNAME, Txxx, OMAKE},
+	{"new", LNAME, Txxx, ONEW},
+	{"panic", LNAME, Txxx, OPANIC},
+	{"print", LNAME, Txxx, OPRINT},
+	{"println", LNAME, Txxx, OPRINTN},
+	{"real", LNAME, Txxx, OREAL},
+	{"recover", LNAME, Txxx, ORECOVER},
+	{"notwithstanding", LIGNORE, Txxx, OXXX},
+	{"thetruthofthematter", LIGNORE, Txxx, OXXX},
+	{"despiteallobjections", LIGNORE, Txxx, OXXX},
+	{"whereas", LIGNORE, Txxx, OXXX},
+	{"insofaras", LIGNORE, Txxx, OXXX},
 }
 
 func lexinit() {
@@ -2690,393 +2388,134 @@
 	lex  int
 	name string
 }{
-	struct {
-		lex  int
-		name string
-	}{LANDAND, "ANDAND"},
-	struct {
-		lex  int
-		name string
-	}{LANDNOT, "ANDNOT"},
-	struct {
-		lex  int
-		name string
-	}{LASOP, "ASOP"},
-	struct {
-		lex  int
-		name string
-	}{LBREAK, "BREAK"},
-	struct {
-		lex  int
-		name string
-	}{LCASE, "CASE"},
-	struct {
-		lex  int
-		name string
-	}{LCHAN, "CHAN"},
-	struct {
-		lex  int
-		name string
-	}{LCOLAS, "COLAS"},
-	struct {
-		lex  int
-		name string
-	}{LCOMM, "<-"},
-	struct {
-		lex  int
-		name string
-	}{LCONST, "CONST"},
-	struct {
-		lex  int
-		name string
-	}{LCONTINUE, "CONTINUE"},
-	struct {
-		lex  int
-		name string
-	}{LDDD, "..."},
-	struct {
-		lex  int
-		name string
-	}{LDEC, "DEC"},
-	struct {
-		lex  int
-		name string
-	}{LDEFAULT, "DEFAULT"},
-	struct {
-		lex  int
-		name string
-	}{LDEFER, "DEFER"},
-	struct {
-		lex  int
-		name string
-	}{LELSE, "ELSE"},
-	struct {
-		lex  int
-		name string
-	}{LEQ, "EQ"},
-	struct {
-		lex  int
-		name string
-	}{LFALL, "FALL"},
-	struct {
-		lex  int
-		name string
-	}{LFOR, "FOR"},
-	struct {
-		lex  int
-		name string
-	}{LFUNC, "FUNC"},
-	struct {
-		lex  int
-		name string
-	}{LGE, "GE"},
-	struct {
-		lex  int
-		name string
-	}{LGO, "GO"},
-	struct {
-		lex  int
-		name string
-	}{LGOTO, "GOTO"},
-	struct {
-		lex  int
-		name string
-	}{LGT, "GT"},
-	struct {
-		lex  int
-		name string
-	}{LIF, "IF"},
-	struct {
-		lex  int
-		name string
-	}{LIMPORT, "IMPORT"},
-	struct {
-		lex  int
-		name string
-	}{LINC, "INC"},
-	struct {
-		lex  int
-		name string
-	}{LINTERFACE, "INTERFACE"},
-	struct {
-		lex  int
-		name string
-	}{LLE, "LE"},
-	struct {
-		lex  int
-		name string
-	}{LLITERAL, "LITERAL"},
-	struct {
-		lex  int
-		name string
-	}{LLSH, "LSH"},
-	struct {
-		lex  int
-		name string
-	}{LLT, "LT"},
-	struct {
-		lex  int
-		name string
-	}{LMAP, "MAP"},
-	struct {
-		lex  int
-		name string
-	}{LNAME, "NAME"},
-	struct {
-		lex  int
-		name string
-	}{LNE, "NE"},
-	struct {
-		lex  int
-		name string
-	}{LOROR, "OROR"},
-	struct {
-		lex  int
-		name string
-	}{LPACKAGE, "PACKAGE"},
-	struct {
-		lex  int
-		name string
-	}{LRANGE, "RANGE"},
-	struct {
-		lex  int
-		name string
-	}{LRETURN, "RETURN"},
-	struct {
-		lex  int
-		name string
-	}{LRSH, "RSH"},
-	struct {
-		lex  int
-		name string
-	}{LSELECT, "SELECT"},
-	struct {
-		lex  int
-		name string
-	}{LSTRUCT, "STRUCT"},
-	struct {
-		lex  int
-		name string
-	}{LSWITCH, "SWITCH"},
-	struct {
-		lex  int
-		name string
-	}{LTYPE, "TYPE"},
-	struct {
-		lex  int
-		name string
-	}{LVAR, "VAR"},
+	{LANDAND, "ANDAND"},
+	{LANDNOT, "ANDNOT"},
+	{LASOP, "ASOP"},
+	{LBREAK, "BREAK"},
+	{LCASE, "CASE"},
+	{LCHAN, "CHAN"},
+	{LCOLAS, "COLAS"},
+	{LCOMM, "<-"},
+	{LCONST, "CONST"},
+	{LCONTINUE, "CONTINUE"},
+	{LDDD, "..."},
+	{LDEC, "DEC"},
+	{LDEFAULT, "DEFAULT"},
+	{LDEFER, "DEFER"},
+	{LELSE, "ELSE"},
+	{LEQ, "EQ"},
+	{LFALL, "FALL"},
+	{LFOR, "FOR"},
+	{LFUNC, "FUNC"},
+	{LGE, "GE"},
+	{LGO, "GO"},
+	{LGOTO, "GOTO"},
+	{LGT, "GT"},
+	{LIF, "IF"},
+	{LIMPORT, "IMPORT"},
+	{LINC, "INC"},
+	{LINTERFACE, "INTERFACE"},
+	{LLE, "LE"},
+	{LLITERAL, "LITERAL"},
+	{LLSH, "LSH"},
+	{LLT, "LT"},
+	{LMAP, "MAP"},
+	{LNAME, "NAME"},
+	{LNE, "NE"},
+	{LOROR, "OROR"},
+	{LPACKAGE, "PACKAGE"},
+	{LRANGE, "RANGE"},
+	{LRETURN, "RETURN"},
+	{LRSH, "RSH"},
+	{LSELECT, "SELECT"},
+	{LSTRUCT, "STRUCT"},
+	{LSWITCH, "SWITCH"},
+	{LTYPE, "TYPE"},
+	{LVAR, "VAR"},
 }
 
-var lexname_buf string
-
 func lexname(lex int) string {
 	for i := 0; i < len(lexn); i++ {
 		if lexn[i].lex == lex {
 			return lexn[i].name
 		}
 	}
-	lexname_buf = fmt.Sprintf("LEX-%d", lex)
-	return lexname_buf
+	return fmt.Sprintf("LEX-%d", lex)
 }
 
 var yytfix = []struct {
 	have string
 	want string
 }{
-	struct {
-		have string
-		want string
-	}{"$end", "EOF"},
-	struct {
-		have string
-		want string
-	}{"LLITERAL", "literal"},
-	struct {
-		have string
-		want string
-	}{"LASOP", "op="},
-	struct {
-		have string
-		want string
-	}{"LBREAK", "break"},
-	struct {
-		have string
-		want string
-	}{"LCASE", "case"},
-	struct {
-		have string
-		want string
-	}{"LCHAN", "chan"},
-	struct {
-		have string
-		want string
-	}{"LCOLAS", ":="},
-	struct {
-		have string
-		want string
-	}{"LCONST", "const"},
-	struct {
-		have string
-		want string
-	}{"LCONTINUE", "continue"},
-	struct {
-		have string
-		want string
-	}{"LDDD", "..."},
-	struct {
-		have string
-		want string
-	}{"LDEFAULT", "default"},
-	struct {
-		have string
-		want string
-	}{"LDEFER", "defer"},
-	struct {
-		have string
-		want string
-	}{"LELSE", "else"},
-	struct {
-		have string
-		want string
-	}{"LFALL", "fallthrough"},
-	struct {
-		have string
-		want string
-	}{"LFOR", "for"},
-	struct {
-		have string
-		want string
-	}{"LFUNC", "func"},
-	struct {
-		have string
-		want string
-	}{"LGO", "go"},
-	struct {
-		have string
-		want string
-	}{"LGOTO", "goto"},
-	struct {
-		have string
-		want string
-	}{"LIF", "if"},
-	struct {
-		have string
-		want string
-	}{"LIMPORT", "import"},
-	struct {
-		have string
-		want string
-	}{"LINTERFACE", "interface"},
-	struct {
-		have string
-		want string
-	}{"LMAP", "map"},
-	struct {
-		have string
-		want string
-	}{"LNAME", "name"},
-	struct {
-		have string
-		want string
-	}{"LPACKAGE", "package"},
-	struct {
-		have string
-		want string
-	}{"LRANGE", "range"},
-	struct {
-		have string
-		want string
-	}{"LRETURN", "return"},
-	struct {
-		have string
-		want string
-	}{"LSELECT", "select"},
-	struct {
-		have string
-		want string
-	}{"LSTRUCT", "struct"},
-	struct {
-		have string
-		want string
-	}{"LSWITCH", "switch"},
-	struct {
-		have string
-		want string
-	}{"LTYPE", "type"},
-	struct {
-		have string
-		want string
-	}{"LVAR", "var"},
-	struct {
-		have string
-		want string
-	}{"LANDAND", "&&"},
-	struct {
-		have string
-		want string
-	}{"LANDNOT", "&^"},
-	struct {
-		have string
-		want string
-	}{"LBODY", "{"},
-	struct {
-		have string
-		want string
-	}{"LCOMM", "<-"},
-	struct {
-		have string
-		want string
-	}{"LDEC", "--"},
-	struct {
-		have string
-		want string
-	}{"LINC", "++"},
-	struct {
-		have string
-		want string
-	}{"LEQ", "=="},
-	struct {
-		have string
-		want string
-	}{"LGE", ">="},
-	struct {
-		have string
-		want string
-	}{"LGT", ">"},
-	struct {
-		have string
-		want string
-	}{"LLE", "<="},
-	struct {
-		have string
-		want string
-	}{"LLT", "<"},
-	struct {
-		have string
-		want string
-	}{"LLSH", "<<"},
-	struct {
-		have string
-		want string
-	}{"LRSH", ">>"},
-	struct {
-		have string
-		want string
-	}{"LOROR", "||"},
-	struct {
-		have string
-		want string
-	}{"LNE", "!="},
+	{"$end", "EOF"},
+	{"LASOP", "op="},
+	{"LBREAK", "break"},
+	{"LCASE", "case"},
+	{"LCHAN", "chan"},
+	{"LCOLAS", ":="},
+	{"LCONST", "const"},
+	{"LCONTINUE", "continue"},
+	{"LDDD", "..."},
+	{"LDEFAULT", "default"},
+	{"LDEFER", "defer"},
+	{"LELSE", "else"},
+	{"LFALL", "fallthrough"},
+	{"LFOR", "for"},
+	{"LFUNC", "func"},
+	{"LGO", "go"},
+	{"LGOTO", "goto"},
+	{"LIF", "if"},
+	{"LIMPORT", "import"},
+	{"LINTERFACE", "interface"},
+	{"LMAP", "map"},
+	{"LNAME", "name"},
+	{"LPACKAGE", "package"},
+	{"LRANGE", "range"},
+	{"LRETURN", "return"},
+	{"LSELECT", "select"},
+	{"LSTRUCT", "struct"},
+	{"LSWITCH", "switch"},
+	{"LTYPE", "type"},
+	{"LVAR", "var"},
+	{"LANDAND", "&&"},
+	{"LANDNOT", "&^"},
+	{"LBODY", "{"},
+	{"LCOMM", "<-"},
+	{"LDEC", "--"},
+	{"LINC", "++"},
+	{"LEQ", "=="},
+	{"LGE", ">="},
+	{"LGT", ">"},
+	{"LLE", "<="},
+	{"LLT", "<"},
+	{"LLSH", "<<"},
+	{"LRSH", ">>"},
+	{"LOROR", "||"},
+	{"LNE", "!="},
 	// spell out to avoid confusion with punctuation in error messages
-	struct {
-		have string
-		want string
-	}{"';'", "semicolon or newline"},
-	struct {
-		have string
-		want string
-	}{"','", "comma"},
+	{"';'", "semicolon or newline"},
+	{"','", "comma"},
+}
+
+func init() {
+	yyErrorVerbose = true
+
+Outer:
+	for i, s := range yyToknames {
+		// Apply yytfix if possible.
+		for _, fix := range yytfix {
+			if s == fix.have {
+				yyToknames[i] = fix.want
+				continue Outer
+			}
+		}
+
+		// Turn 'x' into x.
+		if len(s) == 3 && s[0] == '\'' && s[2] == '\'' {
+			yyToknames[i] = s[1:2]
+			continue
+		}
+	}
 }
 
 func pkgnotused(lineno int, path string, name string) {
diff --git a/src/cmd/internal/gc/mparith1.go b/src/cmd/internal/gc/mparith1.go
deleted file mode 100644
index 51d888a..0000000
--- a/src/cmd/internal/gc/mparith1.go
+++ /dev/null
@@ -1,683 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
-	"cmd/internal/obj"
-	"fmt"
-	"math"
-	"math/big"
-)
-
-/// uses arithmetic
-
-func mpcmpfixflt(a *Mpfix, b *Mpflt) int {
-	var c Mpflt
-
-	buf := _Bconv(a, 0)
-	mpatoflt(&c, buf)
-	return mpcmpfltflt(&c, b)
-}
-
-func mpcmpfltfix(a *Mpflt, b *Mpfix) int {
-	var c Mpflt
-
-	buf := _Bconv(b, 0)
-	mpatoflt(&c, buf)
-	return mpcmpfltflt(a, &c)
-}
-
-func Mpcmpfixfix(a, b *Mpint) int {
-	return a.Val.Cmp(&b.Val)
-}
-
-func mpcmpfixc(b *Mpint, c int64) int {
-	return b.Val.Cmp(big.NewInt(c))
-}
-
-func mpcmpfltflt(a *Mpflt, b *Mpflt) int {
-	var c Mpflt
-
-	mpmovefltflt(&c, a)
-	mpsubfltflt(&c, b)
-	return mptestflt(&c)
-}
-
-func mpcmpfltc(b *Mpflt, c float64) int {
-	var a Mpflt
-
-	Mpmovecflt(&a, c)
-	return mpcmpfltflt(b, &a)
-}
-
-func mpsubfixfix(a, b *Mpint) {
-	a.Val.Sub(&a.Val, &b.Val)
-}
-
-func _mpsubfixfix(a *Mpfix, b *Mpfix) {
-	_mpnegfix(a)
-	_mpaddfixfix(a, b, 0)
-	_mpnegfix(a)
-}
-
-func mpsubfltflt(a *Mpflt, b *Mpflt) {
-	mpnegflt(a)
-	mpaddfltflt(a, b)
-	mpnegflt(a)
-}
-
-func mpaddcfix(a *Mpfix, c int64) {
-	var b Mpfix
-
-	_Mpmovecfix(&b, c)
-	_mpaddfixfix(a, &b, 0)
-}
-
-func mpaddcflt(a *Mpflt, c float64) {
-	var b Mpflt
-
-	Mpmovecflt(&b, c)
-	mpaddfltflt(a, &b)
-}
-
-func mpmulcfix(a *Mpfix, c int64) {
-	var b Mpfix
-
-	_Mpmovecfix(&b, c)
-	_mpmulfixfix(a, &b)
-}
-
-func mpmulcflt(a *Mpflt, c float64) {
-	var b Mpflt
-
-	Mpmovecflt(&b, c)
-	mpmulfltflt(a, &b)
-}
-
-func mpdivfixfix(a, b *Mpint) {
-	a.Val.Quo(&a.Val, &b.Val)
-}
-
-func _mpdivfixfix(a *Mpfix, b *Mpfix) {
-	var q Mpfix
-	var r Mpfix
-
-	mpdivmodfixfix(&q, &r, a, b)
-	_mpmovefixfix(a, &q)
-}
-
-func mpmodfixfix(a, b *Mpint) {
-	a.Val.Rem(&a.Val, &b.Val)
-}
-
-func _mpmodfixfix(a *Mpfix, b *Mpfix) {
-	var q Mpfix
-	var r Mpfix
-
-	mpdivmodfixfix(&q, &r, a, b)
-	_mpmovefixfix(a, &r)
-}
-
-func mpcomfix(a *Mpfix) {
-	var b Mpfix
-
-	_Mpmovecfix(&b, 1)
-	_mpnegfix(a)
-	_mpsubfixfix(a, &b)
-}
-
-// *a = Mpfix(*b)
-func mpmoveintfix(a *Mpfix, b *Mpint) {
-	if b.Ovf {
-		_Mpmovecfix(a, 0)
-		a.Ovf = 1
-		return
-	}
-
-	var bb big.Int
-	bb.Abs(&b.Val)
-	i := 0
-	for ; i < Mpprec && bb.Sign() != 0; i++ {
-		// depends on (unspecified) behavior of Int.Uint64
-		a.A[i] = int(bb.Uint64() & Mpmask)
-		bb.Rsh(&bb, Mpscale)
-	}
-
-	if bb.Sign() != 0 {
-		// MPint overflows
-		_Mpmovecfix(a, 0)
-		a.Ovf = 1
-		return
-	}
-
-	for ; i < Mpprec; i++ {
-		a.A[i] = 0
-	}
-
-	a.Neg = 0
-	if b.Val.Sign() < 0 {
-		a.Neg = 1
-	}
-	a.Ovf = 0
-
-	// leave for debugging
-	// println("mpmoveintfix:", b.Val.String(), "->", _Bconv(a, 0))
-}
-
-// *a = big.Int(*b)
-func mpmovefixint(a *Mpint, b *Mpfix) {
-	if b.Ovf != 0 {
-		mpsetovf(a)
-		return
-	}
-
-	i := Mpprec - 1
-	for ; i >= 0 && b.A[i] == 0; i-- {
-	}
-
-	a.Val.SetUint64(0)
-	var x big.Int
-	for ; i >= 0; i-- {
-		a.Val.Lsh(&a.Val, Mpscale)
-		a.Val.Or(&a.Val, x.SetUint64(uint64(b.A[i]&Mpmask)))
-	}
-
-	if b.Neg != 0 {
-		a.Val.Neg(&a.Val)
-	}
-	a.Ovf = false
-
-	// leave for debugging
-	// println("mpmovefixint:", _Bconv(b, 0), "->", a.Val.String())
-}
-
-func Mpmovefixflt(a *Mpflt, b *Mpint) {
-	mpmoveintfix(&a.Val, b) // a.Val = *b
-	a.Exp = 0
-	mpnorm(a)
-}
-
-func _Mpmovefixflt(a *Mpflt, b *Mpfix) {
-	a.Val = *b
-	a.Exp = 0
-	mpnorm(a)
-}
-
-// convert (truncate) b to a.
-// return -1 (but still convert) if b was non-integer.
-func mpexactfltfix(a *Mpint, b *Mpflt) int {
-	mpmovefixint(a, &b.Val) // *a = b.Val
-	Mpshiftfix(a, int(b.Exp))
-	if b.Exp < 0 {
-		var f Mpflt
-		mpmoveintfix(&f.Val, a) // f.Val = *a
-		f.Exp = 0
-		mpnorm(&f)
-		if mpcmpfltflt(b, &f) != 0 {
-			return -1
-		}
-	}
-
-	return 0
-}
-
-func mpmovefltfix(a *Mpint, b *Mpflt) int {
-	if mpexactfltfix(a, b) == 0 {
-		return 0
-	}
-
-	// try rounding down a little
-	f := *b
-
-	f.Val.A[0] = 0
-	if mpexactfltfix(a, &f) == 0 {
-		return 0
-	}
-
-	// try rounding up a little
-	for i := 1; i < Mpprec; i++ {
-		f.Val.A[i]++
-		if f.Val.A[i] != Mpbase {
-			break
-		}
-		f.Val.A[i] = 0
-	}
-
-	mpnorm(&f)
-	if mpexactfltfix(a, &f) == 0 {
-		return 0
-	}
-
-	return -1
-}
-
-func mpmovefixfix(a, b *Mpint) {
-	a.Val.Set(&b.Val)
-}
-
-func _mpmovefixfix(a *Mpfix, b *Mpfix) {
-	*a = *b
-}
-
-func mpmovefltflt(a *Mpflt, b *Mpflt) {
-	*a = *b
-}
-
-var tab = []float64{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7}
-
-func mppow10flt(a *Mpflt, p int) {
-	if p < 0 {
-		panic("abort")
-	}
-	if p < len(tab) {
-		Mpmovecflt(a, tab[p])
-		return
-	}
-
-	mppow10flt(a, p>>1)
-	mpmulfltflt(a, a)
-	if p&1 != 0 {
-		mpmulcflt(a, 10)
-	}
-}
-
-func mphextofix(a *Mpfix, s string) {
-	for s != "" && s[0] == '0' {
-		s = s[1:]
-	}
-
-	// overflow
-	if 4*len(s) > Mpscale*Mpprec {
-		a.Ovf = 1
-		return
-	}
-
-	end := len(s) - 1
-	var c int8
-	var d int
-	var bit int
-	for hexdigitp := end; hexdigitp >= 0; hexdigitp-- {
-		c = int8(s[hexdigitp])
-		if c >= '0' && c <= '9' {
-			d = int(c) - '0'
-		} else if c >= 'A' && c <= 'F' {
-			d = int(c) - 'A' + 10
-		} else {
-			d = int(c) - 'a' + 10
-		}
-
-		bit = 4 * (end - hexdigitp)
-		for d > 0 {
-			if d&1 != 0 {
-				a.A[bit/Mpscale] |= int(1) << uint(bit%Mpscale)
-			}
-			bit++
-			d = d >> 1
-		}
-	}
-}
-
-//
-// floating point input
-// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
-//
-func mpatoflt(a *Mpflt, as string) {
-	for as[0] == ' ' || as[0] == '\t' {
-		as = as[1:]
-	}
-
-	/* determine base */
-	s := as
-
-	base := -1
-	for base == -1 {
-		if s == "" {
-			base = 10
-			break
-		}
-		c := s[0]
-		s = s[1:]
-		switch c {
-		case '-', '+':
-			break
-
-		case '0':
-			if s != "" && s[0] == 'x' {
-				base = 16
-			} else {
-				base = 10
-			}
-
-		default:
-			base = 10
-		}
-	}
-
-	s = as
-	dp := 0 /* digits after decimal point */
-	f := 0  /* sign */
-	ex := 0 /* exponent */
-	eb := 0 /* binary point */
-
-	Mpmovecflt(a, 0.0)
-	var ef int
-	var c int
-	if base == 16 {
-		start := ""
-		var c int
-		for {
-			c, _ = intstarstringplusplus(s)
-			if c == '-' {
-				f = 1
-				s = s[1:]
-			} else if c == '+' {
-				s = s[1:]
-			} else if c == '0' && s[1] == 'x' {
-				s = s[2:]
-				start = s
-			} else if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') {
-				s = s[1:]
-			} else {
-				break
-			}
-		}
-
-		if start == "" {
-			Yyerror("malformed hex constant: %s", as)
-			goto bad
-		}
-
-		mphextofix(&a.Val, start[:len(start)-len(s)])
-		if a.Val.Ovf != 0 {
-			Yyerror("constant too large: %s", as)
-			goto bad
-		}
-
-		a.Exp = 0
-		mpnorm(a)
-	}
-
-	for {
-		c, s = intstarstringplusplus(s)
-		switch c {
-		default:
-			Yyerror("malformed constant: %s (at %c)", as, c)
-			goto bad
-
-		case '-':
-			f = 1
-			fallthrough
-
-		case ' ', '\t', '+':
-			continue
-
-		case '.':
-			if base == 16 {
-				Yyerror("decimal point in hex constant: %s", as)
-				goto bad
-			}
-
-			dp = 1
-			continue
-
-		case '1',
-			'2',
-			'3',
-			'4',
-			'5',
-			'6',
-			'7',
-			'8',
-			'9',
-			'0':
-			mpmulcflt(a, 10)
-			mpaddcflt(a, float64(c)-'0')
-			if dp != 0 {
-				dp++
-			}
-			continue
-
-		case 'P', 'p':
-			eb = 1
-			fallthrough
-
-		case 'E', 'e':
-			ex = 0
-			ef = 0
-			for {
-				c, s = intstarstringplusplus(s)
-				if c == '+' || c == ' ' || c == '\t' {
-					continue
-				}
-				if c == '-' {
-					ef = 1
-					continue
-				}
-
-				if c >= '0' && c <= '9' {
-					ex = ex*10 + (c - '0')
-					if ex > 1e8 {
-						Yyerror("constant exponent out of range: %s", as)
-						errorexit()
-					}
-
-					continue
-				}
-
-				break
-			}
-
-			if ef != 0 {
-				ex = -ex
-			}
-			fallthrough
-
-		case 0:
-			break
-		}
-
-		break
-	}
-
-	if eb != 0 {
-		if dp != 0 {
-			Yyerror("decimal point and binary point in constant: %s", as)
-			goto bad
-		}
-
-		mpsetexp(a, int(a.Exp)+ex)
-		goto out
-	}
-
-	if dp != 0 {
-		dp--
-	}
-	if mpcmpfltc(a, 0.0) != 0 {
-		if ex >= dp {
-			var b Mpflt
-			mppow10flt(&b, ex-dp)
-			mpmulfltflt(a, &b)
-		} else {
-			// 4 approximates least_upper_bound(log2(10)).
-			if dp-ex >= 1<<(32-3) || int(int16(4*(dp-ex))) != 4*(dp-ex) {
-				Mpmovecflt(a, 0.0)
-			} else {
-				var b Mpflt
-				mppow10flt(&b, dp-ex)
-				mpdivfltflt(a, &b)
-			}
-		}
-	}
-
-out:
-	if f != 0 {
-		mpnegflt(a)
-	}
-	return
-
-bad:
-	Mpmovecflt(a, 0.0)
-}
-
-func mpatofix(a *Mpint, as string) {
-	_, ok := a.Val.SetString(as, 0)
-	if !ok {
-		// required syntax is [+-][0[x]]d*
-		// At the moment we lose precise error cause;
-		// the old code distinguished between:
-		// - malformed hex constant
-		// - malformed octal constant
-		// - malformed decimal constant
-		// TODO(gri) use different conversion function
-		Yyerror("malformed integer constant: %s", as)
-		a.Val.SetUint64(0)
-		return
-	}
-	if mptestovf(a, 0) {
-		Yyerror("constant too large: %s", as)
-	}
-}
-
-func Bconv(xval *Mpint, flag int) string {
-	if flag&obj.FmtSharp != 0 {
-		return fmt.Sprintf("%#x", &xval.Val)
-	}
-	return xval.Val.String()
-}
-
-func _Bconv(xval *Mpfix, flag int) string {
-	var q Mpfix
-
-	_mpmovefixfix(&q, xval)
-	f := 0
-	if mptestfix(&q) < 0 {
-		f = 1
-		_mpnegfix(&q)
-	}
-
-	var buf [500]byte
-	p := len(buf)
-	var r Mpfix
-	if flag&obj.FmtSharp != 0 /*untyped*/ {
-		// Hexadecimal
-		var sixteen Mpfix
-		_Mpmovecfix(&sixteen, 16)
-
-		var digit int
-		for {
-			mpdivmodfixfix(&q, &r, &q, &sixteen)
-			digit = int(_Mpgetfix(&r))
-			if digit < 10 {
-				p--
-				buf[p] = byte(digit + '0')
-			} else {
-				p--
-				buf[p] = byte(digit - 10 + 'A')
-			}
-			if mptestfix(&q) <= 0 {
-				break
-			}
-		}
-
-		p--
-		buf[p] = 'x'
-		p--
-		buf[p] = '0'
-	} else {
-		// Decimal
-		var ten Mpfix
-		_Mpmovecfix(&ten, 10)
-
-		for {
-			mpdivmodfixfix(&q, &r, &q, &ten)
-			p--
-			buf[p] = byte(_Mpgetfix(&r) + '0')
-			if mptestfix(&q) <= 0 {
-				break
-			}
-		}
-	}
-
-	if f != 0 {
-		p--
-		buf[p] = '-'
-	}
-
-	return string(buf[p:])
-}
-
-func Fconv(fvp *Mpflt, flag int) string {
-	if flag&obj.FmtSharp != 0 /*untyped*/ {
-		// alternate form - decimal for error messages.
-		// for well in range, convert to double and use print's %g
-		exp := int(fvp.Exp) + sigfig(fvp)*Mpscale
-
-		var fp string
-		if -900 < exp && exp < 900 {
-			d := mpgetflt(fvp)
-			if d >= 0 && (flag&obj.FmtSign != 0 /*untyped*/) {
-				fp += "+"
-			}
-			fp += fmt.Sprintf("%.6g", d)
-			return fp
-		}
-
-		// very out of range. compute decimal approximation by hand.
-		// decimal exponent
-		dexp := float64(fvp.Exp) * 0.301029995663981195 // log_10(2)
-		exp = int(dexp)
-
-		// decimal mantissa
-		fv := *fvp
-
-		fv.Val.Neg = 0
-		fv.Exp = 0
-		d := mpgetflt(&fv)
-		d *= math.Pow(10, dexp-float64(exp))
-		for d >= 9.99995 {
-			d /= 10
-			exp++
-		}
-
-		if fvp.Val.Neg != 0 {
-			fp += "-"
-		} else if flag&obj.FmtSign != 0 /*untyped*/ {
-			fp += "+"
-		}
-		fp += fmt.Sprintf("%.5fe+%d", d, exp)
-		return fp
-	}
-
-	var fv Mpflt
-	var buf string
-	if sigfig(fvp) == 0 {
-		buf = "0p+0"
-		goto out
-	}
-
-	fv = *fvp
-
-	for fv.Val.A[0] == 0 {
-		_Mpshiftfix(&fv.Val, -Mpscale)
-		fv.Exp += Mpscale
-	}
-
-	for fv.Val.A[0]&1 == 0 {
-		_Mpshiftfix(&fv.Val, -1)
-		fv.Exp += 1
-	}
-
-	if fv.Exp >= 0 {
-		buf = fmt.Sprintf("%vp+%d", _Bconv(&fv.Val, obj.FmtSharp), fv.Exp)
-		goto out
-	}
-
-	buf = fmt.Sprintf("%vp-%d", _Bconv(&fv.Val, obj.FmtSharp), -fv.Exp)
-
-out:
-	var fp string
-	fp += buf
-	return fp
-}
diff --git a/src/cmd/internal/gc/mparith2.go b/src/cmd/internal/gc/mparith2.go
index 80253dd..de96e97 100644
--- a/src/cmd/internal/gc/mparith2.go
+++ b/src/cmd/internal/gc/mparith2.go
@@ -4,189 +4,11 @@
 
 package gc
 
-//
-// return the significant
-// words of the argument
-//
-func mplen(a *Mpfix) int {
-	n := -1
-	for i := 0; i < Mpprec; i++ {
-		if a.A[i] != 0 {
-			n = i
-		}
-	}
-
-	return n + 1
-}
-
-//
-// left shift mpint by one
-// ignores sign
-//
-func mplsh(a *Mpfix, quiet int) {
-	var x int
-
-	c := 0
-	for i := 0; i < Mpprec; i++ {
-		x = (a.A[i] << 1) + c
-		c = 0
-		if x >= Mpbase {
-			x -= Mpbase
-			c = 1
-		}
-
-		a.A[i] = x
-	}
-
-	a.Ovf = uint8(c)
-	if a.Ovf != 0 && quiet == 0 {
-		Yyerror("constant shift overflow")
-	}
-}
-
-//
-// left shift mpint by Mpscale
-// ignores sign
-//
-func mplshw(a *Mpfix, quiet int) {
-	i := Mpprec - 1
-	if a.A[i] != 0 {
-		a.Ovf = 1
-		if quiet == 0 {
-			Yyerror("constant shift overflow")
-		}
-	}
-
-	for ; i > 0; i-- {
-		a.A[i] = a.A[i-1]
-	}
-	a.A[i] = 0
-}
-
-//
-// right shift mpint by one
-// ignores sign and overflow
-//
-func mprsh(a *Mpfix) {
-	var x int
-
-	c := 0
-	lo := a.A[0] & 1
-	for i := Mpprec - 1; i >= 0; i-- {
-		x = a.A[i]
-		a.A[i] = (x + c) >> 1
-		c = 0
-		if x&1 != 0 {
-			c = Mpbase
-		}
-	}
-
-	if a.Neg != 0 && lo != 0 {
-		mpaddcfix(a, -1)
-	}
-}
-
-//
-// right shift mpint by Mpscale
-// ignores sign and overflow
-//
-func mprshw(a *Mpfix) {
-	var i int
-
-	lo := a.A[0]
-	for i = 0; i < Mpprec-1; i++ {
-		a.A[i] = a.A[i+1]
-	}
-
-	a.A[i] = 0
-	if a.Neg != 0 && lo != 0 {
-		mpaddcfix(a, -1)
-	}
-}
-
-//
-// return the sign of (abs(a)-abs(b))
-//
-func mpcmp(a *Mpfix, b *Mpfix) int {
-	if a.Ovf != 0 || b.Ovf != 0 {
-		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in cmp")
-		}
-		return 0
-	}
-
-	var x int
-	for i := Mpprec - 1; i >= 0; i-- {
-		x = a.A[i] - b.A[i]
-		if x > 0 {
-			return +1
-		}
-		if x < 0 {
-			return -1
-		}
-	}
-
-	return 0
-}
-
-//
-// negate a
-// ignore sign and ovf
-//
-func mpneg(a *Mpfix) {
-	var x int
-
-	c := 0
-	for i := 0; i < Mpprec; i++ {
-		x = -a.A[i] - c
-		c = 0
-		if x < 0 {
-			x += Mpbase
-			c = 1
-		}
-
-		a.A[i] = x
-	}
-}
-
-func Mpshiftfix(a *Mpint, s int) {
-	switch {
-	case s > 0:
-		if mptestovf(a, s) {
-			Yyerror("constant shift overflow")
-			return
-		}
-		a.Val.Lsh(&a.Val, uint(s))
-	case s < 0:
-		a.Val.Rsh(&a.Val, uint(-s))
-	}
-}
-
-// shift left by s (or right by -s)
-func _Mpshiftfix(a *Mpfix, s int) {
-	if s >= 0 {
-		for s >= Mpscale {
-			mplshw(a, 0)
-			s -= Mpscale
-		}
-
-		for s > 0 {
-			mplsh(a, 0)
-			s--
-		}
-	} else {
-		s = -s
-		for s >= Mpscale {
-			mprshw(a)
-			s -= Mpscale
-		}
-
-		for s > 0 {
-			mprsh(a)
-			s--
-		}
-	}
-}
+import (
+	"cmd/internal/gc/big"
+	"cmd/internal/obj"
+	"fmt"
+)
 
 /// implements fix arithmetic
 
@@ -198,17 +20,46 @@
 func mptestovf(a *Mpint, extra int) bool {
 	// We don't need to be precise here, any reasonable upper limit would do.
 	// For now, use existing limit so we pass all the tests unchanged.
-	const limit = Mpscale * Mpprec
-	if a.Val.BitLen()+extra > limit {
+	if a.Val.BitLen()+extra > Mpprec {
 		mpsetovf(a)
 	}
 	return a.Ovf
 }
 
+func mpmovefixfix(a, b *Mpint) {
+	a.Val.Set(&b.Val)
+}
+
+func mpmovefltfix(a *Mpint, b *Mpflt) int {
+	if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
+		return 0
+	}
+
+	const delta = 16 // a reasonably small number of bits > 0
+	var t big.Float
+	t.SetPrec(Mpprec - delta)
+
+	// try rounding down a little
+	t.SetMode(big.ToZero)
+	t.Set(&b.Val)
+	if _, acc := t.Int(&a.Val); acc == big.Exact {
+		return 0
+	}
+
+	// try rounding up a little
+	t.SetMode(big.AwayFromZero)
+	t.Set(&b.Val)
+	if _, acc := t.Int(&a.Val); acc == big.Exact {
+		return 0
+	}
+
+	return -1
+}
+
 func mpaddfixfix(a, b *Mpint, quiet int) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in mpaddxx")
+			Yyerror("ovf in mpaddfixfix")
 		}
 		mpsetovf(a)
 		return
@@ -221,71 +72,20 @@
 	}
 }
 
-func _mpaddfixfix(a *Mpfix, b *Mpfix, quiet int) {
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mpsubfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in mpaddxx")
+			Yyerror("ovf in mpsubfixfix")
 		}
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	c := 0
-	if a.Neg != b.Neg {
-		// perform a-b
-		switch mpcmp(a, b) {
-		case 0:
-			_Mpmovecfix(a, 0)
+	a.Val.Sub(&a.Val, &b.Val)
 
-		case 1:
-			var x int
-			for i := 0; i < Mpprec; i++ {
-				x = a.A[i] - b.A[i] - c
-				c = 0
-				if x < 0 {
-					x += Mpbase
-					c = 1
-				}
-
-				a.A[i] = x
-			}
-
-		case -1:
-			a.Neg ^= 1
-			var x int
-			for i := 0; i < Mpprec; i++ {
-				x = b.A[i] - a.A[i] - c
-				c = 0
-				if x < 0 {
-					x += Mpbase
-					c = 1
-				}
-
-				a.A[i] = x
-			}
-		}
-		return
+	if mptestovf(a, 0) {
+		Yyerror("constant subtraction overflow")
 	}
-
-	// perform a+b
-	var x int
-	for i := 0; i < Mpprec; i++ {
-		x = a.A[i] + b.A[i] + c
-		c = 0
-		if x >= Mpbase {
-			x -= Mpbase
-			c = 1
-		}
-
-		a.A[i] = x
-	}
-
-	a.Ovf = uint8(c)
-	if a.Ovf != 0 && quiet == 0 {
-		Yyerror("constant addition overflow")
-	}
-
-	return
 }
 
 func mpmulfixfix(a, b *Mpint) {
@@ -304,107 +104,37 @@
 	}
 }
 
-func _mpmulfixfix(a *Mpfix, b *Mpfix) {
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mpdivfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in mpmulfixfix")
+			Yyerror("ovf in mpdivfixfix")
 		}
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	// pick the smaller
-	// to test for bits
-	na := mplen(a)
+	a.Val.Quo(&a.Val, &b.Val)
 
-	nb := mplen(b)
-	var s Mpfix
-	var c *Mpfix
-	if na > nb {
-		_mpmovefixfix(&s, a)
-		c = b
-		na = nb
-	} else {
-		_mpmovefixfix(&s, b)
-		c = a
-	}
-
-	s.Neg = 0
-
-	var q Mpfix
-	_Mpmovecfix(&q, 0)
-	var j int
-	var x int
-	for i := 0; i < na; i++ {
-		x = c.A[i]
-		for j = 0; j < Mpscale; j++ {
-			if x&1 != 0 {
-				if s.Ovf != 0 {
-					q.Ovf = 1
-					goto out
-				}
-
-				_mpaddfixfix(&q, &s, 1)
-				if q.Ovf != 0 {
-					goto out
-				}
-			}
-
-			mplsh(&s, 1)
-			x >>= 1
-		}
-	}
-
-out:
-	q.Neg = a.Neg ^ b.Neg
-	_mpmovefixfix(a, &q)
-	if a.Ovf != 0 {
-		Yyerror("constant multiplication overflow")
+	if mptestovf(a, 0) {
+		// can only happen for div-0 which should be checked elsewhere
+		Yyerror("constant division overflow")
 	}
 }
 
-func mpmulfract(a *Mpfix, b *Mpfix) {
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mpmodfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in mpmulflt")
+			Yyerror("ovf in mpmodfixfix")
 		}
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	var s Mpfix
-	_mpmovefixfix(&s, b)
-	s.Neg = 0
-	var q Mpfix
-	_Mpmovecfix(&q, 0)
+	a.Val.Rem(&a.Val, &b.Val)
 
-	i := Mpprec - 1
-	x := a.A[i]
-	if x != 0 {
-		Yyerror("mpmulfract not normal")
-	}
-
-	var j int
-	for i--; i >= 0; i-- {
-		x = a.A[i]
-		if x == 0 {
-			mprshw(&s)
-			continue
-		}
-
-		for j = 0; j < Mpscale; j++ {
-			x <<= 1
-			if x&Mpbase != 0 {
-				_mpaddfixfix(&q, &s, 1)
-			}
-			mprsh(&s)
-		}
-	}
-
-	q.Neg = a.Neg ^ b.Neg
-	_mpmovefixfix(a, &q)
-	if a.Ovf != 0 {
-		Yyerror("constant multiplication overflow")
+	if mptestovf(a, 0) {
+		// should never happen
+		Yyerror("constant modulo overflow")
 	}
 }
 
@@ -456,6 +186,20 @@
 	a.Val.Xor(&a.Val, &b.Val)
 }
 
+// shift left by s (or right by -s)
+func Mpshiftfix(a *Mpint, s int) {
+	switch {
+	case s > 0:
+		if mptestovf(a, s) {
+			Yyerror("constant shift overflow")
+			return
+		}
+		a.Val.Lsh(&a.Val, uint(s))
+	case s < 0:
+		a.Val.Rsh(&a.Val, uint(-s))
+	}
+}
+
 func mplshfixfix(a, b *Mpint) {
 	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
@@ -466,7 +210,7 @@
 	}
 
 	s := Mpgetfix(b)
-	if s < 0 || s >= Mpprec*Mpscale {
+	if s < 0 || s >= Mpprec {
 		Yyerror("stupid shift: %d", s)
 		Mpmovecfix(a, 0)
 		return
@@ -485,7 +229,7 @@
 	}
 
 	s := Mpgetfix(b)
-	if s < 0 || s >= Mpprec*Mpscale {
+	if s < 0 || s >= Mpprec {
 		Yyerror("stupid shift: %d", s)
 		if a.Val.Sign() < 0 {
 			Mpmovecfix(a, -1)
@@ -498,12 +242,16 @@
 	Mpshiftfix(a, int(-s))
 }
 
-func mpnegfix(a *Mpint) {
-	a.Val.Neg(&a.Val)
+func Mpcmpfixfix(a, b *Mpint) int {
+	return a.Val.Cmp(&b.Val)
 }
 
-func _mpnegfix(a *Mpfix) {
-	a.Neg ^= 1
+func mpcmpfixc(b *Mpint, c int64) int {
+	return b.Val.Cmp(big.NewInt(c))
+}
+
+func mpnegfix(a *Mpint) {
+	a.Val.Neg(&a.Val)
 }
 
 func Mpgetfix(a *Mpint) int64 {
@@ -517,148 +265,36 @@
 	return a.Val.Int64()
 }
 
-func _Mpgetfix(a *Mpfix) int64 {
-	if a.Ovf != 0 {
-		if nsavederrors+nerrors == 0 {
-			Yyerror("constant overflow")
-		}
-		return 0
-	}
-
-	v := int64(uint64(a.A[0]))
-	v |= int64(uint64(a.A[1]) << Mpscale)
-	v |= int64(uint64(a.A[2]) << (Mpscale + Mpscale))
-	if a.Neg != 0 {
-		v = int64(-uint64(v))
-	}
-	return v
-}
-
 func Mpmovecfix(a *Mpint, c int64) {
 	a.Val.SetInt64(c)
 }
 
-func _Mpmovecfix(a *Mpfix, c int64) {
-	a.Neg = 0
-	a.Ovf = 0
-
-	x := c
-	if x < 0 {
-		a.Neg = 1
-		x = int64(-uint64(x))
-	}
-
-	for i := 0; i < Mpprec; i++ {
-		a.A[i] = int(x & Mpmask)
-		x >>= Mpscale
-	}
-}
-
-func mpdivmodfixfix(q *Mpfix, r *Mpfix, n *Mpfix, d *Mpfix) {
-	var i int
-
-	ns := int(n.Neg)
-	ds := int(d.Neg)
-	n.Neg = 0
-	d.Neg = 0
-
-	_mpmovefixfix(r, n)
-	_Mpmovecfix(q, 0)
-
-	// shift denominator until it
-	// is larger than numerator
-	for i = 0; i < Mpprec*Mpscale; i++ {
-		if mpcmp(d, r) > 0 {
-			break
-		}
-		mplsh(d, 1)
-	}
-
-	// if it never happens
-	// denominator is probably zero
-	if i >= Mpprec*Mpscale {
-		q.Ovf = 1
-		r.Ovf = 1
-		n.Neg = uint8(ns)
-		d.Neg = uint8(ds)
-		Yyerror("constant division overflow")
+func mpatofix(a *Mpint, as string) {
+	_, ok := a.Val.SetString(as, 0)
+	if !ok {
+		// required syntax is [+-][0[x]]d*
+		// At the moment we lose precise error cause;
+		// the old code distinguished between:
+		// - malformed hex constant
+		// - malformed octal constant
+		// - malformed decimal constant
+		// TODO(gri) use different conversion function
+		Yyerror("malformed integer constant: %s", as)
+		a.Val.SetUint64(0)
 		return
 	}
-
-	// shift denominator back creating
-	// quotient a bit at a time
-	// when done the remaining numerator
-	// will be the remainder
-	for ; i > 0; i-- {
-		mplsh(q, 1)
-		mprsh(d)
-		if mpcmp(d, r) <= 0 {
-			mpaddcfix(q, 1)
-			_mpsubfixfix(r, d)
-		}
+	if mptestovf(a, 0) {
+		Yyerror("constant too large: %s", as)
 	}
-
-	n.Neg = uint8(ns)
-	d.Neg = uint8(ds)
-	r.Neg = uint8(ns)
-	q.Neg = uint8(ns ^ ds)
 }
 
-func mpiszero(a *Mpfix) bool {
-	for i := Mpprec - 1; i >= 0; i-- {
-		if a.A[i] != 0 {
-			return false
-		}
-	}
-	return true
+func (x *Mpint) String() string {
+	return Bconv(x, 0)
 }
 
-func mpdivfract(a *Mpfix, b *Mpfix) {
-	var n Mpfix
-	var d Mpfix
-	var j int
-	var x int
-
-	_mpmovefixfix(&n, a) // numerator
-	_mpmovefixfix(&d, b) // denominator
-
-	neg := int(n.Neg) ^ int(d.Neg)
-
-	n.Neg = 0
-	d.Neg = 0
-	for i := Mpprec - 1; i >= 0; i-- {
-		x = 0
-		for j = 0; j < Mpscale; j++ {
-			x <<= 1
-			if mpcmp(&d, &n) <= 0 {
-				if !mpiszero(&d) {
-					x |= 1
-				}
-				_mpsubfixfix(&n, &d)
-			}
-
-			mprsh(&d)
-		}
-
-		a.A[i] = x
+func Bconv(xval *Mpint, flag int) string {
+	if flag&obj.FmtSharp != 0 {
+		return fmt.Sprintf("%#x", &xval.Val)
 	}
-
-	a.Neg = uint8(neg)
-}
-
-func mptestfix(a *Mpfix) int {
-	var b Mpfix
-
-	_Mpmovecfix(&b, 0)
-	r := mpcmp(a, &b)
-	if a.Neg != 0 {
-		if r > 0 {
-			return -1
-		}
-		if r < 0 {
-			return +1
-		}
-	}
-
-	return r
+	return xval.Val.String()
 }
diff --git a/src/cmd/internal/gc/mparith3.go b/src/cmd/internal/gc/mparith3.go
index 57263a0..2700b64 100644
--- a/src/cmd/internal/gc/mparith3.go
+++ b/src/cmd/internal/gc/mparith3.go
@@ -5,285 +5,131 @@
 package gc
 
 import (
+	"cmd/internal/gc/big"
+	"cmd/internal/obj"
 	"fmt"
 	"math"
 )
 
-/*
- * returns the leading non-zero
- * word of the number
- */
-func sigfig(a *Mpflt) int {
-	var i int
-
-	for i = Mpprec - 1; i >= 0; i-- {
-		if a.Val.A[i] != 0 {
-			break
-		}
-	}
-
-	//print("sigfig %d %d\n", i-z+1, z);
-	return i + 1
-}
-
-/*
- * sets the exponent.
- * a too large exponent is an error.
- * a too small exponent rounds the number to zero.
- */
-func mpsetexp(a *Mpflt, exp int) {
-	if int(int16(exp)) != exp {
-		if exp > 0 {
-			Yyerror("float constant is too large")
-			a.Exp = 0x7fff
-		} else {
-			Mpmovecflt(a, 0)
-		}
-	} else {
-		a.Exp = int16(exp)
-	}
-}
-
-/*
- * shifts the leading non-zero
- * word of the number to Mpnorm
- */
-func mpnorm(a *Mpflt) {
-	os := sigfig(a)
-	if os == 0 {
-		// zero
-		a.Exp = 0
-
-		a.Val.Neg = 0
-		return
-	}
-
-	// this will normalize to the nearest word
-	x := a.Val.A[os-1]
-
-	s := (Mpnorm - os) * Mpscale
-
-	// further normalize to the nearest bit
-	for {
-		x <<= 1
-		if x&Mpbase != 0 {
-			break
-		}
-		s++
-		if x == 0 {
-			// this error comes from trying to
-			// convert an Inf or something
-			// where the initial x=0x80000000
-			s = (Mpnorm - os) * Mpscale
-
-			break
-		}
-	}
-
-	_Mpshiftfix(&a.Val, s)
-	mpsetexp(a, int(a.Exp)-s)
-}
-
 /// implements float arihmetic
 
+func newMpflt() *Mpflt {
+	var a Mpflt
+	a.Val.SetPrec(Mpprec)
+	return &a
+}
+
+func Mpmovefixflt(a *Mpflt, b *Mpint) {
+	if b.Ovf {
+		// sign doesn't really matter but copy anyway
+		a.Val.SetInf(b.Val.Sign() < 0)
+		return
+	}
+	a.Val.SetInt(&b.Val)
+}
+
+func mpmovefltflt(a *Mpflt, b *Mpflt) {
+	a.Val.Set(&b.Val)
+}
+
 func mpaddfltflt(a *Mpflt, b *Mpflt) {
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf("\n%v + %v", Fconv(a, 0), Fconv(b, 0))
+	if Mpdebug {
+		fmt.Printf("\n%v + %v", a, b)
 	}
 
-	sa := sigfig(a)
-	var s int
-	var sb int
-	if sa == 0 {
-		mpmovefltflt(a, b)
-		goto out
+	a.Val.Add(&a.Val, &b.Val)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
+	}
+}
+
+func mpaddcflt(a *Mpflt, c float64) {
+	var b Mpflt
+
+	Mpmovecflt(&b, c)
+	mpaddfltflt(a, &b)
+}
+
+func mpsubfltflt(a *Mpflt, b *Mpflt) {
+	if Mpdebug {
+		fmt.Printf("\n%v - %v", a, b)
 	}
 
-	sb = sigfig(b)
-	if sb == 0 {
-		goto out
-	}
+	a.Val.Sub(&a.Val, &b.Val)
 
-	s = int(a.Exp) - int(b.Exp)
-	if s > 0 {
-		// a is larger, shift b right
-		var c Mpflt
-		mpmovefltflt(&c, b)
-
-		_Mpshiftfix(&c.Val, -s)
-		_mpaddfixfix(&a.Val, &c.Val, 0)
-		goto out
-	}
-
-	if s < 0 {
-		// b is larger, shift a right
-		_Mpshiftfix(&a.Val, s)
-
-		mpsetexp(a, int(a.Exp)-s)
-		_mpaddfixfix(&a.Val, &b.Val, 0)
-		goto out
-	}
-
-	_mpaddfixfix(&a.Val, &b.Val, 0)
-
-out:
-	mpnorm(a)
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf(" = %v\n\n", Fconv(a, 0))
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
 	}
 }
 
 func mpmulfltflt(a *Mpflt, b *Mpflt) {
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf("%v\n * %v\n", Fconv(a, 0), Fconv(b, 0))
+	if Mpdebug {
+		fmt.Printf("%v\n * %v\n", a, b)
 	}
 
-	sa := sigfig(a)
-	if sa == 0 {
-		// zero
-		a.Exp = 0
+	a.Val.Mul(&a.Val, &b.Val)
 
-		a.Val.Neg = 0
-		return
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
 	}
+}
 
-	sb := sigfig(b)
-	if sb == 0 {
-		// zero
-		mpmovefltflt(a, b)
+func mpmulcflt(a *Mpflt, c float64) {
+	var b Mpflt
 
-		return
-	}
-
-	mpmulfract(&a.Val, &b.Val)
-	mpsetexp(a, (int(a.Exp)+int(b.Exp))+Mpscale*Mpprec-Mpscale-1)
-
-	mpnorm(a)
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf(" = %v\n\n", Fconv(a, 0))
-	}
+	Mpmovecflt(&b, c)
+	mpmulfltflt(a, &b)
 }
 
 func mpdivfltflt(a *Mpflt, b *Mpflt) {
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf("%v\n / %v\n", Fconv(a, 0), Fconv(b, 0))
+	if Mpdebug {
+		fmt.Printf("%v\n / %v\n", a, b)
 	}
 
-	sb := sigfig(b)
-	if sb == 0 {
-		// zero and ovfl
-		a.Exp = 0
+	a.Val.Quo(&a.Val, &b.Val)
 
-		a.Val.Neg = 0
-		a.Val.Ovf = 1
-		Yyerror("constant division by zero")
-		return
-	}
-
-	sa := sigfig(a)
-	if sa == 0 {
-		// zero
-		a.Exp = 0
-
-		a.Val.Neg = 0
-		return
-	}
-
-	// adjust b to top
-	var c Mpflt
-	mpmovefltflt(&c, b)
-
-	_Mpshiftfix(&c.Val, Mpscale)
-
-	// divide
-	mpdivfract(&a.Val, &c.Val)
-
-	mpsetexp(a, (int(a.Exp)-int(c.Exp))-Mpscale*(Mpprec-1)+1)
-
-	mpnorm(a)
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf(" = %v\n\n", Fconv(a, 0))
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
 	}
 }
 
+func mpcmpfltflt(a *Mpflt, b *Mpflt) int {
+	return a.Val.Cmp(&b.Val)
+}
+
+func mpcmpfltc(b *Mpflt, c float64) int {
+	var a Mpflt
+
+	Mpmovecflt(&a, c)
+	return mpcmpfltflt(b, &a)
+}
+
 func mpgetfltN(a *Mpflt, prec int, bias int) float64 {
-	if a.Val.Ovf != 0 && nsavederrors+nerrors == 0 {
+	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")
+	}
+
+	// check for overflow
+	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
 		Yyerror("mpgetflt ovf")
 	}
 
-	s := sigfig(a)
-	if s == 0 {
-		return 0
-	}
-
-	if s != Mpnorm {
-		Yyerror("mpgetflt norm")
-		mpnorm(a)
-	}
-
-	for a.Val.A[Mpnorm-1]&Mpsign == 0 {
-		_Mpshiftfix(&a.Val, 1)
-		mpsetexp(a, int(a.Exp)-1) // can set 'a' to zero
-		s = sigfig(a)
-		if s == 0 {
-			return 0
-		}
-	}
-
-	// pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
-	s = prec + 2
-
-	v := uint64(0)
-	var i int
-	for i = Mpnorm - 1; s >= Mpscale; i-- {
-		v = v<<Mpscale | uint64(a.Val.A[i])
-		s -= Mpscale
-	}
-
-	if s > 0 {
-		v = v<<uint(s) | uint64(a.Val.A[i])>>uint(Mpscale-s)
-		if a.Val.A[i]&((1<<uint(Mpscale-s))-1) != 0 {
-			v |= 1
-		}
-		i--
-	}
-
-	for ; i >= 0; i-- {
-		if a.Val.A[i] != 0 {
-			v |= 1
-		}
-	}
-
-	// gradual underflow
-	e := Mpnorm*Mpscale + int(a.Exp) - prec
-
-	minexp := bias + 1 - prec + 1
-	if e < minexp {
-		s := minexp - e
-		if s > prec+1 {
-			s = prec + 1
-		}
-		if v&((1<<uint(s))-1) != 0 {
-			v |= 1 << uint(s)
-		}
-		v >>= uint(s)
-		e = minexp
-	}
-
-	// round to even
-	v |= (v & 4) >> 2
-
-	v += v & 1
-	v >>= 2
-
-	f := float64(v)
-	f = math.Ldexp(f, e)
-
-	if a.Val.Neg != 0 {
-		f = -f
-	}
-
-	return f
+	return x
 }
 
 func mpgetflt(a *Mpflt) float64 {
@@ -295,62 +141,95 @@
 }
 
 func Mpmovecflt(a *Mpflt, c float64) {
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
+	if Mpdebug {
 		fmt.Printf("\nconst %g", c)
 	}
-	_Mpmovecfix(&a.Val, 0)
-	a.Exp = 0
-	var f float64
-	var l int
-	var i int
-	if c == 0 {
-		goto out
-	}
-	if c < 0 {
-		a.Val.Neg = 1
-		c = -c
-	}
 
-	f, i = math.Frexp(c)
-	a.Exp = int16(i)
+	a.Val.SetFloat64(c)
 
-	for i := 0; i < 10; i++ {
-		f = f * Mpbase
-		l = int(math.Floor(f))
-		f = f - float64(l)
-		a.Exp -= Mpscale
-		a.Val.A[0] = l
-		if f == 0 {
-			break
-		}
-		_Mpshiftfix(&a.Val, Mpscale)
-	}
-
-out:
-	mpnorm(a)
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf(" = %v\n", Fconv(a, 0))
+	if Mpdebug {
+		fmt.Printf(" = %v\n", a)
 	}
 }
 
 func mpnegflt(a *Mpflt) {
-	a.Val.Neg ^= 1
+	a.Val.Neg(&a.Val)
 }
 
-func mptestflt(a *Mpflt) int {
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf("\n%v?", Fconv(a, 0))
-	}
-	s := sigfig(a)
-	if s != 0 {
-		s = +1
-		if a.Val.Neg != 0 {
-			s = -1
-		}
+//
+// floating point input
+// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
+//
+func mpatoflt(a *Mpflt, as string) {
+	for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
+		as = as[1:]
 	}
 
-	if Mpdebug != 0 /*TypeKind(100016)*/ {
-		fmt.Printf(" = %d\n", s)
+	f, ok := a.Val.SetString(as)
+	if !ok {
+		// At the moment we lose precise error cause;
+		// the old code additionally distinguished between:
+		// - malformed hex constant
+		// - decimal point in hex constant
+		// - constant exponent out of range
+		// - decimal point and binary point in constant
+		// TODO(gri) use different conversion function or check separately
+		Yyerror("malformed constant: %s", as)
+		a.Val.SetUint64(0)
 	}
-	return s
+
+	if f.IsInf() {
+		Yyerror("constant too large: %s", as)
+		a.Val.SetUint64(0)
+	}
+}
+
+func (f *Mpflt) String() string {
+	return Fconv(f, 0)
+}
+
+func Fconv(fvp *Mpflt, flag int) string {
+	if flag&obj.FmtSharp == 0 {
+		return fvp.Val.Format('b', 0)
+	}
+
+	// use decimal format for error messages
+
+	// determine sign
+	f := &fvp.Val
+	var sign string
+	if fvp.Val.Signbit() {
+		sign = "-"
+		f = new(big.Float).Abs(f)
+	} else if flag&obj.FmtSign != 0 {
+		sign = "+"
+	}
+
+	// Use fmt formatting if in float64 range (common case).
+	if x, _ := f.Float64(); !math.IsInf(x, 0) {
+		return fmt.Sprintf("%s%.6g", sign, x)
+	}
+
+	// Out of float64 range. Do approximate manual to decimal
+	// conversion to avoid precise but possibly slow Float
+	// formatting. The exponent is > 0 since a negative out-
+	// of-range exponent would have underflowed and led to 0.
+	// f = mant * 2**exp
+	var mant big.Float
+	exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
+
+	// approximate float64 mantissa m and decimal exponent d
+	// f ~ m * 10**d
+	m, _ := mant.Float64()            // 0.5 <= m < 1.0
+	d := exp * (math.Ln2 / math.Ln10) // log_10(2)
+
+	// adjust m for truncated (integer) decimal exponent e
+	e := int64(d)
+	m *= math.Pow(10, d-float64(e))
+	for m >= 10 {
+		m /= 10
+		e++
+	}
+
+	return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
 }
diff --git a/src/cmd/internal/gc/obj.go b/src/cmd/internal/gc/obj.go
index 34c1070..05c5b1a 100644
--- a/src/cmd/internal/gc/obj.go
+++ b/src/cmd/internal/gc/obj.go
@@ -35,7 +35,7 @@
 	if writearchive != 0 {
 		obj.Bwritestring(bout, "!<arch>\n")
 		arhdr = [ArhdrSize]byte{}
-		obj.Bwrite(bout, arhdr[:])
+		bout.Write(arhdr[:])
 		startobj = obj.Boffset(bout)
 	}
 
@@ -43,19 +43,19 @@
 	dumpexport()
 
 	if writearchive != 0 {
-		obj.Bflush(bout)
+		bout.Flush()
 		size := obj.Boffset(bout) - startobj
 		if size&1 != 0 {
 			obj.Bputc(bout, 0)
 		}
 		obj.Bseek(bout, startobj-ArhdrSize, 0)
 		formathdr(arhdr[:], "__.PKGDEF", size)
-		obj.Bwrite(bout, arhdr[:])
-		obj.Bflush(bout)
+		bout.Write(arhdr[:])
+		bout.Flush()
 
 		obj.Bseek(bout, startobj+size+(size&1), 0)
 		arhdr = [ArhdrSize]byte{}
-		obj.Bwrite(bout, arhdr[:])
+		bout.Write(arhdr[:])
 		startobj = obj.Boffset(bout)
 		fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
 	}
@@ -96,7 +96,7 @@
 	obj.Writeobjdirect(Ctxt, bout)
 
 	if writearchive != 0 {
-		obj.Bflush(bout)
+		bout.Flush()
 		size := obj.Boffset(bout) - startobj
 		if size&1 != 0 {
 			obj.Bputc(bout, 0)
@@ -104,7 +104,7 @@
 		obj.Bseek(bout, startobj-ArhdrSize, 0)
 		name := fmt.Sprintf("_go_.%c", Thearch.Thechar)
 		formathdr(arhdr[:], name, size)
-		obj.Bwrite(bout, arhdr[:])
+		bout.Write(arhdr[:])
 	}
 
 	obj.Bterm(bout)
@@ -121,7 +121,7 @@
 		}
 
 		if n.Type == nil {
-			Fatal("external %v nil type\n", Nconv(n, 0))
+			Fatal("external %v nil type\n", n)
 		}
 		if n.Class == PFUNC {
 			continue
@@ -245,7 +245,7 @@
 
 	off = duint8(sym, off, 0)                    // terminating NUL for runtime
 	off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
-	ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA)
+	ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
 
 	return sym
 }
@@ -269,10 +269,10 @@
 		off = dsname(sym, off, s[n:n+m])
 	}
 
-	ggloblsym(sym, int32(off), obj.NOPTR)
+	ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
 
 	if nam.Op != ONAME {
-		Fatal("slicebytes %v", Nconv(nam, 0))
+		Fatal("slicebytes %v", nam)
 	}
 	off = int(nam.Xoffset)
 	off = dsymptr(nam.Sym, off, sym, 0)
diff --git a/src/cmd/internal/gc/order.go b/src/cmd/internal/gc/order.go
index 9dc9b69..f08f5f2 100644
--- a/src/cmd/internal/gc/order.go
+++ b/src/cmd/internal/gc/order.go
@@ -50,7 +50,7 @@
 // described in the comment at the top of the file.
 func order(fn *Node) {
 	if Debug['W'] > 1 {
-		s := fmt.Sprintf("\nbefore order %v", Sconv(fn.Nname.Sym, 0))
+		s := fmt.Sprintf("\nbefore order %v", fn.Nname.Sym)
 		dumplist(s, fn.Nbody)
 	}
 
@@ -323,7 +323,7 @@
 // and then returns the list t1, t2, ....
 func copyret(n *Node, order *Order) *NodeList {
 	if n.Type.Etype != TSTRUCT || n.Type.Funarg == 0 {
-		Fatal("copyret %v %d", Tconv(n.Type, 0), n.Left.Type.Outtuple)
+		Fatal("copyret %v %d", n.Type, n.Left.Type.Outtuple)
 	}
 
 	var l1 *NodeList
@@ -680,7 +680,7 @@
 		orderexpr(&n.Right, order)
 		switch n.Type.Etype {
 		default:
-			Fatal("orderstmt range %v", Tconv(n.Type, 0))
+			Fatal("orderstmt range %v", n.Type)
 
 			// Mark []byte(str) range expression to reuse string backing storage.
 		// It is safe because the storage cannot be mutated.
@@ -770,7 +770,7 @@
 				// declaration (and possible allocation) until inside the case body.
 				// Delete the ODCL nodes here and recreate them inside the body below.
 				case OSELRECV, OSELRECV2:
-					if r.Colas != 0 {
+					if r.Colas {
 						t = r.Ninit
 						if t != nil && t.N.Op == ODCL && t.N.Left == r.Left {
 							t = t.Next
@@ -814,7 +814,7 @@
 						// the conversion happens in the OAS instead.
 						tmp1 = r.Left
 
-						if r.Colas != 0 {
+						if r.Colas {
 							tmp2 = Nod(ODCL, tmp1, nil)
 							typecheck(&tmp2, Etop)
 							l.N.Ninit = list(l.N.Ninit, tmp2)
@@ -831,7 +831,7 @@
 					}
 					if r.Ntest != nil {
 						tmp1 = r.Ntest
-						if r.Colas != 0 {
+						if r.Colas {
 							tmp2 = Nod(ODCL, tmp1, nil)
 							typecheck(&tmp2, Etop)
 							l.N.Ninit = list(l.N.Ninit, tmp2)
diff --git a/src/cmd/internal/gc/pgen.go b/src/cmd/internal/gc/pgen.go
index 78b41ee..ae7fcce 100644
--- a/src/cmd/internal/gc/pgen.go
+++ b/src/cmd/internal/gc/pgen.go
@@ -88,7 +88,7 @@
 		Fatal("gvardef nil")
 	}
 	if n.Op != ONAME {
-		Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n, 0))
+		Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n)
 		return
 	}
 
@@ -142,12 +142,12 @@
 	var xoffset int64
 	if Curfn.Type.Thistuple > 0 {
 		xoffset = 0
-		twobitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
+		onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
 	}
 
 	if Curfn.Type.Intuple > 0 {
 		xoffset = 0
-		twobitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
+		onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
 	}
 
 	for j := 0; int32(j) < bv.n; j += 32 {
@@ -155,13 +155,13 @@
 	}
 	if Curfn.Type.Outtuple > 0 {
 		xoffset = 0
-		twobitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
+		onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
 		for j := 0; int32(j) < bv.n; j += 32 {
 			off = duint32(sym, off, bv.b[j/32])
 		}
 	}
 
-	ggloblsym(sym, int32(off), obj.RODATA)
+	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
 }
 
 // Sort the list of stack variables. Autos after anything else,
@@ -191,17 +191,17 @@
 	}
 
 	if a.Used != b.Used {
-		return bool2int(b.Used) - bool2int(a.Used)
+		return obj.Bool2int(b.Used) - obj.Bool2int(a.Used)
 	}
 
-	ap := bool2int(haspointers(a.Type))
-	bp := bool2int(haspointers(b.Type))
+	ap := obj.Bool2int(haspointers(a.Type))
+	bp := obj.Bool2int(haspointers(b.Type))
 	if ap != bp {
 		return bp - ap
 	}
 
-	ap = bool2int(a.Needzero)
-	bp = bool2int(b.Needzero)
+	ap = obj.Bool2int(a.Needzero)
+	bp = obj.Bool2int(b.Needzero)
 	if ap != bp {
 		return bp - ap
 	}
@@ -331,7 +331,7 @@
 		Fatal("bad checknil")
 	}
 
-	if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || n.Addable == 0 || n.Op == OLITERAL {
+	if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
 		var reg Node
 		Regalloc(&reg, Types[Tptr], n)
 		Cgen(n, &reg)
diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go
index 876f43e..040a778 100644
--- a/src/cmd/internal/gc/plive.go
+++ b/src/cmd/internal/gc/plive.go
@@ -235,6 +235,11 @@
 			// is the index in the variables list.
 			ll.N.Opt = nil
 
+			// The compiler doesn't emit initializations for zero-width parameters or results.
+			if ll.N.Type.Width == 0 {
+				continue
+			}
+
 			ll.N.Curfn = Curfn
 			switch ll.N.Class {
 			case PAUTO:
@@ -740,7 +745,7 @@
 	if node.Addrtaken {
 		a = "@"
 	}
-	fmt.Printf(" %v%s%s", Nconv(node, 0), p, a)
+	fmt.Printf(" %v%s%s", node, p, a)
 }
 
 // Pretty print a list of variables.  The vars argument is an array of Node*s.
@@ -812,13 +817,13 @@
 	}
 
 	if n == nil {
-		fmt.Printf("%v: checkauto %v: nil node in %v\n", p.Line(), Nconv(Curfn, 0), p)
+		fmt.Printf("%v: checkauto %v: nil node in %v\n", p.Line(), Curfn, p)
 		return
 	}
 
-	fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %v\n", Nconv(Curfn, 0), Nconv(n, 0), n, n.Class, p)
+	fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %v\n", Curfn, n, n, n.Class, p)
 	for l := fn.Func.Dcl; l != nil; l = l.Next {
-		fmt.Printf("\t%v (%p; class=%d)\n", Nconv(l.N, 0), l.N, l.N.Class)
+		fmt.Printf("\t%v (%p; class=%d)\n", l.N, l.N, l.N.Class)
 	}
 	Yyerror("checkauto: invariant lost")
 }
@@ -828,18 +833,18 @@
 		return
 	}
 	var a *Node
-	var class int
+	var class uint8
 	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		a = l.N
-		class = int(a.Class) &^ PHEAP
+		class = a.Class &^ PHEAP
 		if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
 			return
 		}
 	}
 
-	fmt.Printf("checkparam %v: %v (%p; class=%d) not found in %v\n", Nconv(Curfn, 0), Nconv(n, 0), n, n.Class, p)
+	fmt.Printf("checkparam %v: %v (%p; class=%d) not found in %v\n", Curfn, n, n, n.Class, p)
 	for l := fn.Func.Dcl; l != nil; l = l.Next {
-		fmt.Printf("\t%v (%p; class=%d)\n", Nconv(l.N, 0), l.N, l.N.Class)
+		fmt.Printf("\t%v (%p; class=%d)\n", l.N, l.N, l.N.Class)
 	}
 	Yyerror("checkparam: invariant lost")
 }
@@ -881,11 +886,11 @@
 
 // NOTE: The bitmap for a specific type t should be cached in t after the first run
 // and then simply copied into bv at the correct offset on future calls with
-// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1
+// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, onebitwalktype1
 // accounts for 40% of the 6g execution time.
-func twobitwalktype1(t *Type, xoffset *int64, bv Bvec) {
+func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) {
 	if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 {
-		Fatal("twobitwalktype1: invalid initial alignment, %v", Tconv(t, 0))
+		Fatal("onebitwalktype1: invalid initial alignment, %v", t)
 	}
 
 	switch t.Etype {
@@ -905,10 +910,6 @@
 		TFLOAT64,
 		TCOMPLEX64,
 		TCOMPLEX128:
-		for i := int64(0); i < t.Width; i++ {
-			bvset(bv, int32(((*xoffset+i)/int64(Widthptr))*obj.BitsPerPointer)) // 1 = live scalar (BitsScalar)
-		}
-
 		*xoffset += t.Width
 
 	case TPTR32,
@@ -918,46 +919,46 @@
 		TCHAN,
 		TMAP:
 		if *xoffset&int64(Widthptr-1) != 0 {
-			Fatal("twobitwalktype1: invalid alignment, %v", Tconv(t, 0))
+			Fatal("onebitwalktype1: invalid alignment, %v", t)
 		}
-		bvset(bv, int32((*xoffset/int64(Widthptr))*obj.BitsPerPointer+1)) // 2 = live ptr (BitsPointer)
+		bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer
 		*xoffset += t.Width
 
-		// struct { byte *str; intgo len; }
 	case TSTRING:
+		// struct { byte *str; intgo len; }
 		if *xoffset&int64(Widthptr-1) != 0 {
-			Fatal("twobitwalktype1: invalid alignment, %v", Tconv(t, 0))
+			Fatal("onebitwalktype1: invalid alignment, %v", t)
 		}
-		bvset(bv, int32((*xoffset/int64(Widthptr))*obj.BitsPerPointer+1)) // 2 = live ptr in first slot (BitsPointer)
+		bvset(bv, int32(*xoffset/int64(Widthptr))) //pointer in first slot
 		*xoffset += t.Width
 
-		// struct { Itab *tab;	union { void *ptr, uintptr val } data; }
-	// or, when isnilinter(t)==true:
-	// struct { Type *type; union { void *ptr, uintptr val } data; }
 	case TINTER:
+		// struct { Itab *tab;	void *data; }
+		// or, when isnilinter(t)==true:
+		// struct { Type *type; void *data; }
 		if *xoffset&int64(Widthptr-1) != 0 {
-			Fatal("twobitwalktype1: invalid alignment, %v", Tconv(t, 0))
+			Fatal("onebitwalktype1: invalid alignment, %v", t)
 		}
-		bvset(bv, int32((*xoffset/int64(Widthptr))*obj.BitsPerPointer+1)) // 2 = live ptr in first slot (BitsPointer)
-		bvset(bv, int32((*xoffset/int64(Widthptr))*obj.BitsPerPointer+3)) // 2 = live ptr in second slot (BitsPointer)
+		bvset(bv, int32(*xoffset/int64(Widthptr)))   // pointer in first slot
+		bvset(bv, int32(*xoffset/int64(Widthptr)+1)) // pointer in second slot
 		*xoffset += t.Width
 
-		// The value of t->bound is -1 for slices types and >0 for
-	// for fixed array types.  All other values are invalid.
 	case TARRAY:
+		// 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("twobitwalktype1: invalid bound, %v", Tconv(t, 0))
+			Fatal("onebitwalktype1: invalid bound, %v", t)
 		}
 		if Isslice(t) {
 			// struct { byte *array; uintgo len; uintgo cap; }
 			if *xoffset&int64(Widthptr-1) != 0 {
-				Fatal("twobitwalktype1: invalid TARRAY alignment, %v", Tconv(t, 0))
+				Fatal("onebitwalktype1: invalid TARRAY alignment, %v", t)
 			}
-			bvset(bv, int32((*xoffset/int64(Widthptr))*obj.BitsPerPointer+1)) // 2 = live ptr in first slot (BitsPointer)
+			bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
 			*xoffset += t.Width
 		} else {
 			for i := int64(0); i < t.Bound; i++ {
-				twobitwalktype1(t.Type, xoffset, bv)
+				onebitwalktype1(t.Type, xoffset, bv)
 			}
 		}
 
@@ -967,14 +968,14 @@
 		for t1 := t.Type; t1 != nil; t1 = t1.Down {
 			fieldoffset = t1.Width
 			*xoffset += fieldoffset - o
-			twobitwalktype1(t1.Type, xoffset, bv)
+			onebitwalktype1(t1.Type, xoffset, bv)
 			o = fieldoffset + t1.Type.Width
 		}
 
 		*xoffset += t.Width - o
 
 	default:
-		Fatal("twobitwalktype1: unexpected type, %v", Tconv(t, 0))
+		Fatal("onebitwalktype1: unexpected type, %v", t)
 	}
 }
 
@@ -991,7 +992,7 @@
 // Generates live pointer value maps for arguments and local variables.  The
 // this argument and the in arguments are always assumed live.  The vars
 // argument is an array of Node*s.
-func twobitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, locals Bvec) {
+func onebitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, locals Bvec) {
 	var node *Node
 	var xoffset int64
 
@@ -1004,11 +1005,11 @@
 		switch node.Class {
 		case PAUTO:
 			xoffset = node.Xoffset + stkptrsize
-			twobitwalktype1(node.Type, &xoffset, locals)
+			onebitwalktype1(node.Type, &xoffset, locals)
 
 		case PPARAM, PPARAMOUT:
 			xoffset = node.Xoffset
-			twobitwalktype1(node.Type, &xoffset, args)
+			onebitwalktype1(node.Type, &xoffset, args)
 		}
 	}
 
@@ -1020,13 +1021,13 @@
 
 	if thisargtype != nil {
 		xoffset = 0
-		twobitwalktype1(thisargtype, &xoffset, args)
+		onebitwalktype1(thisargtype, &xoffset, args)
 	}
 
 	inargtype := getinargx(lv.fn.Type)
 	if inargtype != nil {
 		xoffset = 0
-		twobitwalktype1(inargtype, &xoffset, args)
+		onebitwalktype1(inargtype, &xoffset, args)
 	}
 }
 
@@ -1197,15 +1198,15 @@
 func islive(n *Node, args Bvec, locals Bvec) bool {
 	switch n.Class {
 	case PPARAM, PPARAMOUT:
-		for i := 0; int64(i) < n.Type.Width/int64(Widthptr)*obj.BitsPerPointer; i++ {
-			if bvget(args, int32(n.Xoffset/int64(Widthptr)*obj.BitsPerPointer+int64(i))) != 0 {
+		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
+			if bvget(args, int32(n.Xoffset/int64(Widthptr)+int64(i))) != 0 {
 				return true
 			}
 		}
 
 	case PAUTO:
-		for i := 0; int64(i) < n.Type.Width/int64(Widthptr)*obj.BitsPerPointer; i++ {
-			if bvget(locals, int32((n.Xoffset+stkptrsize)/int64(Widthptr)*obj.BitsPerPointer+int64(i))) != 0 {
+		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
+			if bvget(locals, int32((n.Xoffset+stkptrsize)/int64(Widthptr)+int64(i))) != 0 {
 				return true
 			}
 		}
@@ -1234,7 +1235,7 @@
 	avarinit := bvalloc(nvars)
 	any := bvalloc(nvars)
 	all := bvalloc(nvars)
-	ambig := bvalloc(localswords() * obj.BitsPerPointer)
+	ambig := bvalloc(localswords())
 	nmsg := int32(0)
 	startmsg := int32(0)
 
@@ -1283,13 +1284,13 @@
 						if !n.Needzero {
 							n.Needzero = true
 							if debuglive >= 1 {
-								Warnl(int(p.Lineno), "%v: %v is ambiguously live", Nconv(Curfn.Nname, 0), Nconv(n, obj.FmtLong))
+								Warnl(int(p.Lineno), "%v: %v is ambiguously live", Curfn.Nname, Nconv(n, obj.FmtLong))
 							}
 
 							// Record in 'ambiguous' bitmap.
 							xoffset = n.Xoffset + stkptrsize
 
-							twobitwalktype1(n.Type, &xoffset, ambig)
+							onebitwalktype1(n.Type, &xoffset, ambig)
 						}
 					}
 				}
@@ -1298,10 +1299,10 @@
 				// value we are tracking.
 
 				// Live stuff first.
-				args = bvalloc(argswords() * obj.BitsPerPointer)
+				args = bvalloc(argswords())
 
 				lv.argslivepointers = append(lv.argslivepointers, args)
-				locals = bvalloc(localswords() * obj.BitsPerPointer)
+				locals = bvalloc(localswords())
 				lv.livepointers = append(lv.livepointers, locals)
 
 				if debuglive >= 3 {
@@ -1314,7 +1315,7 @@
 				// because the any/all calculation requires walking forward
 				// over the block (as this loop does), while the liveout
 				// requires walking backward (as the next loop does).
-				twobitlivepointermap(lv, any, lv.vars, args, locals)
+				onebitlivepointermap(lv, any, lv.vars, args, locals)
 			}
 
 			if p == bb.last {
@@ -1380,7 +1381,7 @@
 						}
 						n = lv.vars[j]
 						if n.Class != PPARAM {
-							yyerrorl(int(p.Lineno), "internal error: %v %v recorded as live on entry", Nconv(Curfn.Nname, 0), Nconv(n, obj.FmtLong))
+							yyerrorl(int(p.Lineno), "internal error: %v %v recorded as live on entry", Curfn.Nname, Nconv(n, obj.FmtLong))
 						}
 					}
 				}
@@ -1389,7 +1390,7 @@
 				args = lv.argslivepointers[pos]
 
 				locals = lv.livepointers[pos]
-				twobitlivepointermap(lv, liveout, lv.vars, args, locals)
+				onebitlivepointermap(lv, liveout, lv.vars, args, locals)
 
 				// Ambiguously live variables are zeroed immediately after
 				// function entry. Mark them live for all the non-entry bitmaps
@@ -1416,7 +1417,7 @@
 					for j = 0; j < int32(len(lv.vars)); j++ {
 						n = lv.vars[j]
 						if islive(n, args, locals) {
-							fmt_ += fmt.Sprintf(" %v", Nconv(n, 0))
+							fmt_ += fmt.Sprintf(" %v", n)
 							numlive++
 						}
 					}
@@ -1689,7 +1690,7 @@
 						if tmp9 != 0 {
 							fmt.Printf(",")
 						}
-						fmt.Printf("%v", Nconv(n, 0))
+						fmt.Printf("%v", n)
 					}
 				}
 
@@ -1722,7 +1723,7 @@
 // length of the bitmaps.  All bitmaps are assumed to be of equal length.  The
 // words that are followed are the raw bitmap words.  The arr argument is an
 // array of Node*s.
-func twobitwritesymbol(arr []Bvec, sym *Sym) {
+func onebitwritesymbol(arr []Bvec, sym *Sym) {
 	var i int
 	var j int
 	var word uint32
@@ -1811,9 +1812,9 @@
 	}
 
 	// Emit the live pointer map data structures
-	twobitwritesymbol(lv.livepointers, livesym)
+	onebitwritesymbol(lv.livepointers, livesym)
 
-	twobitwritesymbol(lv.argslivepointers, argssym)
+	onebitwritesymbol(lv.argslivepointers, argssym)
 
 	// Free everything.
 	for l := fn.Func.Dcl; l != nil; l = l.Next {
diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/internal/gc/popt.go
index 099a0b6..ce904e1 100644
--- a/src/cmd/internal/gc/popt.go
+++ b/src/cmd/internal/gc/popt.go
@@ -263,7 +263,7 @@
 
 	if nf >= MaxFlowProg {
 		if Debug['v'] != 0 {
-			Warn("%v is too big (%d instructions)", Sconv(Curfn.Nname.Sym, 0), nf)
+			Warn("%v is too big (%d instructions)", Curfn.Nname.Sym, nf)
 		}
 		return nil
 	}
@@ -517,15 +517,14 @@
 // ACM TOPLAS 1999.
 
 type TempVar struct {
-	node     *Node
-	def      *Flow    // definition of temp var
-	use      *Flow    // use list, chained through Flow.data
-	freelink *TempVar // next free temp in Type.opt list
-	merge    *TempVar // merge var with this one
-	start    int64    // smallest Prog.pc in live range
-	end      int64    // largest Prog.pc in live range
-	addr     uint8    // address taken - no accurate end
-	removed  uint8    // removed from program
+	node    *Node
+	def     *Flow    // definition of temp var
+	use     *Flow    // use list, chained through Flow.data
+	merge   *TempVar // merge var with this one
+	start   int64    // smallest Prog.pc in live range
+	end     int64    // largest Prog.pc in live range
+	addr    uint8    // address taken - no accurate end
+	removed uint8    // removed from program
 }
 
 type startcmp []*TempVar
@@ -653,7 +652,7 @@
 				p.To = obj.Addr{}
 				v.removed = 1
 				if debugmerge > 0 && Debug['v'] != 0 {
-					fmt.Printf("drop write-only %v\n", Sconv(v.node.Sym, 0))
+					fmt.Printf("drop write-only %v\n", v.node.Sym)
 				}
 			} else {
 				Fatal("temp used and not set: %v", p)
@@ -676,7 +675,7 @@
 				Thearch.Excise(f)
 				v.removed = 1
 				if debugmerge > 0 && Debug['v'] != 0 {
-					fmt.Printf("drop immediate-use %v\n", Sconv(v.node.Sym, 0))
+					fmt.Printf("drop immediate-use %v\n", v.node.Sym)
 				}
 			}
 
@@ -753,7 +752,7 @@
 		for j = nfree; j < len(var_); j++ {
 			v1 = inuse[j]
 			if debugmerge > 0 && Debug['v'] != 0 {
-				fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, obj.FmtSharp), Nconv(v1.node, obj.FmtSharp), Tconv(t, 0), Tconv(v1.node.Type, 0), v.node.Addrtaken, v1.node.Addrtaken)
+				fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, obj.FmtSharp), Nconv(v1.node, obj.FmtSharp), t, v1.node.Type, v.node.Addrtaken, v1.node.Addrtaken)
 			}
 
 			// Require the types to match but also require the addrtaken bits to match.
@@ -787,11 +786,11 @@
 	}
 
 	if debugmerge > 0 && Debug['v'] != 0 {
-		fmt.Printf("%v [%d - %d]\n", Sconv(Curfn.Nname.Sym, 0), len(var_), nkill)
+		fmt.Printf("%v [%d - %d]\n", Curfn.Nname.Sym, len(var_), nkill)
 		var v *TempVar
 		for i := 0; i < len(var_); i++ {
 			v = &var_[i]
-			fmt.Printf("var %v %v %d-%d", Nconv(v.node, obj.FmtSharp), Tconv(v.node.Type, 0), v.start, v.end)
+			fmt.Printf("var %v %v %d-%d", Nconv(v.node, obj.FmtSharp), v.node.Type, v.start, v.end)
 			if v.addr != 0 {
 				fmt.Printf(" addr=1")
 			}
@@ -981,7 +980,7 @@
 	Flowend(g)
 
 	if Debug_checknil > 1 {
-		fmt.Printf("%v: removed %d of %d nil checks\n", Sconv(Curfn.Nname.Sym, 0), nkill, ncheck)
+		fmt.Printf("%v: removed %d of %d nil checks\n", Curfn.Nname.Sym, nkill, ncheck)
 	}
 }
 
diff --git a/src/cmd/internal/gc/racewalk.go b/src/cmd/internal/gc/racewalk.go
index 85225c3..e7f3500 100644
--- a/src/cmd/internal/gc/racewalk.go
+++ b/src/cmd/internal/gc/racewalk.go
@@ -77,11 +77,11 @@
 	fn.Func.Exit = list(fn.Func.Exit, nd)
 
 	if Debug['W'] != 0 {
-		s := fmt.Sprintf("after racewalk %v", Sconv(fn.Nname.Sym, 0))
+		s := fmt.Sprintf("after racewalk %v", fn.Nname.Sym)
 		dumplist(s, fn.Nbody)
-		s = fmt.Sprintf("enter %v", Sconv(fn.Nname.Sym, 0))
+		s = fmt.Sprintf("enter %v", fn.Nname.Sym)
 		dumplist(s, fn.Func.Enter)
-		s = fmt.Sprintf("exit %v", Sconv(fn.Nname.Sym, 0))
+		s = fmt.Sprintf("exit %v", fn.Nname.Sym)
 		dumplist(s, fn.Func.Exit)
 	}
 }
@@ -137,7 +137,7 @@
 	default:
 		Fatal("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
 
-	case OAS, OAS2FUNC:
+	case OAS, OASWB, OAS2FUNC:
 		racewalknode(&n.Left, init, 1, 0)
 		racewalknode(&n.Right, init, 0, 0)
 		goto ret
@@ -219,7 +219,8 @@
 		OPLUS,
 		OREAL,
 		OIMAG,
-		OCOM:
+		OCOM,
+		OSQRT:
 		racewalknode(&n.Left, init, wr, 0)
 		goto ret
 
@@ -390,7 +391,10 @@
 		// impossible nodes: only appear in backend.
 	case ORROTC, OEXTEND:
 		Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
+		goto ret
 
+	case OGETG:
+		Yyerror("racewalk: OGETG can happen only in runtime which we don't instrument")
 		goto ret
 
 		// just do generic traversal
@@ -423,9 +427,8 @@
 		OTYPE,
 		ONONAME,
 		OLITERAL,
-		OSLICESTR,
-		// always preceded by bounds checking, avoid double instrumentation.
-		OTYPESW: // ignored by code generation, do not instrument.
+		OSLICESTR, // always preceded by bounds checking, avoid double instrumentation.
+		OTYPESW:   // ignored by code generation, do not instrument.
 		goto ret
 	}
 
@@ -492,7 +495,7 @@
 	if isartificial(b) {
 		return false
 	}
-	class := int(b.Class)
+	class := b.Class
 
 	// BUG: we _may_ want to instrument PAUTO sometimes
 	// e.g. if we've got a local variable/method receiver
diff --git a/src/cmd/internal/gc/range.go b/src/cmd/internal/gc/range.go
index 979c76a..03beb1c 100644
--- a/src/cmd/internal/gc/range.go
+++ b/src/cmd/internal/gc/range.go
@@ -62,7 +62,7 @@
 
 	case TCHAN:
 		if t.Chan&Crecv == 0 {
-			Yyerror("invalid operation: range %v (receive from send-only type %v)", Nconv(n.Right, 0), Tconv(n.Right.Type, 0))
+			Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
 			goto out
 		}
 
@@ -105,7 +105,7 @@
 		if v1.Defn == n {
 			v1.Type = t1
 		} else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
-			Yyerror("cannot assign type %v to %v in range%s", Tconv(t1, 0), Nconv(v1, obj.FmtLong), why)
+			Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why)
 		}
 		checkassign(n, v1)
 	}
@@ -114,7 +114,7 @@
 		if v2.Defn == n {
 			v2.Type = t2
 		} else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
-			Yyerror("cannot assign type %v to %v in range%s", Tconv(t2, 0), Nconv(v2, obj.FmtLong), why)
+			Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why)
 		}
 		checkassign(n, v2)
 	}
diff --git a/src/cmd/internal/gc/reflect.go b/src/cmd/internal/gc/reflect.go
index bd5be0f..9979fe8 100644
--- a/src/cmd/internal/gc/reflect.go
+++ b/src/cmd/internal/gc/reflect.go
@@ -335,13 +335,13 @@
 	var method *Sym
 	for f := mt.Xmethod; f != nil; f = f.Down {
 		if f.Etype != TFIELD {
-			Fatal("methods: not field %v", Tconv(f, 0))
+			Fatal("methods: not field %v", f)
 		}
 		if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
-			Fatal("non-method on %v method %v %v\n", Tconv(mt, 0), Sconv(f.Sym, 0), Tconv(f, 0))
+			Fatal("non-method on %v method %v %v\n", mt, f.Sym, f)
 		}
 		if getthisx(f.Type).Type == nil {
-			Fatal("receiver with no type on %v method %v %v\n", Tconv(mt, 0), Sconv(f.Sym, 0), Tconv(f, 0))
+			Fatal("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
 		}
 		if f.Nointerface {
 			continue
@@ -484,13 +484,7 @@
 		dimportpath_gopkg.Name = "go"
 	}
 
-	var nam string
-	if p == localpkg {
-		// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
-		nam = "importpath." + pathtoprefix(myimportpath) + "."
-	} else {
-		nam = "importpath." + p.Prefix + "."
-	}
+	nam := "importpath." + p.Prefix + "."
 
 	n := Nod(ONAME, nil, nil)
 	n.Sym = Pkglookup(nam, dimportpath_gopkg)
@@ -499,7 +493,12 @@
 	n.Xoffset = 0
 	p.Pathsym = n.Sym
 
-	gdatastring(n, p.Path)
+	if p == localpkg {
+		// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
+		gdatastring(n, myimportpath)
+	} else {
+		gdatastring(n, p.Path)
+	}
 	ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
 }
 
@@ -677,12 +676,64 @@
 		fallthrough
 	default:
 		ret = true
+
+	case TFIELD:
+		Fatal("haspointers: unexpected type, %v", t)
 	}
 
-	t.Haspointers = 1 + uint8(bool2int(ret))
+	t.Haspointers = 1 + uint8(obj.Bool2int(ret))
 	return ret
 }
 
+// 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 {
+	if !haspointers(t) {
+		return 0
+	}
+
+	switch t.Etype {
+	case TPTR32,
+		TPTR64,
+		TUNSAFEPTR,
+		TFUNC,
+		TCHAN,
+		TMAP:
+		return uint64(Widthptr)
+
+	case TSTRING:
+		// struct { byte *str; intgo len; }
+		return uint64(Widthptr)
+
+	case TINTER:
+		// struct { Itab *tab;	void *data; } or
+		// struct { Type *type; void *data; }
+		return 2 * uint64(Widthptr)
+
+	case TARRAY:
+		if Isslice(t) {
+			// struct { byte *array; uintgo len; uintgo cap; }
+			return uint64(Widthptr)
+		}
+		// haspointers already eliminated t.Bound == 0.
+		return uint64(t.Bound-1)*uint64(t.Type.Width) + typeptrdata(t.Type)
+
+	case TSTRUCT:
+		// Find the last field that has pointers.
+		var lastPtrField *Type
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			if haspointers(t1.Type) {
+				lastPtrField = t1
+			}
+		}
+		return uint64(lastPtrField.Width) + typeptrdata(lastPtrField.Type)
+
+	default:
+		Fatal("typeptrdata: unexpected type, %v", t)
+		return 0
+	}
+}
+
 /*
  * commonType
  * ../../runtime/type.go:/commonType
@@ -729,6 +780,7 @@
 	// actual type structure
 	//	type commonType struct {
 	//		size          uintptr
+	//		ptrsize       uintptr
 	//		hash          uint32
 	//		_             uint8
 	//		align         uint8
@@ -742,6 +794,7 @@
 	//		zero          unsafe.Pointer
 	//	}
 	ot = duintptr(s, ot, uint64(t.Width))
+	ot = duintptr(s, ot, typeptrdata(t))
 
 	ot = duint32(s, ot, typehash(t))
 	ot = duint8(s, ot, 0) // unused
@@ -753,7 +806,7 @@
 		i = 1
 	}
 	if i&(i-1) != 0 {
-		Fatal("invalid alignment %d for %v", t.Align, Tconv(t, 0))
+		Fatal("invalid alignment %d for %v", t.Align, t)
 	}
 	ot = duint8(s, ot, t.Align) // align
 	ot = duint8(s, ot, t.Align) // fieldAlign
@@ -815,7 +868,7 @@
 			for i := 0; i < 2*Widthptr; i++ {
 				duint8(sbits, i, gcmask[i])
 			}
-			ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA)
+			ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA|obj.LOCAL)
 		}
 
 		ot = dsymptr(s, ot, sbits, 0)
@@ -852,10 +905,11 @@
 	// %-T is the complete, unambiguous type name.
 	// We want the types to end up sorted by string field,
 	// so use that first in the name, and then add :%-T to
-	// disambiguate. The names are a little long but they are
-	// discarded by the linker and do not end up in the symbol
-	// table of the final binary.
-	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) + "/" + Tconv(t, obj.FmtLeft)
+	// disambiguate. We use a tab character as the separator to
+	// ensure the types appear sorted by their string field. The
+	// names are a little long but they are discarded by the linker
+	// and do not end up in the symbol table of the final binary.
+	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) + "\t" + Tconv(t, obj.FmtLeft)
 
 	s := Pkglookup(p, typelinkpkg)
 
@@ -875,14 +929,14 @@
 
 func typenamesym(t *Type) *Sym {
 	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
-		Fatal("typename %v", Tconv(t, 0))
+		Fatal("typename %v", t)
 	}
 	s := typesym(t)
 	if s.Def == nil {
 		n := Nod(ONAME, nil, nil)
 		n.Sym = s
 		n.Type = Types[TUINT8]
-		n.Addable = 1
+		n.Addable = true
 		n.Ullman = 1
 		n.Class = PEXTERN
 		n.Xoffset = 0
@@ -899,7 +953,7 @@
 	s := typenamesym(t)
 	n := Nod(OADDR, s.Def, nil)
 	n.Type = Ptrto(s.Def.Type)
-	n.Addable = 1
+	n.Addable = true
 	n.Ullman = 2
 	n.Typecheck = 1
 	return n
@@ -948,7 +1002,7 @@
 
 	case TARRAY:
 		if Isslice(t) {
-			Fatal("slice can't be a map key: %v", Tconv(t, 0))
+			Fatal("slice can't be a map key: %v", t)
 		}
 		return isreflexive(t.Type)
 
@@ -962,7 +1016,7 @@
 		return true
 
 	default:
-		Fatal("bad type for map key: %v", Tconv(t, 0))
+		Fatal("bad type for map key: %v", t)
 		return false
 	}
 }
@@ -976,7 +1030,7 @@
 	}
 
 	if isideal(t) {
-		Fatal("dtypesym %v", Tconv(t, 0))
+		Fatal("dtypesym %v", t)
 	}
 
 	s := typesym(t)
@@ -1066,7 +1120,7 @@
 
 		ot = dcommontype(s, ot, t)
 		xt = ot - 3*Widthptr
-		ot = duint8(s, ot, uint8(bool2int(isddd)))
+		ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
 
 		// two slice headers: in and out.
 		ot = int(Rnd(int64(ot), int64(Widthptr)))
@@ -1146,7 +1200,7 @@
 		}
 
 		ot = duint16(s, ot, uint16(mapbucket(t).Width))
-		ot = duint8(s, ot, uint8(bool2int(isreflexive(t.Down))))
+		ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
 
 	case TPTR32, TPTR64:
 		if t.Type.Etype == TANY {
@@ -1203,7 +1257,7 @@
 	}
 
 	ot = dextratype(s, ot, t, xt)
-	ggloblsym(s, int32(ot), int8(dupok|obj.RODATA))
+	ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
 
 	// generate typelink.foo pointing at s = type.foo.
 	// The linker will leave a table of all the typelinks for
@@ -1212,10 +1266,24 @@
 	// we want be able to find.
 	if t.Sym == nil {
 		switch t.Etype {
-		case TARRAY, TCHAN, TMAP:
+		case TPTR32, TPTR64:
+			// The ptrto field of the type data cannot be relied on when
+			// dynamic linking: a type T may be defined in a module that makes
+			// no use of pointers to that type, but another module can contain
+			// a package that imports the first one and does use *T pointers.
+			// The second module will end up defining type data for *T and a
+			// type.*T symbol pointing at it. It's important that calling
+			// .PtrTo() on the refect.Type for T returns this type data and
+			// not some synthesized object, so we need reflect to be able to
+			// find it!
+			if !Ctxt.Flag_dynlink {
+				break
+			}
+			fallthrough
+		case TARRAY, TCHAN, TFUNC, TMAP:
 			slink := typelinksym(t)
 			dsymptr(slink, 0, s, 0)
-			ggloblsym(slink, int32(Widthptr), int8(dupok|obj.RODATA))
+			ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
 		}
 	}
 
@@ -1390,7 +1458,7 @@
 	xoffset := int64(0)
 
 	vec := bvalloc(2 * int32(Widthptr) * 8)
-	twobitwalktype1(t, &xoffset, vec)
+	onebitwalktype1(t, &xoffset, vec)
 
 	// Unfold the mask for the GC bitmap format:
 	// 4 bits per word, 2 high bits encode pointer info.
@@ -1405,13 +1473,11 @@
 	var bits uint8
 	for j := int64(0); j <= (nptr % 2); j++ {
 		for i = 0; i < nptr; i++ {
-			bits = uint8(bvget(vec, int32(i*obj.BitsPerPointer)) | bvget(vec, int32(i*obj.BitsPerPointer+1))<<1)
-
-			// Some fake types (e.g. Hmap) has missing fileds.
-			// twobitwalktype1 generates BitsDead for that holes,
-			// replace BitsDead with BitsScalar.
-			if bits == obj.BitsDead {
+			// 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 {
@@ -1616,6 +1682,6 @@
 		*xoffset += t.Width - o
 
 	default:
-		Fatal("gengcprog1: unexpected type, %v", Tconv(t, 0))
+		Fatal("gengcprog1: unexpected type, %v", t)
 	}
 }
diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/internal/gc/reg.go
index 66982ef..afe9523 100644
--- a/src/cmd/internal/gc/reg.go
+++ b/src/cmd/internal/gc/reg.go
@@ -1151,7 +1151,7 @@
 		}
 
 		if Debug['R'] != 0 && Debug['v'] != 0 {
-			fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, Econv(int(v.etype), 0), v.width, Nconv(v.node, 0), v.offset)
+			fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, Econv(int(v.etype), 0), v.width, v.node, v.offset)
 		}
 	}
 
@@ -1379,7 +1379,7 @@
 		if rgp.regno != 0 {
 			if Debug['R'] != 0 && Debug['v'] != 0 {
 				v := &vars[rgp.varno]
-				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", Nconv(v.node, 0), v.offset, rgp.varno, Econv(int(v.etype), 0), obj.Rconv(int(rgp.regno)), usedreg, vreg)
+				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, Econv(int(v.etype), 0), obj.Rconv(int(rgp.regno)), usedreg, vreg)
 			}
 
 			paint3(rgp.enter, int(rgp.varno), vreg, int(rgp.regno))
diff --git a/src/cmd/internal/gc/sinit.go b/src/cmd/internal/gc/sinit.go
index f716736..a9af945 100644
--- a/src/cmd/internal/gc/sinit.go
+++ b/src/cmd/internal/gc/sinit.go
@@ -111,16 +111,16 @@
 		for l = initlist; l.N != nv; l = l.Next {
 		}
 		for ; l != nil; l = l.End {
-			fmt.Printf("\t%v %v refers to\n", l.N.Line(), Sconv(l.N.Sym, 0))
+			fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
 		}
 
 		// Print n -> ... -> nv.
 		for l = initlist; l.N != n; l = l.Next {
 		}
 		for ; l.N != nv; l = l.End {
-			fmt.Printf("\t%v %v refers to\n", l.N.Line(), Sconv(l.N.Sym, 0))
+			fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
 		}
-		fmt.Printf("\t%v %v\n", nv.Line(), Sconv(nv.Sym, 0))
+		fmt.Printf("\t%v %v\n", nv.Line(), nv.Sym)
 		errorexit()
 	}
 
@@ -162,7 +162,7 @@
 
 			init2(n.Defn.Right, out)
 			if Debug['j'] != 0 {
-				fmt.Printf("%v\n", Sconv(n.Sym, 0))
+				fmt.Printf("%v\n", n.Sym)
 			}
 			if isblank(n) || !staticinit(n, out) {
 				if Debug['%'] != 0 {
@@ -207,7 +207,7 @@
 	}
 
 	if n.Op == ONAME && n.Ninit != nil {
-		Fatal("name %v with ninit: %v\n", Sconv(n.Sym, 0), Nconv(n, obj.FmtSign))
+		Fatal("name %v with ninit: %v\n", n.Sym, Nconv(n, obj.FmtSign))
 	}
 
 	init1(n, out)
@@ -529,7 +529,7 @@
 	if n.Op != ONAME {
 		return false
 	}
-	if n.Addable == 0 {
+	if !n.Addable {
 		return false
 	}
 	if n.Class&PHEAP != 0 {
@@ -593,7 +593,7 @@
 	for nl := n.List; nl != nil; nl = nl.Next {
 		r = nl.N
 		if r.Op != OKEY {
-			Fatal("structlit: rhs not OKEY: %v", Nconv(r, 0))
+			Fatal("structlit: rhs not OKEY: %v", r)
 		}
 		index = r.Left
 		value = r.Right
@@ -660,7 +660,7 @@
 	for l := n.List; l != nil; l = l.Next {
 		r = l.N
 		if r.Op != OKEY {
-			Fatal("arraylit: rhs not OKEY: %v", Nconv(r, 0))
+			Fatal("arraylit: rhs not OKEY: %v", r)
 		}
 		index = r.Left
 		value = r.Right
@@ -835,7 +835,7 @@
 	for l := n.List; l != nil; l = l.Next {
 		r = l.N
 		if r.Op != OKEY {
-			Fatal("slicelit: rhs not OKEY: %v", Nconv(r, 0))
+			Fatal("slicelit: rhs not OKEY: %v", r)
 		}
 		index = r.Left
 		value = r.Right
@@ -892,7 +892,7 @@
 		r = l.N
 
 		if r.Op != OKEY {
-			Fatal("maplit: rhs not OKEY: %v", Nconv(r, 0))
+			Fatal("maplit: rhs not OKEY: %v", r)
 		}
 		index = r.Left
 		value = r.Right
@@ -943,7 +943,7 @@
 			r = l.N
 
 			if r.Op != OKEY {
-				Fatal("maplit: rhs not OKEY: %v", Nconv(r, 0))
+				Fatal("maplit: rhs not OKEY: %v", r)
 			}
 			index = r.Left
 			value = r.Right
@@ -1012,7 +1012,7 @@
 		r = l.N
 
 		if r.Op != OKEY {
-			Fatal("maplit: rhs not OKEY: %v", Nconv(r, 0))
+			Fatal("maplit: rhs not OKEY: %v", r)
 		}
 		index = r.Left
 		value = r.Right
@@ -1239,7 +1239,7 @@
 	switch n.Op {
 	case ONAME:
 		*nam = *n
-		return n.Addable != 0
+		return n.Addable
 
 	case ODOT:
 		if !stataddr(nam, n.Left) {
@@ -1363,7 +1363,7 @@
 			return n.Val.U.Sval == ""
 
 		case CTBOOL:
-			return n.Val.U.Bval == 0
+			return !n.Val.U.Bval
 
 		case CTINT, CTRUNE:
 			return mpcmpfixc(n.Val.U.Xval, 0) == 0
diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go
index 5508e07..06ceff5 100644
--- a/src/cmd/internal/gc/subr.go
+++ b/src/cmd/internal/gc/subr.go
@@ -25,10 +25,6 @@
 
 var errors []Error
 
-var nerr int
-
-var merr int
-
 func errorexit() {
 	Flusherrors()
 	if outfile != "" {
@@ -49,13 +45,13 @@
 	if n.Op != ODOT {
 		return
 	}
-	old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), Nconv(n.Left, 0))
+	old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
 	if len(errors) > 0 && int32(errors[len(errors)-1].lineno) == n.Lineno && errors[len(errors)-1].msg == old {
-		errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), Nconv(n.Left, 0), Nconv(n, 0))
+		errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
 	}
 }
 
-func adderr(line int, format string, args []interface{}) {
+func adderr(line int, format string, args ...interface{}) {
 	errors = append(errors, Error{
 		seq:    len(errors),
 		lineno: line,
@@ -86,7 +82,7 @@
 }
 
 func Flusherrors() {
-	obj.Bflush(&bstdout)
+	bstdout.Flush()
 	if len(errors) == 0 {
 		return
 	}
@@ -110,8 +106,8 @@
 	}
 }
 
-func yyerrorl(line int, fmt_ string, args ...interface{}) {
-	adderr(line, fmt_, args)
+func yyerrorl(line int, format string, args ...interface{}) {
+	adderr(line, format, args...)
 
 	hcrash()
 	nerrors++
@@ -122,25 +118,18 @@
 	}
 }
 
-var yystate int
-
-var yychar_subr int
-
 var yyerror_lastsyntax int
 
-func Yyerror(fmt_ string, args ...interface{}) {
-	// bison used to invoke yyerror("syntax error").
-	// With Go yacc we get yyerror("%s", "syntax error").
-	// Convert to keep the old code working.
-	if fmt_ == "%s" && len(args) == 1 && args[0] == "syntax error" {
-		fmt_ = "syntax error"
-		args = nil
-	}
-	if strings.HasPrefix(fmt_, "syntax error") {
+func Yyerror(format string, args ...interface{}) {
+	msg := fmt.Sprintf(format, args...)
+	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_subr)
+			fmt.Printf("yyerror: yystate=%d yychar=%d\n", yystate, yychar)
 		}
 
 		// An unexpected EOF caused a syntax error. Use the previous
@@ -155,41 +144,35 @@
 		}
 		yyerror_lastsyntax = int(lexlineno)
 
-		if strings.Contains(fmt_, "{ or {") || strings.Contains(fmt_, " or ?") || strings.Contains(fmt_, " or @") {
-			// The grammar has { and LBRACE but both show up as {.
-			// Rewrite syntax error referring to "{ or {" to say just "{".
-			// The grammar has ? and @ but only for reading imports.
-			// Silence them in ordinary errors.
-			fmt_ = strings.Replace(fmt_, "{ or {", "{", -1)
-			fmt_ = strings.Replace(fmt_, " or ?", "", -1)
-			fmt_ = strings.Replace(fmt_, " or @", "", -1)
-		}
-
 		// look for parse state-specific errors in list (see go.errors).
-		for i := 0; i < len(yymsg); i++ {
-			if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar_subr {
+		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 fmt_ == "syntax error" {
+		if msg == "syntax error" {
 			yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String())
 			return
 		}
 
-		// if bison says "syntax error, more info"; print "syntax error: more info".
-		if fmt_[12] == ',' {
-			yyerrorl(int(lexlineno), "syntax error:%s", fmt_[13:])
-			return
-		}
+		// The grammar has { and LBRACE but both show up as {.
+		// Rewrite syntax error referring to "{ or {" to say just "{".
+		// The grammar has ? and @ but only for reading imports.
+		// Silence them in ordinary errors.
+		msg = strings.Replace(msg, "{ or {", "{", -1)
+		msg = strings.Replace(msg, " or ?", "", -1)
+		msg = strings.Replace(msg, " or @", "", -1)
 
-		yyerrorl(int(lexlineno), "%s", fmt_)
+		msg = strings.Replace(msg, "LLITERAL", litbuf, -1)
+
+		yyerrorl(int(lexlineno), "%s", msg)
 		return
 	}
 
-	adderr(parserline(), fmt_, args)
+	adderr(parserline(), "%s", msg)
 
 	hcrash()
 	nerrors++
@@ -201,13 +184,13 @@
 }
 
 func Warn(fmt_ string, args ...interface{}) {
-	adderr(parserline(), fmt_, args)
+	adderr(parserline(), fmt_, args...)
 
 	hcrash()
 }
 
 func Warnl(line int, fmt_ string, args ...interface{}) {
-	adderr(line, fmt_, args)
+	adderr(line, fmt_, args...)
 	if Debug['m'] != 0 {
 		Flusherrors()
 	}
@@ -415,7 +398,7 @@
 // the last field, total gives the size of the enclosing struct.
 func ispaddedfield(t *Type, total int64) bool {
 	if t.Etype != TFIELD {
-		Fatal("ispaddedfield called non-field %v", Tconv(t, 0))
+		Fatal("ispaddedfield called non-field %v", t)
 	}
 	if t.Down == nil {
 		return t.Width+t.Type.Width != total
@@ -531,7 +514,7 @@
 		return ret
 	}
 
-	Fatal("algtype1: unexpected type %v", Tconv(t, 0))
+	Fatal("algtype1: unexpected type %v", t)
 	return 0
 }
 
@@ -578,7 +561,7 @@
 		switch mtype {
 		default:
 			if atype == ANOEQ {
-				Yyerror("invalid map key type %v", Tconv(key, 0))
+				Yyerror("invalid map key type %v", key)
 			}
 
 			// will be resolved later.
@@ -682,7 +665,7 @@
 
 func Nodintconst(v int64) *Node {
 	c := Nod(OLITERAL, nil, nil)
-	c.Addable = 1
+	c.Addable = true
 	c.Val.U.Xval = new(Mpint)
 	Mpmovecfix(c.Val.U.Xval, v)
 	c.Val.Ctype = CTINT
@@ -693,8 +676,8 @@
 
 func nodfltconst(v *Mpflt) *Node {
 	c := Nod(OLITERAL, nil, nil)
-	c.Addable = 1
-	c.Val.U.Fval = new(Mpflt)
+	c.Addable = true
+	c.Val.U.Fval = newMpflt()
 	mpmovefltflt(c.Val.U.Fval, v)
 	c.Val.Ctype = CTFLT
 	c.Type = Types[TIDEAL]
@@ -705,7 +688,7 @@
 func Nodconst(n *Node, t *Type, v int64) {
 	*n = Node{}
 	n.Op = OLITERAL
-	n.Addable = 1
+	n.Addable = true
 	ullmancalc(n)
 	n.Val.U.Xval = new(Mpint)
 	Mpmovecfix(n.Val.U.Xval, v)
@@ -713,7 +696,7 @@
 	n.Type = t
 
 	if Isfloat[t.Etype] {
-		Fatal("nodconst: bad type %v", Tconv(t, 0))
+		Fatal("nodconst: bad type %v", t)
 	}
 }
 
@@ -727,7 +710,7 @@
 func Nodbool(b bool) *Node {
 	c := Nodintconst(0)
 	c.Val.Ctype = CTBOOL
-	c.Val.U.Bval = int16(bool2int(b))
+	c.Val.U.Bval = b
 	c.Type = idealbool
 	return c
 }
@@ -1003,7 +986,7 @@
 		t2 = t2.Type
 		for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down {
 			if t1.Etype != TFIELD || t2.Etype != TFIELD {
-				Fatal("struct/interface missing field: %v %v", Tconv(t1, 0), Tconv(t2, 0))
+				Fatal("struct/interface missing field: %v %v", t1, t2)
 			}
 			if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, &l) || !eqnote(t1.Note, t2.Note) {
 				return false
@@ -1021,7 +1004,7 @@
 		t2 = t2.Type
 		for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down {
 			if t1.Etype != TSTRUCT || t2.Etype != TSTRUCT {
-				Fatal("func missing struct: %v %v", Tconv(t1, 0), Tconv(t2, 0))
+				Fatal("func missing struct: %v %v", t1, t2)
 			}
 
 			// Loop over fields in structs, ignoring argument names.
@@ -1029,7 +1012,7 @@
 			tb := t2.Type
 			for ; ta != nil && tb != nil; ta, tb = ta.Down, tb.Down {
 				if ta.Etype != TFIELD || tb.Etype != TFIELD {
-					Fatal("func struct missing field: %v %v", Tconv(ta, 0), Tconv(tb, 0))
+					Fatal("func struct missing field: %v %v", ta, tb)
 				}
 				if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, &l) {
 					return false
@@ -1137,17 +1120,17 @@
 
 		if why != nil {
 			if isptrto(src, TINTER) {
-				*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", Tconv(src, 0))
+				*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
 			} else if have != nil && have.Sym == missing.Sym && have.Nointerface {
-				*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", Tconv(src, 0), Tconv(dst, 0), Sconv(missing.Sym, 0))
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
 			} else if have != nil && have.Sym == missing.Sym {
-				*why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(src, 0), Tconv(dst, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", src, dst, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
 			} else if ptr != 0 {
-				*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", Tconv(src, 0), Tconv(dst, 0), Sconv(missing.Sym, 0))
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
 			} else if have != nil {
-				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(src, 0), Tconv(dst, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", src, dst, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
 			} else {
-				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", Tconv(src, 0), Tconv(dst, 0), Sconv(missing.Sym, 0))
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
 			}
 		}
 
@@ -1156,7 +1139,7 @@
 
 	if isptrto(dst, TINTER) {
 		if why != nil {
-			*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", Tconv(dst, 0))
+			*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
 		}
 		return 0
 	}
@@ -1350,7 +1333,7 @@
 	var why string
 	op := assignop(n.Type, t, &why)
 	if op == 0 {
-		Yyerror("cannot use %v as type %v in %s%s", Nconv(n, obj.FmtLong), Tconv(t, 0), context(), why)
+		Yyerror("cannot use %v as type %v in %s%s", Nconv(n, obj.FmtLong), t, context(), why)
 		op = OCONV
 	}
 
@@ -1563,10 +1546,25 @@
 	return binary.LittleEndian.Uint32(h[:4])
 }
 
-func Ptrto(t *Type) *Type {
-	if Tptr == 0 {
-		Fatal("ptrto: no tptr")
-	}
+var initPtrtoDone bool
+
+var (
+	ptrToUint8  *Type
+	ptrToAny    *Type
+	ptrToString *Type
+	ptrToBool   *Type
+	ptrToInt32  *Type
+)
+
+func initPtrto() {
+	ptrToUint8 = ptrto1(Types[TUINT8])
+	ptrToAny = ptrto1(Types[TANY])
+	ptrToString = ptrto1(Types[TSTRING])
+	ptrToBool = ptrto1(Types[TBOOL])
+	ptrToInt32 = ptrto1(Types[TINT32])
+}
+
+func ptrto1(t *Type) *Type {
 	t1 := typ(Tptr)
 	t1.Type = t
 	t1.Width = int64(Widthptr)
@@ -1574,6 +1572,32 @@
 	return t1
 }
 
+// Ptrto returns the Type *t.
+// The returned struct must not be modified.
+func Ptrto(t *Type) *Type {
+	if Tptr == 0 {
+		Fatal("ptrto: no tptr")
+	}
+	// Reduce allocations by pre-creating common cases.
+	if !initPtrtoDone {
+		initPtrto()
+		initPtrtoDone = true
+	}
+	switch t {
+	case Types[TUINT8]:
+		return ptrToUint8
+	case Types[TINT32]:
+		return ptrToInt32
+	case Types[TANY]:
+		return ptrToAny
+	case Types[TSTRING]:
+		return ptrToString
+	case Types[TBOOL]:
+		return ptrToBool
+	}
+	return ptrto1(t)
+}
+
 func frame(context int) {
 	var l *NodeList
 
@@ -1581,7 +1605,7 @@
 		fmt.Printf("--- external frame ---\n")
 		l = externdcl
 	} else if Curfn != nil {
-		fmt.Printf("--- %v frame ---\n", Sconv(Curfn.Nname.Sym, 0))
+		fmt.Printf("--- %v frame ---\n", Curfn.Nname.Sym)
 		l = Curfn.Func.Dcl
 	} else {
 		return
@@ -1597,10 +1621,10 @@
 		}
 		switch n.Op {
 		case ONAME:
-			fmt.Printf("%v %v G%d %v width=%d\n", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), n.Vargen, Tconv(n.Type, 0), w)
+			fmt.Printf("%v %v G%d %v width=%d\n", Oconv(int(n.Op), 0), n.Sym, n.Vargen, n.Type, w)
 
 		case OTYPE:
-			fmt.Printf("%v %v width=%d\n", Oconv(int(n.Op), 0), Tconv(n.Type, 0), w)
+			fmt.Printf("%v %v width=%d\n", Oconv(int(n.Op), 0), n.Type, w)
 		}
 	}
 }
@@ -1631,7 +1655,7 @@
 		}
 		goto out
 
-	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OASWB:
 		ul = UINF
 		goto out
 
@@ -1668,10 +1692,10 @@
 func badtype(o int, tl *Type, tr *Type) {
 	fmt_ := ""
 	if tl != nil {
-		fmt_ += fmt.Sprintf("\n\t%v", Tconv(tl, 0))
+		fmt_ += fmt.Sprintf("\n\t%v", tl)
 	}
 	if tr != nil {
-		fmt_ += fmt.Sprintf("\n\t%v", Tconv(tr, 0))
+		fmt_ += fmt.Sprintf("\n\t%v", tr)
 	}
 
 	// common mistake: *struct and *interface.
@@ -1712,14 +1736,14 @@
 	}
 
 	if t.Etype != TFIELD {
-		Fatal("structfirst: not field %v", Tconv(t, 0))
+		Fatal("structfirst: not field %v", t)
 	}
 
 	s.T = t
 	return t
 
 bad:
-	Fatal("structfirst: not struct %v", Tconv(n, 0))
+	Fatal("structfirst: not struct %v", n)
 
 	return nil
 }
@@ -1732,7 +1756,7 @@
 	}
 
 	if t.Etype != TFIELD {
-		Fatal("structnext: not struct %v", Tconv(n, 0))
+		Fatal("structnext: not struct %v", n)
 
 		return nil
 	}
@@ -1766,7 +1790,7 @@
 	return fp
 
 bad:
-	Fatal("funcfirst: not func %v", Tconv(t, 0))
+	Fatal("funcfirst: not func %v", t)
 	return nil
 }
 
@@ -1782,21 +1806,21 @@
 
 func getthis(t *Type) **Type {
 	if t.Etype != TFUNC {
-		Fatal("getthis: not a func %v", Tconv(t, 0))
+		Fatal("getthis: not a func %v", t)
 	}
 	return &t.Type
 }
 
 func Getoutarg(t *Type) **Type {
 	if t.Etype != TFUNC {
-		Fatal("getoutarg: not a func %v", Tconv(t, 0))
+		Fatal("getoutarg: not a func %v", t)
 	}
 	return &t.Type.Down
 }
 
 func getinarg(t *Type) **Type {
 	if t.Etype != TFUNC {
-		Fatal("getinarg: not a func %v", Tconv(t, 0))
+		Fatal("getinarg: not a func %v", t)
 	}
 	return &t.Type.Down.Down
 }
@@ -1813,10 +1837,8 @@
 	return *getinarg(t)
 }
 
-/*
- * return !(op)
- * eg == <=> !=
- */
+// Brcom returns !(op).
+// For example, Brcom(==) is !=.
 func Brcom(a int) int {
 	switch a {
 	case OEQ:
@@ -1832,15 +1854,12 @@
 	case OGE:
 		return OLT
 	}
-
-	Fatal("brcom: no com for %v\n", Oconv(int(a), 0))
+	Fatal("brcom: no com for %v\n", Oconv(a, 0))
 	return a
 }
 
-/*
- * return reverse(op)
- * eg a op b <=> b r(op) a
- */
+// Brrev returns reverse(op).
+// For example, Brrev(<) is >.
 func Brrev(a int) int {
 	switch a {
 	case OEQ:
@@ -1856,8 +1875,7 @@
 	case OGE:
 		return OLE
 	}
-
-	Fatal("brcom: no rev for %v\n", Oconv(int(a), 0))
+	Fatal("brrev: no rev for %v\n", Oconv(a, 0))
 	return a
 }
 
@@ -1919,7 +1937,7 @@
 
 	// make a copy; must not be used as an lvalue
 	if islvalue(n) {
-		Fatal("missing lvalue case in safeexpr: %v", Nconv(n, 0))
+		Fatal("missing lvalue case in safeexpr: %v", n)
 	}
 	return cheapexpr(n, init)
 }
@@ -1963,11 +1981,11 @@
 	dowidth(t)
 	w := t.Argwid
 	if w >= Thearch.MAXWIDTH {
-		Fatal("bad argwid %v", Tconv(t, 0))
+		Fatal("bad argwid %v", t)
 	}
 	w += int64(extra)
 	if w >= Thearch.MAXWIDTH {
-		Fatal("bad argwid %d + %v", extra, Tconv(t, 0))
+		Fatal("bad argwid %d + %v", extra, t)
 	}
 	if w > Maxarg {
 		Maxarg = w
@@ -2096,7 +2114,7 @@
 		c = adddot1(s, t, d, nil, 0)
 		if c > 0 {
 			if c > 1 {
-				Yyerror("ambiguous selector %v", Nconv(n, 0))
+				Yyerror("ambiguous selector %v", n)
 				n.Left = nil
 				return n
 			}
@@ -2334,7 +2352,7 @@
 
 func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 	if false && Debug['r'] != 0 {
-		fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", Tconv(rcvr, 0), Tconv(method, 0), Sconv(newnam, 0))
+		fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
 	}
 
 	lexlineno++
@@ -2537,7 +2555,7 @@
  */
 func genhash(sym *Sym, t *Type) {
 	if Debug['r'] != 0 {
-		fmt.Printf("genhash %v %v\n", Sconv(sym, 0), Tconv(t, 0))
+		fmt.Printf("genhash %v %v\n", sym, t)
 	}
 
 	lineno = 1 // less confusing than end of input
@@ -2569,11 +2587,11 @@
 	// so t must be either an array or a struct.
 	switch t.Etype {
 	default:
-		Fatal("genhash %v", Tconv(t, 0))
+		Fatal("genhash %v", t)
 
 	case TARRAY:
 		if Isslice(t) {
-			Fatal("genhash %v", Tconv(t, 0))
+			Fatal("genhash %v", t)
 		}
 
 		// An array of pure memory would be handled by the
@@ -2585,7 +2603,7 @@
 		ni := newname(Lookup("i"))
 		ni.Type = Types[TINT]
 		n.List = list1(ni)
-		n.Colas = 1
+		n.Colas = true
 		colasdefn(n.List, n)
 		ni = n.List.N
 
@@ -2789,7 +2807,7 @@
  */
 func geneq(sym *Sym, t *Type) {
 	if Debug['r'] != 0 {
-		fmt.Printf("geneq %v %v\n", Sconv(sym, 0), Tconv(t, 0))
+		fmt.Printf("geneq %v %v\n", sym, t)
 	}
 
 	lineno = 1 // less confusing than end of input
@@ -2820,11 +2838,11 @@
 	// so t must be either an array or a struct.
 	switch t.Etype {
 	default:
-		Fatal("geneq %v", Tconv(t, 0))
+		Fatal("geneq %v", t)
 
 	case TARRAY:
 		if Isslice(t) {
-			Fatal("geneq %v", Tconv(t, 0))
+			Fatal("geneq %v", t)
 		}
 
 		// An array of pure memory would be handled by the
@@ -2837,7 +2855,7 @@
 		ni := newname(Lookup("i"))
 		ni.Type = Types[TINT]
 		nrange.List = list1(ni)
-		nrange.Colas = 1
+		nrange.Colas = true
 		colasdefn(nrange.List, nrange)
 		ni = nrange.List.N
 
@@ -2954,7 +2972,7 @@
 	for d := 0; d < len(dotlist); d++ {
 		c = adddot1(s, t, d, &m, ignorecase)
 		if c > 1 {
-			Yyerror("%v.%v is ambiguous", Tconv(t, 0), Sconv(s, 0))
+			Yyerror("%v.%v is ambiguous", t, s)
 			return nil
 		}
 
@@ -2967,7 +2985,7 @@
 			}
 
 			if m.Type.Etype != TFUNC || m.Type.Thistuple == 0 {
-				Yyerror("%v.%v is a field, not a method", Tconv(t, 0), Sconv(s, 0))
+				Yyerror("%v.%v is a field, not a method", t, s)
 				return nil
 			}
 
@@ -3157,7 +3175,7 @@
 	// that this relation is immutable
 	switch t.Etype {
 	default:
-		fmt.Printf("tounsigned: unknown type %v\n", Tconv(t, 0))
+		fmt.Printf("tounsigned: unknown type %v\n", t)
 		t = nil
 
 	case TINT:
diff --git a/src/cmd/internal/gc/swt.go b/src/cmd/internal/gc/swt.go
index 991f3ac..7cb632c 100644
--- a/src/cmd/internal/gc/swt.go
+++ b/src/cmd/internal/gc/swt.go
@@ -94,7 +94,7 @@
 			case t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ:
 				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
 			case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ:
-				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Ntest, obj.FmtLong), Tconv(badtype, 0))
+				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Ntest, obj.FmtLong), badtype)
 			case t.Etype == TFUNC:
 				nilonly = "func"
 			case t.Etype == TMAP:
@@ -131,15 +131,15 @@
 					defaultlit(&ll.N, t)
 					switch {
 					case ll.N.Op == OTYPE:
-						Yyerror("type %v is not an expression", Tconv(ll.N.Type, 0))
+						Yyerror("type %v is not an expression", ll.N.Type)
 					case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0:
 						if n.Ntest != nil {
-							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", Nconv(ll.N, 0), Nconv(n.Ntest, 0), Tconv(ll.N.Type, 0), Tconv(t, 0))
+							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", ll.N, n.Ntest, ll.N.Type, t)
 						} else {
-							Yyerror("invalid case %v in switch (mismatched types %v and bool)", Nconv(ll.N, 0), Tconv(ll.N.Type, 0))
+							Yyerror("invalid case %v in switch (mismatched types %v and bool)", ll.N, ll.N.Type)
 						}
 					case nilonly != "" && !Isconst(ll.N, CTNIL):
-						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", Nconv(ll.N, 0), nilonly, Nconv(n.Ntest, 0))
+						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", ll.N, nilonly, n.Ntest)
 					}
 
 				// type switch
@@ -154,9 +154,9 @@
 						ll.N = n.Ntest.Right
 					case ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr):
 						if have != nil && missing.Broke == 0 && have.Broke == 0 {
-							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort))
+							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Ntest.Right, obj.FmtLong), ll.N.Type, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort), missing.Sym, Tconv(missing.Type, obj.FmtShort))
 						} else if missing.Broke == 0 {
-							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0))
+							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Ntest.Right, obj.FmtLong), ll.N.Type, missing.Sym)
 						}
 					}
 				}
@@ -218,7 +218,7 @@
 	s.kind = switchKindExpr
 	if Isconst(sw.Ntest, CTBOOL) {
 		s.kind = switchKindTrue
-		if sw.Ntest.Val.U.Bval == 0 {
+		if !sw.Ntest.Val.U.Bval {
 			s.kind = switchKindFalse
 		}
 	}
@@ -481,7 +481,7 @@
 					break
 				}
 				if Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
-					yyerrorl(int(c2.node.Lineno), "duplicate case %v in type switch\n\tprevious case at %v", Tconv(c2.node.Left.Type, 0), c1.node.Line())
+					yyerrorl(int(c2.node.Lineno), "duplicate case %v in type switch\n\tprevious case at %v", c2.node.Left.Type, c1.node.Line())
 				}
 			}
 		}
@@ -497,7 +497,7 @@
 				continue
 			}
 			setlineno(c2.node)
-			Yyerror("duplicate case %v in switch\n\tprevious case at %v", Nconv(c1.node.Left, 0), c1.node.Line())
+			Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line())
 		}
 	}
 
diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go
index 8f5b85d..7c9fb8d 100644
--- a/src/cmd/internal/gc/syntax.go
+++ b/src/cmd/internal/gc/syntax.go
@@ -26,13 +26,13 @@
 	Op          uint8
 	Nointerface bool
 	Ullman      uint8 // sethi/ullman number
-	Addable     uint8 // type of addressability - 0 is not addressable
+	Addable     bool  // addressable
 	Etype       uint8 // op for OASOP, etype for OTYPE, exclam for export
 	Bounded     bool  // bounds check unnecessary
 	Class       uint8 // PPARAM, PAUTO, PEXTERN, etc
-	Method      uint8 // OCALLMETH name
+	Method      bool  // OCALLMETH is direct method call
 	Embedded    uint8 // ODCLFIELD embedded type
-	Colas       uint8 // OAS resulting from :=
+	Colas       bool  // OAS resulting from :=
 	Diag        uint8 // already printed error about this
 	Noescape    bool  // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
 	Walkdef     uint8
@@ -44,15 +44,15 @@
 	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         uint8 // EscXXX
+	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
 
 	// most nodes
@@ -63,9 +63,12 @@
 	// func
 	Func *Func
 
-	// OLITERAL/OREGISTER
+	// OLITERAL
 	Val Val
 
+	// OREGISTER, OINDREG
+	Reg int16
+
 	// ONAME
 	Ntype     *Node
 	Defn      *Node // ONAME: initializing assignment; OLABEL: labeled statement
@@ -100,14 +103,14 @@
 	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
+	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 int32
+	Esclevel Level
 	Opt      interface{} // for optimization passes
 }
 
@@ -167,6 +170,7 @@
 	OAS2MAPR         // x, ok = m["foo"]
 	OAS2DOTTYPE      // x, ok = I.(int)
 	OASOP            // x += y
+	OASWB            // OAS but with write barrier
 	OCALL            // function call, method call or type conversion, possibly preceded by defer or go.
 	OCALLFUNC        // f()
 	OCALLMETH        // t.Method()
@@ -293,7 +297,7 @@
 	OREGISTER // a register, such as AX.
 	OINDREG   // offset plus indirect of a register, such as 8(SP).
 
-	// 386/amd64-specific opcodes
+	// arch-specific opcodes
 	OCMP    // compare: ACMP.
 	ODEC    // decrement: ADEC.
 	OINC    // increment: AINC.
@@ -303,6 +307,9 @@
 	ORROTC  // right rotate-carry: ARCR.
 	ORETJMP // return to other function
 	OPS     // compare parity set (for x86 NaN check)
+	OPC     // compare parity clear (for x86 NaN check)
+	OSQRT   // sqrt(float64), on systems that have hw support
+	OGETG   // runtime.getg() (read g pointer)
 
 	OEND
 )
diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go
index 4399164..6daf842 100644
--- a/src/cmd/internal/gc/typecheck.go
+++ b/src/cmd/internal/gc/typecheck.go
@@ -75,8 +75,6 @@
 	TIDEAL:      "untyped number",
 }
 
-var typekind_buf string
-
 func typekind(t *Type) string {
 	if Isslice(t) {
 		return "slice"
@@ -88,8 +86,7 @@
 			return s
 		}
 	}
-	typekind_buf = fmt.Sprintf("etype=%d", et)
-	return typekind_buf
+	return fmt.Sprintf("etype=%d", et)
 }
 
 /*
@@ -104,7 +101,7 @@
 			if l.N != first {
 				sprint_depchain(fmt_, l.Next, l.N, first)
 			}
-			*fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", l.N.Line(), Nconv(l.N, 0), Nconv(cur, 0))
+			*fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", l.N.Line(), l.N, cur)
 			return
 		}
 	}
@@ -163,12 +160,12 @@
 		// We can already diagnose variables used as types.
 		case ONAME:
 			if top&(Erv|Etype) == Etype {
-				Yyerror("%v is not a type", Nconv(n, 0))
+				Yyerror("%v is not a type", n)
 			}
 
 		case OLITERAL:
 			if top&(Erv|Etype) == Etype {
-				Yyerror("%v is not a type", Nconv(n, 0))
+				Yyerror("%v is not a type", n)
 				break
 			}
 
@@ -180,9 +177,9 @@
 		if nsavederrors+nerrors == 0 {
 			fmt_ = ""
 			for l := typecheck_tcstack; l != nil; l = l.Next {
-				fmt_ += fmt.Sprintf("\n\t%v %v", l.N.Line(), Nconv(l.N, 0))
+				fmt_ += fmt.Sprintf("\n\t%v %v", l.N.Line(), l.N)
 			}
-			Yyerror("typechecking loop involving %v%s", Nconv(n, 0), fmt_)
+			Yyerror("typechecking loop involving %v%s", n, fmt_)
 		}
 
 		lineno = int32(lno)
@@ -277,7 +274,7 @@
 
 	if n.Sym != nil {
 		if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
-			Yyerror("use of builtin %v not in function call", Sconv(n.Sym, 0))
+			Yyerror("use of builtin %v not in function call", n.Sym)
 			n.Type = nil
 			return
 		}
@@ -334,7 +331,7 @@
 		}
 
 		if top&Ecall == 0 && isunsafebuiltin(n) {
-			Yyerror("%v is not an expression, must be called", Nconv(n, 0))
+			Yyerror("%v is not an expression, must be called", n)
 			n.Type = nil
 			return
 		}
@@ -343,7 +340,7 @@
 		break OpSwitch
 
 	case OPACK:
-		Yyerror("use of package %v without selector", Sconv(n.Sym, 0))
+		Yyerror("use of package %v without selector", n.Sym)
 		n.Type = nil
 		return
 
@@ -387,9 +384,9 @@
 
 			default:
 				if l.Type != nil && Isint[l.Type.Etype] && l.Op != OLITERAL {
-					Yyerror("non-constant array bound %v", Nconv(l, 0))
+					Yyerror("non-constant array bound %v", l)
 				} else {
-					Yyerror("invalid array bound %v", Nconv(l, 0))
+					Yyerror("invalid array bound %v", l)
 				}
 				n.Type = nil
 				return
@@ -566,14 +563,14 @@
 			n.Right = r
 			t := r.Type
 			if !Isint[t.Etype] || Issigned[t.Etype] {
-				Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0))
+				Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", n, r.Type)
 				n.Type = nil
 				return
 			}
 
 			t = l.Type
 			if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] {
-				Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
+				Yyerror("invalid operation: %v (shift of type %v)", n, t)
 				n.Type = nil
 				return
 			}
@@ -615,7 +612,7 @@
 				aop = assignop(l.Type, r.Type, nil)
 				if aop != 0 {
 					if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ {
-						Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type))
+						Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(int(op), 0), typekind(l.Type))
 						n.Type = nil
 						return
 					}
@@ -637,7 +634,7 @@
 				aop = assignop(r.Type, l.Type, nil)
 				if aop != 0 {
 					if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ {
-						Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type))
+						Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(int(op), 0), typekind(r.Type))
 						n.Type = nil
 						return
 					}
@@ -661,20 +658,20 @@
 		if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
 			defaultlit2(&l, &r, 1)
 			if n.Op == OASOP && n.Implicit {
-				Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0))
+				Yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type)
 				n.Type = nil
 				return
 			}
 
 			if Isinter(r.Type) == Isinter(l.Type) || aop == 0 {
-				Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
+				Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
 				n.Type = nil
 				return
 			}
 		}
 
 		if !okfor[op][et] {
-			Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t))
+			Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(int(op), 0), typekind(t))
 			n.Type = nil
 			return
 		}
@@ -682,32 +679,32 @@
 		// okfor allows any array == array, map == map, func == func.
 		// restrict to slice/map/func == nil and nil == slice/map/func.
 		if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ {
-			Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0))
+			Yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
 			n.Type = nil
 			return
 		}
 
 		if Isslice(l.Type) && !isnil(l) && !isnil(r) {
-			Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0))
+			Yyerror("invalid operation: %v (slice can only be compared to nil)", n)
 			n.Type = nil
 			return
 		}
 
 		if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
-			Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0))
+			Yyerror("invalid operation: %v (map can only be compared to nil)", n)
 			n.Type = nil
 			return
 		}
 
 		if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
-			Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0))
+			Yyerror("invalid operation: %v (func can only be compared to nil)", n)
 			n.Type = nil
 			return
 		}
 
 		var badtype *Type
 		if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ {
-			Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0))
+			Yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, badtype)
 			n.Type = nil
 			return
 		}
@@ -792,7 +789,7 @@
 			return
 		}
 		if !okfor[n.Op][t.Etype] {
-			Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), t)
 			n.Type = nil
 			return
 		}
@@ -822,7 +819,7 @@
 		}
 
 		if l.Orig != l && l.Op == ONAME {
-			Fatal("found non-orig name node %v", Nconv(l, 0))
+			Fatal("found non-orig name node %v", l)
 		}
 		l.Addrtaken = true
 		if l.Closure != nil {
@@ -878,16 +875,16 @@
 		if n.Left.Op == OTYPE {
 			if !looktypedot(n, t, 0) {
 				if looktypedot(n, t, 1) {
-					Yyerror("%v undefined (cannot refer to unexported method %v)", Nconv(n, 0), Sconv(n.Right.Sym, 0))
+					Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Right.Sym)
 				} else {
-					Yyerror("%v undefined (type %v has no method %v)", Nconv(n, 0), Tconv(t, 0), Sconv(n.Right.Sym, 0))
+					Yyerror("%v undefined (type %v has no method %v)", n, t, n.Right.Sym)
 				}
 				n.Type = nil
 				return
 			}
 
 			if n.Type.Etype != TFUNC || n.Type.Thistuple != 1 {
-				Yyerror("type %v has no method %v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort))
+				Yyerror("type %v has no method %v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort))
 				n.Type = nil
 				n.Type = nil
 				return
@@ -918,11 +915,26 @@
 			return
 		}
 
-		if !lookdot(n, t, 0) {
-			if lookdot(n, t, 1) {
-				Yyerror("%v undefined (cannot refer to unexported field or method %v)", Nconv(n, 0), Sconv(n.Right.Sym, 0))
-			} else {
-				Yyerror("%v undefined (type %v has no field or method %v)", Nconv(n, 0), Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
+		if lookdot(n, t, 0) == nil {
+			// Legitimate field or method lookup failed, try to explain the error
+			switch {
+			case isnilinter(t):
+				Yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
+
+			case Isptr[t.Etype] && Isinter(t.Type):
+				// Pointer to interface is almost always a mistake.
+				Yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
+
+			case lookdot(n, t, 1) != nil:
+				// Field or method matches by name, but it is not exported.
+				Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Right.Sym)
+
+			default:
+				if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
+					Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Right.Sym, mt.Sym)
+				} else {
+					Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
+				}
 			}
 			n.Type = nil
 			return
@@ -954,7 +966,7 @@
 			return
 		}
 		if !Isinter(t) {
-			Yyerror("invalid type assertion: %v (non-interface type %v on left)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t)
 			n.Type = nil
 			return
 		}
@@ -975,13 +987,13 @@
 			var ptr int
 			if !implements(n.Type, t, &missing, &have, &ptr) {
 				if have != nil && have.Sym == missing.Sym {
-					Yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", n.Type, t, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
 				} else if ptr != 0 {
-					Yyerror("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0))
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type, t, missing.Sym)
 				} else if have != nil {
-					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", n.Type, t, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
 				} else {
-					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0))
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type, t, missing.Sym)
 				}
 				n.Type = nil
 				return
@@ -1005,7 +1017,7 @@
 		}
 		switch t.Etype {
 		default:
-			Yyerror("invalid operation: %v (type %v does not support indexing)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (type %v does not support indexing)", n, t)
 			n.Type = nil
 			return
 
@@ -1026,20 +1038,20 @@
 			}
 
 			if n.Right.Type != nil && !Isint[n.Right.Type.Etype] {
-				Yyerror("non-integer %s index %v", why, Nconv(n.Right, 0))
+				Yyerror("non-integer %s index %v", why, n.Right)
 				break
 			}
 
 			if Isconst(n.Right, CTINT) {
 				x := Mpgetfix(n.Right.Val.U.Xval)
 				if x < 0 {
-					Yyerror("invalid %s index %v (index must be non-negative)", why, Nconv(n.Right, 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)", Nconv(n.Right, 0), 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)", Nconv(n.Right, 0), 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 {
-					Yyerror("invalid %s index %v (index too large)", why, Nconv(n.Right, 0))
+					Yyerror("invalid %s index %v (index too large)", why, n.Right)
 				}
 			}
 
@@ -1066,13 +1078,13 @@
 			return
 		}
 		if t.Etype != TCHAN {
-			Yyerror("invalid operation: %v (receive from non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (receive from non-chan type %v)", n, t)
 			n.Type = nil
 			return
 		}
 
 		if t.Chan&Crecv == 0 {
-			Yyerror("invalid operation: %v (receive from send-only type %v)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (receive from send-only type %v)", n, t)
 			n.Type = nil
 			return
 		}
@@ -1092,13 +1104,13 @@
 			return
 		}
 		if t.Etype != TCHAN {
-			Yyerror("invalid operation: %v (send to non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (send to non-chan type %v)", n, t)
 			n.Type = nil
 			return
 		}
 
 		if t.Chan&Csend == 0 {
-			Yyerror("invalid operation: %v (send to receive-only type %v)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (send to receive-only type %v)", n, t)
 			n.Type = nil
 			return
 		}
@@ -1128,7 +1140,7 @@
 		l := n.Left
 		if Isfixedarray(l.Type) {
 			if !islvalue(n.Left) {
-				Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0))
+				Yyerror("invalid operation %v (slice of unaddressable value)", n)
 				n.Type = nil
 				return
 			}
@@ -1158,7 +1170,7 @@
 		} else if Isslice(t) {
 			n.Type = t
 		} else {
-			Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0))
+			Yyerror("cannot slice %v (type %v)", l, t)
 			n.Type = nil
 			return
 		}
@@ -1192,7 +1204,7 @@
 		l := n.Left
 		if Isfixedarray(l.Type) {
 			if !islvalue(n.Left) {
-				Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0))
+				Yyerror("invalid operation %v (slice of unaddressable value)", n)
 				n.Type = nil
 				return
 			}
@@ -1209,7 +1221,7 @@
 			return
 		}
 		if Istype(t, TSTRING) {
-			Yyerror("invalid operation %v (3-index slice of string)", Nconv(n, 0))
+			Yyerror("invalid operation %v (3-index slice of string)", n)
 			n.Type = nil
 			return
 		}
@@ -1225,7 +1237,7 @@
 		} else if Isslice(t) {
 			n.Type = t
 		} else {
-			Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0))
+			Yyerror("cannot slice %v (type %v)", l, t)
 			n.Type = nil
 			return
 		}
@@ -1261,7 +1273,7 @@
 			r := unsafenmagic(n)
 			if r != nil {
 				if n.Isddd {
-					Yyerror("invalid use of ... with builtin %v", Nconv(l, 0))
+					Yyerror("invalid use of ... with builtin %v", l)
 				}
 				n = r
 				typecheck1(&n, top)
@@ -1274,7 +1286,7 @@
 		l = n.Left
 		if l.Op == ONAME && l.Etype != 0 {
 			if n.Isddd && l.Etype != OAPPEND {
-				Yyerror("invalid use of ... with builtin %v", Nconv(l, 0))
+				Yyerror("invalid use of ... with builtin %v", l)
 			}
 
 			// builtin: OLEN, OCAP, etc.
@@ -1304,7 +1316,7 @@
 
 			n.Op = OCONV
 			n.Type = l.Type
-			if onearg(n, "conversion to %v", Tconv(l.Type, 0)) < 0 {
+			if onearg(n, "conversion to %v", l.Type) < 0 {
 				n.Type = nil
 				return
 			}
@@ -1344,13 +1356,13 @@
 		default:
 			n.Op = OCALLFUNC
 			if t.Etype != TFUNC {
-				Yyerror("cannot call non-function %v (type %v)", Nconv(l, 0), Tconv(t, 0))
+				Yyerror("cannot call non-function %v (type %v)", l, t)
 				n.Type = nil
 				return
 			}
 		}
 
-		typecheckaste(OCALL, n.Left, n.Isddd, getinargx(t), n.List, func() string { return fmt.Sprintf("argument to %v", Nconv(n.Left, 0)) })
+		typecheckaste(OCALL, n.Left, n.Isddd, getinargx(t), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
 		ok |= Etop
 		if t.Outtuple == 0 {
 			break OpSwitch
@@ -1366,16 +1378,28 @@
 				t = t.Type
 			}
 			n.Type = t
+
+			if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime != 0 || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
+				// Emit code for runtime.getg() directly instead of calling function.
+				// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
+				// so that the ordering pass can make sure to preserve the semantics of the original code
+				// (in particular, the exact time of the function call) by introducing temporaries.
+				// In this case, we know getg() always returns the same result within a given function
+				// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
+				n.Op = OGETG
+			}
+
 			break OpSwitch
 		}
 
 		// multiple return
 		if top&(Efnstruct|Etop) == 0 {
-			Yyerror("multiple-value %v() in single-value context", Nconv(l, 0))
+			Yyerror("multiple-value %v() in single-value context", l)
 			break OpSwitch
 		}
 
 		n.Type = getoutargx(l.Type)
+
 		break OpSwitch
 
 	case OCAP, OLEN, OREAL, OIMAG:
@@ -1467,7 +1491,7 @@
 
 			t := n.List.N.Left.Type
 			if t.Outtuple != 2 {
-				Yyerror("invalid operation: complex expects two arguments, %v returns %d results", Nconv(n.List.N, 0), t.Outtuple)
+				Yyerror("invalid operation: complex expects two arguments, %v returns %d results", n.List.N, t.Outtuple)
 				n.Type = nil
 				return
 			}
@@ -1496,7 +1520,7 @@
 		}
 
 		if !Eqtype(l.Type, r.Type) {
-			Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
+			Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
 			n.Type = nil
 			return
 		}
@@ -1504,7 +1528,7 @@
 		var t *Type
 		switch l.Type.Etype {
 		default:
-			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", Nconv(n, 0), Tconv(l.Type, 0), r.Type)
+			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type, r.Type)
 			n.Type = nil
 			return
 
@@ -1543,13 +1567,13 @@
 			return
 		}
 		if t.Etype != TCHAN {
-			Yyerror("invalid operation: %v (non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
+			Yyerror("invalid operation: %v (non-chan type %v)", n, t)
 			n.Type = nil
 			return
 		}
 
 		if t.Chan&Csend == 0 {
-			Yyerror("invalid operation: %v (cannot close receive-only channel)", Nconv(n, 0))
+			Yyerror("invalid operation: %v (cannot close receive-only channel)", n)
 			n.Type = nil
 			return
 		}
@@ -1726,51 +1750,48 @@
 		break OpSwitch
 
 	case OCONV:
-		{
-			ok |= Erv
-			saveorignode(n)
-			typecheck(&n.Left, Erv|top&(Eindir|Eiota))
-			convlit1(&n.Left, n.Type, true)
-			t := n.Left.Type
-			if t == nil || n.Type == nil {
-				n.Type = nil
-				return
-			}
-			var why string
-			n.Op = uint8(convertop(t, n.Type, &why))
-			if (n.Op) == 0 {
-				if n.Diag == 0 && n.Type.Broke == 0 {
-					Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why)
-					n.Diag = 1
-				}
-
-				n.Op = OCONV
-			}
-
-			switch n.Op {
-			case OCONVNOP:
-				if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] {
-					r := Nod(OXXX, nil, nil)
-					n.Op = OCONV
-					n.Orig = r
-					*r = *n
-					n.Op = OLITERAL
-					n.Val = n.Left.Val
-				}
-
-				// do not use stringtoarraylit.
-			// generated code and compiler memory footprint is better without it.
-			case OSTRARRAYBYTE:
-				break
-
-			case OSTRARRAYRUNE:
-				if n.Left.Op == OLITERAL {
-					stringtoarraylit(&n)
-				}
-			}
-
-			break OpSwitch
+		ok |= Erv
+		saveorignode(n)
+		typecheck(&n.Left, Erv|top&(Eindir|Eiota))
+		convlit1(&n.Left, n.Type, true)
+		t := n.Left.Type
+		if t == nil || n.Type == nil {
+			n.Type = nil
+			return
 		}
+		var why string
+		n.Op = uint8(convertop(t, n.Type, &why))
+		if (n.Op) == 0 {
+			if n.Diag == 0 && n.Type.Broke == 0 {
+				Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), n.Type, why)
+				n.Diag = 1
+			}
+
+			n.Op = OCONV
+		}
+
+		switch n.Op {
+		case OCONVNOP:
+			if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] {
+				r := Nod(OXXX, nil, nil)
+				n.Op = OCONV
+				n.Orig = r
+				*r = *n
+				n.Op = OLITERAL
+				n.Val = n.Left.Val
+			}
+
+			// do not use stringtoarraylit.
+		// generated code and compiler memory footprint is better without it.
+		case OSTRARRAYBYTE:
+			break
+
+		case OSTRARRAYRUNE:
+			if n.Left.Op == OLITERAL {
+				stringtoarraylit(&n)
+			}
+		}
+
 		break OpSwitch
 
 	case OMAKE:
@@ -1794,19 +1815,19 @@
 
 		switch t.Etype {
 		default:
-			Yyerror("cannot make type %v", Tconv(t, 0))
+			Yyerror("cannot make type %v", t)
 			n.Type = nil
 			return
 
 		case TARRAY:
 			if !Isslice(t) {
-				Yyerror("cannot make type %v", Tconv(t, 0))
+				Yyerror("cannot make type %v", t)
 				n.Type = nil
 				return
 			}
 
 			if args == nil {
-				Yyerror("missing len argument to make(%v)", Tconv(t, 0))
+				Yyerror("missing len argument to make(%v)", t)
 				n.Type = nil
 				return
 			}
@@ -1825,14 +1846,14 @@
 				n.Type = nil
 				return
 			}
-			et := bool2int(checkmake(t, "len", l) < 0)
-			et |= bool2int(r != nil && checkmake(t, "cap", r) < 0)
+			et := obj.Bool2int(checkmake(t, "len", l) < 0)
+			et |= obj.Bool2int(r != nil && checkmake(t, "cap", r) < 0)
 			if et != 0 {
 				n.Type = nil
 				return
 			}
 			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 {
-				Yyerror("len larger than cap in make(%v)", Tconv(t, 0))
+				Yyerror("len larger than cap in make(%v)", t)
 				n.Type = nil
 				return
 			}
@@ -1884,7 +1905,7 @@
 		}
 
 		if args != nil {
-			Yyerror("too many arguments to make(%v)", Tconv(t, 0))
+			Yyerror("too many arguments to make(%v)", t)
 			n.Op = OMAKE
 			n.Type = nil
 			return
@@ -1910,7 +1931,7 @@
 			return
 		}
 		if args.Next != nil {
-			Yyerror("too many arguments to new(%v)", Tconv(t, 0))
+			Yyerror("too many arguments to new(%v)", t)
 			n.Type = nil
 			return
 		}
@@ -1976,7 +1997,7 @@
 			return
 		}
 		if t.Etype != TINTER {
-			Fatal("OITAB of %v", Tconv(t, 0))
+			Fatal("OITAB of %v", t)
 		}
 		n.Type = Ptrto(Types[TUINTPTR])
 		break OpSwitch
@@ -1990,7 +2011,7 @@
 			return
 		}
 		if !Isslice(t) && t.Etype != TSTRING {
-			Fatal("OSPTR of %v", Tconv(t, 0))
+			Fatal("OSPTR of %v", t)
 		}
 		if t.Etype == TSTRING {
 			n.Type = Ptrto(Types[TUINT8])
@@ -2182,27 +2203,27 @@
 
 	evconst(n)
 	if n.Op == OTYPE && top&Etype == 0 {
-		Yyerror("type %v is not an expression", Tconv(n.Type, 0))
+		Yyerror("type %v is not an expression", n.Type)
 		n.Type = nil
 		return
 	}
 
 	if top&(Erv|Etype) == Etype && n.Op != OTYPE {
-		Yyerror("%v is not a type", Nconv(n, 0))
+		Yyerror("%v is not a type", n)
 		n.Type = nil
 		return
 	}
 
 	// TODO(rsc): simplify
 	if (top&(Ecall|Erv|Etype) != 0) && top&Etop == 0 && ok&(Erv|Etype|Ecall) == 0 {
-		Yyerror("%v used as value", Nconv(n, 0))
+		Yyerror("%v used as value", n)
 		n.Type = nil
 		return
 	}
 
 	if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
 		if n.Diag == 0 {
-			Yyerror("%v evaluated but not used", Nconv(n, 0))
+			Yyerror("%v evaluated but not used", n)
 			n.Diag = 1
 		}
 
@@ -2222,22 +2243,22 @@
 		return -1
 	}
 	if !Isint[t.Etype] {
-		Yyerror("invalid slice index %v (type %v)", Nconv(r, 0), Tconv(t, 0))
+		Yyerror("invalid slice index %v (type %v)", r, t)
 		return -1
 	}
 
 	if r.Op == OLITERAL {
 		if Mpgetfix(r.Val.U.Xval) < 0 {
-			Yyerror("invalid slice index %v (index must be non-negative)", Nconv(r, 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 {
-			Yyerror("invalid slice index %v (out of bounds for %d-element array)", Nconv(r, 0), 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)", Nconv(r, 0), len(l.Val.U.Sval))
+			Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.Sval))
 			return -1
 		} else if Mpcmpfixfix(r.Val.U.Xval, Maxintval[TINT]) > 0 {
-			Yyerror("invalid slice index %v (index too large)", Nconv(r, 0))
+			Yyerror("invalid slice index %v (index too large)", r)
 			return -1
 		}
 	}
@@ -2247,7 +2268,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 {
-		Yyerror("invalid slice index: %v > %v", Nconv(lo, 0), Nconv(hi, 0))
+		Yyerror("invalid slice index: %v > %v", lo, hi)
 		return -1
 	}
 
@@ -2289,7 +2310,7 @@
 		if n.Left.Orig != nil && n.Left.Orig.Op == OCONV {
 			break
 		}
-		Yyerror("%s discards result of %v", what, Nconv(n.Left, 0))
+		Yyerror("%s discards result of %v", what, n.Left)
 		return
 	}
 
@@ -2335,13 +2356,13 @@
 	}
 	if n.List == nil {
 		p := fmt.Sprintf(f, args...)
-		Yyerror("missing argument to %s: %v", p, Nconv(n, 0))
+		Yyerror("missing argument to %s: %v", p, n)
 		return -1
 	}
 
 	if n.List.Next != nil {
 		p := fmt.Sprintf(f, args...)
-		Yyerror("too many arguments to %s: %v", p, Nconv(n, 0))
+		Yyerror("too many arguments to %s: %v", p, n)
 		n.Left = n.List.N
 		n.List = nil
 		return -1
@@ -2357,19 +2378,19 @@
 		return 0
 	}
 	if n.List == nil {
-		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), Nconv(n, 0))
+		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), n)
 		return -1
 	}
 
 	n.Left = n.List.N
 	if n.List.Next == nil {
-		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), Nconv(n, 0))
+		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), n)
 		n.List = nil
 		return -1
 	}
 
 	if n.List.Next.Next != nil {
-		Yyerror("too many arguments to %v - %v", Oconv(int(n.Op), 0), Nconv(n, 0))
+		Yyerror("too many arguments to %v - %v", Oconv(int(n.Op), 0), n)
 		n.List = nil
 		return -1
 	}
@@ -2385,16 +2406,19 @@
 		if dostrcmp != 0 && f.Sym.Name == s.Name {
 			return f
 		}
+		if dostrcmp == 2 && strings.EqualFold(f.Sym.Name, s.Name) {
+			return f
+		}
 		if f.Sym != s {
 			continue
 		}
 		if r != nil {
 			if errnode != nil {
-				Yyerror("ambiguous selector %v", Nconv(errnode, 0))
+				Yyerror("ambiguous selector %v", errnode)
 			} else if Isptr[t.Etype] {
-				Yyerror("ambiguous selector (%v).%v", Tconv(t, 0), Sconv(s, 0))
+				Yyerror("ambiguous selector (%v).%v", t, s)
 			} else {
-				Yyerror("ambiguous selector %v.%v", Tconv(t, 0), Sconv(s, 0))
+				Yyerror("ambiguous selector %v.%v", t, s)
 			}
 			break
 		}
@@ -2437,7 +2461,7 @@
 
 	// disallow T.m if m requires *T receiver
 	if Isptr[getthisx(f2.Type).Type.Type.Etype] && !Isptr[t.Etype] && f2.Embedded != 2 && !isifacemethod(f2.Type) {
-		Yyerror("invalid method expression %v (needs pointer receiver: (*%v).%v)", Nconv(n, 0), Tconv(t, 0), Sconv(f2.Sym, obj.FmtShort))
+		Yyerror("invalid method expression %v (needs pointer receiver: (*%v).%v)", n, t, Sconv(f2.Sym, obj.FmtShort))
 		return false
 	}
 
@@ -2455,7 +2479,7 @@
 	return t
 }
 
-func lookdot(n *Node, t *Type, dostrcmp int) bool {
+func lookdot(n *Node, t *Type, dostrcmp int) *Type {
 	s := n.Right.Sym
 
 	dowidth(t)
@@ -2475,11 +2499,15 @@
 	}
 
 	if f1 != nil {
+		if dostrcmp > 1 {
+			// Already in the process of diagnosing an error.
+			return f1
+		}
 		if f2 != nil {
-			Yyerror("%v is both field and method", Sconv(n.Right.Sym, 0))
+			Yyerror("%v is both field and method", n.Right.Sym)
 		}
 		if f1.Width == BADWIDTH {
-			Fatal("lookdot badwidth %v %p", Tconv(f1, 0), f1)
+			Fatal("lookdot badwidth %v %p", f1, f1)
 		}
 		n.Xoffset = f1.Width
 		n.Type = f1.Type
@@ -2494,10 +2522,14 @@
 			n.Op = ODOTINTER
 		}
 
-		return true
+		return f1
 	}
 
 	if f2 != nil {
+		if dostrcmp > 1 {
+			// Already in the process of diagnosing an error.
+			return f2
+		}
 		tt := n.Left.Type
 		dowidth(tt)
 		rcvr := getthisx(f2.Type).Type.Type
@@ -2512,7 +2544,7 @@
 				n.Left.Implicit = true
 				typecheck(&n.Left, Etype|Erv)
 			} else if int(tt.Etype) == Tptr && int(tt.Type.Etype) == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
-				Yyerror("calling method %v with receiver %v requires explicit dereference", Nconv(n.Right, 0), Nconv(n.Left, obj.FmtLong))
+				Yyerror("calling method %v with receiver %v requires explicit dereference", n.Right, Nconv(n.Left, obj.FmtLong))
 				for int(tt.Etype) == Tptr {
 					// Stop one level early for method with pointer receiver.
 					if int(rcvr.Etype) == Tptr && int(tt.Type.Etype) != Tptr {
@@ -2524,7 +2556,7 @@
 					tt = tt.Type
 				}
 			} else {
-				Fatal("method mismatch: %v for %v", Tconv(rcvr, 0), Tconv(tt, 0))
+				Fatal("method mismatch: %v for %v", rcvr, tt)
 			}
 		}
 
@@ -2537,7 +2569,7 @@
 				// It is invalid to automatically dereference a named pointer type when selecting a method.
 				// Make n->left == ll to clarify error message.
 				n.Left = ll
-				return false
+				return nil
 			}
 		}
 
@@ -2548,10 +2580,10 @@
 		//		print("lookdot found [%p] %T\n", f2->type, f2->type);
 		n.Op = ODOTMETH
 
-		return true
+		return f2
 	}
 
-	return false
+	return nil
 }
 
 func nokeys(l *NodeList) bool {
@@ -2620,9 +2652,9 @@
 						for ; tn != nil; tn = tn.Down {
 							if assignop(tn.Type, tl.Type.Type, &why) == 0 {
 								if call != nil {
-									Yyerror("cannot use %v as type %v in argument to %v%s", Tconv(tn.Type, 0), Tconv(tl.Type.Type, 0), Nconv(call, 0), why)
+									Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Type, call, why)
 								} else {
-									Yyerror("cannot use %v as type %v in %s%s", Tconv(tn.Type, 0), Tconv(tl.Type.Type, 0), desc(), why)
+									Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Type, desc(), why)
 								}
 							}
 						}
@@ -2635,9 +2667,9 @@
 					}
 					if assignop(tn.Type, tl.Type, &why) == 0 {
 						if call != nil {
-							Yyerror("cannot use %v as type %v in argument to %v%s", Tconv(tn.Type, 0), Tconv(tl.Type, 0), Nconv(call, 0), why)
+							Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why)
 						} else {
-							Yyerror("cannot use %v as type %v in %s%s", Tconv(tn.Type, 0), Tconv(tl.Type, 0), desc(), why)
+							Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
 						}
 					}
 
@@ -2721,7 +2753,7 @@
 	}
 	if isddd {
 		if call != nil {
-			Yyerror("invalid use of ... in call to %v", Nconv(call, 0))
+			Yyerror("invalid use of ... in call to %v", call)
 		} else {
 			Yyerror("invalid use of ... in %v", Oconv(int(op), 0))
 		}
@@ -2734,7 +2766,7 @@
 notenough:
 	if n == nil || n.Diag == 0 {
 		if call != nil {
-			Yyerror("not enough arguments in call to %v", Nconv(call, 0))
+			Yyerror("not enough arguments in call to %v", call)
 		} else {
 			Yyerror("not enough arguments to %v", Oconv(int(op), 0))
 		}
@@ -2747,7 +2779,7 @@
 
 toomany:
 	if call != nil {
-		Yyerror("too many arguments in call to %v", Nconv(call, 0))
+		Yyerror("too many arguments in call to %v", call)
 	} else {
 		Yyerror("too many arguments to %v", Oconv(int(op), 0))
 	}
@@ -2814,16 +2846,16 @@
 			if Eqtype(a.Left.Type, n.Type) {
 				cmp.Right = a.Left
 				evconst(&cmp)
-				b = uint32(cmp.Val.U.Bval)
+				b = uint32(obj.Bool2int(cmp.Val.U.Bval))
 			}
 		} else if Eqtype(a.Type, n.Type) {
 			cmp.Right = a
 			evconst(&cmp)
-			b = uint32(cmp.Val.U.Bval)
+			b = uint32(obj.Bool2int(cmp.Val.U.Bval))
 		}
 
 		if b != 0 {
-			Yyerror("duplicate key %v in map literal", Nconv(n, 0))
+			Yyerror("duplicate key %v in map literal", n)
 			return
 		}
 	}
@@ -2926,7 +2958,7 @@
 	} else if Debug['s'] != 0 {
 		typecheck(&n.Right, Etype)
 		if n.Right.Type != nil && Eqtype(n.Right.Type, t) {
-			fmt.Printf("%v: redundant type: %v\n", n.Line(), Tconv(t, 0))
+			fmt.Printf("%v: redundant type: %v\n", n.Line(), t)
 		}
 	}
 }
@@ -2967,14 +2999,14 @@
 		// For better or worse, we don't allow pointers as the composite literal type,
 		// except when using the &T syntax, which sets implicit on the OIND.
 		if !n.Right.Implicit {
-			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", Tconv(t, 0), Tconv(t.Type, 0))
+			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Type)
 			n.Type = nil
 			return
 		}
 
 		// Also, the underlying type must be a struct, map, slice, or array.
 		if !iscomptype(t) {
-			Yyerror("invalid pointer type %v for composite literal", Tconv(t, 0))
+			Yyerror("invalid pointer type %v for composite literal", t)
 			n.Type = nil
 			return
 		}
@@ -2985,7 +3017,7 @@
 	var r *Node
 	switch t.Etype {
 	default:
-		Yyerror("invalid type for composite literal: %v", Tconv(t, 0))
+		Yyerror("invalid type for composite literal: %v", t)
 		n.Type = nil
 
 	case TARRAY:
@@ -3093,7 +3125,7 @@
 
 				s = f.Sym
 				if s != nil && !exportname(s.Name) && s.Pkg != localpkg {
-					Yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, Tconv(t, 0))
+					Yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
 				}
 
 				// No pushtype allowed here.  Must name fields for that.
@@ -3131,7 +3163,7 @@
 
 				s = l.Left.Sym
 				if s == nil {
-					Yyerror("invalid field name %v in struct initializer", Nconv(l.Left, 0))
+					Yyerror("invalid field name %v in struct initializer", l.Left)
 					typecheck(&l.Right, Erv)
 					continue
 				}
@@ -3148,7 +3180,7 @@
 
 				f = lookdot1(nil, s, t, t.Type, 0)
 				if f == nil {
-					Yyerror("unknown %v field '%v' in struct literal", Tconv(t, 0), Sconv(s, 0))
+					Yyerror("unknown %v field '%v' in struct literal", t, s)
 					continue
 				}
 
@@ -3220,7 +3252,7 @@
 
 func checklvalue(n *Node, verb string) {
 	if !islvalue(n) {
-		Yyerror("cannot %s %v", verb, Nconv(n, 0))
+		Yyerror("cannot %s %v", verb, n)
 	}
 }
 
@@ -3255,7 +3287,7 @@
 		return
 	}
 
-	Yyerror("cannot assign to %v", Nconv(n, 0))
+	Yyerror("cannot assign to %v", n)
 }
 
 func checkassignlist(stmt *Node, l *NodeList) {
@@ -3357,7 +3389,7 @@
 	var why string
 
 	if assignop(src, dst.Type, &why) == 0 {
-		Yyerror("cannot assign %v to %v in multiple assignment%s", Tconv(src, 0), Nconv(dst, obj.FmtLong), why)
+		Yyerror("cannot assign %v to %v in multiple assignment%s", src, Nconv(dst, obj.FmtLong), why)
 		return
 	}
 }
@@ -3698,7 +3730,7 @@
 
 			// Note: adderrorname looks for this string and
 			// adds context about the outer expression
-			Yyerror("undefined: %v", Sconv(n.Sym, 0))
+			Yyerror("undefined: %v", n.Sym)
 		}
 
 		return n
@@ -3717,7 +3749,7 @@
 		Flusherrors()
 		fmt.Printf("typecheckdef loop:")
 		for l := typecheckdefstack; l != nil; l = l.Next {
-			fmt.Printf(" %v", Sconv(l.N.Sym, 0))
+			fmt.Printf(" %v", l.N.Sym)
 		}
 		fmt.Printf("\n")
 		Fatal("typecheckdef loop")
@@ -3764,7 +3796,7 @@
 
 		if e.Type != nil && e.Op != OLITERAL || !isgoconst(e) {
 			if e.Diag == 0 {
-				Yyerror("const initializer %v is not a constant", Nconv(e, 0))
+				Yyerror("const initializer %v is not a constant", e)
 				e.Diag = 1
 			}
 
@@ -3774,12 +3806,12 @@
 		t := n.Type
 		if t != nil {
 			if !okforconst[t.Etype] {
-				Yyerror("invalid constant type %v", Tconv(t, 0))
+				Yyerror("invalid constant type %v", t)
 				goto ret
 			}
 
 			if !isideal(e.Type) && !Eqtype(t, e.Type) {
-				Yyerror("cannot use %v as type %v in const initializer", Nconv(e, obj.FmtLong), Tconv(t, 0))
+				Yyerror("cannot use %v as type %v in const initializer", Nconv(e, obj.FmtLong), t)
 				goto ret
 			}
 
@@ -3815,7 +3847,7 @@
 				break
 			}
 
-			Fatal("var without type, init: %v", Sconv(n.Sym, 0))
+			Fatal("var without type, init: %v", n.Sym)
 		}
 
 		if n.Defn.Op == ONAME {
@@ -3852,7 +3884,7 @@
 
 ret:
 	if n.Op != OLITERAL && n.Type != nil && isideal(n.Type) {
-		Fatal("got %v for %v", Tconv(n.Type, 0), Nconv(n, 0))
+		Fatal("got %v for %v", n.Type, n)
 	}
 	if typecheckdefstack.N != n {
 		Fatal("typecheckdefstack mismatch")
@@ -3871,12 +3903,12 @@
 		case CTINT, CTRUNE, CTFLT, CTCPLX:
 			n.Val = toint(n.Val)
 			if mpcmpfixc(n.Val.U.Xval, 0) < 0 {
-				Yyerror("negative %s argument in make(%v)", arg, Tconv(t, 0))
+				Yyerror("negative %s argument in make(%v)", arg, t)
 				return -1
 			}
 
 			if Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT]) > 0 {
-				Yyerror("%s argument too large in make(%v)", arg, Tconv(t, 0))
+				Yyerror("%s argument too large in make(%v)", arg, t)
 				return -1
 			}
 
@@ -3892,7 +3924,7 @@
 	}
 
 	if !Isint[n.Type.Etype] && n.Type.Etype != TIDEAL {
-		Yyerror("non-integer %s argument in make(%v) - %v", arg, Tconv(t, 0), Tconv(n.Type, 0))
+		Yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
 		return -1
 	}
 
diff --git a/src/cmd/internal/gc/unsafe.go b/src/cmd/internal/gc/unsafe.go
index 7bd35f8..aa90a19 100644
--- a/src/cmd/internal/gc/unsafe.go
+++ b/src/cmd/internal/gc/unsafe.go
@@ -29,7 +29,7 @@
 	}
 
 	if args == nil {
-		Yyerror("missing argument for %v", Sconv(s, 0))
+		Yyerror("missing argument for %v", s)
 		return nil
 	}
 
@@ -66,7 +66,7 @@
 			break
 
 		case OCALLPART:
-			Yyerror("invalid expression %v: argument is a method value", Nconv(nn, 0))
+			Yyerror("invalid expression %v: argument is a method value", nn)
 			v = 0
 			goto ret
 
@@ -84,7 +84,7 @@
 				v += r1.Xoffset
 
 			case ODOTPTR:
-				Yyerror("invalid expression %v: selector implies indirection of embedded %v", Nconv(nn, 0), Nconv(r1.Left, 0))
+				Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left)
 				goto ret
 
 			default:
@@ -126,13 +126,13 @@
 	return nil
 
 bad:
-	Yyerror("invalid expression %v", Nconv(nn, 0))
+	Yyerror("invalid expression %v", nn)
 	v = 0
 	goto ret
 
 yes:
 	if args.Next != nil {
-		Yyerror("extra arguments for %v", Sconv(s, 0))
+		Yyerror("extra arguments for %v", s)
 	}
 
 	// any side effects disappear; ignore init
diff --git a/src/cmd/internal/gc/util.go b/src/cmd/internal/gc/util.go
index c3f7db2..5dc6561 100644
--- a/src/cmd/internal/gc/util.go
+++ b/src/cmd/internal/gc/util.go
@@ -3,18 +3,12 @@
 import (
 	"cmd/internal/obj"
 	"os"
+	"runtime"
 	"runtime/pprof"
 	"strconv"
 	"strings"
 )
 
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
-
 func (n *Node) Line() string {
 	return obj.Linklinefmt(Ctxt, int(n.Lineno), false, false)
 }
@@ -49,14 +43,6 @@
 	return s
 }
 
-// simulation of int(*s++) in C
-func intstarstringplusplus(s string) (int, string) {
-	if s == "" {
-		return 0, ""
-	}
-	return int(s[0]), s[1:]
-}
-
 // strings.Compare, introduced in Go 1.5.
 func stringsCompare(a, b string) int {
 	if a == b {
@@ -83,8 +69,11 @@
 	os.Exit(code)
 }
 
-var cpuprofile string
-var memprofile string
+var (
+	cpuprofile     string
+	memprofile     string
+	memprofilerate int64
+)
 
 func startProfile() {
 	if cpuprofile != "" {
@@ -98,11 +87,15 @@
 		AtExit(pprof.StopCPUProfile)
 	}
 	if memprofile != "" {
+		if memprofilerate != 0 {
+			runtime.MemProfileRate = int(memprofilerate)
+		}
 		f, err := os.Create(memprofile)
 		if err != nil {
 			Fatal("%v", err)
 		}
 		AtExit(func() {
+			runtime.GC() // profile all outstanding allocations
 			if err := pprof.WriteHeapProfile(f); err != nil {
 				Fatal("%v", err)
 			}
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go
index 03e7926..c32a813 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/internal/gc/walk.go
@@ -21,7 +21,7 @@
 	Curfn = fn
 
 	if Debug['W'] != 0 {
-		s := fmt.Sprintf("\nbefore %v", Sconv(Curfn.Nname.Sym, 0))
+		s := fmt.Sprintf("\nbefore %v", Curfn.Nname.Sym)
 		dumplist(s, Curfn.Nbody)
 	}
 
@@ -51,11 +51,11 @@
 				continue
 			}
 			lineno = l.N.Defn.Left.Lineno
-			Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
+			Yyerror("%v declared and not used", l.N.Sym)
 			l.N.Defn.Left.Used = true // suppress repeats
 		} else {
 			lineno = l.N.Lineno
-			Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
+			Yyerror("%v declared and not used", l.N.Sym)
 		}
 	}
 
@@ -65,13 +65,13 @@
 	}
 	walkstmtlist(Curfn.Nbody)
 	if Debug['W'] != 0 {
-		s := fmt.Sprintf("after walk %v", Sconv(Curfn.Nname.Sym, 0))
+		s := fmt.Sprintf("after walk %v", Curfn.Nname.Sym)
 		dumplist(s, Curfn.Nbody)
 	}
 
 	heapmoves()
 	if Debug['W'] != 0 && Curfn.Func.Enter != nil {
-		s := fmt.Sprintf("enter %v", Sconv(Curfn.Nname.Sym, 0))
+		s := fmt.Sprintf("enter %v", Curfn.Nname.Sym)
 		dumplist(s, Curfn.Func.Enter)
 	}
 }
@@ -154,7 +154,7 @@
 	switch n.Op {
 	default:
 		if n.Op == ONAME {
-			Yyerror("%v is not a top level statement", Sconv(n.Sym, 0))
+			Yyerror("%v is not a top level statement", n.Sym)
 		} else {
 			Yyerror("%v is not a top level statement", Oconv(int(n.Op), 0))
 		}
@@ -179,7 +179,8 @@
 		OPRINTN,
 		OPANIC,
 		OEMPTY,
-		ORECOVER:
+		ORECOVER,
+		OGETG:
 		if n.Typecheck == 0 {
 			Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
 		}
@@ -287,9 +288,9 @@
 			// so that reorder3 can fix up conflicts
 			var rl *NodeList
 
-			var cl int
+			var cl uint8
 			for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-				cl = int(ll.N.Class) &^ PHEAP
+				cl = ll.N.Class &^ PHEAP
 				if cl == PAUTO {
 					break
 				}
@@ -310,7 +311,7 @@
 				f := n.List.N
 
 				if f.Op != OCALLFUNC && f.Op != OCALLMETH && f.Op != OCALLINTER {
-					Fatal("expected return of call, have %v", Nconv(f, 0))
+					Fatal("expected return of call, have %v", f)
 				}
 				n.List = concat(list1(f), ascompatet(int(n.Op), rl, &f.Type, 0, &n.Ninit))
 				break
@@ -424,7 +425,8 @@
 		ONONAME,
 		OINDREG,
 		OEMPTY,
-		OPARAM:
+		OPARAM,
+		OGETG:
 		goto ret
 
 	case ONOT,
@@ -564,16 +566,16 @@
 		goto ret
 
 	case OLITERAL:
-		n.Addable = 1
+		n.Addable = true
 		goto ret
 
 	case OCLOSUREVAR, OCFUNC:
-		n.Addable = 1
+		n.Addable = true
 		goto ret
 
 	case ONAME:
 		if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
-			n.Addable = 1
+			n.Addable = true
 		}
 		goto ret
 
@@ -622,6 +624,16 @@
 		walkexpr(&n.Left, init)
 		walkexprlist(n.List, init)
 
+		if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
+			switch Thearch.Thechar {
+			case '5', '6', '7':
+				n.Op = OSQRT
+				n.Left = n.List.N
+				n.List = nil
+				goto ret
+			}
+		}
+
 		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
 		n.List = reorder1(ll)
 		goto ret
@@ -965,7 +977,7 @@
 				l := Nod(ONAME, nil, nil)
 				l.Sym = sym
 				l.Type = Ptrto(Types[TUINT8])
-				l.Addable = 1
+				l.Addable = true
 				l.Class = PEXTERN
 				l.Xoffset = 0
 				sym.Def = l
@@ -973,7 +985,7 @@
 			}
 
 			l := Nod(OADDR, sym.Def, nil)
-			l.Addable = 1
+			l.Addable = true
 			ll = list(ll, l)
 
 			if isdirectiface(n.Left.Type) {
@@ -1259,7 +1271,6 @@
 		}
 		fallthrough
 
-		// fallthrough
 	case OSLICEARR, OSLICESTR:
 		if n.Right == nil { // already processed
 			goto ret
@@ -1378,7 +1389,7 @@
 
 		typecheck(&r, Erv)
 		if n.Type.Etype != TBOOL {
-			Fatal("cmp %v", Tconv(n.Type, 0))
+			Fatal("cmp %v", n.Type)
 		}
 		r.Type = n.Type
 		n = r
@@ -1558,7 +1569,7 @@
 		// ifaceeq(i1 any-1, i2 any-2) (ret bool);
 	case OCMPIFACE:
 		if !Eqtype(n.Left.Type, n.Right.Type) {
-			Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), Tconv(n.Left.Type, 0), Tconv(n.Right.Type, 0))
+			Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
 		}
 		var fn *Node
 		if isnilinter(n.Left.Type) {
@@ -1766,7 +1777,7 @@
 * package all the arguments that match a ... T parameter into a []T.
  */
 func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
-	esc := uint8(EscUnknown)
+	esc := uint16(EscUnknown)
 	if ddd != nil {
 		esc = ddd.Esc
 	}
@@ -2207,6 +2218,17 @@
 		if Curfn != nil && Curfn.Func.Nowritebarrier {
 			Yyerror("write barrier prohibited")
 		}
+		if flag_race == 0 {
+			if Debug_wb > 1 {
+				Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
+			}
+			n.Op = OASWB
+			return n
+		}
+		// Use slow path always for race detector.
+		if Debug_wb > 0 {
+			Warnl(int(n.Lineno), "write barrier")
+		}
 		t := n.Left.Type
 		l := Nod(OADDR, n.Left, nil)
 		l.Etype = 1 // addr does not escape
@@ -2221,33 +2243,26 @@
 		} else if t.Width <= int64(4*Widthptr) {
 			x := int64(0)
 			if applywritebarrier_bv.b == nil {
-				applywritebarrier_bv = bvalloc(obj.BitsPerPointer * 4)
+				applywritebarrier_bv = bvalloc(4)
 			}
 			bvresetall(applywritebarrier_bv)
-			twobitwalktype1(t, &x, applywritebarrier_bv)
-			const (
-				PtrBit = 1
-			)
-			// The bvgets are looking for BitsPointer in successive slots.
-			if obj.BitsPointer != 1<<PtrBit {
-				Fatal("wrong PtrBit")
-			}
+			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), Tconv(t, 0))
+				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, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit))
+				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, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 2*obj.BitsPerPointer+PtrBit))
+				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, PtrBit), bvget(applywritebarrier_bv, obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 2*obj.BitsPerPointer+PtrBit), bvget(applywritebarrier_bv, 3*obj.BitsPerPointer+PtrBit))
+				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, nodnil(), n.Right)
+			n = mkcall1(writebarrierfn(name, t, n.Right.Type), nil, init, l, Nodintconst(0), n.Right)
 		} else {
 			r := n.Right
 			for r.Op == OCONVNOP {
@@ -2260,7 +2275,6 @@
 			n = mkcall1(writebarrierfn("typedmemmove", t, r.Left.Type), nil, init, typename(t), l, r)
 		}
 	}
-
 	return n
 }
 
@@ -2709,7 +2723,7 @@
 
 		// generate allocation & copying code
 		if compiling_runtime != 0 {
-			Yyerror("%v escapes to heap, not allowed in runtime.", Nconv(v, 0))
+			Yyerror("%v escapes to heap, not allowed in runtime.", v)
 		}
 		if v.Alloc == nil {
 			v.Alloc = callnew(v.Type)
@@ -2765,7 +2779,7 @@
 
 func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
 	if fn.Type == nil || fn.Type.Etype != TFUNC {
-		Fatal("mkcall %v %v", Nconv(fn, 0), Tconv(fn.Type, 0))
+		Fatal("mkcall %v %v", fn, fn.Type)
 	}
 
 	var args *NodeList
@@ -2806,7 +2820,7 @@
 
 func chanfn(name string, n int, t *Type) *Node {
 	if t.Etype != TCHAN {
-		Fatal("chanfn %v", Tconv(t, 0))
+		Fatal("chanfn %v", t)
 	}
 	fn := syslook(name, 1)
 	switch n {
@@ -2822,7 +2836,7 @@
 
 func mapfn(name string, t *Type) *Node {
 	if t.Etype != TMAP {
-		Fatal("mapfn %v", Tconv(t, 0))
+		Fatal("mapfn %v", t)
 	}
 	fn := syslook(name, 1)
 	substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
@@ -2831,7 +2845,7 @@
 
 func mapfndel(name string, t *Type) *Node {
 	if t.Etype != TMAP {
-		Fatal("mapfn %v", Tconv(t, 0))
+		Fatal("mapfn %v", t)
 	}
 	fn := syslook(name, 1)
 	substArgTypes(fn, t.Down, t.Type, t.Down)
@@ -3367,7 +3381,7 @@
 	a := algtype1(t, nil)
 
 	if a != AMEM && a != -1 {
-		Fatal("eqfor %v", Tconv(t, 0))
+		Fatal("eqfor %v", t)
 	}
 
 	if a == AMEM {
@@ -3474,7 +3488,7 @@
 	}
 
 	if !islvalue(cmpl) || !islvalue(cmpr) {
-		Fatal("arguments of comparison must be lvalues - %v %v", Nconv(cmpl, 0), Nconv(cmpr, 0))
+		Fatal("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
 	}
 
 	l = temp(Ptrto(t))
@@ -4075,7 +4089,7 @@
 
 	field := n.Paramfld
 	if field == nil {
-		Fatal("usefield %v %v without paramfld", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
+		Fatal("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
 	}
 	if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
 		return
diff --git a/src/cmd/internal/gc/y.go b/src/cmd/internal/gc/y.go
index 8b272ec..f2c8b96 100644
--- a/src/cmd/internal/gc/y.go
+++ b/src/cmd/internal/gc/y.go
@@ -69,7 +69,10 @@
 const NotParen = 57393
 const PreferToRightParen = 57394
 
-var yyToknames = []string{
+var yyToknames = [...]string{
+	"$end",
+	"error",
+	"$unk",
 	"LLITERAL",
 	"LASOP",
 	"LCOLAS",
@@ -129,8 +132,22 @@
 	"'('",
 	"')'",
 	"PreferToRightParen",
+	"';'",
+	"'.'",
+	"'$'",
+	"'='",
+	"':'",
+	"'{'",
+	"'}'",
+	"'!'",
+	"'~'",
+	"'['",
+	"']'",
+	"'?'",
+	"'@'",
+	"','",
 }
-var yyStatenames = []string{}
+var yyStatenames = [...]string{}
 
 const yyEofCode = 1
 const yyErrCode = 2
@@ -147,7 +164,7 @@
 }
 
 //line yacctab:1
-var yyExca = []int{
+var yyExca = [...]int{
 	-1, 1,
 	1, -1,
 	-2, 0,
@@ -272,7 +289,7 @@
 
 const yyLast = 2282
 
-var yyAct = []int{
+var yyAct = [...]int{
 
 	74, 381, 304, 285, 291, 486, 610, 398, 545, 478,
 	549, 296, 186, 75, 400, 229, 302, 401, 103, 389,
@@ -504,7 +521,7 @@
 	137, 136, 0, 151, 141, 142, 143, 144, 145, 146,
 	147, 148,
 }
-var yyPact = []int{
+var yyPact = [...]int{
 
 	-1000, -1000, 542, 536, -1000, 164, -1000, 550, 555, 318,
 	-1000, -1000, -1000, 588, -1000, -1000, 549, 1340, 316, 155,
@@ -574,7 +591,7 @@
 	110, -1000, 37, 2017, -1000, -1000, 2017, -1000, -1000, -1000,
 	-1000, -1000, -1000, -1000, -1000, 1689, 518, -1000,
 }
-var yyPgo = []int{
+var yyPgo = [...]int{
 
 	0, 57, 771, 774, 45, 150, 26, 540, 29, 770,
 	768, 2, 28, 61, 322, 766, 17, 4, 765, 761,
@@ -592,7 +609,7 @@
 	648, 647, 642, 639, 637, 634, 631, 627, 38, 623,
 	596, 593,
 }
-var yyR1 = []int{
+var yyR1 = [...]int{
 
 	0, 112, 114, 114, 116, 113, 115, 115, 119, 119,
 	119, 120, 120, 121, 121, 2, 2, 2, 117, 123,
@@ -631,7 +648,7 @@
 	94, 94, 93, 93, 125, 125, 100, 100, 104, 104,
 	102, 102,
 }
-var yyR2 = []int{
+var yyR2 = [...]int{
 
 	0, 4, 0, 3, 0, 3, 0, 3, 2, 5,
 	3, 3, 2, 1, 3, 1, 2, 2, 4, 0,
@@ -670,7 +687,7 @@
 	2, 1, 1, 5, 0, 2, 1, 3, 1, 3,
 	1, 3,
 }
-var yyChk = []int{
+var yyChk = [...]int{
 
 	-1000, -112, -113, -116, -114, 26, -117, 26, -115, -3,
 	25, -91, 74, 75, -118, -124, 25, -60, -119, 22,
@@ -740,7 +757,7 @@
 	15, 73, -58, 61, 61, 61, 61, -52, 67, 67,
 	21, -11, 69, -99, -99, -134, -24, -53,
 }
-var yyDef = []int{
+var yyDef = [...]int{
 
 	4, -2, 2, 0, 6, 0, 21, 0, 218, 0,
 	157, 158, 159, 0, 5, 344, 19, -2, 0, 0,
@@ -810,7 +827,7 @@
 	0, 133, 0, 335, 343, 337, 335, 206, 56, 57,
 	82, 87, 145, 333, 208, 294, 0, 83,
 }
-var yyTok1 = []int{
+var yyTok1 = [...]int{
 
 	1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
@@ -826,7 +843,7 @@
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 68, 52, 69, 71,
 }
-var yyTok2 = []int{
+var yyTok2 = [...]int{
 
 	2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
 	12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
@@ -835,7 +852,7 @@
 	42, 43, 44, 45, 46, 47, 48, 49, 58, 59,
 	62,
 }
-var yyTok3 = []int{
+var yyTok3 = [...]int{
 	0,
 }
 
@@ -843,7 +860,10 @@
 
 /*	parser for yacc output	*/
 
-var yyDebug = 0
+var (
+	yyDebug        = 0
+	yyErrorVerbose = false
+)
 
 type yyLexer interface {
 	Lex(lval *yySymType) int
@@ -857,6 +877,7 @@
 
 type yyParserImpl struct {
 	lookahead func() int
+	state     func() int
 }
 
 func (p *yyParserImpl) Lookahead() int {
@@ -866,6 +887,7 @@
 func yyNewParser() yyParser {
 	p := &yyParserImpl{
 		lookahead: func() int { return -1 },
+		state:     func() int { return -1 },
 	}
 	return p
 }
@@ -873,10 +895,9 @@
 const yyFlag = -1000
 
 func yyTokname(c int) string {
-	// 4 is TOKSTART above
-	if c >= 4 && c-4 < len(yyToknames) {
-		if yyToknames[c-4] != "" {
-			return yyToknames[c-4]
+	if c >= 1 && c-1 < len(yyToknames) {
+		if yyToknames[c-1] != "" {
+			return yyToknames[c-1]
 		}
 	}
 	return __yyfmt__.Sprintf("tok-%v", c)
@@ -891,6 +912,63 @@
 	return __yyfmt__.Sprintf("state-%v", s)
 }
 
+func yyErrorMessage(state, lookAhead int) string {
+	const TOKSTART = 4
+
+	if !yyErrorVerbose {
+		return "syntax error"
+	}
+	res := "syntax error: unexpected " + yyTokname(lookAhead)
+
+	// To match Bison, suggest at most four expected tokens.
+	expected := make([]int, 0, 4)
+
+	// Look for shiftable tokens.
+	base := yyPact[state]
+	for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
+		if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok {
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+	}
+
+	if yyDef[state] == -2 {
+		i := 0
+		for yyExca[i] != -1 || yyExca[i+1] != state {
+			i += 2
+		}
+
+		// Look for tokens that we accept or reduce.
+		for i += 2; yyExca[i] >= 0; i += 2 {
+			tok := yyExca[i]
+			if tok < TOKSTART || yyExca[i+1] == 0 {
+				continue
+			}
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+
+		// If the default action is to accept or reduce, give up.
+		if yyExca[i+1] != 0 {
+			return res
+		}
+	}
+
+	for i, tok := range expected {
+		if i == 0 {
+			res += ", expecting "
+		} else {
+			res += " or "
+		}
+		res += yyTokname(tok)
+	}
+	return res
+}
+
 func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
 	token = 0
 	char = lex.Lex(lval)
@@ -942,9 +1020,11 @@
 	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.
+		yystate = -1
 		yychar = -1
 		yytoken = -1
 	}()
@@ -1027,7 +1107,7 @@
 		/* error ... attempt to resume parsing */
 		switch Errflag {
 		case 0: /* brand new error */
-			yylex.Error("syntax error")
+			yylex.Error(yyErrorMessage(yystate, yytoken))
 			Nerrs++
 			if yyDebug >= 1 {
 				__yyfmt__.Printf("%s", yyStatname(yystate))
@@ -1265,8 +1345,6 @@
 			Yyerror("empty top-level declaration")
 			yyVAL.list = nil
 		}
-	case 24:
-		yyVAL.list = yyS[yypt-0].list
 	case 25:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:292
@@ -1389,8 +1467,6 @@
 		{
 			yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list)
 		}
-	case 44:
-		yyVAL.list = yyS[yypt-0].list
 	case 45:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:387
@@ -1467,7 +1543,7 @@
 				if yyDollar[1].list.Next != nil {
 					Yyerror("argument count mismatch: %d = %d", count(yyDollar[1].list), 1)
 				} else if (yyDollar[1].list.N.Op != ONAME && yyDollar[1].list.N.Op != OTYPE && yyDollar[1].list.N.Op != ONONAME) || isblank(yyDollar[1].list.N) {
-					Yyerror("invalid variable name %s in type switch", Nconv(yyDollar[1].list.N, 0))
+					Yyerror("invalid variable name %s in type switch", yyDollar[1].list.N)
 				} else {
 					yyVAL.node.Left = dclname(yyDollar[1].list.N.Sym)
 				} // it's a colas, so must not re-use an oldname.
@@ -1657,7 +1733,7 @@
 		{
 			yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
 			yyVAL.node.List = yyDollar[1].list
-			yyVAL.node.Colas = 1
+			yyVAL.node.Colas = true
 			colasdefn(yyDollar[1].list, yyVAL.node)
 		}
 	case 69:
@@ -1672,7 +1748,7 @@
 		//line go.y:632
 		{
 			// init ; test ; incr
-			if yyDollar[5].node != nil && yyDollar[5].node.Colas != 0 {
+			if yyDollar[5].node != nil && yyDollar[5].node.Colas {
 				Yyerror("cannot declare in the for-increment")
 			}
 			yyVAL.node = Nod(OFOR, nil, nil)
@@ -1690,8 +1766,6 @@
 			yyVAL.node = Nod(OFOR, nil, nil)
 			yyVAL.node.Ntest = yyDollar[1].node
 		}
-	case 72:
-		yyVAL.node = yyS[yypt-0].node
 	case 73:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:654
@@ -1853,8 +1927,6 @@
 			yyVAL.node.List = yyDollar[4].list
 			typesw = typesw.Left
 		}
-	case 93:
-		yyVAL.node = yyS[yypt-0].node
 	case 94:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:796
@@ -1975,8 +2047,6 @@
 		{
 			yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node)
 		}
-	case 114:
-		yyVAL.node = yyS[yypt-0].node
 	case 115:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:880
@@ -2060,8 +2130,6 @@
 		{
 			yyVAL.node = nodlit(yyDollar[1].val)
 		}
-	case 127:
-		yyVAL.node = yyS[yypt-0].node
 	case 128:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:948
@@ -2111,8 +2179,6 @@
 			}
 			yyVAL.node = Nod(OSLICE3, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, Nod(OKEY, yyDollar[5].node, yyDollar[7].node)))
 		}
-	case 134:
-		yyVAL.node = yyS[yypt-0].node
 	case 135:
 		yyDollar = yyS[yypt-5 : yypt+1]
 		//line go.y:986
@@ -2147,8 +2213,6 @@
 			yyVAL.node.Right = yyDollar[2].node
 			yyVAL.node.List = yyDollar[6].list
 		}
-	case 139:
-		yyVAL.node = yyS[yypt-0].node
 	case 140:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1014
@@ -2185,8 +2249,6 @@
 			yyVAL.node = yyDollar[2].node
 			yyVAL.node.List = yyDollar[3].list
 		}
-	case 144:
-		yyVAL.node = yyS[yypt-0].node
 	case 145:
 		yyDollar = yyS[yypt-4 : yypt+1]
 		//line go.y:1049
@@ -2194,8 +2256,6 @@
 			yyVAL.node = yyDollar[2].node
 			yyVAL.node.List = yyDollar[3].list
 		}
-	case 146:
-		yyVAL.node = yyS[yypt-0].node
 	case 147:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1057
@@ -2210,12 +2270,6 @@
 				yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
 			}
 		}
-	case 148:
-		yyVAL.node = yyS[yypt-0].node
-	case 149:
-		yyVAL.node = yyS[yypt-0].node
-	case 150:
-		yyVAL.node = yyS[yypt-0].node
 	case 151:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1078
@@ -2250,8 +2304,6 @@
 		{
 			yyVAL.node = nil
 		}
-	case 156:
-		yyVAL.node = yyS[yypt-0].node
 	case 157:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1115
@@ -2262,8 +2314,6 @@
 				yyVAL.sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg)
 			}
 		}
-	case 158:
-		yyVAL.sym = yyS[yypt-0].sym
 	case 159:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1124
@@ -2311,8 +2361,6 @@
 				yyVAL.node.Pack.Used = true
 			}
 		}
-	case 163:
-		yyVAL.node = yyS[yypt-0].node
 	case 164:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1181
@@ -2326,66 +2374,24 @@
 		{
 			yyVAL.node = Nod(ODDD, yyDollar[2].node, nil)
 		}
-	case 166:
-		yyVAL.node = yyS[yypt-0].node
-	case 167:
-		yyVAL.node = yyS[yypt-0].node
-	case 168:
-		yyVAL.node = yyS[yypt-0].node
-	case 169:
-		yyVAL.node = yyS[yypt-0].node
-	case 170:
-		yyVAL.node = yyS[yypt-0].node
 	case 171:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1197
 		{
 			yyVAL.node = yyDollar[2].node
 		}
-	case 172:
-		yyVAL.node = yyS[yypt-0].node
-	case 173:
-		yyVAL.node = yyS[yypt-0].node
-	case 174:
-		yyVAL.node = yyS[yypt-0].node
 	case 175:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:1206
 		{
 			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
 		}
-	case 176:
-		yyVAL.node = yyS[yypt-0].node
-	case 177:
-		yyVAL.node = yyS[yypt-0].node
-	case 178:
-		yyVAL.node = yyS[yypt-0].node
-	case 179:
-		yyVAL.node = yyS[yypt-0].node
 	case 180:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1216
 		{
 			yyVAL.node = yyDollar[2].node
 		}
-	case 181:
-		yyVAL.node = yyS[yypt-0].node
-	case 182:
-		yyVAL.node = yyS[yypt-0].node
-	case 183:
-		yyVAL.node = yyS[yypt-0].node
-	case 184:
-		yyVAL.node = yyS[yypt-0].node
-	case 185:
-		yyVAL.node = yyS[yypt-0].node
-	case 186:
-		yyVAL.node = yyS[yypt-0].node
-	case 187:
-		yyVAL.node = yyS[yypt-0].node
-	case 188:
-		yyVAL.node = yyS[yypt-0].node
-	case 189:
-		yyVAL.node = yyS[yypt-0].node
 	case 190:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1237
@@ -2432,10 +2438,6 @@
 		{
 			yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node)
 		}
-	case 196:
-		yyVAL.node = yyS[yypt-0].node
-	case 197:
-		yyVAL.node = yyS[yypt-0].node
 	case 198:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:1277
@@ -2586,7 +2588,7 @@
 					dclcontext = PDISCARD // since we skip funchdr below
 					break
 				}
-				Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0))
+				Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", s, s.Def.Type, t)
 			}
 
 			yyVAL.node = newfuncname(s)
@@ -2694,16 +2696,12 @@
 			nosplit = false
 			nowritebarrier = false
 		}
-	case 220:
-		yyVAL.list = yyS[yypt-0].list
 	case 221:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1526
 		{
 			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
 		}
-	case 222:
-		yyVAL.list = yyS[yypt-0].list
 	case 223:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1533
@@ -2722,8 +2720,6 @@
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
-	case 226:
-		yyVAL.list = yyS[yypt-0].list
 	case 227:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:1550
@@ -2828,7 +2824,7 @@
 			var pkg *Pkg
 
 			if yyDollar[1].sym.Def == nil || yyDollar[1].sym.Def.Op != OPACK {
-				Yyerror("%v is not a package", Sconv(yyDollar[1].sym, 0))
+				Yyerror("%v is not a package", yyDollar[1].sym)
 				pkg = localpkg
 			} else {
 				yyDollar[1].sym.Def.Used = true
@@ -2872,8 +2868,6 @@
 			yyVAL.node.List = yyDollar[2].list
 			yyVAL.node.Rlist = yyDollar[4].list
 		}
-	case 243:
-		yyVAL.node = yyS[yypt-0].node
 	case 244:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:1684
@@ -2890,8 +2884,6 @@
 			yyVAL.node.Sym = yyDollar[1].sym
 			yyVAL.node = Nod(OKEY, yyVAL.node, yyDollar[2].node)
 		}
-	case 246:
-		yyVAL.node = yyS[yypt-0].node
 	case 247:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1699
@@ -2922,32 +2914,18 @@
 		{
 			yyVAL.node = nil
 		}
-	case 252:
-		yyVAL.node = yyS[yypt-0].node
 	case 253:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1725
 		{
 			yyVAL.node = liststmt(yyDollar[1].list)
 		}
-	case 254:
-		yyVAL.node = yyS[yypt-0].node
 	case 255:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:1730
 		{
 			yyVAL.node = nil
 		}
-	case 256:
-		yyVAL.node = yyS[yypt-0].node
-	case 257:
-		yyVAL.node = yyS[yypt-0].node
-	case 258:
-		yyVAL.node = yyS[yypt-0].node
-	case 259:
-		yyVAL.node = yyS[yypt-0].node
-	case 260:
-		yyVAL.node = yyS[yypt-0].node
 	case 261:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:1741
@@ -3137,56 +3115,42 @@
 		{
 			yyVAL.node = nil
 		}
-	case 291:
-		yyVAL.node = yyS[yypt-0].node
 	case 292:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1906
 		{
 			yyVAL.list = nil
 		}
-	case 293:
-		yyVAL.list = yyS[yypt-0].list
 	case 294:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1912
 		{
 			yyVAL.node = nil
 		}
-	case 295:
-		yyVAL.node = yyS[yypt-0].node
 	case 296:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1918
 		{
 			yyVAL.list = nil
 		}
-	case 297:
-		yyVAL.list = yyS[yypt-0].list
 	case 298:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1924
 		{
 			yyVAL.list = nil
 		}
-	case 299:
-		yyVAL.list = yyS[yypt-0].list
 	case 300:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1930
 		{
 			yyVAL.list = nil
 		}
-	case 301:
-		yyVAL.list = yyS[yypt-0].list
 	case 302:
 		yyDollar = yyS[yypt-0 : yypt+1]
 		//line go.y:1936
 		{
 			yyVAL.val.Ctype = CTxxx
 		}
-	case 303:
-		yyVAL.val = yyS[yypt-0].val
 	case 304:
 		yyDollar = yyS[yypt-4 : yypt+1]
 		//line go.y:1946
@@ -3252,16 +3216,6 @@
 			yyVAL.typ = pkgtype(yyDollar[1].sym)
 			importsym(yyDollar[1].sym, OTYPE)
 		}
-	case 312:
-		yyVAL.typ = yyS[yypt-0].typ
-	case 313:
-		yyVAL.typ = yyS[yypt-0].typ
-	case 314:
-		yyVAL.typ = yyS[yypt-0].typ
-	case 315:
-		yyVAL.typ = yyS[yypt-0].typ
-	case 316:
-		yyVAL.typ = yyS[yypt-0].typ
 	case 317:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		//line go.y:2014
@@ -3424,8 +3378,6 @@
 		{
 			yyVAL.list = nil
 		}
-	case 336:
-		yyVAL.list = yyS[yypt-0].list
 	case 337:
 		yyDollar = yyS[yypt-3 : yypt+1]
 		//line go.y:2152
@@ -3470,11 +3422,9 @@
 		{
 			yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg))
 			if yyVAL.node.Op != OLITERAL {
-				Yyerror("bad constant %v", Sconv(yyVAL.node.Sym, 0))
+				Yyerror("bad constant %v", yyVAL.node.Sym)
 			}
 		}
-	case 342:
-		yyVAL.node = yyS[yypt-0].node
 	case 343:
 		yyDollar = yyS[yypt-5 : yypt+1]
 		//line go.y:2198
diff --git a/src/cmd/internal/gc/yaccerrors.go b/src/cmd/internal/gc/yaccerrors.go
new file mode 100644
index 0000000..9dc54d9
--- /dev/null
+++ b/src/cmd/internal/gc/yaccerrors.go
@@ -0,0 +1,194 @@
+// 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
new file mode 100644
index 0000000..cb45cb8
--- /dev/null
+++ b/src/cmd/internal/gc/yymsg.go
@@ -0,0 +1,83 @@
+// 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/goobj/read.go b/src/cmd/internal/goobj/read.go
index 79a83e5..1b0c964 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -12,6 +12,7 @@
 import (
 	"bufio"
 	"bytes"
+	"cmd/internal/obj"
 	"errors"
 	"fmt"
 	"io"
@@ -31,45 +32,46 @@
 	_ SymKind = iota
 
 	// readonly, executable
-	STEXT
-	SELFRXSECT
+	STEXT      SymKind = obj.STEXT
+	SELFRXSECT SymKind = obj.SELFRXSECT
 
 	// readonly, non-executable
-	STYPE
-	SSTRING
-	SGOSTRING
-	SGOFUNC
-	SRODATA
-	SFUNCTAB
-	STYPELINK
-	SSYMTAB // TODO: move to unmapped section
-	SPCLNTAB
-	SELFROSECT
+	STYPE      SymKind = obj.STYPE
+	SSTRING    SymKind = obj.SSTRING
+	SGOSTRING  SymKind = obj.SGOSTRING
+	SGOFUNC    SymKind = obj.SGOFUNC
+	SRODATA    SymKind = obj.SRODATA
+	SFUNCTAB   SymKind = obj.SFUNCTAB
+	STYPELINK  SymKind = obj.STYPELINK
+	SSYMTAB    SymKind = obj.SSYMTAB // TODO: move to unmapped section
+	SPCLNTAB   SymKind = obj.SPCLNTAB
+	SELFROSECT SymKind = obj.SELFROSECT
 
 	// writable, non-executable
-	SMACHOPLT
-	SELFSECT
-	SMACHO // Mach-O __nl_symbol_ptr
-	SMACHOGOT
-	SNOPTRDATA
-	SINITARR
-	SDATA
-	SWINDOWS
-	SBSS
-	SNOPTRBSS
-	STLSBSS
+	SMACHOPLT  SymKind = obj.SMACHOPLT
+	SELFSECT   SymKind = obj.SELFSECT
+	SMACHO     SymKind = obj.SMACHO // Mach-O __nl_symbol_ptr
+	SMACHOGOT  SymKind = obj.SMACHOGOT
+	SWINDOWS   SymKind = obj.SWINDOWS
+	SELFGOT    SymKind = obj.SELFGOT
+	SNOPTRDATA SymKind = obj.SNOPTRDATA
+	SINITARR   SymKind = obj.SINITARR
+	SDATA      SymKind = obj.SDATA
+	SBSS       SymKind = obj.SBSS
+	SNOPTRBSS  SymKind = obj.SNOPTRBSS
+	STLSBSS    SymKind = obj.STLSBSS
 
 	// not mapped
-	SXREF
-	SMACHOSYMSTR
-	SMACHOSYMTAB
-	SMACHOINDIRECTPLT
-	SMACHOINDIRECTGOT
-	SFILE
-	SFILEPATH
-	SCONST
-	SDYNIMPORT
-	SHOSTOBJ
+	SXREF             SymKind = obj.SXREF
+	SMACHOSYMSTR      SymKind = obj.SMACHOSYMSTR
+	SMACHOSYMTAB      SymKind = obj.SMACHOSYMTAB
+	SMACHOINDIRECTPLT SymKind = obj.SMACHOINDIRECTPLT
+	SMACHOINDIRECTGOT SymKind = obj.SMACHOINDIRECTGOT
+	SFILE             SymKind = obj.SFILE
+	SFILEPATH         SymKind = obj.SFILEPATH
+	SCONST            SymKind = obj.SCONST
+	SDYNIMPORT        SymKind = obj.SDYNIMPORT
+	SHOSTOBJ          SymKind = obj.SHOSTOBJ
 )
 
 var symKindStrings = []string{
diff --git a/src/cmd/internal/ld/data.go b/src/cmd/internal/ld/data.go
index bc2021a..3194bd5 100644
--- a/src/cmd/internal/ld/data.go
+++ b/src/cmd/internal/ld/data.go
@@ -58,7 +58,7 @@
 
 func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
 	if s.Type == 0 {
-		s.Type = SDATA
+		s.Type = obj.SDATA
 	}
 	s.Reachable = true
 	if s.Size < off+wid {
@@ -102,6 +102,10 @@
 	return adduintxx(ctxt, s, v, 8)
 }
 
+func adduint(ctxt *Link, s *LSym, v uint64) int64 {
+	return adduintxx(ctxt, s, v, Thearch.Intsize)
+}
+
 func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
 	return setuintxx(ctxt, s, r, uint64(v), 1)
 }
@@ -112,7 +116,7 @@
 
 func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = SDATA
+		s.Type = obj.SDATA
 	}
 	s.Reachable = true
 	i := s.Size
@@ -122,14 +126,14 @@
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = uint8(ctxt.Arch.Ptrsize)
-	r.Type = R_ADDR
+	r.Type = obj.R_ADDR
 	r.Add = add
 	return i + int64(r.Siz)
 }
 
 func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = SDATA
+		s.Type = obj.SDATA
 	}
 	s.Reachable = true
 	i := s.Size
@@ -139,7 +143,7 @@
 	r.Sym = t
 	r.Off = int32(i)
 	r.Add = add
-	r.Type = R_PCREL
+	r.Type = obj.R_PCREL
 	r.Siz = 4
 	return i + int64(r.Siz)
 }
@@ -150,7 +154,7 @@
 
 func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = SDATA
+		s.Type = obj.SDATA
 	}
 	s.Reachable = true
 	if off+int64(ctxt.Arch.Ptrsize) > s.Size {
@@ -162,7 +166,7 @@
 	r.Sym = t
 	r.Off = int32(off)
 	r.Siz = uint8(ctxt.Arch.Ptrsize)
-	r.Type = R_ADDR
+	r.Type = obj.R_ADDR
 	r.Add = add
 	return off + int64(r.Siz)
 }
@@ -173,7 +177,7 @@
 
 func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
 	if s.Type == 0 {
-		s.Type = SDATA
+		s.Type = obj.SDATA
 	}
 	s.Reachable = true
 	i := s.Size
@@ -183,13 +187,13 @@
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = uint8(ctxt.Arch.Ptrsize)
-	r.Type = R_SIZE
+	r.Type = obj.R_SIZE
 	return i + int64(r.Siz)
 }
 
 func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	if s.Type == 0 {
-		s.Type = SDATA
+		s.Type = obj.SDATA
 	}
 	s.Reachable = true
 	i := s.Size
@@ -199,7 +203,7 @@
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = 4
-	r.Type = R_ADDR
+	r.Type = obj.R_ADDR
 	r.Add = add
 	return i + int64(r.Siz)
 }
@@ -218,7 +222,7 @@
 	// from input files.  Both are type SELFGOT, so in that case
 	// fall through to the name comparison (conveniently, .got
 	// sorts before .toc).
-	if s1.Type != SELFGOT && s1.Size != s2.Size {
+	if s1.Type != obj.SELFGOT && s1.Size != s2.Size {
 		if s1.Size < s2.Size {
 			return -1
 		}
@@ -328,9 +332,15 @@
 			continue
 		}
 
-		if r.Sym != nil && (r.Sym.Type&(SMASK|SHIDDEN) == 0 || r.Sym.Type&SMASK == SXREF) {
-			Diag("%s: not defined", r.Sym.Name)
-			continue
+		if r.Sym != nil && (r.Sym.Type&(obj.SMASK|obj.SHIDDEN) == 0 || r.Sym.Type&obj.SMASK == obj.SXREF) {
+			// When putting the runtime but not main into a shared library
+			// these symbols are undefined and that's OK.
+			if Buildmode == BuildmodeShared && (r.Sym.Name == "main.main" || r.Sym.Name == "main.init") {
+				r.Sym.Type = obj.SDYNIMPORT
+			} else {
+				Diag("%s: not defined", r.Sym.Name)
+				continue
+			}
 		}
 
 		if r.Type >= 256 {
@@ -340,17 +350,18 @@
 			continue
 		}
 
-		// Solaris needs the ability to reference dynimport symbols.
-		if HEADTYPE != Hsolaris && r.Sym != nil && r.Sym.Type == SDYNIMPORT {
+		// We need to be able to reference dynimport symbols when linking against
+		// shared libraries, and Solaris needs it always
+		if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() {
 			Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
 		}
-		if r.Sym != nil && r.Sym.Type != STLSBSS && !r.Sym.Reachable {
+		if r.Sym != nil && r.Sym.Type != obj.STLSBSS && !r.Sym.Reachable {
 			Diag("unreachable sym in relocation: %s %s", s.Name, r.Sym.Name)
 		}
 
 		// Android emulates runtime.tlsg as a regular variable.
-		if r.Type == R_TLS && goos == "android" {
-			r.Type = R_ADDR
+		if r.Type == obj.R_TLS && goos == "android" {
+			r.Type = obj.R_ADDR
 		}
 
 		switch r.Type {
@@ -360,7 +371,15 @@
 				Diag("unknown reloc %d", r.Type)
 			}
 
-		case R_TLS:
+		case obj.R_TLS:
+			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+				r.Done = 0
+				r.Sym = Ctxt.Tlsg
+				r.Xsym = Ctxt.Tlsg
+				r.Xadd = r.Add
+				o = r.Add
+				break
+			}
 			if Linkmode == LinkInternal && Iself && Thearch.Thechar == '5' {
 				// On ELF ARM, the thread pointer is 8 bytes before
 				// the start of the thread-local data block, so add 8
@@ -380,8 +399,8 @@
 				o = r.Add
 			}
 
-		case R_TLS_LE:
-			if Linkmode == LinkExternal && Iself && HEADTYPE != Hopenbsd {
+		case obj.R_TLS_LE:
+			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
 				r.Done = 0
 				r.Sym = Ctxt.Tlsg
 				r.Xsym = Ctxt.Tlsg
@@ -393,31 +412,30 @@
 				break
 			}
 
-			o = int64(Ctxt.Tlsoffset) + r.Add
-
-		case R_TLS_IE:
-			if Linkmode == LinkExternal && Iself && HEADTYPE != Hopenbsd {
-				r.Done = 0
-				r.Sym = Ctxt.Tlsg
-				r.Xsym = Ctxt.Tlsg
-				r.Xadd = r.Add
-				o = 0
-				if Thearch.Thechar != '6' {
-					o = r.Add
-				}
-				break
-			}
-
-			if Iself || Ctxt.Headtype == Hplan9 {
+			if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin {
 				o = int64(Ctxt.Tlsoffset) + r.Add
-			} else if Ctxt.Headtype == Hwindows {
+			} else if Ctxt.Headtype == obj.Hwindows {
 				o = r.Add
 			} else {
-				log.Fatalf("unexpected R_TLS_IE relocation for %s", Headstr(Ctxt.Headtype))
+				log.Fatalf("unexpected R_TLS_LE relocation for %s", Headstr(Ctxt.Headtype))
 			}
 
-		case R_ADDR:
-			if Linkmode == LinkExternal && r.Sym.Type != SCONST {
+		case obj.R_TLS_IE:
+			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+				r.Done = 0
+				r.Sym = Ctxt.Tlsg
+				r.Xsym = Ctxt.Tlsg
+				r.Xadd = r.Add
+				o = 0
+				if Thearch.Thechar != '6' {
+					o = r.Add
+				}
+				break
+			}
+			log.Fatalf("cannot handle R_TLS_IE when linking internally")
+
+		case obj.R_ADDR:
+			if Linkmode == LinkExternal && r.Sym.Type != obj.SCONST {
 				r.Done = 0
 
 				// set up addend for eventual relocation via outer symbol.
@@ -429,7 +447,7 @@
 					rs = rs.Outer
 				}
 
-				if rs.Type != SHOSTOBJ && rs.Type != SDYNIMPORT && rs.Sect == nil {
+				if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
 					Diag("missing section for %s", rs.Name)
 				}
 				r.Xsym = rs
@@ -439,11 +457,21 @@
 					if Thearch.Thechar == '6' {
 						o = 0
 					}
-				} else if HEADTYPE == Hdarwin {
-					if rs.Type != SHOSTOBJ {
-						o += Symaddr(rs)
+				} else if HEADTYPE == obj.Hdarwin {
+					// ld64 for arm64 has a bug where if the address pointed to by o exists in the
+					// symbol table (dynid >= 0), or is inside a symbol that exists in the symbol
+					// table, then it will add o twice into the relocated value.
+					// The workaround is that on arm64 don't ever add symaddr to o and always use
+					// extern relocation by requiring rs->dynid >= 0.
+					if rs.Type != obj.SHOSTOBJ {
+						if Thearch.Thechar == '7' && rs.Dynid < 0 {
+							Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
+						}
+						if Thearch.Thechar != '7' {
+							o += Symaddr(rs)
+						}
 					}
-				} else if HEADTYPE == Hwindows {
+				} else if HEADTYPE == obj.Hwindows {
 					// nothing to do
 				} else {
 					Diag("unhandled pcrel relocation for %s", headstring)
@@ -461,12 +489,12 @@
 			// 64-bit architectures so as to be future-proof.
 			if int32(o) < 0 && Thearch.Ptrsize > 4 && siz == 4 {
 				Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add)
-				Errorexit()
+				errorexit()
 			}
 
 			// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
-		case R_CALL, R_PCREL:
-			if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != SCONST && r.Sym.Sect != Ctxt.Cursym.Sect {
+		case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL:
+			if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != Ctxt.Cursym.Sect || r.Type == obj.R_GOTPCREL) {
 				r.Done = 0
 
 				// set up addend for eventual relocation via outer symbol.
@@ -479,7 +507,7 @@
 				}
 
 				r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
-				if rs.Type != SHOSTOBJ && rs.Type != SDYNIMPORT && rs.Sect == nil {
+				if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
 					Diag("missing section for %s", rs.Name)
 				}
 				r.Xsym = rs
@@ -489,16 +517,16 @@
 					if Thearch.Thechar == '6' {
 						o = 0
 					}
-				} else if HEADTYPE == Hdarwin {
-					if r.Type == R_CALL {
-						if rs.Type != SHOSTOBJ {
+				} 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(r.Off) // relative to section offset, not symbol
 					} else {
 						o += int64(r.Siz)
 					}
-				} else if HEADTYPE == Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL
+				} else if HEADTYPE == obj.Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL
 					// PE/COFF's PC32 relocation uses the address after the relocated
 					// bytes as the base. Compensate by skewing the addend.
 					o += int64(r.Siz)
@@ -525,7 +553,7 @@
 			// the standard host compiler (gcc on most other systems).
 			o += r.Add - (s.Value + int64(r.Off) + int64(int32(r.Siz)))
 
-		case R_SIZE:
+		case obj.R_SIZE:
 			o = r.Sym.Size + r.Add
 		}
 
@@ -558,7 +586,7 @@
 			Ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
 
 		case 4:
-			if r.Type == R_PCREL || r.Type == R_CALL {
+			if r.Type == obj.R_PCREL || r.Type == obj.R_CALL {
 				if o != int64(int32(o)) {
 					Diag("pc-relative relocation address is too big: %#x", o)
 				}
@@ -581,7 +609,7 @@
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
 	}
-	Bflush(&Bso)
+	Bso.Flush()
 
 	for s := Ctxt.Textp; s != nil; s = s.Next {
 		relocsym(s)
@@ -592,7 +620,7 @@
 }
 
 func dynrelocsym(s *LSym) {
-	if HEADTYPE == Hwindows && Linkmode != LinkExternal {
+	if HEADTYPE == obj.Hwindows && Linkmode != LinkExternal {
 		rel := Linklookup(Ctxt, ".rel", 0)
 		if s == rel {
 			return
@@ -639,7 +667,7 @@
 	var r *Reloc
 	for ri := 0; ri < len(s.R); ri++ {
 		r = &s.R[ri]
-		if r.Sym != nil && r.Sym.Type == SDYNIMPORT || r.Type >= 256 {
+		if r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT || r.Type >= 256 {
 			if r.Sym != nil && !r.Sym.Reachable {
 				Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name)
 			}
@@ -651,13 +679,13 @@
 func dynreloc() {
 	// -d suppresses dynamic loader format, so we may as well not
 	// compute these sections or mark their symbols as reachable.
-	if Debug['d'] != 0 && HEADTYPE != Hwindows {
+	if Debug['d'] != 0 && HEADTYPE != obj.Hwindows {
 		return
 	}
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
 	}
-	Bflush(&Bso)
+	Bso.Flush()
 
 	for s := Ctxt.Textp; s != nil; s = s.Next {
 		dynrelocsym(s)
@@ -674,7 +702,7 @@
 	var sym *LSym
 
 	for sym = start; sym != nil; sym = sym.Next {
-		if sym.Type&SSUB == 0 && sym.Value >= addr {
+		if sym.Type&obj.SSUB == 0 && sym.Value >= addr {
 			break
 		}
 	}
@@ -683,7 +711,7 @@
 	var ep []byte
 	var p []byte
 	for ; sym != nil; sym = sym.Next {
-		if sym.Type&SSUB != 0 {
+		if sym.Type&obj.SSUB != 0 {
 			continue
 		}
 		if sym.Value >= eaddr {
@@ -692,7 +720,7 @@
 		Ctxt.Cursym = sym
 		if sym.Value < addr {
 			Diag("phase error: addr=%#x but sym=%#x type=%d", int64(addr), int64(sym.Value), sym.Type)
-			Errorexit()
+			errorexit()
 		}
 
 		for ; addr < sym.Value; addr++ {
@@ -710,7 +738,7 @@
 		}
 		if addr != sym.Value+sym.Size {
 			Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size)
-			Errorexit()
+			errorexit()
 		}
 
 		if sym.Value+sym.Size >= eaddr {
@@ -770,14 +798,14 @@
 		q = sym.P
 
 		for n >= 16 {
-			fmt.Fprintf(&Bso, "%.6x\t%%-20.16I\n", uint64(addr), q)
+			fmt.Fprintf(&Bso, "%.6x\t%-20.16I\n", uint64(addr), q)
 			addr += 16
 			q = q[16:]
 			n -= 16
 		}
 
 		if n > 0 {
-			fmt.Fprintf(&Bso, "%.6x\t%%-20.*I\n", uint64(addr), int(n), q)
+			fmt.Fprintf(&Bso, "%.6x\t%-20.*I\n", uint64(addr), int(n), q)
 		}
 		addr += n
 	}
@@ -789,7 +817,7 @@
 		}
 	}
 
-	Bflush(&Bso)
+	Bso.Flush()
 }
 
 func Datblk(addr int64, size int64) {
@@ -853,13 +881,13 @@
 				}
 				typ = "?"
 				switch r.Type {
-				case R_ADDR:
+				case obj.R_ADDR:
 					typ = "addr"
 
-				case R_PCREL:
+				case obj.R_PCREL:
 					typ = "pcrel"
 
-				case R_CALL:
+				case obj.R_CALL:
 					typ = "call"
 				}
 
@@ -901,7 +929,7 @@
 	sp := Linklookup(Ctxt, p, 0)
 
 	Addstring(sp, value)
-	sp.Type = SRODATA
+	sp.Type = obj.SRODATA
 
 	s := Linklookup(Ctxt, name, 0)
 	s.Size = 0
@@ -920,7 +948,7 @@
 
 func Addstring(s *LSym, str string) int64 {
 	if s.Type == 0 {
-		s.Type = SNOPTRDATA
+		s.Type = obj.SNOPTRDATA
 	}
 	s.Reachable = true
 	r := int32(s.Size)
@@ -938,7 +966,7 @@
 func addinitarrdata(s *LSym) {
 	p := s.Name + ".ptr"
 	sp := Linklookup(Ctxt, p, 0)
-	sp.Type = SINITARR
+	sp.Type = obj.SINITARR
 	sp.Size = 0
 	sp.Dupok = 1
 	Addaddr(Ctxt, sp, s)
@@ -947,17 +975,20 @@
 func dosymtype() {
 	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if len(s.P) > 0 {
-			if s.Type == SBSS {
-				s.Type = SDATA
+			if s.Type == obj.SBSS {
+				s.Type = obj.SDATA
 			}
-			if s.Type == SNOPTRBSS {
-				s.Type = SNOPTRDATA
+			if s.Type == obj.SNOPTRBSS {
+				s.Type = obj.SNOPTRDATA
 			}
 		}
 		// Create a new entry in the .init_array section that points to the
 		// library initializer function.
-		if Flag_shared != 0 && s.Name == INITENTRY {
-			addinitarrdata(s)
+		switch Buildmode {
+		case BuildmodeCArchive, BuildmodeCShared:
+			if s.Name == INITENTRY {
+				addinitarrdata(s)
+			}
 		}
 	}
 }
@@ -1173,7 +1204,7 @@
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime())
 	}
-	Bflush(&Bso)
+	Bso.Flush()
 
 	var last *LSym
 	datap = nil
@@ -1182,7 +1213,7 @@
 		if !s.Reachable || s.Special != 0 {
 			continue
 		}
-		if STEXT < s.Type && s.Type < SXREF {
+		if obj.STEXT < s.Type && s.Type < obj.SXREF {
 			if s.Onlist != 0 {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -1211,7 +1242,7 @@
 	 *
 	 * on darwin, we need the symbol table numbers for dynreloc.
 	 */
-	if HEADTYPE == Hdarwin {
+	if HEADTYPE == obj.Hdarwin {
 		machosymorder()
 	}
 	dynreloc()
@@ -1225,7 +1256,7 @@
 			break
 		}
 
-		if s.Type <= STEXT || SXREF <= s.Type {
+		if s.Type <= obj.STEXT || obj.SXREF <= s.Type {
 			*l = s.Next
 		} else {
 			l = &s.Next
@@ -1236,6 +1267,27 @@
 
 	datap = listsort(datap, datcmp, listnextp)
 
+	if Iself {
+		// Make .rela and .rela.plt contiguous, the ELF ABI requires this
+		// and Solaris actually cares.
+		var relplt *LSym
+		for l = &datap; *l != nil; l = &(*l).Next {
+			if (*l).Name == ".rel.plt" || (*l).Name == ".rela.plt" {
+				relplt = (*l)
+				*l = (*l).Next
+				break
+			}
+		}
+		if relplt != nil {
+			for s = datap; s != nil; s = s.Next {
+				if s.Name == ".rel" || s.Name == ".rela" {
+					relplt.Next = s.Next
+					s.Next = relplt
+				}
+			}
+		}
+	}
+
 	/*
 	 * allocate sections.  list is sorted by type,
 	 * so we can just walk it for each piece we want to emit.
@@ -1249,36 +1301,36 @@
 	/* skip symbols belonging to segtext */
 	s = datap
 
-	for ; s != nil && s.Type < SELFSECT; s = s.Next {
+	for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
 	}
 
 	/* writable ELF sections */
 	datsize := int64(0)
 
 	var sect *Section
-	for ; s != nil && s.Type < SELFGOT; s = s.Next {
+	for ; s != nil && s.Type < obj.SELFGOT; s = s.Next {
 		sect = addsection(&Segdata, s.Name, 06)
 		sect.Align = symalign(s)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
 		s.Sect = sect
-		s.Type = SDATA
+		s.Type = obj.SDATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
 
 	/* .got (and .toc on ppc64) */
-	if s.Type == SELFGOT {
+	if s.Type == obj.SELFGOT {
 		sect := addsection(&Segdata, ".got", 06)
-		sect.Align = maxalign(s, SELFGOT)
+		sect.Align = maxalign(s, obj.SELFGOT)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
 		var toc *LSym
-		for ; s != nil && s.Type == SELFGOT; s = s.Next {
+		for ; s != nil && s.Type == obj.SELFGOT; s = s.Next {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
-			s.Type = SDATA
+			s.Type = obj.SDATA
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
 
 			// Resolve .TOC. symbol for this object file (ppc64)
@@ -1302,28 +1354,35 @@
 	/* pointer-free data */
 	sect = addsection(&Segdata, ".noptrdata", 06)
 
-	sect.Align = maxalign(s, SINITARR-1)
+	sect.Align = maxalign(s, obj.SINITARR-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect
-	for ; s != nil && s.Type < SINITARR; s = s.Next {
+	for ; s != nil && s.Type < obj.SINITARR; s = s.Next {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = SDATA
+		s.Type = obj.SDATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 	}
 
 	sect.Length = uint64(datsize) - sect.Vaddr
 
+	hasinitarr := Linkshared
+
 	/* shared library initializer */
-	if Flag_shared != 0 {
+	switch Buildmode {
+	case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
+		hasinitarr = true
+	}
+
+	if hasinitarr {
 		sect := addsection(&Segdata, ".init_array", 06)
-		sect.Align = maxalign(s, SINITARR)
+		sect.Align = maxalign(s, obj.SINITARR)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
-		for ; s != nil && s.Type == SINITARR; s = s.Next {
+		for ; s != nil && s.Type == obj.SINITARR; s = s.Next {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1336,7 +1395,7 @@
 	/* data */
 	sect = addsection(&Segdata, ".data", 06)
 
-	sect.Align = maxalign(s, SBSS-1)
+	sect.Align = maxalign(s, obj.SBSS-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.data", 0).Sect = sect
@@ -1344,14 +1403,14 @@
 	gcdata := Linklookup(Ctxt, "runtime.gcdata", 0)
 	var gen ProgGen
 	proggeninit(&gen, gcdata)
-	for ; s != nil && s.Type < SBSS; s = s.Next {
-		if s.Type == SINITARR {
+	for ; s != nil && s.Type < obj.SBSS; s = s.Next {
+		if s.Type == obj.SINITARR {
 			Ctxt.Cursym = s
 			Diag("unexpected symbol type %d", s.Type)
 		}
 
 		s.Sect = sect
-		s.Type = SDATA
+		s.Type = obj.SDATA
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		proggenaddsym(&gen, s) // gc
@@ -1364,14 +1423,14 @@
 	/* bss */
 	sect = addsection(&Segdata, ".bss", 06)
 
-	sect.Align = maxalign(s, SNOPTRBSS-1)
+	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)
-	for ; s != nil && s.Type < SNOPTRBSS; s = s.Next {
+	for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next {
 		s.Sect = sect
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1385,12 +1444,12 @@
 	/* pointer-free bss */
 	sect = addsection(&Segdata, ".noptrbss", 06)
 
-	sect.Align = maxalign(s, SNOPTRBSS)
+	sect.Align = maxalign(s, obj.SNOPTRBSS)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect
-	for ; s != nil && s.Type == SNOPTRBSS; s = s.Next {
+	for ; s != nil && s.Type == obj.SNOPTRBSS; s = s.Next {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1405,12 +1464,12 @@
 		Diag("data or bss segment too large")
 	}
 
-	if Iself && Linkmode == LinkExternal && s != nil && s.Type == STLSBSS && HEADTYPE != Hopenbsd {
+	if Iself && Linkmode == LinkExternal && s != nil && s.Type == obj.STLSBSS && HEADTYPE != obj.Hopenbsd {
 		sect := addsection(&Segdata, ".tbss", 06)
 		sect.Align = int32(Thearch.Ptrsize)
 		sect.Vaddr = 0
 		datsize = 0
-		for ; s != nil && s.Type == STLSBSS; s = s.Next {
+		for ; s != nil && s.Type == obj.STLSBSS; s = s.Next {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1422,7 +1481,7 @@
 		// Might be internal linking but still using cgo.
 		// In that case, the only possible STLSBSS symbol is runtime.tlsg.
 		// Give it offset 0, because it's the only thing here.
-		if s != nil && s.Type == STLSBSS && s.Name == "runtime.tlsg" {
+		if s != nil && s.Type == obj.STLSBSS && s.Name == "runtime.tlsg" {
 			s.Value = 0
 			s = s.Next
 		}
@@ -1455,13 +1514,13 @@
 	datsize = 0
 
 	/* read-only executable ELF, Mach-O sections */
-	for ; s != nil && s.Type < STYPE; s = s.Next {
+	for ; s != nil && s.Type < obj.STYPE; s = s.Next {
 		sect = addsection(&Segtext, s.Name, 04)
 		sect.Align = symalign(s)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
 		s.Sect = sect
-		s.Type = SRODATA
+		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 		sect.Length = uint64(datsize) - sect.Vaddr
@@ -1470,15 +1529,15 @@
 	/* read-only data */
 	sect = addsection(segro, ".rodata", 04)
 
-	sect.Align = maxalign(s, STYPELINK-1)
+	sect.Align = maxalign(s, obj.STYPELINK-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = 0
 	Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
-	for ; s != nil && s.Type < STYPELINK; s = s.Next {
+	for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = SRODATA
+		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 	}
@@ -1488,15 +1547,15 @@
 	/* typelink */
 	sect = addsection(segro, ".typelink", 04)
 
-	sect.Align = maxalign(s, STYPELINK)
+	sect.Align = maxalign(s, obj.STYPELINK)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect
-	for ; s != nil && s.Type == STYPELINK; s = s.Next {
+	for ; s != nil && s.Type == obj.STYPELINK; s = s.Next {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = SRODATA
+		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 	}
@@ -1506,15 +1565,15 @@
 	/* gosymtab */
 	sect = addsection(segro, ".gosymtab", 04)
 
-	sect.Align = maxalign(s, SPCLNTAB-1)
+	sect.Align = maxalign(s, obj.SPCLNTAB-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect
-	for ; s != nil && s.Type < SPCLNTAB; s = s.Next {
+	for ; s != nil && s.Type < obj.SPCLNTAB; s = s.Next {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = SRODATA
+		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 	}
@@ -1524,15 +1583,15 @@
 	/* gopclntab */
 	sect = addsection(segro, ".gopclntab", 04)
 
-	sect.Align = maxalign(s, SELFROSECT-1)
+	sect.Align = maxalign(s, obj.SELFROSECT-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect
-	for ; s != nil && s.Type < SELFROSECT; s = s.Next {
+	for ; s != nil && s.Type < obj.SELFROSECT; s = s.Next {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
-		s.Type = SRODATA
+		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 	}
@@ -1540,13 +1599,13 @@
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* read-only ELF, Mach-O sections */
-	for ; s != nil && s.Type < SELFSECT; s = s.Next {
+	for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
 		sect = addsection(segro, s.Name, 04)
 		sect.Align = symalign(s)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
 		s.Sect = sect
-		s.Type = SRODATA
+		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		growdatsize(&datsize, s)
 		sect.Length = uint64(datsize) - sect.Vaddr
@@ -1592,7 +1651,7 @@
 	sect.Vaddr = va
 	for sym := Ctxt.Textp; sym != nil; sym = sym.Next {
 		sym.Sect = sect
-		if sym.Type&SSUB != 0 {
+		if sym.Type&obj.SSUB != 0 {
 			continue
 		}
 		if sym.Align != 0 {
@@ -1631,7 +1690,7 @@
 
 	Segtext.Length = va - uint64(INITTEXT)
 	Segtext.Filelen = Segtext.Length
-	if HEADTYPE == Hnacl {
+	if HEADTYPE == obj.Hnacl {
 		va += 32 // room for the "halt sled"
 	}
 
@@ -1659,10 +1718,10 @@
 	Segdata.Vaddr = va
 	Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
 	Segdata.Filelen = 0
-	if HEADTYPE == Hwindows {
+	if HEADTYPE == obj.Hwindows {
 		Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
 	}
-	if HEADTYPE == Hplan9 {
+	if HEADTYPE == obj.Hplan9 {
 		Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
 	}
 	var data *Section
@@ -1716,32 +1775,34 @@
 		}
 	}
 
-	xdefine("runtime.text", STEXT, int64(text.Vaddr))
-	xdefine("runtime.etext", STEXT, int64(text.Vaddr+text.Length))
-	xdefine("runtime.rodata", SRODATA, int64(rodata.Vaddr))
-	xdefine("runtime.erodata", SRODATA, int64(rodata.Vaddr+rodata.Length))
-	xdefine("runtime.typelink", SRODATA, int64(typelink.Vaddr))
-	xdefine("runtime.etypelink", SRODATA, int64(typelink.Vaddr+typelink.Length))
+	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))
+	xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
+	xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
+	xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
 
 	sym := Linklookup(Ctxt, "runtime.gcdata", 0)
-	xdefine("runtime.egcdata", SRODATA, Symaddr(sym)+sym.Size)
+	sym.Local = true
+	xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size)
 	Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
 
 	sym = Linklookup(Ctxt, "runtime.gcbss", 0)
-	xdefine("runtime.egcbss", SRODATA, Symaddr(sym)+sym.Size)
+	sym.Local = true
+	xdefine("runtime.egcbss", obj.SRODATA, Symaddr(sym)+sym.Size)
 	Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect
 
-	xdefine("runtime.symtab", SRODATA, int64(symtab.Vaddr))
-	xdefine("runtime.esymtab", SRODATA, int64(symtab.Vaddr+symtab.Length))
-	xdefine("runtime.pclntab", SRODATA, int64(pclntab.Vaddr))
-	xdefine("runtime.epclntab", SRODATA, int64(pclntab.Vaddr+pclntab.Length))
-	xdefine("runtime.noptrdata", SNOPTRDATA, int64(noptr.Vaddr))
-	xdefine("runtime.enoptrdata", SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
-	xdefine("runtime.bss", SBSS, int64(bss.Vaddr))
-	xdefine("runtime.ebss", SBSS, int64(bss.Vaddr+bss.Length))
-	xdefine("runtime.data", SDATA, int64(data.Vaddr))
-	xdefine("runtime.edata", SDATA, int64(data.Vaddr+data.Length))
-	xdefine("runtime.noptrbss", SNOPTRBSS, int64(noptrbss.Vaddr))
-	xdefine("runtime.enoptrbss", SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
-	xdefine("runtime.end", SBSS, int64(Segdata.Vaddr+Segdata.Length))
+	xdefine("runtime.symtab", obj.SRODATA, int64(symtab.Vaddr))
+	xdefine("runtime.esymtab", obj.SRODATA, int64(symtab.Vaddr+symtab.Length))
+	xdefine("runtime.pclntab", obj.SRODATA, int64(pclntab.Vaddr))
+	xdefine("runtime.epclntab", obj.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
+	xdefine("runtime.noptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr))
+	xdefine("runtime.enoptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
+	xdefine("runtime.bss", obj.SBSS, int64(bss.Vaddr))
+	xdefine("runtime.ebss", obj.SBSS, int64(bss.Vaddr+bss.Length))
+	xdefine("runtime.data", obj.SDATA, int64(data.Vaddr))
+	xdefine("runtime.edata", obj.SDATA, int64(data.Vaddr+data.Length))
+	xdefine("runtime.noptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr))
+	xdefine("runtime.enoptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
+	xdefine("runtime.end", obj.SBSS, int64(Segdata.Vaddr+Segdata.Length))
 }
diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/internal/ld/decodesym.go
index e960f10..754c89f 100644
--- a/src/cmd/internal/ld/decodesym.go
+++ b/src/cmd/internal/ld/decodesym.go
@@ -35,29 +35,31 @@
 		return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
 	case 8:
 		return Ctxt.Arch.ByteOrder.Uint64(p)
+	default:
+		Exitf("dwarf: decode inuxi %d", sz)
+		panic("unreachable")
 	}
-	Diag("dwarf: decode inuxi %d", sz)
-	Errorexit()
-	return 0
 }
 
+// commonsize returns the size of the common prefix for all type
+// structures (runtime._type).
 func commonsize() int {
-	return 8*Thearch.Ptrsize + 8
+	return 9*Thearch.Ptrsize + 8
 }
 
 // Type.commonType.kind
 func decodetype_kind(s *LSym) uint8 {
-	return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindMask) //  0x13 / 0x1f
+	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) //  0x13 / 0x1f
 }
 
 // Type.commonType.kind
 func decodetype_noptr(s *LSym) uint8 {
-	return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindNoPointers) //  0x13 / 0x1f
+	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) //  0x13 / 0x1f
 }
 
 // Type.commonType.kind
 func decodetype_usegcprog(s *LSym) uint8 {
-	return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindGCProg) //  0x13 / 0x1f
+	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) //  0x13 / 0x1f
 }
 
 // Type.commonType.size
@@ -67,11 +69,25 @@
 
 // Type.commonType.gc
 func decodetype_gcprog(s *LSym) *LSym {
-	return decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
+	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)
+	}
+	return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
+}
+
+func decodetype_gcprog_shlib(s *LSym) uint64 {
+	return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
 }
 
 func decodetype_gcmask(s *LSym) []byte {
-	mask := decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
+	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
+	}
+	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/internal/ld/dwarf.go
index 37625f1..6d90404 100644
--- a/src/cmd/internal/ld/dwarf.go
+++ b/src/cmd/internal/ld/dwarf.go
@@ -158,16 +158,16 @@
 	return int(length)
 }
 
+var encbuf [10]byte
+
 func uleb128put(v int64) {
-	var buf [10]byte
-	n := uleb128enc(uint64(v), buf[:])
-	Cwrite(buf[:n])
+	n := uleb128enc(uint64(v), encbuf[:])
+	Cwrite(encbuf[:n])
 }
 
 func sleb128put(v int64) {
-	var buf [10]byte
-	n := sleb128enc(v, buf[:])
-	Cwrite(buf[:n])
+	n := sleb128enc(v, encbuf[:])
+	Cwrite(encbuf[:n])
 }
 
 /*
@@ -223,382 +223,261 @@
 type DWAbbrev struct {
 	tag      uint8
 	children uint8
-	attr     [30]DWAttrForm
+	attr     []DWAttrForm
 }
 
-var abbrevs = [DW_NABRV]struct {
-	tag      uint8
-	children uint8
-	attr     [30]DWAttrForm
-}{
+var abbrevs = [DW_NABRV]DWAbbrev{
 	/* The mandatory DW_ABRV_NULL entry. */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{0, 0, [30]DWAttrForm{}},
+	{0, 0, []DWAttrForm{}},
 
 	/* COMPUNIT */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_compile_unit,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_language, DW_FORM_data1},
-			DWAttrForm{DW_AT_low_pc, DW_FORM_addr},
-			DWAttrForm{DW_AT_high_pc, DW_FORM_addr},
-			DWAttrForm{DW_AT_stmt_list, DW_FORM_data4},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_language, DW_FORM_data1},
+			{DW_AT_low_pc, DW_FORM_addr},
+			{DW_AT_high_pc, DW_FORM_addr},
+			{DW_AT_stmt_list, DW_FORM_data4},
 		},
 	},
 
 	/* FUNCTION */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_subprogram,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_low_pc, DW_FORM_addr},
-			DWAttrForm{DW_AT_high_pc, DW_FORM_addr},
-			DWAttrForm{DW_AT_external, DW_FORM_flag},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_low_pc, DW_FORM_addr},
+			{DW_AT_high_pc, DW_FORM_addr},
+			{DW_AT_external, DW_FORM_flag},
 		},
 	},
 
 	/* VARIABLE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_variable,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_location, DW_FORM_block1},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_external, DW_FORM_flag},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_external, DW_FORM_flag},
 		},
 	},
 
 	/* AUTO */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_variable,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_location, DW_FORM_block1},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
 		},
 	},
 
 	/* PARAM */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_formal_parameter,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_location, DW_FORM_block1},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
 		},
 	},
 
 	/* STRUCTFIELD */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_member,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_data_member_location, DW_FORM_block1},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_data_member_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
 		},
 	},
 
 	/* FUNCTYPEPARAM */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_formal_parameter,
 		DW_CHILDREN_no,
 
 		// No name!
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_type, DW_FORM_ref_addr},
 		},
 	},
 
 	/* DOTDOTDOT */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_unspecified_parameters,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{DWAttrForm{0, 0}},
+		[]DWAttrForm{},
 	},
 
 	/* ARRAYRANGE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_subrange_type,
 		DW_CHILDREN_no,
 
 		// No name!
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_count, DW_FORM_udata},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_count, DW_FORM_udata},
 		},
 	},
 
 	// Below here are the types considered public by ispubtype
 	/* NULLTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_unspecified_type,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
 		},
 	},
 
 	/* BASETYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_base_type,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_encoding, DW_FORM_data1},
-			DWAttrForm{DW_AT_byte_size, DW_FORM_data1},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_encoding, DW_FORM_data1},
+			{DW_AT_byte_size, DW_FORM_data1},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* ARRAYTYPE */
 	// child is subrange with upper bound
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_array_type,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* CHANTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_typedef,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{DW_AT_go_elem, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+			{DW_AT_go_elem, DW_FORM_ref_addr},
 		},
 	},
 
 	/* FUNCTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_subroutine_type,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-
-			//		{DW_AT_type,	DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			// {DW_AT_type,	DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* IFACETYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_typedef,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* MAPTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_typedef,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{DW_AT_go_key, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_go_elem, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+			{DW_AT_go_key, DW_FORM_ref_addr},
+			{DW_AT_go_elem, DW_FORM_ref_addr},
 		},
 	},
 
 	/* PTRTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_pointer_type,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* BARE_PTRTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_pointer_type,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
 		},
 	},
 
 	/* SLICETYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_structure_type,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{DW_AT_go_elem, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
+			{DW_AT_go_elem, DW_FORM_ref_addr},
 		},
 	},
 
 	/* STRINGTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_structure_type,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* STRUCTTYPE */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_structure_type,
 		DW_CHILDREN_yes,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_byte_size, DW_FORM_udata},
-			DWAttrForm{DW_AT_go_kind, DW_FORM_data1},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
 		},
 	},
 
 	/* TYPEDECL */
-	struct {
-		tag      uint8
-		children uint8
-		attr     [30]DWAttrForm
-	}{
+	{
 		DW_TAG_typedef,
 		DW_CHILDREN_no,
-		[30]DWAttrForm{
-			DWAttrForm{DW_AT_name, DW_FORM_string},
-			DWAttrForm{DW_AT_type, DW_FORM_ref_addr},
-			DWAttrForm{0, 0},
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
 		},
 	},
 }
 
 func writeabbrev() {
-	var j int
-	var f *DWAttrForm
-
 	abbrevo = Cpos()
 	for i := 1; i < DW_NABRV; i++ {
 		// See section 7.5.3
@@ -606,14 +485,12 @@
 
 		uleb128put(int64(abbrevs[i].tag))
 		Cput(abbrevs[i].children)
-		for j = 0; j < len(abbrevs[i].attr); j++ {
-			f = &abbrevs[i].attr[j]
+		for _, f := range abbrevs[i].attr {
 			uleb128put(int64(f.attr))
 			uleb128put(int64(f.form))
-			if f.attr == 0 {
-				break
-			}
 		}
+		uleb128put(0)
+		uleb128put(0)
 	}
 
 	Cput(0)
@@ -797,13 +674,11 @@
 	return nil
 }
 
-func find_or_diag(die *DWDie, name string) *DWDie {
+func mustFind(die *DWDie, name string) *DWDie {
 	r := find(die, name)
 	if r == nil {
-		Diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
-		Errorexit()
+		Exitf("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
 	}
-
 	return r
 }
 
@@ -813,7 +688,7 @@
 	r.Xsym = sym
 	r.Off = int32(Cpos() - offsetbase)
 	r.Siz = uint8(siz)
-	r.Type = R_ADDR
+	r.Type = obj.R_ADDR
 	r.Add = addend
 	r.Xadd = addend
 	if Iself && Thearch.Thechar == '6' {
@@ -966,27 +841,23 @@
 		DW_FORM_indirect: // (see Section 7.5.3)
 		fallthrough
 	default:
-		Diag("dwarf: unsupported attribute form %d / class %d", form, cls)
-
-		Errorexit()
+		Exitf("dwarf: unsupported attribute form %d / class %d", form, cls)
 	}
 }
 
 // Note that we can (and do) add arbitrary attributes to a DIE, but
 // only the ones actually listed in the Abbrev will be written out.
 func putattrs(abbrev int, attr *DWAttr) {
-	var ap *DWAttr
-
-	for af := abbrevs[abbrev].attr[:]; af[0].attr != 0; af = af[1:] {
-		for ap = attr; ap != nil; ap = ap.link {
-			if ap.atr == af[0].attr {
-				putattr(abbrev, int(af[0].form), int(ap.cls), ap.value, ap.data)
-				goto done
+Outer:
+	for _, f := range abbrevs[abbrev].attr {
+		for ap := attr; ap != nil; ap = ap.link {
+			if ap.atr == f.attr {
+				putattr(abbrev, int(f.form), int(ap.cls), ap.value, ap.data)
+				continue Outer
 			}
 		}
 
-		putattr(abbrev, int(af[0].form), 0, 0, nil)
-	done:
+		putattr(abbrev, int(f.form), 0, 0, nil)
 	}
 }
 
@@ -1049,8 +920,7 @@
 func lookup_or_diag(n string) *LSym {
 	s := Linkrlookup(Ctxt, n, 0)
 	if s == nil || s.Size == 0 {
-		Diag("dwarf: missing type: %s", n)
-		Errorexit()
+		Exitf("dwarf: missing type: %s", n)
 	}
 
 	return s
@@ -1086,12 +956,12 @@
 // Define gotype, for composite ones recurse into constituents.
 func defgotype(gotype *LSym) *DWDie {
 	if gotype == nil {
-		return find_or_diag(&dwtypes, "<unspecified>")
+		return mustFind(&dwtypes, "<unspecified>")
 	}
 
 	if !strings.HasPrefix(gotype.Name, "type.") {
 		Diag("dwarf: type name doesn't start with \".type\": %s", gotype.Name)
-		return find_or_diag(&dwtypes, "<unspecified>")
+		return mustFind(&dwtypes, "<unspecified>")
 	}
 
 	name := gotype.Name[5:] // could also decode from Type.string
@@ -1103,7 +973,7 @@
 	}
 
 	if false && Debug['v'] > 2 {
-		fmt.Printf("new type: %%Y\n", gotype)
+		fmt.Printf("new type: %v\n", gotype)
 	}
 
 	kind := decodetype_kind(gotype)
@@ -1157,7 +1027,7 @@
 		// use actual length not upper bound; correct for 0-length arrays.
 		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0)
 
-		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+		newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
 
 	case obj.KindChan:
 		die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name)
@@ -1168,7 +1038,7 @@
 	case obj.KindFunc:
 		die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name)
 		dotypedef(&dwtypes, name, die)
-		newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"))
+		newrefattr(die, DW_AT_type, mustFind(&dwtypes, "void"))
 		nfields := decodetype_funcincount(gotype)
 		var fld *DWDie
 		var s *LSym
@@ -1250,7 +1120,7 @@
 	default:
 		Diag("dwarf: definition of unknown kind %d: %s", kind, gotype.Name)
 		die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name)
-		newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"))
+		newrefattr(die, DW_AT_type, mustFind(&dwtypes, "<unspecified>"))
 	}
 
 	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0)
@@ -1298,7 +1168,7 @@
 // Search children (assumed to have DW_TAG_member) for the one named
 // field and set its DW_AT_type to dwtype
 func substitutetype(structdie *DWDie, field string, dwtype *DWDie) {
-	child := find_or_diag(structdie, field)
+	child := mustFind(structdie, field)
 	if child == nil {
 		return
 	}
@@ -1427,7 +1297,7 @@
 		newrefattr(dwhk, DW_AT_type, t)
 		fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size")
 		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
-		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+		newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
 
 		// Construct type to represent an array of BucketSize values
 		dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]val", getattr(valtype, DW_AT_name).data.(string), ""))
@@ -1440,7 +1310,7 @@
 		newrefattr(dwhv, DW_AT_type, t)
 		fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size")
 		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
-		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+		newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
 
 		// Construct bucket<K,V>
 		dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("bucket", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
@@ -1460,7 +1330,7 @@
 		newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
 		if Thearch.Regsize > Thearch.Ptrsize {
 			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad")
-			newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"))
+			newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
 			newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(Thearch.Ptrsize))
 		}
 
@@ -1565,7 +1435,6 @@
 		}
 		fallthrough
 
-		// fallthrough
 	case 'a', 'p':
 		dt = defgotype(gotype)
 	}
@@ -1821,11 +1690,11 @@
 		varhash = [HASHSIZE]*DWDie{}
 		for a = s.Autom; a != nil; a = a.Link {
 			switch a.Name {
-			case A_AUTO:
+			case obj.A_AUTO:
 				dt = DW_ABRV_AUTO
 				offs = int64(a.Aoffset) - int64(Thearch.Ptrsize)
 
-			case A_PARAM:
+			case obj.A_PARAM:
 				dt = DW_ABRV_PARAM
 				offs = int64(a.Aoffset)
 
@@ -1929,8 +1798,7 @@
 	pad := CIERESERVE + frameo + 4 - Cpos()
 
 	if pad < 0 {
-		Diag("dwarf: CIERESERVE too small by %d bytes.", -pad)
-		Errorexit()
+		Exitf("dwarf: CIERESERVE too small by %d bytes.", -pad)
 	}
 
 	strnput("", int(pad))
@@ -2170,7 +2038,7 @@
 }
 
 func align(size int64) {
-	if HEADTYPE == Hwindows { // Only Windows PE need section align.
+	if HEADTYPE == obj.Hwindows { // Only Windows PE need section align.
 		strnput("", int(Rnd(size, PEFILEALIGN)-size))
 	}
 }
@@ -2184,7 +2052,7 @@
 		r = &s.R[ri]
 		if Iself {
 			i = Thearch.Elfreloc1(r, int64(r.Off))
-		} else if HEADTYPE == Hdarwin {
+		} else if HEADTYPE == obj.Hdarwin {
 			i = Thearch.Machoreloc1(r, int64(r.Off))
 		} else {
 			i = -1
@@ -2275,13 +2143,11 @@
 		Cseek(infoo)
 		writeinfo()
 		if fwdcount > 0 {
-			Diag("dwarf: unresolved references after first dwarf info pass")
-			Errorexit()
+			Exitf("dwarf: unresolved references after first dwarf info pass")
 		}
 
 		if infoe != Cpos() {
-			Diag("dwarf: inconsistent second dwarf info pass")
-			Errorexit()
+			Exitf("dwarf: inconsistent second dwarf info pass")
 		}
 	}
 
@@ -2367,12 +2233,13 @@
 	elfstrdbg[ElfStrDebugStr] = Addstring(shstrtab, ".debug_str")
 	elfstrdbg[ElfStrGDBScripts] = Addstring(shstrtab, ".debug_gdb_scripts")
 	if Linkmode == LinkExternal {
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rela.debug_info")
 			elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rela.debug_aranges")
 			elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rela.debug_line")
 			elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rela.debug_frame")
-		} else {
+		default:
 			elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rel.debug_info")
 			elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rel.debug_aranges")
 			elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line")
@@ -2419,9 +2286,10 @@
 
 func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) {
 	sh := newElfShdr(elfstrdbg[elfstr])
-	if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+	switch Thearch.Thechar {
+	case '6', '7', '9':
 		sh.type_ = SHT_RELA
-	} else {
+	default:
 		sh.type_ = SHT_REL
 	}
 
diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/internal/ld/elf.go
index f2d819d..5c17b2d 100644
--- a/src/cmd/internal/ld/elf.go
+++ b/src/cmd/internal/ld/elf.go
@@ -5,9 +5,9 @@
 package ld
 
 import (
+	"cmd/internal/obj"
 	"encoding/binary"
 	"fmt"
-	"os"
 )
 
 /*
@@ -320,283 +320,285 @@
  * Relocation types.
  */
 const (
-	R_X86_64_NONE          = 0
-	R_X86_64_64            = 1
-	R_X86_64_PC32          = 2
-	R_X86_64_GOT32         = 3
-	R_X86_64_PLT32         = 4
-	R_X86_64_COPY          = 5
-	R_X86_64_GLOB_DAT      = 6
-	R_X86_64_JMP_SLOT      = 7
-	R_X86_64_RELATIVE      = 8
-	R_X86_64_GOTPCREL      = 9
-	R_X86_64_32            = 10
-	R_X86_64_32S           = 11
-	R_X86_64_16            = 12
-	R_X86_64_PC16          = 13
-	R_X86_64_8             = 14
-	R_X86_64_PC8           = 15
-	R_X86_64_DTPMOD64      = 16
-	R_X86_64_DTPOFF64      = 17
-	R_X86_64_TPOFF64       = 18
-	R_X86_64_TLSGD         = 19
-	R_X86_64_TLSLD         = 20
-	R_X86_64_DTPOFF32      = 21
-	R_X86_64_GOTTPOFF      = 22
-	R_X86_64_TPOFF32       = 23
-	R_X86_64_COUNT         = 24
-	R_AARCH64_ABS64        = 257
-	R_AARCH64_ABS32        = 258
-	R_AARCH64_CALL26       = 283
-	R_ALPHA_NONE           = 0
-	R_ALPHA_REFLONG        = 1
-	R_ALPHA_REFQUAD        = 2
-	R_ALPHA_GPREL32        = 3
-	R_ALPHA_LITERAL        = 4
-	R_ALPHA_LITUSE         = 5
-	R_ALPHA_GPDISP         = 6
-	R_ALPHA_BRADDR         = 7
-	R_ALPHA_HINT           = 8
-	R_ALPHA_SREL16         = 9
-	R_ALPHA_SREL32         = 10
-	R_ALPHA_SREL64         = 11
-	R_ALPHA_OP_PUSH        = 12
-	R_ALPHA_OP_STORE       = 13
-	R_ALPHA_OP_PSUB        = 14
-	R_ALPHA_OP_PRSHIFT     = 15
-	R_ALPHA_GPVALUE        = 16
-	R_ALPHA_GPRELHIGH      = 17
-	R_ALPHA_GPRELLOW       = 18
-	R_ALPHA_IMMED_GP_16    = 19
-	R_ALPHA_IMMED_GP_HI32  = 20
-	R_ALPHA_IMMED_SCN_HI32 = 21
-	R_ALPHA_IMMED_BR_HI32  = 22
-	R_ALPHA_IMMED_LO32     = 23
-	R_ALPHA_COPY           = 24
-	R_ALPHA_GLOB_DAT       = 25
-	R_ALPHA_JMP_SLOT       = 26
-	R_ALPHA_RELATIVE       = 27
-	R_ALPHA_COUNT          = 28
-	R_ARM_NONE             = 0
-	R_ARM_PC24             = 1
-	R_ARM_ABS32            = 2
-	R_ARM_REL32            = 3
-	R_ARM_PC13             = 4
-	R_ARM_ABS16            = 5
-	R_ARM_ABS12            = 6
-	R_ARM_THM_ABS5         = 7
-	R_ARM_ABS8             = 8
-	R_ARM_SBREL32          = 9
-	R_ARM_THM_PC22         = 10
-	R_ARM_THM_PC8          = 11
-	R_ARM_AMP_VCALL9       = 12
-	R_ARM_SWI24            = 13
-	R_ARM_THM_SWI8         = 14
-	R_ARM_XPC25            = 15
-	R_ARM_THM_XPC22        = 16
-	R_ARM_COPY             = 20
-	R_ARM_GLOB_DAT         = 21
-	R_ARM_JUMP_SLOT        = 22
-	R_ARM_RELATIVE         = 23
-	R_ARM_GOTOFF           = 24
-	R_ARM_GOTPC            = 25
-	R_ARM_GOT32            = 26
-	R_ARM_PLT32            = 27
-	R_ARM_CALL             = 28
-	R_ARM_JUMP24           = 29
-	R_ARM_V4BX             = 40
-	R_ARM_GOT_PREL         = 96
-	R_ARM_GNU_VTENTRY      = 100
-	R_ARM_GNU_VTINHERIT    = 101
-	R_ARM_TLS_IE32         = 107
-	R_ARM_TLS_LE32         = 108
-	R_ARM_RSBREL32         = 250
-	R_ARM_THM_RPC22        = 251
-	R_ARM_RREL32           = 252
-	R_ARM_RABS32           = 253
-	R_ARM_RPC24            = 254
-	R_ARM_RBASE            = 255
-	R_ARM_COUNT            = 38
-	R_386_NONE             = 0
-	R_386_32               = 1
-	R_386_PC32             = 2
-	R_386_GOT32            = 3
-	R_386_PLT32            = 4
-	R_386_COPY             = 5
-	R_386_GLOB_DAT         = 6
-	R_386_JMP_SLOT         = 7
-	R_386_RELATIVE         = 8
-	R_386_GOTOFF           = 9
-	R_386_GOTPC            = 10
-	R_386_TLS_TPOFF        = 14
-	R_386_TLS_IE           = 15
-	R_386_TLS_GOTIE        = 16
-	R_386_TLS_LE           = 17
-	R_386_TLS_GD           = 18
-	R_386_TLS_LDM          = 19
-	R_386_TLS_GD_32        = 24
-	R_386_TLS_GD_PUSH      = 25
-	R_386_TLS_GD_CALL      = 26
-	R_386_TLS_GD_POP       = 27
-	R_386_TLS_LDM_32       = 28
-	R_386_TLS_LDM_PUSH     = 29
-	R_386_TLS_LDM_CALL     = 30
-	R_386_TLS_LDM_POP      = 31
-	R_386_TLS_LDO_32       = 32
-	R_386_TLS_IE_32        = 33
-	R_386_TLS_LE_32        = 34
-	R_386_TLS_DTPMOD32     = 35
-	R_386_TLS_DTPOFF32     = 36
-	R_386_TLS_TPOFF32      = 37
-	R_386_COUNT            = 38
-	R_PPC_NONE             = 0
-	R_PPC_ADDR32           = 1
-	R_PPC_ADDR24           = 2
-	R_PPC_ADDR16           = 3
-	R_PPC_ADDR16_LO        = 4
-	R_PPC_ADDR16_HI        = 5
-	R_PPC_ADDR16_HA        = 6
-	R_PPC_ADDR14           = 7
-	R_PPC_ADDR14_BRTAKEN   = 8
-	R_PPC_ADDR14_BRNTAKEN  = 9
-	R_PPC_REL24            = 10
-	R_PPC_REL14            = 11
-	R_PPC_REL14_BRTAKEN    = 12
-	R_PPC_REL14_BRNTAKEN   = 13
-	R_PPC_GOT16            = 14
-	R_PPC_GOT16_LO         = 15
-	R_PPC_GOT16_HI         = 16
-	R_PPC_GOT16_HA         = 17
-	R_PPC_PLTREL24         = 18
-	R_PPC_COPY             = 19
-	R_PPC_GLOB_DAT         = 20
-	R_PPC_JMP_SLOT         = 21
-	R_PPC_RELATIVE         = 22
-	R_PPC_LOCAL24PC        = 23
-	R_PPC_UADDR32          = 24
-	R_PPC_UADDR16          = 25
-	R_PPC_REL32            = 26
-	R_PPC_PLT32            = 27
-	R_PPC_PLTREL32         = 28
-	R_PPC_PLT16_LO         = 29
-	R_PPC_PLT16_HI         = 30
-	R_PPC_PLT16_HA         = 31
-	R_PPC_SDAREL16         = 32
-	R_PPC_SECTOFF          = 33
-	R_PPC_SECTOFF_LO       = 34
-	R_PPC_SECTOFF_HI       = 35
-	R_PPC_SECTOFF_HA       = 36
-	R_PPC_COUNT            = 37
-	R_PPC_TLS              = 67
-	R_PPC_DTPMOD32         = 68
-	R_PPC_TPREL16          = 69
-	R_PPC_TPREL16_LO       = 70
-	R_PPC_TPREL16_HI       = 71
-	R_PPC_TPREL16_HA       = 72
-	R_PPC_TPREL32          = 73
-	R_PPC_DTPREL16         = 74
-	R_PPC_DTPREL16_LO      = 75
-	R_PPC_DTPREL16_HI      = 76
-	R_PPC_DTPREL16_HA      = 77
-	R_PPC_DTPREL32         = 78
-	R_PPC_GOT_TLSGD16      = 79
-	R_PPC_GOT_TLSGD16_LO   = 80
-	R_PPC_GOT_TLSGD16_HI   = 81
-	R_PPC_GOT_TLSGD16_HA   = 82
-	R_PPC_GOT_TLSLD16      = 83
-	R_PPC_GOT_TLSLD16_LO   = 84
-	R_PPC_GOT_TLSLD16_HI   = 85
-	R_PPC_GOT_TLSLD16_HA   = 86
-	R_PPC_GOT_TPREL16      = 87
-	R_PPC_GOT_TPREL16_LO   = 88
-	R_PPC_GOT_TPREL16_HI   = 89
-	R_PPC_GOT_TPREL16_HA   = 90
-	R_PPC_EMB_NADDR32      = 101
-	R_PPC_EMB_NADDR16      = 102
-	R_PPC_EMB_NADDR16_LO   = 103
-	R_PPC_EMB_NADDR16_HI   = 104
-	R_PPC_EMB_NADDR16_HA   = 105
-	R_PPC_EMB_SDAI16       = 106
-	R_PPC_EMB_SDA2I16      = 107
-	R_PPC_EMB_SDA2REL      = 108
-	R_PPC_EMB_SDA21        = 109
-	R_PPC_EMB_MRKREF       = 110
-	R_PPC_EMB_RELSEC16     = 111
-	R_PPC_EMB_RELST_LO     = 112
-	R_PPC_EMB_RELST_HI     = 113
-	R_PPC_EMB_RELST_HA     = 114
-	R_PPC_EMB_BIT_FLD      = 115
-	R_PPC_EMB_RELSDA       = 116
-	R_PPC_EMB_COUNT        = R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1
-	R_PPC64_REL24          = R_PPC_REL24
-	R_PPC64_JMP_SLOT       = R_PPC_JMP_SLOT
-	R_PPC64_ADDR64         = 38
-	R_PPC64_TOC16          = 47
-	R_PPC64_TOC16_LO       = 48
-	R_PPC64_TOC16_HI       = 49
-	R_PPC64_TOC16_HA       = 50
-	R_PPC64_TOC16_DS       = 63
-	R_PPC64_TOC16_LO_DS    = 64
-	R_PPC64_REL16_LO       = 250
-	R_PPC64_REL16_HI       = 251
-	R_PPC64_REL16_HA       = 252
-	R_SPARC_NONE           = 0
-	R_SPARC_8              = 1
-	R_SPARC_16             = 2
-	R_SPARC_32             = 3
-	R_SPARC_DISP8          = 4
-	R_SPARC_DISP16         = 5
-	R_SPARC_DISP32         = 6
-	R_SPARC_WDISP30        = 7
-	R_SPARC_WDISP22        = 8
-	R_SPARC_HI22           = 9
-	R_SPARC_22             = 10
-	R_SPARC_13             = 11
-	R_SPARC_LO10           = 12
-	R_SPARC_GOT10          = 13
-	R_SPARC_GOT13          = 14
-	R_SPARC_GOT22          = 15
-	R_SPARC_PC10           = 16
-	R_SPARC_PC22           = 17
-	R_SPARC_WPLT30         = 18
-	R_SPARC_COPY           = 19
-	R_SPARC_GLOB_DAT       = 20
-	R_SPARC_JMP_SLOT       = 21
-	R_SPARC_RELATIVE       = 22
-	R_SPARC_UA32           = 23
-	R_SPARC_PLT32          = 24
-	R_SPARC_HIPLT22        = 25
-	R_SPARC_LOPLT10        = 26
-	R_SPARC_PCPLT32        = 27
-	R_SPARC_PCPLT22        = 28
-	R_SPARC_PCPLT10        = 29
-	R_SPARC_10             = 30
-	R_SPARC_11             = 31
-	R_SPARC_64             = 32
-	R_SPARC_OLO10          = 33
-	R_SPARC_HH22           = 34
-	R_SPARC_HM10           = 35
-	R_SPARC_LM22           = 36
-	R_SPARC_PC_HH22        = 37
-	R_SPARC_PC_HM10        = 38
-	R_SPARC_PC_LM22        = 39
-	R_SPARC_WDISP16        = 40
-	R_SPARC_WDISP19        = 41
-	R_SPARC_GLOB_JMP       = 42
-	R_SPARC_7              = 43
-	R_SPARC_5              = 44
-	R_SPARC_6              = 45
-	R_SPARC_DISP64         = 46
-	R_SPARC_PLT64          = 47
-	R_SPARC_HIX22          = 48
-	R_SPARC_LOX10          = 49
-	R_SPARC_H44            = 50
-	R_SPARC_M44            = 51
-	R_SPARC_L44            = 52
-	R_SPARC_REGISTER       = 53
-	R_SPARC_UA64           = 54
-	R_SPARC_UA16           = 55
-	ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
+	R_X86_64_NONE              = 0
+	R_X86_64_64                = 1
+	R_X86_64_PC32              = 2
+	R_X86_64_GOT32             = 3
+	R_X86_64_PLT32             = 4
+	R_X86_64_COPY              = 5
+	R_X86_64_GLOB_DAT          = 6
+	R_X86_64_JMP_SLOT          = 7
+	R_X86_64_RELATIVE          = 8
+	R_X86_64_GOTPCREL          = 9
+	R_X86_64_32                = 10
+	R_X86_64_32S               = 11
+	R_X86_64_16                = 12
+	R_X86_64_PC16              = 13
+	R_X86_64_8                 = 14
+	R_X86_64_PC8               = 15
+	R_X86_64_DTPMOD64          = 16
+	R_X86_64_DTPOFF64          = 17
+	R_X86_64_TPOFF64           = 18
+	R_X86_64_TLSGD             = 19
+	R_X86_64_TLSLD             = 20
+	R_X86_64_DTPOFF32          = 21
+	R_X86_64_GOTTPOFF          = 22
+	R_X86_64_TPOFF32           = 23
+	R_X86_64_COUNT             = 24
+	R_AARCH64_ABS64            = 257
+	R_AARCH64_ABS32            = 258
+	R_AARCH64_CALL26           = 283
+	R_AARCH64_ADR_PREL_PG_HI21 = 275
+	R_AARCH64_ADD_ABS_LO12_NC  = 277
+	R_ALPHA_NONE               = 0
+	R_ALPHA_REFLONG            = 1
+	R_ALPHA_REFQUAD            = 2
+	R_ALPHA_GPREL32            = 3
+	R_ALPHA_LITERAL            = 4
+	R_ALPHA_LITUSE             = 5
+	R_ALPHA_GPDISP             = 6
+	R_ALPHA_BRADDR             = 7
+	R_ALPHA_HINT               = 8
+	R_ALPHA_SREL16             = 9
+	R_ALPHA_SREL32             = 10
+	R_ALPHA_SREL64             = 11
+	R_ALPHA_OP_PUSH            = 12
+	R_ALPHA_OP_STORE           = 13
+	R_ALPHA_OP_PSUB            = 14
+	R_ALPHA_OP_PRSHIFT         = 15
+	R_ALPHA_GPVALUE            = 16
+	R_ALPHA_GPRELHIGH          = 17
+	R_ALPHA_GPRELLOW           = 18
+	R_ALPHA_IMMED_GP_16        = 19
+	R_ALPHA_IMMED_GP_HI32      = 20
+	R_ALPHA_IMMED_SCN_HI32     = 21
+	R_ALPHA_IMMED_BR_HI32      = 22
+	R_ALPHA_IMMED_LO32         = 23
+	R_ALPHA_COPY               = 24
+	R_ALPHA_GLOB_DAT           = 25
+	R_ALPHA_JMP_SLOT           = 26
+	R_ALPHA_RELATIVE           = 27
+	R_ALPHA_COUNT              = 28
+	R_ARM_NONE                 = 0
+	R_ARM_PC24                 = 1
+	R_ARM_ABS32                = 2
+	R_ARM_REL32                = 3
+	R_ARM_PC13                 = 4
+	R_ARM_ABS16                = 5
+	R_ARM_ABS12                = 6
+	R_ARM_THM_ABS5             = 7
+	R_ARM_ABS8                 = 8
+	R_ARM_SBREL32              = 9
+	R_ARM_THM_PC22             = 10
+	R_ARM_THM_PC8              = 11
+	R_ARM_AMP_VCALL9           = 12
+	R_ARM_SWI24                = 13
+	R_ARM_THM_SWI8             = 14
+	R_ARM_XPC25                = 15
+	R_ARM_THM_XPC22            = 16
+	R_ARM_COPY                 = 20
+	R_ARM_GLOB_DAT             = 21
+	R_ARM_JUMP_SLOT            = 22
+	R_ARM_RELATIVE             = 23
+	R_ARM_GOTOFF               = 24
+	R_ARM_GOTPC                = 25
+	R_ARM_GOT32                = 26
+	R_ARM_PLT32                = 27
+	R_ARM_CALL                 = 28
+	R_ARM_JUMP24               = 29
+	R_ARM_V4BX                 = 40
+	R_ARM_GOT_PREL             = 96
+	R_ARM_GNU_VTENTRY          = 100
+	R_ARM_GNU_VTINHERIT        = 101
+	R_ARM_TLS_IE32             = 107
+	R_ARM_TLS_LE32             = 108
+	R_ARM_RSBREL32             = 250
+	R_ARM_THM_RPC22            = 251
+	R_ARM_RREL32               = 252
+	R_ARM_RABS32               = 253
+	R_ARM_RPC24                = 254
+	R_ARM_RBASE                = 255
+	R_ARM_COUNT                = 38
+	R_386_NONE                 = 0
+	R_386_32                   = 1
+	R_386_PC32                 = 2
+	R_386_GOT32                = 3
+	R_386_PLT32                = 4
+	R_386_COPY                 = 5
+	R_386_GLOB_DAT             = 6
+	R_386_JMP_SLOT             = 7
+	R_386_RELATIVE             = 8
+	R_386_GOTOFF               = 9
+	R_386_GOTPC                = 10
+	R_386_TLS_TPOFF            = 14
+	R_386_TLS_IE               = 15
+	R_386_TLS_GOTIE            = 16
+	R_386_TLS_LE               = 17
+	R_386_TLS_GD               = 18
+	R_386_TLS_LDM              = 19
+	R_386_TLS_GD_32            = 24
+	R_386_TLS_GD_PUSH          = 25
+	R_386_TLS_GD_CALL          = 26
+	R_386_TLS_GD_POP           = 27
+	R_386_TLS_LDM_32           = 28
+	R_386_TLS_LDM_PUSH         = 29
+	R_386_TLS_LDM_CALL         = 30
+	R_386_TLS_LDM_POP          = 31
+	R_386_TLS_LDO_32           = 32
+	R_386_TLS_IE_32            = 33
+	R_386_TLS_LE_32            = 34
+	R_386_TLS_DTPMOD32         = 35
+	R_386_TLS_DTPOFF32         = 36
+	R_386_TLS_TPOFF32          = 37
+	R_386_COUNT                = 38
+	R_PPC_NONE                 = 0
+	R_PPC_ADDR32               = 1
+	R_PPC_ADDR24               = 2
+	R_PPC_ADDR16               = 3
+	R_PPC_ADDR16_LO            = 4
+	R_PPC_ADDR16_HI            = 5
+	R_PPC_ADDR16_HA            = 6
+	R_PPC_ADDR14               = 7
+	R_PPC_ADDR14_BRTAKEN       = 8
+	R_PPC_ADDR14_BRNTAKEN      = 9
+	R_PPC_REL24                = 10
+	R_PPC_REL14                = 11
+	R_PPC_REL14_BRTAKEN        = 12
+	R_PPC_REL14_BRNTAKEN       = 13
+	R_PPC_GOT16                = 14
+	R_PPC_GOT16_LO             = 15
+	R_PPC_GOT16_HI             = 16
+	R_PPC_GOT16_HA             = 17
+	R_PPC_PLTREL24             = 18
+	R_PPC_COPY                 = 19
+	R_PPC_GLOB_DAT             = 20
+	R_PPC_JMP_SLOT             = 21
+	R_PPC_RELATIVE             = 22
+	R_PPC_LOCAL24PC            = 23
+	R_PPC_UADDR32              = 24
+	R_PPC_UADDR16              = 25
+	R_PPC_REL32                = 26
+	R_PPC_PLT32                = 27
+	R_PPC_PLTREL32             = 28
+	R_PPC_PLT16_LO             = 29
+	R_PPC_PLT16_HI             = 30
+	R_PPC_PLT16_HA             = 31
+	R_PPC_SDAREL16             = 32
+	R_PPC_SECTOFF              = 33
+	R_PPC_SECTOFF_LO           = 34
+	R_PPC_SECTOFF_HI           = 35
+	R_PPC_SECTOFF_HA           = 36
+	R_PPC_COUNT                = 37
+	R_PPC_TLS                  = 67
+	R_PPC_DTPMOD32             = 68
+	R_PPC_TPREL16              = 69
+	R_PPC_TPREL16_LO           = 70
+	R_PPC_TPREL16_HI           = 71
+	R_PPC_TPREL16_HA           = 72
+	R_PPC_TPREL32              = 73
+	R_PPC_DTPREL16             = 74
+	R_PPC_DTPREL16_LO          = 75
+	R_PPC_DTPREL16_HI          = 76
+	R_PPC_DTPREL16_HA          = 77
+	R_PPC_DTPREL32             = 78
+	R_PPC_GOT_TLSGD16          = 79
+	R_PPC_GOT_TLSGD16_LO       = 80
+	R_PPC_GOT_TLSGD16_HI       = 81
+	R_PPC_GOT_TLSGD16_HA       = 82
+	R_PPC_GOT_TLSLD16          = 83
+	R_PPC_GOT_TLSLD16_LO       = 84
+	R_PPC_GOT_TLSLD16_HI       = 85
+	R_PPC_GOT_TLSLD16_HA       = 86
+	R_PPC_GOT_TPREL16          = 87
+	R_PPC_GOT_TPREL16_LO       = 88
+	R_PPC_GOT_TPREL16_HI       = 89
+	R_PPC_GOT_TPREL16_HA       = 90
+	R_PPC_EMB_NADDR32          = 101
+	R_PPC_EMB_NADDR16          = 102
+	R_PPC_EMB_NADDR16_LO       = 103
+	R_PPC_EMB_NADDR16_HI       = 104
+	R_PPC_EMB_NADDR16_HA       = 105
+	R_PPC_EMB_SDAI16           = 106
+	R_PPC_EMB_SDA2I16          = 107
+	R_PPC_EMB_SDA2REL          = 108
+	R_PPC_EMB_SDA21            = 109
+	R_PPC_EMB_MRKREF           = 110
+	R_PPC_EMB_RELSEC16         = 111
+	R_PPC_EMB_RELST_LO         = 112
+	R_PPC_EMB_RELST_HI         = 113
+	R_PPC_EMB_RELST_HA         = 114
+	R_PPC_EMB_BIT_FLD          = 115
+	R_PPC_EMB_RELSDA           = 116
+	R_PPC_EMB_COUNT            = R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1
+	R_PPC64_REL24              = R_PPC_REL24
+	R_PPC64_JMP_SLOT           = R_PPC_JMP_SLOT
+	R_PPC64_ADDR64             = 38
+	R_PPC64_TOC16              = 47
+	R_PPC64_TOC16_LO           = 48
+	R_PPC64_TOC16_HI           = 49
+	R_PPC64_TOC16_HA           = 50
+	R_PPC64_TOC16_DS           = 63
+	R_PPC64_TOC16_LO_DS        = 64
+	R_PPC64_REL16_LO           = 250
+	R_PPC64_REL16_HI           = 251
+	R_PPC64_REL16_HA           = 252
+	R_SPARC_NONE               = 0
+	R_SPARC_8                  = 1
+	R_SPARC_16                 = 2
+	R_SPARC_32                 = 3
+	R_SPARC_DISP8              = 4
+	R_SPARC_DISP16             = 5
+	R_SPARC_DISP32             = 6
+	R_SPARC_WDISP30            = 7
+	R_SPARC_WDISP22            = 8
+	R_SPARC_HI22               = 9
+	R_SPARC_22                 = 10
+	R_SPARC_13                 = 11
+	R_SPARC_LO10               = 12
+	R_SPARC_GOT10              = 13
+	R_SPARC_GOT13              = 14
+	R_SPARC_GOT22              = 15
+	R_SPARC_PC10               = 16
+	R_SPARC_PC22               = 17
+	R_SPARC_WPLT30             = 18
+	R_SPARC_COPY               = 19
+	R_SPARC_GLOB_DAT           = 20
+	R_SPARC_JMP_SLOT           = 21
+	R_SPARC_RELATIVE           = 22
+	R_SPARC_UA32               = 23
+	R_SPARC_PLT32              = 24
+	R_SPARC_HIPLT22            = 25
+	R_SPARC_LOPLT10            = 26
+	R_SPARC_PCPLT32            = 27
+	R_SPARC_PCPLT22            = 28
+	R_SPARC_PCPLT10            = 29
+	R_SPARC_10                 = 30
+	R_SPARC_11                 = 31
+	R_SPARC_64                 = 32
+	R_SPARC_OLO10              = 33
+	R_SPARC_HH22               = 34
+	R_SPARC_HM10               = 35
+	R_SPARC_LM22               = 36
+	R_SPARC_PC_HH22            = 37
+	R_SPARC_PC_HM10            = 38
+	R_SPARC_PC_LM22            = 39
+	R_SPARC_WDISP16            = 40
+	R_SPARC_WDISP19            = 41
+	R_SPARC_GLOB_JMP           = 42
+	R_SPARC_7                  = 43
+	R_SPARC_5                  = 44
+	R_SPARC_6                  = 45
+	R_SPARC_DISP64             = 46
+	R_SPARC_PLT64              = 47
+	R_SPARC_HIX22              = 48
+	R_SPARC_LOX10              = 49
+	R_SPARC_H44                = 50
+	R_SPARC_M44                = 51
+	R_SPARC_L44                = 52
+	R_SPARC_REGISTER           = 53
+	R_SPARC_UA64               = 54
+	R_SPARC_UA16               = 55
+	ARM_MAGIC_TRAMP_NUMBER     = 0x5c000003
 )
 
 /*
@@ -723,7 +725,7 @@
 
 var Nelfsym int = 1
 
-var elf64 int
+var elf64 bool
 
 var ehdr ElfEhdr
 
@@ -762,7 +764,7 @@
 		fallthrough
 
 	case '6', '7':
-		elf64 = 1
+		elf64 = true
 
 		ehdr.phoff = ELF64HDRSIZE      /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
 		ehdr.shoff = ELF64HDRSIZE      /* Will move as we add PHeaders */
@@ -774,12 +776,11 @@
 	// 32-bit architectures
 	case '5':
 		// we use EABI on both linux/arm and freebsd/arm.
-		if HEADTYPE == Hlinux || HEADTYPE == Hfreebsd {
+		if HEADTYPE == obj.Hlinux || HEADTYPE == obj.Hfreebsd {
 			ehdr.flags = 0x5000002 // has entry point, Version5 EABI
 		}
 		fallthrough
 
-		// fallthrough
 	default:
 		ehdr.phoff = ELF32HDRSIZE
 		/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
@@ -852,7 +853,7 @@
 }
 
 func elfwriteshdrs() uint32 {
-	if elf64 != 0 {
+	if elf64 {
 		for i := 0; i < int(ehdr.shnum); i++ {
 			elf64shdr(shdr[i])
 		}
@@ -868,7 +869,7 @@
 func elfsetstring(s string, off int) {
 	if nelfstr >= len(elfstr) {
 		Diag("too many elf strings")
-		Errorexit()
+		errorexit()
 	}
 
 	elfstr[nelfstr].s = s
@@ -877,7 +878,7 @@
 }
 
 func elfwritephdrs() uint32 {
-	if elf64 != 0 {
+	if elf64 {
 		for i := 0; i < int(ehdr.phnum); i++ {
 			elf64phdr(phdr[i])
 		}
@@ -898,7 +899,7 @@
 		phdr[ehdr.phnum] = e
 		ehdr.phnum++
 	}
-	if elf64 != 0 {
+	if elf64 {
 		ehdr.shoff += ELF64PHDRSIZE
 	} else {
 		ehdr.shoff += ELF32PHDRSIZE
@@ -965,7 +966,7 @@
 }
 
 func elfwritehdr() uint32 {
-	if elf64 != 0 {
+	if elf64 {
 		return elf64writehdr()
 	}
 	return elf32writehdr()
@@ -989,7 +990,7 @@
 }
 
 func Elfwritedynent(s *LSym, tag int, val uint64) {
-	if elf64 != 0 {
+	if elf64 {
 		Adduint64(Ctxt, s, uint64(tag))
 		Adduint64(Ctxt, s, val)
 	} else {
@@ -1003,7 +1004,7 @@
 }
 
 func Elfwritedynentsymplus(s *LSym, tag int, t *LSym, add int64) {
-	if elf64 != 0 {
+	if elf64 {
 		Adduint64(Ctxt, s, uint64(tag))
 	} else {
 		Adduint32(Ctxt, s, uint32(tag))
@@ -1012,7 +1013,7 @@
 }
 
 func elfwritedynentsymsize(s *LSym, tag int, t *LSym) {
-	if elf64 != 0 {
+	if elf64 {
 		Adduint64(Ctxt, s, uint64(tag))
 	} else {
 		Adduint32(Ctxt, s, uint32(tag))
@@ -1033,16 +1034,18 @@
 func elfwriteinterp() int {
 	sh := elfshname(".interp")
 	Cseek(int64(sh.off))
-	coutbuf.w.WriteString(interp)
+	coutbuf.WriteString(interp)
 	Cput(0)
 	return int(sh.size)
 }
 
-func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
+func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int, alloc bool) int {
 	n := 3*4 + uint64(sz) + resoff%4
 
 	sh.type_ = SHT_NOTE
-	sh.flags = SHF_ALLOC
+	if alloc {
+		sh.flags = SHF_ALLOC
+	}
 	sh.addralign = 4
 	sh.addr = startva + resoff - n
 	sh.off = resoff - n
@@ -1076,7 +1079,7 @@
 
 func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
 	n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
-	return elfnote(sh, startva, resoff, n)
+	return elfnote(sh, startva, resoff, n, true)
 }
 
 func elfwritenetbsdsig() int {
@@ -1108,7 +1111,7 @@
 
 func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
 	n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
-	return elfnote(sh, startva, resoff, n)
+	return elfnote(sh, startva, resoff, n, true)
 }
 
 func elfwriteopenbsdsig() int {
@@ -1131,8 +1134,7 @@
 	var j int
 
 	if val[0] != '0' || val[1] != 'x' {
-		fmt.Fprintf(os.Stderr, "%s: -B argument must start with 0x: %s\n", os.Args[0], val)
-		Exit(2)
+		Exitf("-B argument must start with 0x: %s", val)
 	}
 
 	ov := val
@@ -1141,8 +1143,7 @@
 	var b int
 	for val != "" {
 		if len(val) == 1 {
-			fmt.Fprintf(os.Stderr, "%s: -B argument must have even number of digits: %s\n", os.Args[0], ov)
-			Exit(2)
+			Exitf("-B argument must have even number of digits: %s", ov)
 		}
 
 		b = 0
@@ -1155,15 +1156,13 @@
 			} else if val[0] >= 'A' && val[0] <= 'F' {
 				b += int(val[0]) - 'A' + 10
 			} else {
-				fmt.Fprintf(os.Stderr, "%s: -B argument contains invalid hex digit %c: %s\n", os.Args[0], val[0], ov)
-				Exit(2)
+				Exitf("-B argument contains invalid hex digit %c: %s", val[0], ov)
 			}
 		}
 
 		const maxLen = 32
 		if i >= maxLen {
-			fmt.Fprintf(os.Stderr, "%s: -B option too long (max %d digits): %s\n", os.Args[0], maxLen, ov)
-			Exit(2)
+			Exitf("-B option too long (max %d digits): %s", maxLen, ov)
 		}
 
 		buildinfo = append(buildinfo, uint8(b))
@@ -1183,7 +1182,7 @@
 
 func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
 	n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
-	return elfnote(sh, startva, resoff, n)
+	return elfnote(sh, startva, resoff, n, true)
 }
 
 func elfwritebuildinfo() int {
@@ -1200,6 +1199,32 @@
 	return int(sh.size)
 }
 
+// Go package list note
+const (
+	ELF_NOTE_GOPKGLIST_TAG = 1
+)
+
+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 {
@@ -1248,7 +1273,7 @@
 
 	nsym := Nelfsym
 	s := Linklookup(Ctxt, ".hash", 0)
-	s.Type = SELFROSECT
+	s.Type = obj.SELFROSECT
 	s.Reachable = true
 
 	i := nsym
@@ -1262,21 +1287,7 @@
 	need := make([]*Elfaux, nsym)
 	chain := make([]uint32, nsym)
 	buckets := make([]uint32, nbucket)
-	if need == nil || chain == nil || buckets == nil {
-		Ctxt.Cursym = nil
-		Diag("out of memory")
-		Errorexit()
-	}
 
-	for i := 0; i < nsym; i++ {
-		need[i] = nil
-	}
-	for i := 0; i < nsym; i++ {
-		chain[i] = 0
-	}
-	for i := 0; i < nbucket; i++ {
-		buckets[i] = 0
-	}
 	var b int
 	var hc uint32
 	var name string
@@ -1432,7 +1443,7 @@
 	}
 
 	Diag("cannot find elf name %s", name)
-	Errorexit()
+	errorexit()
 	return nil
 }
 
@@ -1489,10 +1500,11 @@
 
 	var prefix string
 	var typ int
-	if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+	switch Thearch.Thechar {
+	case '6', '7', '9':
 		prefix = ".rela"
 		typ = SHT_RELA
-	} else {
+	default:
 		prefix = ".rel"
 		typ = SHT_REL
 	}
@@ -1592,7 +1604,7 @@
 	/* predefine strings we need for section headers */
 	shstrtab := Linklookup(Ctxt, ".shstrtab", 0)
 
-	shstrtab.Type = SELFROSECT
+	shstrtab.Type = obj.SELFROSECT
 	shstrtab.Reachable = true
 
 	Addstring(shstrtab, "")
@@ -1606,20 +1618,23 @@
 	// for dynamic internal linker or external linking, so that various
 	// binutils could correctly calculate PT_TLS size.
 	// see http://golang.org/issue/5200.
-	if HEADTYPE != Hopenbsd {
+	if HEADTYPE != obj.Hopenbsd {
 		if Debug['d'] == 0 || Linkmode == LinkExternal {
 			Addstring(shstrtab, ".tbss")
 		}
 	}
-	if HEADTYPE == Hnetbsd {
+	if HEADTYPE == obj.Hnetbsd {
 		Addstring(shstrtab, ".note.netbsd.ident")
 	}
-	if HEADTYPE == Hopenbsd {
+	if HEADTYPE == obj.Hopenbsd {
 		Addstring(shstrtab, ".note.openbsd.ident")
 	}
 	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")
@@ -1655,11 +1670,20 @@
 		Addstring(shstrtab, ".note.GNU-stack")
 	}
 
-	if Flag_shared != 0 {
+	hasinitarr := Linkshared
+
+	/* shared library initializer */
+	switch Buildmode {
+	case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
+		hasinitarr = true
+	}
+
+	if hasinitarr {
 		Addstring(shstrtab, ".init_array")
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			Addstring(shstrtab, ".rela.init_array")
-		} else {
+		default:
 			Addstring(shstrtab, ".rel.init_array")
 		}
 	}
@@ -1683,10 +1707,11 @@
 		Addstring(shstrtab, ".dynamic")
 		Addstring(shstrtab, ".dynsym")
 		Addstring(shstrtab, ".dynstr")
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			Addstring(shstrtab, ".rela")
 			Addstring(shstrtab, ".rela.plt")
-		} else {
+		default:
 			Addstring(shstrtab, ".rel")
 			Addstring(shstrtab, ".rel.plt")
 		}
@@ -1698,18 +1723,19 @@
 		/* dynamic symbol table - first entry all zeros */
 		s := Linklookup(Ctxt, ".dynsym", 0)
 
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 		s.Reachable = true
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			s.Size += ELF64SYMSIZE
-		} else {
+		default:
 			s.Size += ELF32SYMSIZE
 		}
 
 		/* dynamic string table */
 		s = Linklookup(Ctxt, ".dynstr", 0)
 
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 		s.Reachable = true
 		if s.Size == 0 {
 			Addstring(s, "")
@@ -1724,30 +1750,30 @@
 			s = Linklookup(Ctxt, ".rel", 0)
 		}
 		s.Reachable = true
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 
 		/* global offset table */
 		s = Linklookup(Ctxt, ".got", 0)
 
 		s.Reachable = true
-		s.Type = SELFGOT // writable
+		s.Type = obj.SELFGOT // writable
 
 		/* ppc64 glink resolver */
 		if Thearch.Thechar == '9' {
 			s := Linklookup(Ctxt, ".glink", 0)
 			s.Reachable = true
-			s.Type = SELFRXSECT
+			s.Type = obj.SELFRXSECT
 		}
 
 		/* hash */
 		s = Linklookup(Ctxt, ".hash", 0)
 
 		s.Reachable = true
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 
 		s = Linklookup(Ctxt, ".got.plt", 0)
 		s.Reachable = true
-		s.Type = SELFSECT // writable
+		s.Type = obj.SELFSECT // writable
 
 		s = Linklookup(Ctxt, ".plt", 0)
 
@@ -1755,9 +1781,9 @@
 		if Thearch.Thechar == '9' {
 			// In the ppc64 ABI, .plt is a data section
 			// written by the dynamic linker.
-			s.Type = SELFSECT
+			s.Type = obj.SELFSECT
 		} else {
-			s.Type = SELFRXSECT
+			s.Type = obj.SELFRXSECT
 		}
 
 		Thearch.Elfsetupplt()
@@ -1769,21 +1795,21 @@
 			s = Linklookup(Ctxt, ".rel.plt", 0)
 		}
 		s.Reachable = true
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 
 		s = Linklookup(Ctxt, ".gnu.version", 0)
 		s.Reachable = true
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 
 		s = Linklookup(Ctxt, ".gnu.version_r", 0)
 		s.Reachable = true
-		s.Type = SELFROSECT
+		s.Type = obj.SELFROSECT
 
 		/* define dynamic elf table */
 		s = Linklookup(Ctxt, ".dynamic", 0)
 
 		s.Reachable = true
-		s.Type = SELFSECT // writable
+		s.Type = obj.SELFSECT // writable
 
 		/*
 		 * .dynamic table
@@ -1791,9 +1817,10 @@
 		elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0))
 
 		elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0))
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE)
-		} else {
+		default:
 			Elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE)
 		}
 		elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0))
@@ -1809,8 +1836,8 @@
 			Elfwritedynent(s, DT_RELENT, ELF32RELSIZE)
 		}
 
-		if rpath != "" {
-			Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath)))
+		if rpath.val != "" {
+			Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
 		}
 
 		if Thearch.Thechar == '9' {
@@ -1869,28 +1896,22 @@
 	eh := getElfEhdr()
 	switch Thearch.Thechar {
 	default:
-		Diag("unknown architecture in asmbelf")
-		Errorexit()
-		fallthrough
-
+		Exitf("unknown architecture in asmbelf: %v", Thearch.Thechar)
 	case '5':
 		eh.machine = EM_ARM
-
 	case '6':
 		eh.machine = EM_X86_64
-
 	case '7':
 		eh.machine = EM_AARCH64
-
 	case '8':
 		eh.machine = EM_386
-
 	case '9':
 		eh.machine = EM_PPC64
 	}
 
+	elfreserve := int64(ELFRESERVE)
 	startva := INITTEXT - int64(HEADR)
-	resoff := int64(ELFRESERVE)
+	resoff := elfreserve
 
 	var pph *ElfPhdr
 	var pnote *ElfPhdr
@@ -1899,6 +1920,18 @@
 		eh.phoff = 0
 
 		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)))
+		}
 		goto elfobj
 	}
 
@@ -1917,7 +1950,7 @@
 	 * segment boundaries downwards to include it.
 	 * Except on NaCl where it must not be loaded.
 	 */
-	if HEADTYPE != Hnacl {
+	if HEADTYPE != obj.Hnacl {
 		o := int64(Segtext.Vaddr - pph.vaddr)
 		Segtext.Vaddr -= uint64(o)
 		Segtext.Length += uint64(o)
@@ -1935,22 +1968,22 @@
 		sh.addralign = 1
 		if interpreter == "" {
 			switch HEADTYPE {
-			case Hlinux:
+			case obj.Hlinux:
 				interpreter = Thearch.Linuxdynld
 
-			case Hfreebsd:
+			case obj.Hfreebsd:
 				interpreter = Thearch.Freebsddynld
 
-			case Hnetbsd:
+			case obj.Hnetbsd:
 				interpreter = Thearch.Netbsddynld
 
-			case Hopenbsd:
+			case obj.Hopenbsd:
 				interpreter = Thearch.Openbsddynld
 
-			case Hdragonfly:
+			case obj.Hdragonfly:
 				interpreter = Thearch.Dragonflydynld
 
-			case Hsolaris:
+			case obj.Hsolaris:
 				interpreter = Thearch.Solarisdynld
 			}
 		}
@@ -1964,14 +1997,14 @@
 	}
 
 	pnote = nil
-	if HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd {
+	if HEADTYPE == obj.Hnetbsd || HEADTYPE == obj.Hopenbsd {
 		var sh *ElfShdr
 		switch HEADTYPE {
-		case Hnetbsd:
+		case obj.Hnetbsd:
 			sh = elfshname(".note.netbsd.ident")
 			resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
 
-		case Hopenbsd:
+		case obj.Hopenbsd:
 			sh = elfshname(".note.openbsd.ident")
 			resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
 		}
@@ -2008,7 +2041,7 @@
 		sh := elfshname(".dynsym")
 		sh.type_ = SHT_DYNSYM
 		sh.flags = SHF_ALLOC
-		if elf64 != 0 {
+		if elf64 {
 			sh.entsize = ELF64SYMSIZE
 		} else {
 			sh.entsize = ELF32SYMSIZE
@@ -2152,7 +2185,7 @@
 		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
 		// not currently support it. This is handled
 		// appropriately in runtime/cgo.
-		if Ctxt.Tlsoffset != 0 && HEADTYPE != Hopenbsd {
+		if Ctxt.Tlsoffset != 0 && HEADTYPE != obj.Hopenbsd {
 			ph := newElfPhdr()
 			ph.type_ = PT_TLS
 			ph.flags = PF_R
@@ -2161,7 +2194,7 @@
 		}
 	}
 
-	if HEADTYPE == Hlinux {
+	if HEADTYPE == obj.Hlinux {
 		ph := newElfPhdr()
 		ph.type_ = PT_GNU_STACK
 		ph.flags = PF_W + PF_R
@@ -2217,7 +2250,7 @@
 
 	// generate .tbss section for dynamic internal linking (except for OpenBSD)
 	// external linking generates .tbss in data.c
-	if Linkmode == LinkInternal && Debug['d'] == 0 && HEADTYPE != Hopenbsd {
+	if Linkmode == LinkInternal && Debug['d'] == 0 && HEADTYPE != obj.Hopenbsd {
 		sh := elfshname(".tbss")
 		sh.type_ = SHT_NOBITS
 		sh.addralign = uint64(Thearch.Regsize)
@@ -2250,16 +2283,16 @@
 	eh.ident[EI_MAG1] = 'E'
 	eh.ident[EI_MAG2] = 'L'
 	eh.ident[EI_MAG3] = 'F'
-	if HEADTYPE == Hfreebsd {
+	if HEADTYPE == obj.Hfreebsd {
 		eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
-	} else if HEADTYPE == Hnetbsd {
+	} else if HEADTYPE == obj.Hnetbsd {
 		eh.ident[EI_OSABI] = ELFOSABI_NETBSD
-	} else if HEADTYPE == Hopenbsd {
+	} else if HEADTYPE == obj.Hopenbsd {
 		eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
-	} else if HEADTYPE == Hdragonfly {
+	} else if HEADTYPE == obj.Hdragonfly {
 		eh.ident[EI_OSABI] = ELFOSABI_NONE
 	}
-	if elf64 != 0 {
+	if elf64 {
 		eh.ident[EI_CLASS] = ELFCLASS64
 	} else {
 		eh.ident[EI_CLASS] = ELFCLASS32
@@ -2297,19 +2330,22 @@
 		a += int64(elfwriteinterp())
 	}
 	if Linkmode != LinkExternal {
-		if HEADTYPE == Hnetbsd {
+		if HEADTYPE == obj.Hnetbsd {
 			a += int64(elfwritenetbsdsig())
 		}
-		if HEADTYPE == Hopenbsd {
+		if HEADTYPE == obj.Hopenbsd {
 			a += int64(elfwriteopenbsdsig())
 		}
 		if len(buildinfo) > 0 {
 			a += int64(elfwritebuildinfo())
 		}
 	}
+	if Buildmode == BuildmodeShared {
+		a += int64(elfwritegopkgnote())
+	}
 
-	if a > ELFRESERVE {
-		Diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE)
+	if a > elfreserve {
+		Diag("ELFRESERVE too small: %d > %d", a, elfreserve)
 	}
 }
 
diff --git a/src/cmd/internal/ld/go.go b/src/cmd/internal/ld/go.go
index c50e82b..0223bfa 100644
--- a/src/cmd/internal/ld/go.go
+++ b/src/cmd/internal/ld/go.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.
 
+// go-specific code shared across loaders (5l, 6l, 8l).
+
 package ld
 
 import (
@@ -20,12 +22,6 @@
 	return strings.Replace(t0, `"".`, pkg+".", -1)
 }
 
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// go-specific code shared across loaders (5l, 6l, 8l).
-
 // accumulate all type information from .6 files.
 // check for inconsistencies.
 
@@ -57,7 +53,7 @@
 	return x
 }
 
-func ldpkg(f *Biobuf, pkg string, length int64, filename string, whence int) {
+func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) {
 	var p0, p1 int
 
 	if Debug['g'] != 0 {
@@ -67,16 +63,16 @@
 	if int64(int(length)) != length {
 		fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
 		if Debug['u'] != 0 {
-			Errorexit()
+			errorexit()
 		}
 		return
 	}
 
 	bdata := make([]byte, length)
-	if int64(Bread(f, bdata)) != length {
+	if int64(obj.Bread(f, bdata)) != length {
 		fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
 		if Debug['u'] != 0 {
-			Errorexit()
+			errorexit()
 		}
 		return
 	}
@@ -86,8 +82,7 @@
 	p0 = strings.Index(data, "\n$$")
 	if p0 < 0 {
 		if Debug['u'] != 0 && whence != ArchiveObj {
-			fmt.Fprintf(os.Stderr, "%s: cannot find export data in %s\n", os.Args[0], filename)
-			Errorexit()
+			Exitf("cannot find export data in %s", filename)
 		}
 		return
 	}
@@ -102,7 +97,7 @@
 	if p1 < 0 {
 		fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
 		if Debug['u'] != 0 {
-			Errorexit()
+			errorexit()
 		}
 		return
 	}
@@ -115,7 +110,7 @@
 		if !strings.HasPrefix(data[p0:], "package ") {
 			fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
 			if Debug['u'] != 0 {
-				Errorexit()
+				errorexit()
 			}
 			return
 		}
@@ -129,9 +124,7 @@
 			p0++
 		}
 		if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
-			fmt.Fprintf(os.Stderr, "%s: load of unsafe package %s\n", os.Args[0], filename)
-			nerrors++
-			Errorexit()
+			Exitf("load of unsafe package %s", filename)
 		}
 
 		name := data[pname:p0]
@@ -143,9 +136,7 @@
 		}
 
 		if pkg == "main" && name != "main" {
-			fmt.Fprintf(os.Stderr, "%s: %s: not package main (package %s)\n", os.Args[0], filename, name)
-			nerrors++
-			Errorexit()
+			Exitf("%s: not package main (package %s)", filename, name)
 		}
 
 		loadpkgdata(filename, pkg, data[p0:p1])
@@ -164,7 +155,7 @@
 		if i < 0 {
 			fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
 			if Debug['u'] != 0 {
-				Errorexit()
+				errorexit()
 			}
 			return
 		}
@@ -177,7 +168,7 @@
 		if p1 < 0 {
 			fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
 			if Debug['u'] != 0 {
-				Errorexit()
+				errorexit()
 			}
 			return
 		}
@@ -437,12 +428,12 @@
 			s = Linklookup(Ctxt, local, 0)
 			if local != f[1] {
 			}
-			if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ {
+			if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ {
 				s.Dynimplib = lib
 				s.Extname = remote
 				s.Dynimpvers = q
-				if s.Type != SHOSTOBJ {
-					s.Type = SDYNIMPORT
+				if s.Type != obj.SHOSTOBJ {
+					s.Type = obj.SDYNIMPORT
 				}
 				havedynamic = 1
 			}
@@ -456,7 +447,7 @@
 			}
 			local = f[1]
 			s = Linklookup(Ctxt, local, 0)
-			s.Type = SHOSTOBJ
+			s.Type = obj.SHOSTOBJ
 			s.Size = 0
 			continue
 		}
@@ -474,8 +465,11 @@
 			local = expandpkg(local, pkg)
 			s = Linklookup(Ctxt, local, 0)
 
-			if Flag_shared != 0 && s == Linklookup(Ctxt, "main", 0) {
-				continue
+			switch Buildmode {
+			case BuildmodeCShared, BuildmodeCArchive:
+				if s == Linklookup(Ctxt, "main", 0) {
+					continue
+				}
 			}
 
 			// export overrides import, for openbsd/cgo.
@@ -570,7 +564,7 @@
 	var i int
 
 	for s := markq; s != nil; s = s.Queue {
-		if s.Type == STEXT {
+		if s.Type == obj.STEXT {
 			if Debug['v'] > 1 {
 				fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
 			}
@@ -619,45 +613,62 @@
 		fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
 	}
 
-	mark(Linklookup(Ctxt, INITENTRY, 0))
-	for i := 0; i < len(markextra); i++ {
-		mark(Linklookup(Ctxt, markextra[i], 0))
-	}
-
-	for i := 0; i < len(dynexp); i++ {
-		mark(dynexp[i])
-	}
-
-	markflood()
-
-	// keep each beginning with 'typelink.' if the symbol it points at is being kept.
-	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-		if strings.HasPrefix(s.Name, "go.typelink.") {
-			s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
+	if Buildmode == BuildmodeShared {
+		// Mark all symbols as reachable when building a
+		// shared library.
+		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+			if s.Type != 0 {
+				mark(s)
+			}
 		}
-	}
-
-	// remove dead text but keep file information (z symbols).
-	var last *LSym
-
-	for s := Ctxt.Textp; s != nil; s = s.Next {
-		if !s.Reachable {
-			continue
-		}
-
-		// NOTE: Removing s from old textp and adding to new, shorter textp.
-		if last == nil {
-			Ctxt.Textp = s
-		} else {
-			last.Next = s
-		}
-		last = s
-	}
-
-	if last == nil {
-		Ctxt.Textp = nil
+		mark(Linkrlookup(Ctxt, "main.main", 0))
+		mark(Linkrlookup(Ctxt, "main.init", 0))
 	} else {
-		last.Next = nil
+		mark(Linklookup(Ctxt, INITENTRY, 0))
+		if Linkshared && Buildmode == BuildmodeExe {
+			mark(Linkrlookup(Ctxt, "main.main", 0))
+			mark(Linkrlookup(Ctxt, "main.init", 0))
+		}
+		for i := 0; i < len(markextra); i++ {
+			mark(Linklookup(Ctxt, markextra[i], 0))
+		}
+
+		for i := 0; i < len(dynexp); i++ {
+			mark(dynexp[i])
+		}
+		markflood()
+
+		// keep each beginning with 'typelink.' if the symbol it points at is being kept.
+		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+			if strings.HasPrefix(s.Name, "go.typelink.") {
+				s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
+			}
+		}
+
+		// remove dead text but keep file information (z symbols).
+		var last *LSym
+
+		for s := Ctxt.Textp; s != nil; s = s.Next {
+			if !s.Reachable {
+				continue
+			}
+
+			// NOTE: Removing s from old textp and adding to new, shorter textp.
+			if last == nil {
+				Ctxt.Textp = s
+			} else {
+				last.Next = s
+			}
+			last = s
+		}
+
+		if last == nil {
+			Ctxt.Textp = nil
+			Ctxt.Etextp = nil
+		} else {
+			last.Next = nil
+			Ctxt.Etextp = last
+		}
 	}
 
 	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
@@ -684,7 +695,7 @@
 				buf.WriteString("\n")
 			}
 
-			s.Type = SCONST
+			s.Type = obj.SCONST
 			s.Value = 0
 		}
 	}
@@ -712,7 +723,7 @@
 				s.Type = t.Type
 				s.Outer = t
 			} else {
-				s.Type = SCONST
+				s.Type = obj.SCONST
 				s.Value = 0
 			}
 
@@ -722,7 +733,7 @@
 }
 
 func addexport() {
-	if HEADTYPE == Hdarwin {
+	if HEADTYPE == obj.Hdarwin {
 		return
 	}
 
@@ -812,7 +823,6 @@
 	} else if arg == "auto" {
 		Linkmode = LinkAuto
 	} else {
-		fmt.Fprintf(os.Stderr, "unknown link mode -linkmode %s\n", arg)
-		Errorexit()
+		Exitf("unknown link mode -linkmode %s", arg)
 	}
 }
diff --git a/src/cmd/internal/ld/ld.go b/src/cmd/internal/ld/ld.go
index a0f1f32..7242301 100644
--- a/src/cmd/internal/ld/ld.go
+++ b/src/cmd/internal/ld/ld.go
@@ -34,6 +34,7 @@
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"io/ioutil"
 	"os"
 	"path"
 	"strconv"
@@ -57,11 +58,19 @@
 	}
 
 	var pname string
+	isshlib := false
 	if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
 		pname = name
 	} else {
 		// try dot, -L "libdir", and then goroot.
 		for _, dir := range ctxt.Libdir {
+			if Linkshared {
+				pname = dir + "/" + pkg + ".shlibname"
+				if _, err := os.Stat(pname); err == nil {
+					isshlib = true
+					break
+				}
+			}
 			pname = dir + "/" + name
 			if _, err := os.Stat(pname); err == nil {
 				break
@@ -72,10 +81,14 @@
 	pname = path.Clean(pname)
 
 	if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
-		fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s\n", elapsed(), obj, src, pname)
+		fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
 	}
 
-	addlibpath(ctxt, src, obj, pname, pkg)
+	if isshlib {
+		addlibpath(ctxt, src, obj, "", pkg, pname)
+	} else {
+		addlibpath(ctxt, src, obj, pname, pkg, "")
+	}
 }
 
 /*
@@ -85,15 +98,15 @@
  *	file: object file, e.g., /home/rsc/go/pkg/container/vector.a
  *	pkg: package import path, e.g. container/vector
  */
-func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string) {
+func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) {
 	for i := 0; i < len(ctxt.Library); i++ {
-		if file == ctxt.Library[i].File {
+		if pkg == ctxt.Library[i].Pkg {
 			return
 		}
 	}
 
 	if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
-		fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", obj.Cputime(), srcref, objref, file, pkg)
+		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{})
@@ -102,6 +115,13 @@
 	l.Srcref = srcref
 	l.File = file
 	l.Pkg = pkg
+	if shlibnamefile != "" {
+		shlibbytes, err := ioutil.ReadFile(shlibnamefile)
+		if err != nil {
+			Diag("cannot read %s: %v", shlibnamefile, err)
+		}
+		l.Shlib = strings.TrimSpace(string(shlibbytes))
+	}
 }
 
 func atolwhex(s string) int64 {
diff --git a/src/cmd/internal/ld/ldelf.go b/src/cmd/internal/ld/ldelf.go
index beb62b7..3efdb75 100644
--- a/src/cmd/internal/ld/ldelf.go
+++ b/src/cmd/internal/ld/ldelf.go
@@ -265,7 +265,7 @@
 }
 
 type ElfObj struct {
-	f         *Biobuf
+	f         *obj.Biobuf
 	base      int64 // offset in f where ELF begins
 	length    int64 // length of ELF
 	is64      int
@@ -315,13 +315,13 @@
 	return 0
 }
 
-func ldelf(f *Biobuf, pkg string, length int64, pn string) {
+func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
 	}
 
 	Ctxt.Version++
-	base := int32(Boffset(f))
+	base := int32(obj.Boffset(f))
 
 	var add uint64
 	var e binary.ByteOrder
@@ -344,7 +344,7 @@
 	var sect *ElfSect
 	var sym ElfSym
 	var symbols []*LSym
-	if Bread(f, hdrbuf[:]) != len(hdrbuf) {
+	if obj.Bread(f, hdrbuf[:]) != len(hdrbuf) {
 		goto bad
 	}
 	hdr = new(ElfHdrBytes)
@@ -457,7 +457,7 @@
 
 	elfobj.nsect = uint(elfobj.shnum)
 	for i := 0; uint(i) < elfobj.nsect; i++ {
-		if Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
+		if obj.Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
 			goto bad
 		}
 		sect = &elfobj.sect[i]
@@ -567,21 +567,21 @@
 			goto bad
 
 		case ElfSectFlagAlloc:
-			s.Type = SRODATA
+			s.Type = obj.SRODATA
 
 		case ElfSectFlagAlloc + ElfSectFlagWrite:
 			if sect.type_ == ElfSectNobits {
-				s.Type = SNOPTRBSS
+				s.Type = obj.SNOPTRBSS
 			} else {
-				s.Type = SNOPTRDATA
+				s.Type = obj.SNOPTRDATA
 			}
 
 		case ElfSectFlagAlloc + ElfSectFlagExec:
-			s.Type = STEXT
+			s.Type = obj.STEXT
 		}
 
 		if sect.name == ".got" || sect.name == ".toc" {
-			s.Type = SELFGOT
+			s.Type = obj.SELFGOT
 		}
 		if sect.type_ == ElfSectProgbits {
 			s.P = sect.base
@@ -597,11 +597,6 @@
 	// symbol 0 is the null symbol.
 	symbols = make([]*LSym, elfobj.nsymtab)
 
-	if symbols == nil {
-		Diag("out of memory")
-		Errorexit()
-	}
-
 	for i := 1; i < elfobj.nsymtab; i++ {
 		if err = readelfsym(elfobj, i, &sym, 1); err != nil {
 			goto bad
@@ -615,8 +610,8 @@
 			if uint64(s.Size) < sym.size {
 				s.Size = int64(sym.size)
 			}
-			if s.Type == 0 || s.Type == SXREF {
-				s.Type = SNOPTRBSS
+			if s.Type == 0 || s.Type == obj.SXREF {
+				s.Type = obj.SNOPTRBSS
 			}
 			continue
 		}
@@ -643,20 +638,19 @@
 			if s.Dupok != 0 {
 				continue
 			}
-			Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
-			Errorexit()
+			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
 		}
 
 		s.Sub = sect.sym.Sub
 		sect.sym.Sub = s
-		s.Type = sect.sym.Type | s.Type&^SMASK | SSUB
+		s.Type = sect.sym.Type | s.Type&^obj.SMASK | obj.SSUB
 		if s.Cgoexport&CgoExportDynamic == 0 {
 			s.Dynimplib = "" // satisfy dynimport
 		}
 		s.Value = int64(sym.value)
 		s.Size = int64(sym.size)
 		s.Outer = sect.sym
-		if sect.sym.Type == STEXT {
+		if sect.sym.Type == obj.STEXT {
 			if s.External != 0 && s.Dupok == 0 {
 				Diag("%s: duplicate definition of %s", pn, s.Name)
 			}
@@ -683,7 +677,7 @@
 		if s.Sub != nil {
 			s.Sub = listsort(s.Sub, valuecmp, listsubp)
 		}
-		if s.Type == STEXT {
+		if s.Type == obj.STEXT {
 			if s.Onlist != 0 {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -832,7 +826,7 @@
 
 	sect.base = make([]byte, sect.size)
 	err = fmt.Errorf("short read")
-	if Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || Bread(elfobj.f, sect.base) != len(sect.base) {
+	if obj.Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || obj.Bread(elfobj.f, sect.base) != len(sect.base) {
 		return err
 	}
 
@@ -899,7 +893,7 @@
 				// set dupok generally. See http://codereview.appspot.com/5823055/
 				// comment #5 for details.
 				if s != nil && sym.other == 2 {
-					s.Type |= SHIDDEN
+					s.Type |= obj.SHIDDEN
 					s.Dupok = 1
 				}
 			}
@@ -916,7 +910,7 @@
 				// so put it in the hash table.
 				if needSym != 0 {
 					s = Linklookup(Ctxt, sym.name, Ctxt.Version)
-					s.Type |= SHIDDEN
+					s.Type |= obj.SHIDDEN
 				}
 
 				break
@@ -928,14 +922,14 @@
 				// don't bother to add them into hash table
 				s = linknewsym(Ctxt, sym.name, Ctxt.Version)
 
-				s.Type |= SHIDDEN
+				s.Type |= obj.SHIDDEN
 			}
 
 		case ElfSymBindWeak:
 			if needSym != 0 {
 				s = linknewsym(Ctxt, sym.name, 0)
 				if sym.other == 2 {
-					s.Type |= SHIDDEN
+					s.Type |= obj.SHIDDEN
 				}
 			}
 
@@ -946,7 +940,7 @@
 	}
 
 	if s != nil && s.Type == 0 && sym.type_ != ElfSymTypeSection {
-		s.Type = SXREF
+		s.Type = obj.SXREF
 	}
 	sym.sym = s
 
diff --git a/src/cmd/internal/ld/ldmacho.go b/src/cmd/internal/ld/ldmacho.go
index 9ed4093..2abfa33 100644
--- a/src/cmd/internal/ld/ldmacho.go
+++ b/src/cmd/internal/ld/ldmacho.go
@@ -1,6 +1,7 @@
 package ld
 
 import (
+	"cmd/internal/obj"
 	"encoding/binary"
 	"fmt"
 	"log"
@@ -40,7 +41,7 @@
 )
 
 type LdMachoObj struct {
-	f          *Biobuf
+	f          *obj.Biobuf
 	base       int64 // off in f where Mach-O begins
 	length     int64 // length of Mach-O
 	is64       bool
@@ -296,7 +297,7 @@
 	rel := make([]LdMachoRel, sect.nreloc)
 	n := int(sect.nreloc * 8)
 	buf := make([]byte, n)
-	if Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || Bread(m.f, buf) != n {
+	if obj.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || obj.Bread(m.f, buf) != n {
 		return -1
 	}
 	var p []byte
@@ -342,7 +343,7 @@
 	n := int(d.nindirectsyms)
 
 	p := make([]byte, n*4)
-	if Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || Bread(m.f, p) != len(p) {
+	if obj.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || obj.Bread(m.f, p) != len(p) {
 		return -1
 	}
 
@@ -359,7 +360,7 @@
 	}
 
 	strbuf := make([]byte, symtab.strsize)
-	if Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || Bread(m.f, strbuf) != len(strbuf) {
+	if obj.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || obj.Bread(m.f, strbuf) != len(strbuf) {
 		return -1
 	}
 
@@ -369,7 +370,7 @@
 	}
 	n := int(symtab.nsym * uint32(symsize))
 	symbuf := make([]byte, n)
-	if Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || Bread(m.f, symbuf) != len(symbuf) {
+	if obj.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || obj.Bread(m.f, symbuf) != len(symbuf) {
 		return -1
 	}
 	sym := make([]LdMachoSym, symtab.nsym)
@@ -399,7 +400,7 @@
 	return 0
 }
 
-func ldmacho(f *Biobuf, pkg string, length int64, pn string) {
+func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 	var err error
 	var j int
 	var is64 bool
@@ -429,8 +430,8 @@
 	var name string
 
 	Ctxt.Version++
-	base := Boffset(f)
-	if Bread(f, hdr[:]) != len(hdr) {
+	base := obj.Boffset(f)
+	if obj.Bread(f, hdr[:]) != len(hdr) {
 		goto bad
 	}
 
@@ -453,7 +454,7 @@
 
 	if is64 {
 		var tmp [4]uint8
-		Bread(f, tmp[:4]) // skip reserved word in header
+		obj.Bread(f, tmp[:4]) // skip reserved word in header
 	}
 
 	m = new(LdMachoObj)
@@ -491,7 +492,7 @@
 	m.cmd = make([]LdMachoCmd, ncmd)
 	off = uint32(len(hdr))
 	cmdp = make([]byte, cmdsz)
-	if Bread(f, cmdp) != len(cmdp) {
+	if obj.Bread(f, cmdp) != len(cmdp) {
 		err = fmt.Errorf("reading cmds: %v", err)
 		goto bad
 	}
@@ -554,7 +555,7 @@
 	}
 
 	dat = make([]byte, c.seg.filesz)
-	if Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || Bread(f, dat) != len(dat) {
+	if obj.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || obj.Bread(f, dat) != len(dat) {
 		err = fmt.Errorf("cannot load object data: %v", err)
 		goto bad
 	}
@@ -583,16 +584,16 @@
 
 		if sect.segname == "__TEXT" {
 			if sect.name == "__text" {
-				s.Type = STEXT
+				s.Type = obj.STEXT
 			} else {
-				s.Type = SRODATA
+				s.Type = obj.SRODATA
 			}
 		} else {
 			if sect.name == "__bss" {
-				s.Type = SNOPTRBSS
+				s.Type = obj.SNOPTRBSS
 				s.P = s.P[:0]
 			} else {
-				s.Type = SNOPTRDATA
+				s.Type = obj.SNOPTRDATA
 			}
 		}
 
@@ -641,11 +642,10 @@
 			if s.Dupok != 0 {
 				continue
 			}
-			Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
-			Errorexit()
+			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
 		}
 
-		s.Type = outer.Type | SSUB
+		s.Type = outer.Type | obj.SSUB
 		s.Sub = outer.Sub
 		outer.Sub = s
 		s.Outer = outer
@@ -653,7 +653,7 @@
 		if s.Cgoexport&CgoExportDynamic == 0 {
 			s.Dynimplib = "" // satisfy dynimport
 		}
-		if outer.Type == STEXT {
+		if outer.Type == obj.STEXT {
 			if s.External != 0 && s.Dupok == 0 {
 				Diag("%s: duplicate definition of %s", pn, s.Name)
 			}
@@ -684,7 +684,7 @@
 			}
 		}
 
-		if s.Type == STEXT {
+		if s.Type == obj.STEXT {
 			if s.Onlist != 0 {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -761,7 +761,7 @@
 				// want to make it pc-relative aka relative to rp->off+4
 				// but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
 				// adjust rp->add accordingly.
-				rp.Type = R_PCREL
+				rp.Type = obj.R_PCREL
 
 				rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))
 
diff --git a/src/cmd/internal/ld/ldpe.go b/src/cmd/internal/ld/ldpe.go
index e124d81..b98cf02 100644
--- a/src/cmd/internal/ld/ldpe.go
+++ b/src/cmd/internal/ld/ldpe.go
@@ -115,7 +115,7 @@
 }
 
 type PeObj struct {
-	f      *Biobuf
+	f      *obj.Biobuf
 	name   string
 	base   uint32
 	sect   []PeSect
@@ -126,14 +126,14 @@
 	snames []byte
 }
 
-func ldpe(f *Biobuf, pkg string, length int64, pn string) {
+func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
 	}
 
 	var sect *PeSect
 	Ctxt.Version++
-	base := int32(Boffset(f))
+	base := int32(obj.Boffset(f))
 
 	peobj := new(PeObj)
 	peobj.f = f
@@ -171,15 +171,15 @@
 	// TODO return error if found .cormeta
 
 	// load string table
-	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
 
-	if Bread(f, symbuf[:4]) != 4 {
+	if obj.Bread(f, symbuf[:4]) != 4 {
 		goto bad
 	}
 	l = Le32(symbuf[:])
 	peobj.snames = make([]byte, l)
-	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
-	if Bread(f, peobj.snames) != len(peobj.snames) {
+	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+	if obj.Bread(f, peobj.snames) != len(peobj.snames) {
 		goto bad
 	}
 
@@ -199,10 +199,10 @@
 	peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
 
 	peobj.npesym = uint(peobj.fh.NumberOfSymbols)
-	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
+	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
 	for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
-		Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
-		if Bread(f, symbuf[:]) != len(symbuf) {
+		obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
+		if obj.Bread(f, symbuf[:]) != len(symbuf) {
 			goto bad
 		}
 
@@ -246,16 +246,16 @@
 
 		switch sect.sh.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
-			s.Type = SRODATA
+			s.Type = obj.SRODATA
 
 		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
-			s.Type = SNOPTRBSS
+			s.Type = obj.SNOPTRBSS
 
 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
-			s.Type = SNOPTRDATA
+			s.Type = obj.SNOPTRDATA
 
 		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
-			s.Type = STEXT
+			s.Type = obj.STEXT
 
 		default:
 			err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
@@ -287,10 +287,10 @@
 		}
 
 		r = make([]Reloc, rsect.sh.NumberOfRelocations)
-		Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
+		obj.Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
 		for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
 			rp = &r[j]
-			if Bread(f, symbuf[:10]) != 10 {
+			if obj.Bread(f, symbuf[:10]) != 10 {
 				goto bad
 			}
 			rva := Le32(symbuf[0:])
@@ -315,12 +315,12 @@
 			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
 				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
 				IMAGE_REL_AMD64_ADDR32NB:
-				rp.Type = R_PCREL
+				rp.Type = obj.R_PCREL
 
 				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
 
 			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
-				rp.Type = R_ADDR
+				rp.Type = obj.R_ADDR
 
 				// load addend from image
 				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
@@ -328,7 +328,7 @@
 			case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
 				rp.Siz = 8
 
-				rp.Type = R_ADDR
+				rp.Type = obj.R_ADDR
 
 				// load addend from image
 				rp.Add = int64(Le64(rsect.base[rp.Off:]))
@@ -373,11 +373,11 @@
 
 		s = sym.sym
 		if sym.sectnum == 0 { // extern
-			if s.Type == SDYNIMPORT {
+			if s.Type == obj.SDYNIMPORT {
 				s.Plt = -2 // flag for dynimport in PE object files.
 			}
-			if s.Type == SXREF && sym.value > 0 { // global data
-				s.Type = SNOPTRDATA
+			if s.Type == obj.SXREF && sym.value > 0 { // global data
+				s.Type = obj.SNOPTRDATA
 				s.Size = int64(sym.value)
 			}
 
@@ -399,17 +399,16 @@
 			if s.Dupok != 0 {
 				continue
 			}
-			Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
-			Errorexit()
+			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
 		}
 
 		s.Sub = sect.sym.Sub
 		sect.sym.Sub = s
-		s.Type = sect.sym.Type | SSUB
+		s.Type = sect.sym.Type | obj.SSUB
 		s.Value = int64(sym.value)
 		s.Size = 4
 		s.Outer = sect.sym
-		if sect.sym.Type == STEXT {
+		if sect.sym.Type == obj.STEXT {
 			if s.External != 0 && s.Dupok == 0 {
 				Diag("%s: duplicate definition of %s", pn, s.Name)
 			}
@@ -427,7 +426,7 @@
 		if s.Sub != nil {
 			s.Sub = listsort(s.Sub, valuecmp, listsubp)
 		}
-		if s.Type == STEXT {
+		if s.Type == obj.STEXT {
 			if s.Onlist != 0 {
 				log.Fatalf("symbol %s listed multiple times", s.Name)
 			}
@@ -464,7 +463,7 @@
 	if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
 		return 0
 	}
-	if Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || Bread(peobj.f, sect.base) != len(sect.base) {
+	if obj.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || obj.Bread(peobj.f, sect.base) != len(sect.base) {
 		return -1
 	}
 
@@ -524,7 +523,7 @@
 	}
 
 	if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
-		s.Type = SXREF
+		s.Type = obj.SXREF
 	}
 	if strings.HasPrefix(sym.name, "__imp_") {
 		s.Got = -2 // flag for __imp_
diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go
index e4b1820..184175e 100644
--- a/src/cmd/internal/ld/lib.go
+++ b/src/cmd/internal/ld/lib.go
@@ -31,13 +31,17 @@
 package ld
 
 import (
+	"bufio"
 	"bytes"
 	"cmd/internal/obj"
+	"debug/elf"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
 	"os"
 	"os/exec"
+	"path/filepath"
 	"strings"
 )
 
@@ -105,12 +109,27 @@
 	Vput             func(uint64)
 }
 
+type Rpath struct {
+	set bool
+	val string
+}
+
+func (r *Rpath) Set(val string) error {
+	r.set = true
+	r.val = val
+	return nil
+}
+
+func (r *Rpath) String() string {
+	return r.val
+}
+
 var (
 	Thearch Arch
 	datap   *LSym
 	Debug   [128]int
 	Lcsize  int32
-	rpath   string
+	rpath   Rpath
 	Spsize  int32
 	Symsize int32
 )
@@ -148,6 +167,12 @@
 	Rellen  uint64
 }
 
+// DynlinkingGo returns whether we are producing Go code that can live
+// in separate shared libraries linked together at runtime.
+func DynlinkingGo() bool {
+	return Buildmode == BuildmodeShared || Linkshared
+}
+
 var (
 	Thestring          string
 	Thelinkarch        *LinkArch
@@ -160,7 +185,8 @@
 	elfglobalsymndx    int
 	flag_installsuffix string
 	flag_race          int
-	Flag_shared        int
+	Buildmode          BuildMode
+	Linkshared         bool
 	tracksym           string
 	interpreter        string
 	tmpdir             string
@@ -204,10 +230,14 @@
 var (
 	headstring string
 	// buffered output
-	Bso     Biobuf
-	coutbuf Biobuf
+	Bso obj.Biobuf
 )
 
+var coutbuf struct {
+	*bufio.Writer
+	f *os.File
+}
+
 const (
 	// Whether to assume that the external linker is "gold"
 	// (http://sourceware.org/ml/binutils/2008-03/msg00162.html).
@@ -220,7 +250,6 @@
 )
 
 var (
-	cout *os.File
 	// Set if we see an object compiled by the host compiler that is not
 	// from a package that is known to support internal linking mode.
 	externalobj = false
@@ -234,6 +263,69 @@
 	Ctxt.Libdir = append(Ctxt.Libdir, arg)
 }
 
+// A BuildMode indicates the sort of object we are building:
+//   "exe": build a main package and everything it imports into an executable.
+//   "c-shared": build a main package, plus all packages that it imports, into a
+//     single C shared library. The only callable symbols will be those functions
+//     marked as exported.
+//   "shared": combine all packages passed on the command line, and their
+//     dependencies, into a single shared library that will be used when
+//     building with the -linkshared option.
+type BuildMode uint8
+
+const (
+	BuildmodeExe BuildMode = iota
+	BuildmodeCArchive
+	BuildmodeCShared
+	BuildmodeShared
+)
+
+func (mode *BuildMode) Set(s string) error {
+	goos := obj.Getgoos()
+	goarch := obj.Getgoarch()
+	badmode := func() error {
+		return fmt.Errorf("buildmode %s not supported on %s/%s", s, goos, goarch)
+	}
+	switch s {
+	default:
+		return fmt.Errorf("invalid buildmode: %q", s)
+	case "exe":
+		*mode = BuildmodeExe
+	case "c-archive":
+		switch goos {
+		case "darwin", "linux":
+		default:
+			return badmode()
+		}
+		*mode = BuildmodeCArchive
+	case "c-shared":
+		if goarch != "amd64" && goarch != "arm" {
+			return badmode()
+		}
+		*mode = BuildmodeCShared
+	case "shared":
+		if goos != "linux" || goarch != "amd64" {
+			return badmode()
+		}
+		*mode = BuildmodeShared
+	}
+	return nil
+}
+
+func (mode *BuildMode) String() string {
+	switch *mode {
+	case BuildmodeExe:
+		return "exe"
+	case BuildmodeCArchive:
+		return "c-archive"
+	case BuildmodeCShared:
+		return "c-shared"
+	case BuildmodeShared:
+		return "shared"
+	}
+	return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
+}
+
 /*
  * Unix doesn't like it when we write to a running (or, sometimes,
  * recently run) binary, so remove the output file before writing it.
@@ -268,32 +360,52 @@
 	mayberemoveoutfile()
 	f, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
 	if err != nil {
-		Diag("cannot create %s: %v", outfile, err)
-		Errorexit()
+		Exitf("cannot create %s: %v", outfile, err)
 	}
 
-	cout = f
-	coutbuf = *Binitw(f)
+	coutbuf.Writer = bufio.NewWriter(f)
+	coutbuf.f = f
 
 	if INITENTRY == "" {
-		if Flag_shared == 0 {
-			INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
-		} else {
+		switch Buildmode {
+		case BuildmodeCShared, BuildmodeCArchive:
 			INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
+		case BuildmodeExe:
+			INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
+		case BuildmodeShared:
+			// No INITENTRY for -buildmode=shared
+		default:
+			Diag("unknown INITENTRY for buildmode %v", Buildmode)
 		}
 	}
 
-	Linklookup(Ctxt, INITENTRY, 0).Type = SXREF
+	if !DynlinkingGo() {
+		Linklookup(Ctxt, INITENTRY, 0).Type = obj.SXREF
+	}
 }
 
-func Errorexit() {
-	if cout != nil {
+func Exitf(format string, a ...interface{}) {
+	fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
+	if coutbuf.f != nil {
+		coutbuf.f.Close()
+		mayberemoveoutfile()
+	}
+	Exit(2)
+}
+
+func errorexit() {
+	if coutbuf.f != nil {
+		if nerrors != 0 {
+			Cflush()
+		}
 		// For rmtemp run at atexit time on Windows.
-		cout.Close()
+		if err := coutbuf.f.Close(); err != nil {
+			Exitf("close: %v", err)
+		}
 	}
 
 	if nerrors != 0 {
-		if cout != nil {
+		if coutbuf.f != nil {
 			mayberemoveoutfile()
 		}
 		Exit(2)
@@ -303,16 +415,25 @@
 }
 
 func loadinternal(name string) {
-	var pname string
-
 	found := 0
 	for i := 0; i < len(Ctxt.Libdir); i++ {
-		pname = fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
+		if Linkshared {
+			shlibname := fmt.Sprintf("%s/%s.shlibname", Ctxt.Libdir[i], name)
+			if Debug['v'] != 0 {
+				fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, shlibname)
+			}
+			if obj.Access(shlibname, obj.AEXIST) >= 0 {
+				addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
+				found = 1
+				break
+			}
+		}
+		pname := fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
 		if Debug['v'] != 0 {
 			fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
 		}
 		if obj.Access(pname, obj.AEXIST) >= 0 {
-			addlibpath(Ctxt, "internal", "internal", pname, name)
+			addlibpath(Ctxt, "internal", "internal", pname, name, "")
 			found = 1
 			break
 		}
@@ -324,10 +445,15 @@
 }
 
 func loadlib() {
-	if Flag_shared != 0 {
+	switch Buildmode {
+	case BuildmodeCShared:
 		s := Linklookup(Ctxt, "runtime.islibrary", 0)
 		s.Dupok = 1
 		Adduint8(Ctxt, s, 1)
+	case BuildmodeCArchive:
+		s := Linklookup(Ctxt, "runtime.isarchive", 0)
+		s.Dupok = 1
+		Adduint8(Ctxt, s, 1)
 	}
 
 	loadinternal("runtime")
@@ -344,7 +470,11 @@
 			fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
 		}
 		iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
-		objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+		if Ctxt.Library[i].Shlib != "" {
+			ldshlibsyms(Ctxt.Library[i].Shlib)
+		} else {
+			objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+		}
 	}
 
 	if Linkmode == LinkAuto {
@@ -364,11 +494,17 @@
 		// dependency problems when compiling natively (external linking requires
 		// runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
 		// compiled using external linking.)
-		if Thearch.Thechar == '5' && HEADTYPE == Hdarwin && iscgo {
+		if (Thearch.Thechar == '5' || Thearch.Thechar == '7') && HEADTYPE == obj.Hdarwin && iscgo {
 			Linkmode = LinkExternal
 		}
 	}
 
+	// cmd/7l doesn't support cgo internal linking
+	// This is https://golang.org/issue/10373.
+	if iscgo && goarch == "arm64" {
+		Linkmode = LinkExternal
+	}
+
 	if Linkmode == LinkExternal && !iscgo {
 		// This indicates a user requested -linkmode=external.
 		// The startup code uses an import of runtime/cgo to decide
@@ -377,7 +513,14 @@
 		loadinternal("runtime/cgo")
 
 		if i < len(Ctxt.Library) {
-			objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+			if Ctxt.Library[i].Shlib != "" {
+				ldshlibsyms(Ctxt.Library[i].Shlib)
+			} else {
+				if DynlinkingGo() {
+					Exitf("cannot implicitly include runtime/cgo in a shared library")
+				}
+				objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+			}
 		}
 	}
 
@@ -385,13 +528,13 @@
 		// Drop all the cgo_import_static declarations.
 		// Turns out we won't be needing them.
 		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-			if s.Type == SHOSTOBJ {
+			if s.Type == obj.SHOSTOBJ {
 				// If a symbol was marked both
 				// cgo_import_static and cgo_import_dynamic,
 				// then we want to make it cgo_import_dynamic
 				// now.
 				if s.Extname != "" && s.Dynimplib != "" && s.Cgoexport == 0 {
-					s.Type = SDYNIMPORT
+					s.Type = obj.SDYNIMPORT
 				} else {
 					s.Type = 0
 				}
@@ -408,8 +551,8 @@
 	// TODO(crawshaw): android should require leaving the tlsg->type
 	// alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
 	// But some other part of the linker is expecting STLSBSS.
-	if goos != "darwin" || Thearch.Thechar != '5' {
-		tlsg.Type = STLSBSS
+	if tlsg.Type != obj.SDYNIMPORT && (goos != "darwin" || Thearch.Thechar != '5') {
+		tlsg.Type = obj.STLSBSS
 	}
 	tlsg.Size = int64(Thearch.Ptrsize)
 	tlsg.Reachable = true
@@ -448,7 +591,7 @@
 	// binaries, so leave it enabled on OS X (Mach-O) binaries.
 	// Also leave it enabled on Solaris which doesn't support
 	// statically linked binaries.
-	if Flag_shared == 0 && havedynamic == 0 && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris {
+	if Buildmode == BuildmodeExe && havedynamic == 0 && HEADTYPE != obj.Hdarwin && HEADTYPE != obj.Hsolaris {
 		Debug['d'] = 1
 	}
 
@@ -459,13 +602,13 @@
  * look for the next file in an archive.
  * adapted from libmach.
  */
-func nextar(bp *Biobuf, off int64, a *ArHdr) int64 {
+func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
 	if off&1 != 0 {
 		off++
 	}
-	Bseek(bp, off, 0)
+	obj.Bseek(bp, off, 0)
 	buf := make([]byte, SAR_HDR)
-	if n := Bread(bp, buf); n < len(buf) {
+	if n := obj.Bread(bp, buf); n < len(buf) {
 		if n >= 0 {
 			return 0
 		}
@@ -493,29 +636,28 @@
 	if Debug['v'] > 1 {
 		fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), file, pkg)
 	}
-	Bflush(&Bso)
+	Bso.Flush()
 	var err error
-	var f *Biobuf
-	f, err = Bopenr(file)
+	var f *obj.Biobuf
+	f, err = obj.Bopenr(file)
 	if err != nil {
-		Diag("cannot open file %s: %v", file, err)
-		Errorexit()
+		Exitf("cannot open file %s: %v", file, err)
 	}
 
 	magbuf := make([]byte, len(ARMAG))
-	if Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) {
+	if obj.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) {
 		/* load it as a regular file */
-		l := Bseek(f, 0, 2)
+		l := obj.Bseek(f, 0, 2)
 
-		Bseek(f, 0, 0)
+		obj.Bseek(f, 0, 0)
 		ldobj(f, pkg, l, file, file, FileObj)
-		Bterm(f)
+		obj.Bterm(f)
 
 		return
 	}
 
 	/* skip over optional __.GOSYMDEF and process __.PKGDEF */
-	off := Boffset(f)
+	off := obj.Boffset(f)
 
 	var arhdr ArHdr
 	l := nextar(f, off, &arhdr)
@@ -563,9 +705,7 @@
 			break
 		}
 		if l < 0 {
-			Diag("%s: malformed archive", file)
-			Errorexit()
-			goto out
+			Exitf("%s: malformed archive", file)
 		}
 
 		off += l
@@ -576,11 +716,11 @@
 	}
 
 out:
-	Bterm(f)
+	obj.Bterm(f)
 }
 
 type Hostobj struct {
-	ld     func(*Biobuf, string, int64, string)
+	ld     func(*obj.Biobuf, string, int64, string)
 	pkg    string
 	pn     string
 	file   string
@@ -600,7 +740,7 @@
 	"runtime/race",
 }
 
-func ldhostobj(ld func(*Biobuf, string, int64, string), f *Biobuf, pkg string, length int64, pn string, file string) {
+func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg string, length int64, pn string, file string) {
 	isinternal := false
 	for i := 0; i < len(internalpkg); i++ {
 		if pkg == internalpkg[i] {
@@ -615,7 +755,7 @@
 	// force external linking for any libraries that link in code that
 	// uses errno. This can be removed if the Go linker ever supports
 	// these relocation types.
-	if HEADTYPE == Hdragonfly {
+	if HEADTYPE == obj.Hdragonfly {
 		if pkg == "net" || pkg == "os/user" {
 			isinternal = false
 		}
@@ -631,27 +771,25 @@
 	h.pkg = pkg
 	h.pn = pn
 	h.file = file
-	h.off = Boffset(f)
+	h.off = obj.Boffset(f)
 	h.length = length
 }
 
 func hostobjs() {
-	var f *Biobuf
+	var f *obj.Biobuf
 	var h *Hostobj
 
 	for i := 0; i < len(hostobj); i++ {
 		h = &hostobj[i]
 		var err error
-		f, err = Bopenr(h.file)
+		f, err = obj.Bopenr(h.file)
 		if f == nil {
-			Ctxt.Cursym = nil
-			Diag("cannot reopen %s: %v", h.pn, err)
-			Errorexit()
+			Exitf("cannot reopen %s: %v", h.pn, err)
 		}
 
-		Bseek(f, h.off, 0)
+		obj.Bseek(f, h.off, 0)
 		h.ld(f, h.pkg, h.length, h.pn)
-		Bterm(f)
+		obj.Bterm(f)
 	}
 }
 
@@ -677,29 +815,80 @@
 	}
 
 	// change our output to temporary object file
-	cout.Close()
+	coutbuf.f.Close()
 
 	p := fmt.Sprintf("%s/go.o", tmpdir)
 	var err error
-	cout, err = os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
+	f, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
 	if err != nil {
-		Diag("cannot create %s: %v", p, err)
-		Errorexit()
+		Exitf("cannot create %s: %v", p, err)
 	}
 
-	coutbuf = *Binitw(cout)
+	coutbuf.Writer = bufio.NewWriter(f)
+	coutbuf.f = f
 }
 
-var hostlink_buf = make([]byte, 64*1024)
+// hostobjCopy creates a copy of the object files in hostobj in a
+// temporary directory.
+func hostobjCopy() (paths []string) {
+	for i, h := range hostobj {
+		f, err := os.Open(h.file)
+		if err != nil {
+			Exitf("cannot reopen %s: %v", h.pn, err)
+		}
+		if _, err := f.Seek(h.off, 0); err != nil {
+			Exitf("cannot seek %s: %v", h.pn, err)
+		}
+
+		p := fmt.Sprintf("%s/%06d.o", tmpdir, i)
+		paths = append(paths, p)
+		w, err := os.Create(p)
+		if err != nil {
+			Exitf("cannot create %s: %v", p, err)
+		}
+		if _, err := io.CopyN(w, f, h.length); err != nil {
+			Exitf("cannot write %s: %v", p, err)
+		}
+		if err := w.Close(); err != nil {
+			Exitf("cannot close %s: %v", p, err)
+		}
+	}
+	return paths
+}
+
+// archive builds a .a archive from the hostobj object files.
+func archive() {
+	if Buildmode != BuildmodeCArchive {
+		return
+	}
+
+	os.Remove(outfile)
+	argv := []string{"ar", "-q", "-c", outfile}
+	argv = append(argv, hostobjCopy()...)
+	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "archive: %s\n", strings.Join(argv, " "))
+		Bso.Flush()
+	}
+
+	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
+		Exitf("running %s failed: %v\n%s", argv[0], err, out)
+	}
+}
 
 func hostlink() {
 	if Linkmode != LinkExternal || nerrors > 0 {
 		return
 	}
+	if Buildmode == BuildmodeCArchive {
+		return
+	}
 
 	if extld == "" {
 		extld = "gcc"
 	}
+
 	var argv []string
 	argv = append(argv, extld)
 	switch Thearch.Thechar {
@@ -711,6 +900,9 @@
 
 	case '5':
 		argv = append(argv, "-marm")
+
+	case '7':
+		// nothing needed
 	}
 
 	if Debug['s'] == 0 && debug_s == 0 {
@@ -719,13 +911,13 @@
 		argv = append(argv, "-s")
 	}
 
-	if HEADTYPE == Hdarwin {
+	if HEADTYPE == obj.Hdarwin {
 		argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000")
 	}
-	if HEADTYPE == Hopenbsd {
+	if HEADTYPE == obj.Hopenbsd {
 		argv = append(argv, "-Wl,-nopie")
 	}
-	if HEADTYPE == Hwindows {
+	if HEADTYPE == obj.Hwindows {
 		if headstring == "windowsgui" {
 			argv = append(argv, "-mwindows")
 		} else {
@@ -737,16 +929,34 @@
 		argv = append(argv, "-Wl,--rosegment")
 	}
 
-	if Flag_shared != 0 {
+	switch Buildmode {
+	case BuildmodeCShared:
 		argv = append(argv, "-Wl,-Bsymbolic")
 		argv = append(argv, "-shared")
+	case BuildmodeShared:
+		// TODO(mwhudson): unless you do this, dynamic relocations fill
+		// out the findfunctab table and for some reason shared libraries
+		// and the executable both define a main function and putting the
+		// address of executable's main into the shared libraries
+		// findfunctab violates the assumptions of the runtime.  TBH, I
+		// think we may well end up wanting to use -Bsymbolic here
+		// anyway.
+		argv = append(argv, "-Wl,-Bsymbolic-functions")
+		argv = append(argv, "-shared")
+	}
+
+	if Linkshared && Iself {
+		// We force all symbol resolution to be done at program startup
+		// because lazy PLT resolution can use large amounts of stack at
+		// times we cannot allow it to do so.
+		argv = append(argv, "-Wl,-znow")
 	}
 
 	argv = append(argv, "-o")
 	argv = append(argv, outfile)
 
-	if rpath != "" {
-		argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath))
+	if rpath.val != "" {
+		argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
 	}
 
 	// Force global symbols to be exported for dlopen, etc.
@@ -758,64 +968,25 @@
 		argv = append(argv, "-Qunused-arguments")
 	}
 
-	// already wrote main object file
-	// copy host objects to temporary directory
-	var f *Biobuf
-	var h *Hostobj
-	var length int
-	var n int
-	var p string
-	for i := 0; i < len(hostobj); i++ {
-		h = &hostobj[i]
-		var err error
-		f, err = Bopenr(h.file)
-		if f == nil {
-			Ctxt.Cursym = nil
-			Diag("cannot reopen %s: %v", h.pn, err)
-			Errorexit()
-		}
-
-		Bseek(f, h.off, 0)
-		p = fmt.Sprintf("%s/%06d.o", tmpdir, i)
-		argv = append(argv, p)
-		w, err := os.Create(p)
-		if err != nil {
-			Ctxt.Cursym = nil
-			Diag("cannot create %s: %v", p, err)
-			Errorexit()
-		}
-
-		length = int(h.length)
-		for length > 0 {
-			n = Bread(f, hostlink_buf)
-			if n <= 0 {
-				break
-			}
-			if n > length {
-				n = length
-			}
-			if _, err = w.Write(hostlink_buf[:n]); err != nil {
-				log.Fatal(err)
-			}
-			length -= n
-		}
-
-		if err := w.Close(); err != nil {
-			Ctxt.Cursym = nil
-			Diag("cannot write %s: %v", p, err)
-			Errorexit()
-		}
-
-		Bterm(f)
-	}
-
+	argv = append(argv, hostobjCopy()...)
 	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
-	var i int
-	for i = 0; i < len(ldflag); i++ {
-		argv = append(argv, ldflag[i])
+
+	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)
+			}
+			base = strings.TrimSuffix(base, ".so")
+			base = strings.TrimPrefix(base, "lib")
+			argv = append(argv, "-l"+base)
+		}
 	}
 
-	for _, p = range strings.Fields(extldflags) {
+	argv = append(argv, ldflag...)
+
+	for _, p := range strings.Fields(extldflags) {
 		argv = append(argv, p)
 
 		// clang, unlike GCC, passes -rdynamic to the linker
@@ -825,44 +996,40 @@
 		// only adding -rdynamic later, so that -extldflags
 		// can override -rdynamic without using -static.
 		if Iself && p == "-static" {
-			for i = range argv {
+			for i := range argv {
 				if argv[i] == "-rdynamic" {
 					argv[i] = "-static"
 				}
 			}
 		}
 	}
-	if HEADTYPE == Hwindows {
+	if HEADTYPE == obj.Hwindows {
 		argv = append(argv, peimporteddlls()...)
 	}
 
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "host link:")
-		for i = range argv {
-			fmt.Fprintf(&Bso, " %v", plan9quote(argv[i]))
+		for _, v := range argv {
+			fmt.Fprintf(&Bso, " %q", v)
 		}
 		fmt.Fprintf(&Bso, "\n")
-		Bflush(&Bso)
+		Bso.Flush()
 	}
 
 	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
-		Ctxt.Cursym = nil
-		Diag("%s: running %s failed: %v\n%s", os.Args[0], argv[0], err, out)
-		Errorexit()
+		Exitf("running %s failed: %v\n%s", argv[0], err, out)
 	}
 }
 
-func ldobj(f *Biobuf, pkg string, length int64, pn string, file string, whence int) {
-	eof := Boffset(f) + length
+func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) {
+	eof := obj.Boffset(f) + length
 
-	pn = pn
-
-	start := Boffset(f)
-	c1 := Bgetc(f)
-	c2 := Bgetc(f)
-	c3 := Bgetc(f)
-	c4 := Bgetc(f)
-	Bseek(f, start, 0)
+	start := obj.Boffset(f)
+	c1 := obj.Bgetc(f)
+	c2 := obj.Bgetc(f)
+	c3 := obj.Bgetc(f)
+	c4 := obj.Bgetc(f)
+	obj.Bseek(f, start, 0)
 
 	magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
 	if magic == 0x7f454c46 { // \x7F E L F
@@ -881,40 +1048,33 @@
 	}
 
 	/* check the header */
-	line := Brdline(f, '\n')
-
-	var import0 int64
-	var import1 int64
-	var t string
+	line := obj.Brdline(f, '\n')
 	if line == "" {
-		if Blinelen(f) > 0 {
+		if obj.Blinelen(f) > 0 {
 			Diag("%s: not an object file", pn)
 			return
 		}
-
-		goto eof
+		Diag("truncated object file: %s", pn)
+		return
 	}
 
 	if !strings.HasPrefix(line, "go object ") {
 		if strings.HasSuffix(pn, ".go") {
-			fmt.Printf("%cl: input %s is not .%c file (use %cg to compile .go files)\n", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
-			Errorexit()
+			Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
 		}
 
 		if line == Thestring {
 			// old header format: just $GOOS
 			Diag("%s: stale object file", pn)
-
 			return
 		}
 
 		Diag("%s: not an object file", pn)
-
 		return
 	}
 
 	// First, check that the basic goos, goarch, and version match.
-	t = fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())
+	t := fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())
 
 	line = strings.TrimRight(line, "\n")
 	if !strings.HasPrefix(line[10:]+" ", t) && Debug['f'] == 0 {
@@ -935,32 +1095,166 @@
 	}
 
 	/* skip over exports and other info -- ends with \n!\n */
-	import0 = Boffset(f)
+	import0 := obj.Boffset(f)
 
 	c1 = '\n' // the last line ended in \n
-	c2 = Bgetc(f)
-	c3 = Bgetc(f)
+	c2 = obj.Bgetc(f)
+	c3 = obj.Bgetc(f)
 	for c1 != '\n' || c2 != '!' || c3 != '\n' {
 		c1 = c2
 		c2 = c3
-		c3 = Bgetc(f)
-		if c3 == Beof {
-			goto eof
+		c3 = obj.Bgetc(f)
+		if c3 == obj.Beof {
+			Diag("truncated object file: %s", pn)
+			return
 		}
 	}
 
-	import1 = Boffset(f)
+	import1 := obj.Boffset(f)
 
-	Bseek(f, import0, 0)
+	obj.Bseek(f, import0, 0)
 	ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
-	Bseek(f, import1, 0)
+	obj.Bseek(f, import1, 0)
 
-	ldobjfile(Ctxt, f, pkg, eof-Boffset(f), pn)
+	ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
+}
 
-	return
+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
+		}
+	}
+	if !found {
+		Diag("cannot find shared library: %s", shlib)
+		return
+	}
+	for _, processedname := range Ctxt.Shlibs {
+		if processedname == libpath {
+			return
+		}
+	}
+	if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil {
+		fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
+		Ctxt.Bso.Flush()
+	}
 
-eof:
-	Diag("truncated object file: %s", pn)
+	f, err := elf.Open(libpath)
+	if err != nil {
+		Diag("cannot open shared library: %s", libpath)
+		return
+	}
+	defer f.Close()
+	syms, err := f.Symbols()
+	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 {
+			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)
+			}
+		}
+	}
+
+	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
+	// list.
+	var last *LSym
+
+	for s := Ctxt.Textp; s != nil; s = s.Next {
+		if s.Type == obj.SDYNIMPORT {
+			continue
+		}
+
+		if last == nil {
+			Ctxt.Textp = s
+		} else {
+			last.Next = s
+		}
+		last = s
+	}
+
+	if last == nil {
+		Ctxt.Textp = nil
+		Ctxt.Etextp = nil
+	} else {
+		last.Next = nil
+		Ctxt.Etextp = last
+	}
+
+	Ctxt.Shlibs = append(Ctxt.Shlibs, libpath)
 }
 
 func mywhatsys() {
@@ -1131,7 +1425,8 @@
 		// external function.
 		// should never be called directly.
 		// only diagnose the direct caller.
-		if depth == 1 && s.Type != SXREF {
+		// TODO(mwhudson): actually think about this.
+		if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() {
 			Diag("call to external function %s", s.Name)
 		}
 		return -1
@@ -1172,7 +1467,7 @@
 			r = &s.R[ri]
 			switch r.Type {
 			// Direct call.
-			case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER:
+			case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER:
 				ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
 
 				ch.sym = r.Sym
@@ -1193,7 +1488,7 @@
 			// so we have to make sure it can call morestack.
 			// Arrange the data structures to report both calls, so that
 			// if there is an error, stkprint shows all the steps involved.
-			case R_CALLIND:
+			case obj.R_CALLIND:
 				ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
 
 				ch.sym = nil
@@ -1271,23 +1566,33 @@
 }
 
 func Cflush() {
-	Bflush(&coutbuf)
+	if err := coutbuf.Writer.Flush(); err != nil {
+		Exitf("flushing %s: %v", coutbuf.f.Name(), err)
+	}
 }
 
 func Cpos() int64 {
-	return Boffset(&coutbuf)
+	Cflush()
+	off, err := coutbuf.f.Seek(0, 1)
+	if err != nil {
+		Exitf("seeking in output [0, 1]: %v", err)
+	}
+	return off
 }
 
 func Cseek(p int64) {
-	Bseek(&coutbuf, p, 0)
+	Cflush()
+	if _, err := coutbuf.f.Seek(p, 0); err != nil {
+		Exitf("seeking in output [0, 1]: %v", err)
+	}
 }
 
 func Cwrite(p []byte) {
-	Bwrite(&coutbuf, p)
+	coutbuf.Write(p)
 }
 
 func Cput(c uint8) {
-	Bputc(&coutbuf, c)
+	coutbuf.WriteByte(c)
 }
 
 func usage() {
@@ -1299,8 +1604,7 @@
 func setheadtype(s string) {
 	h := headtype(s)
 	if h < 0 {
-		fmt.Fprintf(os.Stderr, "unknown header type -H %s\n", s)
-		Errorexit()
+		Exitf("unknown header type -H %s", s)
 	}
 
 	headstring = s
@@ -1313,8 +1617,7 @@
 }
 
 func doversion() {
-	fmt.Printf("%cl version %s\n", Thearch.Thechar, obj.Getgoversion())
-	Errorexit()
+	Exitf("version %s", obj.Getgoversion())
 }
 
 func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
@@ -1322,11 +1625,11 @@
 	// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
 	s := Linklookup(Ctxt, "runtime.text", 0)
 
-	if s.Type == STEXT {
+	if s.Type == obj.STEXT {
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
 	}
 	s = Linklookup(Ctxt, "runtime.etext", 0)
-	if s.Type == STEXT {
+	if s.Type == obj.STEXT {
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
 	}
 
@@ -1334,26 +1637,27 @@
 		if s.Hide != 0 || (s.Name[0] == '.' && s.Version == 0 && s.Name != ".rathole") {
 			continue
 		}
-		switch s.Type & SMASK {
-		case SCONST,
-			SRODATA,
-			SSYMTAB,
-			SPCLNTAB,
-			SINITARR,
-			SDATA,
-			SNOPTRDATA,
-			SELFROSECT,
-			SMACHOGOT,
-			STYPE,
-			SSTRING,
-			SGOSTRING,
-			SWINDOWS:
+		switch s.Type & obj.SMASK {
+		case obj.SCONST,
+			obj.SRODATA,
+			obj.SSYMTAB,
+			obj.SPCLNTAB,
+			obj.SINITARR,
+			obj.SDATA,
+			obj.SNOPTRDATA,
+			obj.SELFROSECT,
+			obj.SMACHOGOT,
+			obj.STYPE,
+			obj.SSTRING,
+			obj.SGOSTRING,
+			obj.SGOFUNC,
+			obj.SWINDOWS:
 			if !s.Reachable {
 				continue
 			}
 			put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
 
-		case SBSS, SNOPTRBSS:
+		case obj.SBSS, obj.SNOPTRBSS:
 			if !s.Reachable {
 				continue
 			}
@@ -1362,22 +1666,22 @@
 			}
 			put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
 
-		case SFILE:
+		case obj.SFILE:
 			put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
 
-		case SHOSTOBJ:
-			if HEADTYPE == Hwindows || Iself {
+		case obj.SHOSTOBJ:
+			if HEADTYPE == obj.Hwindows || Iself {
 				put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
 			}
 
-		case SDYNIMPORT:
+		case obj.SDYNIMPORT:
 			if !s.Reachable {
 				continue
 			}
 			put(s, s.Extname, 'U', 0, 0, int(s.Version), nil)
 
-		case STLSBSS:
-			if Linkmode == LinkExternal && HEADTYPE != Hopenbsd {
+		case obj.STLSBSS:
+			if Linkmode == LinkExternal && HEADTYPE != obj.Hopenbsd {
 				var type_ int
 				if goos == "android" {
 					type_ = 'B'
@@ -1400,12 +1704,12 @@
 		for a = s.Autom; a != nil; a = a.Link {
 			// Emit a or p according to actual offset, even if label is wrong.
 			// This avoids negative offsets, which cannot be encoded.
-			if a.Name != A_AUTO && a.Name != A_PARAM {
+			if a.Name != obj.A_AUTO && a.Name != obj.A_PARAM {
 				continue
 			}
 
 			// compute offset relative to FP
-			if a.Name == A_PARAM {
+			if a.Name == obj.A_PARAM {
 				off = a.Aoffset
 			} else {
 				off = a.Aoffset - int32(Thearch.Ptrsize)
@@ -1430,7 +1734,7 @@
 	if Debug['v'] != 0 || Debug['n'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
 	}
-	Bflush(&Bso)
+	Bso.Flush()
 }
 
 func Symaddr(s *LSym) int64 {
@@ -1446,6 +1750,7 @@
 	s.Value = v
 	s.Reachable = true
 	s.Special = 1
+	s.Local = true
 }
 
 func datoff(addr int64) int64 {
@@ -1468,7 +1773,7 @@
 	if s.Type == 0 {
 		return INITTEXT
 	}
-	if s.Type != STEXT {
+	if s.Type != obj.STEXT {
 		Diag("entry not text: %s", s.Name)
 	}
 	return s.Value
@@ -1483,7 +1788,7 @@
 		if r.Sym == nil { // happens for some external ARM relocs
 			continue
 		}
-		if r.Sym.Type == Sxxx || r.Sym.Type == SXREF {
+		if r.Sym.Type == obj.Sxxx || r.Sym.Type == obj.SXREF {
 			Diag("undefined: %s", r.Sym.Name)
 		}
 		if !r.Sym.Reachable {
@@ -1500,7 +1805,7 @@
 		undefsym(s)
 	}
 	if nerrors > 0 {
-		Errorexit()
+		errorexit()
 	}
 }
 
@@ -1517,7 +1822,7 @@
 			if r.Sym == nil {
 				continue
 			}
-			if (r.Type == R_CALL || r.Type == R_CALLARM || r.Type == R_CALLPOWER) && r.Sym.Type == STEXT {
+			if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM || r.Type == obj.R_CALLPOWER) && r.Sym.Type == obj.STEXT {
 				fmt.Fprintf(&Bso, "%s calls %s\n", s.Name, r.Sym.Name)
 			}
 		}
@@ -1535,8 +1840,7 @@
 
 	nerrors++
 	if nerrors > 20 {
-		fmt.Printf("too many errors\n")
-		Errorexit()
+		Exitf("too many errors")
 	}
 }
 
@@ -1562,7 +1866,7 @@
 					if r.Sym == nil {
 						continue
 					}
-					if (r.Type == R_CALL || r.Type == R_CALLARM) && r.Sym.Type == STEXT {
+					if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM) && r.Sym.Type == obj.STEXT {
 						if r.Sym.Cfunc == 1 {
 							changed = 1
 							r.Sym.Cfunc = 2
@@ -1585,7 +1889,7 @@
 				if r.Sym == nil {
 					continue
 				}
-				if (r.Type == R_CALL || r.Type == R_CALLARM) && r.Sym.Type == STEXT {
+				if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM) && r.Sym.Type == obj.STEXT {
 					if s.Cfunc == 0 && r.Sym.Cfunc == 2 && r.Sym.Nosplit == 0 {
 						fmt.Printf("Go %s calls C %s\n", s.Name, r.Sym.Name)
 					} else if s.Cfunc == 2 && s.Nosplit != 0 && r.Sym.Nosplit == 0 {
diff --git a/src/cmd/internal/ld/link.go b/src/cmd/internal/ld/link.go
index a5624ed..03da52a 100644
--- a/src/cmd/internal/ld/link.go
+++ b/src/cmd/internal/ld/link.go
@@ -30,25 +30,33 @@
 
 package ld
 
-import "encoding/binary"
+import (
+	"cmd/internal/obj"
+	"debug/elf"
+	"encoding/binary"
+)
 
 type LSym struct {
-	Name        string
-	Extname     string
-	Type        int16
-	Version     int16
-	Dupok       uint8
-	Cfunc       uint8
-	External    uint8
-	Nosplit     uint8
-	Reachable   bool
-	Cgoexport   uint8
-	Special     uint8
-	Stkcheck    uint8
-	Hide        uint8
-	Leaf        uint8
-	Localentry  uint8
-	Onlist      uint8
+	Name       string
+	Extname    string
+	Type       int16
+	Version    int16
+	Dupok      uint8
+	Cfunc      uint8
+	External   uint8
+	Nosplit    uint8
+	Reachable  bool
+	Cgoexport  uint8
+	Special    uint8
+	Stkcheck   uint8
+	Hide       uint8
+	Leaf       uint8
+	Localentry uint8
+	Onlist     uint8
+	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
+	// is not set for symbols defined by the packages being linked or by symbols
+	// read by ldelf (and so is left as elf.STT_NOTYPE).
+	ElfType     elf.SymType
 	Dynid       int32
 	Plt         int32
 	Got         int32
@@ -74,6 +82,8 @@
 	Pcln        *Pcln
 	P           []byte
 	R           []Reloc
+	Local       bool
+	gcmask      []byte
 }
 
 type Reloc struct {
@@ -104,7 +114,7 @@
 	Arch      *LinkArch
 	Debugasm  int32
 	Debugvlog int32
-	Bso       *Biobuf
+	Bso       *obj.Biobuf
 	Windows   int32
 	Goroot    string
 	Hash      map[symVer]*LSym
@@ -113,6 +123,7 @@
 	Tlsg      *LSym
 	Libdir    []string
 	Library   []Library
+	Shlibs    []string
 	Tlsoffset int
 	Diag      func(string, ...interface{})
 	Cursym    *LSym
@@ -137,6 +148,7 @@
 	Srcref string
 	File   string
 	Pkg    string
+	Shlib  string
 }
 
 type Pcln struct {
@@ -170,71 +182,6 @@
 	done    int
 }
 
-// LSym.type
-const (
-	Sxxx = iota
-	STEXT
-	SELFRXSECT
-	STYPE
-	SSTRING
-	SGOSTRING
-	SGOFUNC
-	SRODATA
-	SFUNCTAB
-	STYPELINK
-	SSYMTAB
-	SPCLNTAB
-	SELFROSECT
-	SMACHOPLT
-	SELFSECT
-	SMACHO
-	SMACHOGOT
-	SWINDOWS
-	SELFGOT
-	SNOPTRDATA
-	SINITARR
-	SDATA
-	SBSS
-	SNOPTRBSS
-	STLSBSS
-	SXREF
-	SMACHOSYMSTR
-	SMACHOSYMTAB
-	SMACHOINDIRECTPLT
-	SMACHOINDIRECTGOT
-	SFILE
-	SFILEPATH
-	SCONST
-	SDYNIMPORT
-	SHOSTOBJ
-	SSUB    = 1 << 8
-	SMASK   = SSUB - 1
-	SHIDDEN = 1 << 9
-)
-
-// Reloc.type
-const (
-	R_ADDR = 1 + iota
-	R_ADDRPOWER
-	R_SIZE
-	R_CALL
-	R_CALLARM
-	R_CALLARM64
-	R_CALLIND
-	R_CALLPOWER
-	R_CONST
-	R_PCREL
-	R_TLS
-	R_TLS_LE
-	R_TLS_IE
-	R_GOTOFF
-	R_PLT0
-	R_PLT1
-	R_PLT2
-	R_USEFIELD
-	R_POWER_TOC
-)
-
 // Reloc.variant
 const (
 	RV_NONE = iota
@@ -246,12 +193,6 @@
 	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
 )
 
-// Auto.name
-const (
-	A_AUTO = 1 + iota
-	A_PARAM
-)
-
 const (
 	LINKHASH = 100003
 )
@@ -259,33 +200,11 @@
 // Pcdata iterator.
 //	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
 
-// symbol version, incremented each time a file is loaded.
-// version==1 is reserved for savehist.
-const (
-	HistVersion = 1
-)
-
 // Link holds the context for writing object code from a compiler
 // to be linker input or for reading that input into the linker.
 
 // LinkArch is the definition of a single architecture.
 
-/* executable header types */
-const (
-	Hunknown = 0 + iota
-	Hdarwin
-	Hdragonfly
-	Helf
-	Hfreebsd
-	Hlinux
-	Hnacl
-	Hnetbsd
-	Hopenbsd
-	Hplan9
-	Hsolaris
-	Hwindows
-)
-
 const (
 	LinkAuto = 0 + iota
 	LinkInternal
diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/internal/ld/macho.go
index bff73339..ceeb7b0 100644
--- a/src/cmd/internal/ld/macho.go
+++ b/src/cmd/internal/ld/macho.go
@@ -5,6 +5,7 @@
 package ld
 
 import (
+	"cmd/internal/obj"
 	"sort"
 	"strings"
 )
@@ -63,6 +64,8 @@
 	MACHO_CPU_ARM                 = 12
 	MACHO_SUBCPU_ARM              = 0
 	MACHO_SUBCPU_ARMV7            = 9
+	MACHO_CPU_ARM64               = 1<<24 | 12
+	MACHO_SUBCPU_ARM64_ALL        = 0
 	MACHO32SYMSIZE                = 12
 	MACHO64SYMSIZE                = 16
 	MACHO_X86_64_RELOC_UNSIGNED   = 0
@@ -76,6 +79,11 @@
 	MACHO_X86_64_RELOC_SIGNED_4   = 8
 	MACHO_ARM_RELOC_VANILLA       = 0
 	MACHO_ARM_RELOC_BR24          = 5
+	MACHO_ARM64_RELOC_UNSIGNED    = 0
+	MACHO_ARM64_RELOC_BRANCH26    = 2
+	MACHO_ARM64_RELOC_PAGE21      = 3
+	MACHO_ARM64_RELOC_PAGEOFF12   = 4
+	MACHO_ARM64_RELOC_ADDEND      = 10
 	MACHO_GENERIC_RELOC_VANILLA   = 0
 	MACHO_FAKE_GOTPCREL           = 100
 )
@@ -125,7 +133,7 @@
 func Machoinit() {
 	switch Thearch.Thechar {
 	// 64-bit architectures
-	case '6', '9':
+	case '6', '7', '9':
 		macho64 = true
 
 		// 32-bit architectures
@@ -152,8 +160,7 @@
 
 func newMachoSeg(name string, msect int) *MachoSeg {
 	if nseg >= len(seg) {
-		Diag("too many segs")
-		Errorexit()
+		Exitf("too many segs")
 	}
 
 	s := &seg[nseg]
@@ -166,8 +173,7 @@
 
 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
 	if seg.nsect >= seg.msect {
-		Diag("too many sects in segment %s", seg.name)
-		Errorexit()
+		Exitf("too many sects in segment %s", seg.name)
 	}
 
 	s := &seg.sect[seg.nsect]
@@ -301,31 +307,31 @@
 	// empirically, string table must begin with " \x00".
 	s := Linklookup(Ctxt, ".machosymstr", 0)
 
-	s.Type = SMACHOSYMSTR
+	s.Type = obj.SMACHOSYMSTR
 	s.Reachable = true
 	Adduint8(Ctxt, s, ' ')
 	Adduint8(Ctxt, s, '\x00')
 
 	s = Linklookup(Ctxt, ".machosymtab", 0)
-	s.Type = SMACHOSYMTAB
+	s.Type = obj.SMACHOSYMTAB
 	s.Reachable = true
 
 	if Linkmode != LinkExternal {
 		s := Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
-		s.Type = SMACHOPLT
+		s.Type = obj.SMACHOPLT
 		s.Reachable = true
 
 		s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
-		s.Type = SMACHOGOT
+		s.Type = obj.SMACHOGOT
 		s.Reachable = true
 		s.Align = 4
 
 		s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
-		s.Type = SMACHOINDIRECTPLT
+		s.Type = obj.SMACHOINDIRECTPLT
 		s.Reachable = true
 
 		s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
-		s.Type = SMACHOINDIRECTGOT
+		s.Type = obj.SMACHOINDIRECTGOT
 		s.Reachable = true
 	}
 }
@@ -349,7 +355,15 @@
 func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
 	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
 
-	msect := newMachoSect(mseg, buf, segname)
+	var msect *MachoSect
+	if Thearch.Thechar == '7' && sect.Rwx&1 == 0 {
+		// darwin/arm64 forbids absolute relocs in __TEXT, so if
+		// the section is not executable, put it in __DATA segment.
+		msect = newMachoSect(mseg, buf, "__DATA")
+	} else {
+		msect = newMachoSect(mseg, buf, segname)
+	}
+
 	if sect.Rellen > 0 {
 		msect.reloc = uint32(sect.Reloff)
 		msect.nreloc = uint32(sect.Rellen / 8)
@@ -390,6 +404,11 @@
 		msect.flag = 6                                                     /* section with nonlazy symbol pointers */
 		msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
 	}
+
+	if sect.Name == ".init_array" {
+		msect.name = "__mod_init_func"
+		msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS
+	}
 }
 
 func Asmbmacho() {
@@ -399,9 +418,7 @@
 	mh := getMachoHdr()
 	switch Thearch.Thechar {
 	default:
-		Diag("unknown mach architecture")
-		Errorexit()
-		fallthrough
+		Exitf("unknown macho architecture: %v", Thearch.Thechar)
 
 	case '5':
 		mh.cpu = MACHO_CPU_ARM
@@ -411,6 +428,10 @@
 		mh.cpu = MACHO_CPU_AMD64
 		mh.subcpu = MACHO_SUBCPU_X86
 
+	case '7':
+		mh.cpu = MACHO_CPU_ARM64
+		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
+
 	case '8':
 		mh.cpu = MACHO_CPU_386
 		mh.subcpu = MACHO_SUBCPU_X86
@@ -467,9 +488,7 @@
 	if Linkmode != LinkExternal {
 		switch Thearch.Thechar {
 		default:
-			Diag("unknown macho architecture")
-			Errorexit()
-			fallthrough
+			Exitf("unknown macho architecture: %v", Thearch.Thechar)
 
 		case '5':
 			ml := newMachoLoad(5, 17+2)          /* unix thread */
@@ -478,11 +497,18 @@
 			ml.data[2+15] = uint32(Entryvalue()) /* start pc */
 
 		case '6':
-			ml := newMachoLoad(5, 42+2)                        /* unix thread */
-			ml.data[0] = 4                                     /* thread type */
-			ml.data[1] = 42                                    /* word count */
-			ml.data[2+32] = uint32(Entryvalue())               /* start pc */
-			ml.data[2+32+1] = uint32(Entryvalue() >> 16 >> 16) // hide >>32 for 8l
+			ml := newMachoLoad(5, 42+2)          /* unix thread */
+			ml.data[0] = 4                       /* thread type */
+			ml.data[1] = 42                      /* word count */
+			ml.data[2+32] = uint32(Entryvalue()) /* start pc */
+			ml.data[2+32+1] = uint32(Entryvalue() >> 32)
+
+		case '7':
+			ml := newMachoLoad(5, 68+2)          /* unix thread */
+			ml.data[0] = 6                       /* thread type */
+			ml.data[1] = 68                      /* word count */
+			ml.data[2+64] = uint32(Entryvalue()) /* start pc */
+			ml.data[2+64+1] = uint32(Entryvalue() >> 32)
 
 		case '8':
 			ml := newMachoLoad(5, 16+2)          /* unix thread */
@@ -541,12 +567,12 @@
 
 	a := machowrite()
 	if int32(a) > HEADR {
-		Diag("HEADR too small: %d > %d", a, HEADR)
+		Exitf("HEADR too small: %d > %d", a, HEADR)
 	}
 }
 
 func symkind(s *LSym) int {
-	if s.Type == SDYNIMPORT {
+	if s.Type == obj.SDYNIMPORT {
 		return SymKindUndef
 	}
 	if s.Cgoexport != 0 {
@@ -602,7 +628,7 @@
 func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 	genasmsym(put)
 	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-		if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
+		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
 			if s.Reachable {
 				put(s, "", 'D', 0, 0, 0, nil)
 			}
@@ -660,7 +686,7 @@
 			Adduint8(Ctxt, symstr, '\x00')
 		}
 
-		if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
+		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
 			Adduint8(Ctxt, symtab, 0x01)                // type N_EXT, external symbol
 			Adduint8(Ctxt, symtab, 0)                   // no section
 			Adduint16(Ctxt, symtab, 0)                  // desc
diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/internal/ld/objfile.go
index 34176be..3d59323 100644
--- a/src/cmd/internal/ld/objfile.go
+++ b/src/cmd/internal/ld/objfile.go
@@ -6,6 +6,7 @@
 
 import (
 	"bytes"
+	"cmd/internal/obj"
 	"fmt"
 	"log"
 	"strconv"
@@ -17,15 +18,15 @@
 	endmagic   = "\xff\xffgo13ld"
 )
 
-func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) {
-	start := Boffset(f)
+func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
+	start := obj.Boffset(f)
 	ctxt.Version++
 	var buf [8]uint8
-	Bread(f, buf[:])
+	obj.Bread(f, buf[:])
 	if string(buf[:]) != startmagic {
 		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
 	}
-	c := Bgetc(f)
+	c := obj.Bgetc(f)
 	if c != 1 {
 		log.Fatalf("%s: invalid file version number %d", pn, c)
 	}
@@ -40,29 +41,31 @@
 	}
 
 	for {
-		c = Bgetc(f)
-		Bungetc(f)
-		if c == 0xff {
+		c, err := f.Peek(1)
+		if err != nil {
+			log.Fatalf("%s: peeking: %v", pn, err)
+		}
+		if c[0] == 0xff {
 			break
 		}
 		readsym(ctxt, f, pkg, pn)
 	}
 
 	buf = [8]uint8{}
-	Bread(f, buf[:])
+	obj.Bread(f, buf[:])
 	if string(buf[:]) != endmagic {
 		log.Fatalf("%s: invalid file end", pn)
 	}
 
-	if Boffset(f) != start+length {
-		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(Boffset(f)), int64(start+length))
+	if obj.Boffset(f) != start+length {
+		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
 	}
 }
 
 var readsym_ndup int
 
-func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
-	if Bgetc(f) != 0xfe {
+func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
+	if obj.Bgetc(f) != 0xfe {
 		log.Fatalf("readsym out of sync")
 	}
 	t := int(rdint(f))
@@ -71,12 +74,15 @@
 	if v != 0 && v != 1 {
 		log.Fatalf("invalid symbol version %d", v)
 	}
-	dupok := int(rdint(f))
-	dupok &= 1
+	flags := int(rdint(f))
+	dupok := flags & 1
+	local := false
+	if flags&2 != 0 {
+		local = true
+	}
 	size := int(rdint(f))
 	typ := rdsym(ctxt, f, pkg)
-	var data []byte
-	rddata(f, &data)
+	data := rddata(f)
 	nreloc := int(rdint(f))
 
 	if v != 0 {
@@ -84,8 +90,8 @@
 	}
 	s := Linklookup(ctxt, name, v)
 	var dup *LSym
-	if s.Type != 0 && s.Type != SXREF {
-		if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
+	if s.Type != 0 && s.Type != obj.SXREF {
+		if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
 			if s.Size < int64(size) {
 				s.Size = int64(size)
 			}
@@ -95,10 +101,10 @@
 			return
 		}
 
-		if (s.Type == SDATA || s.Type == SBSS || s.Type == SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
+		if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
 			goto overwrite
 		}
-		if s.Type != SBSS && s.Type != SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
+		if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
 			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
 		}
 		if len(s.P) > 0 {
@@ -111,19 +117,20 @@
 overwrite:
 	s.File = pkg
 	s.Dupok = uint8(dupok)
-	if t == SXREF {
+	if t == obj.SXREF {
 		log.Fatalf("bad sxref")
 	}
 	if t == 0 {
 		log.Fatalf("missing type for %s in %s", name, pn)
 	}
-	if t == SBSS && (s.Type == SRODATA || s.Type == SNOPTRBSS) {
+	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
 		t = int(s.Type)
 	}
 	s.Type = int16(t)
 	if s.Size < int64(size) {
 		s.Size = int64(size)
 	}
+	s.Local = local
 	if typ != nil { // if bss sym defined multiple times, take type from any one def
 		s.Gotype = typ
 	}
@@ -142,9 +149,9 @@
 			r.Siz = uint8(rdint(f))
 			r.Type = int32(rdint(f))
 			r.Add = rdint(f)
-			r.Xadd = rdint(f)
+			rdint(f) // Xadd, ignored
 			r.Sym = rdsym(ctxt, f, pkg)
-			r.Xsym = rdsym(ctxt, f, pkg)
+			rdsym(ctxt, f, pkg) // Xsym, ignored
 		}
 	}
 
@@ -156,7 +163,7 @@
 		}
 	}
 
-	if s.Type == STEXT {
+	if s.Type == obj.STEXT {
 		s.Args = int32(rdint(f))
 		s.Locals = int32(rdint(f))
 		s.Nosplit = uint8(rdint(f))
@@ -177,14 +184,14 @@
 
 		s.Pcln = new(Pcln)
 		pc := s.Pcln
-		rddata(f, &pc.Pcsp.P)
-		rddata(f, &pc.Pcfile.P)
-		rddata(f, &pc.Pcline.P)
+		pc.Pcsp.P = rddata(f)
+		pc.Pcfile.P = rddata(f)
+		pc.Pcline.P = rddata(f)
 		n = int(rdint(f))
 		pc.Pcdata = make([]Pcdata, n)
 		pc.Npcdata = n
 		for i := 0; i < n; i++ {
-			rddata(f, &pc.Pcdata[i].P)
+			pc.Pcdata[i].P = rddata(f)
 		}
 		n = int(rdint(f))
 		pc.Funcdata = make([]*LSym, n)
@@ -235,7 +242,7 @@
 			fmt.Fprintf(ctxt.Bso, "nosplit ")
 		}
 		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
-		if s.Type == STEXT {
+		if s.Type == obj.STEXT {
 			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
 		}
 		fmt.Fprintf(ctxt.Bso, "\n")
@@ -271,7 +278,7 @@
 	}
 }
 
-func rdint(f *Biobuf) int64 {
+func rdint(f *obj.Biobuf) int64 {
 	var c int
 
 	uv := uint64(0)
@@ -279,7 +286,7 @@
 		if shift >= 64 {
 			log.Fatalf("corrupt input")
 		}
-		c = Bgetc(f)
+		c = obj.Bgetc(f)
 		uv |= uint64(c&0x7F) << uint(shift)
 		if c&0x80 == 0 {
 			break
@@ -289,22 +296,23 @@
 	return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
 }
 
-func rdstring(f *Biobuf) string {
+func rdstring(f *obj.Biobuf) string {
 	n := rdint(f)
 	p := make([]byte, n)
-	Bread(f, p)
+	obj.Bread(f, p)
 	return string(p)
 }
 
-func rddata(f *Biobuf, pp *[]byte) {
+func rddata(f *obj.Biobuf) []byte {
 	n := rdint(f)
-	*pp = make([]byte, n)
-	Bread(f, *pp)
+	p := make([]byte, n)
+	obj.Bread(f, p)
+	return p
 }
 
 var symbuf []byte
 
-func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
+func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym {
 	n := int(rdint(f))
 	if n == 0 {
 		rdint(f)
@@ -314,7 +322,7 @@
 	if len(symbuf) < n {
 		symbuf = make([]byte, n)
 	}
-	Bread(f, symbuf[:n])
+	obj.Bread(f, symbuf[:n])
 	p := string(symbuf[:n])
 	v := int(rdint(f))
 	if v != 0 {
@@ -326,17 +334,21 @@
 		if strings.HasPrefix(s.Name, "$f32.") {
 			x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
 			i32 := int32(x)
-			s.Type = SRODATA
+			s.Type = obj.SRODATA
+			s.Local = true
 			Adduint32(ctxt, s, uint32(i32))
 			s.Reachable = false
 		} else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
 			x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
 			i64 := int64(x)
-			s.Type = SRODATA
+			s.Type = obj.SRODATA
+			s.Local = true
 			Adduint64(ctxt, s, uint64(i64))
 			s.Reachable = false
 		}
 	}
-
+	if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
+		s.Local = true
+	}
 	return s
 }
diff --git a/src/cmd/internal/ld/pcln.go b/src/cmd/internal/ld/pcln.go
index 0250ca0..be2568d 100644
--- a/src/cmd/internal/ld/pcln.go
+++ b/src/cmd/internal/ld/pcln.go
@@ -143,10 +143,10 @@
 	// Give files numbers.
 	for i := 0; i < len(files); i++ {
 		f = files[i]
-		if f.Type != SFILEPATH {
+		if f.Type != obj.SFILEPATH {
 			ctxt.Nhistfile++
 			f.Value = int64(ctxt.Nhistfile)
-			f.Type = SFILEPATH
+			f.Type = obj.SFILEPATH
 			f.Next = ctxt.Filesyms
 			ctxt.Filesyms = f
 		}
@@ -202,10 +202,17 @@
 
 var pclntab_zpcln Pcln
 
+// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
+var pclntabNfunc int32
+var pclntabFiletabOffset int32
+var pclntabPclntabOffset int32
+var pclntabFirstFunc *LSym
+var pclntabLastFunc *LSym
+
 func pclntab() {
 	funcdata_bytes := int64(0)
 	ftab := Linklookup(Ctxt, "runtime.pclntab", 0)
-	ftab.Type = SPCLNTAB
+	ftab.Type = obj.SPCLNTAB
 	ftab.Reachable = true
 
 	// See golang.org/s/go12symtab for the format. Briefly:
@@ -222,11 +229,13 @@
 		}
 	}
 
+	pclntabNfunc = nfunc
 	Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
 	setuint32(Ctxt, ftab, 0, 0xfffffffb)
 	setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
 	setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
 	setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
+	pclntabPclntabOffset = int32(8 + Thearch.Ptrsize)
 
 	nfunc = 0
 	var last *LSym
@@ -246,6 +255,10 @@
 			pcln = &pclntab_zpcln
 		}
 
+		if pclntabFirstFunc == nil {
+			pclntabFirstFunc = Ctxt.Cursym
+		}
+
 		funcstart = int32(len(ftab.P))
 		funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
 
@@ -285,7 +298,7 @@
 				for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
 					if it.value < 1 || it.value > Ctxt.Nhistfile {
 						Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile)
-						Errorexit()
+						errorexit()
 					}
 				}
 			}
@@ -324,12 +337,13 @@
 
 		if off != end {
 			Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln.Npcdata, pcln.Nfuncdata, Thearch.Ptrsize)
-			Errorexit()
+			errorexit()
 		}
 
 		nfunc++
 	}
 
+	pclntabLastFunc = last
 	// Final entry of table is just end pc.
 	setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
 
@@ -337,6 +351,7 @@
 	start := int32(len(ftab.P))
 
 	start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+	pclntabFiletabOffset = start
 	setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
 
 	Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
@@ -363,8 +378,9 @@
 // function for a pc.  See src/runtime/symtab.go:findfunc for details.
 func findfunctab() {
 	t := Linklookup(Ctxt, "runtime.findfunctab", 0)
-	t.Type = SRODATA
+	t.Type = obj.SRODATA
 	t.Reachable = true
+	t.Local = true
 
 	// find min and max address
 	min := Ctxt.Textp.Value
diff --git a/src/cmd/internal/ld/pe.go b/src/cmd/internal/ld/pe.go
index 53bf0af..cb82c05 100644
--- a/src/cmd/internal/ld/pe.go
+++ b/src/cmd/internal/ld/pe.go
@@ -5,6 +5,7 @@
 package ld
 
 import (
+	"cmd/internal/obj"
 	"encoding/binary"
 	"fmt"
 	"sort"
@@ -389,7 +390,7 @@
 func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
 	if pensect == 16 {
 		Diag("too many sections")
-		Errorexit()
+		errorexit()
 	}
 
 	h := &sh[pensect]
@@ -410,19 +411,19 @@
 func chksectoff(h *IMAGE_SECTION_HEADER, off int64) {
 	if off != int64(h.PointerToRawData) {
 		Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
-		Errorexit()
+		errorexit()
 	}
 }
 
 func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
 	if s.Vaddr-PEBASE != uint64(h.VirtualAddress) {
 		Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
-		Errorexit()
+		errorexit()
 	}
 
 	if s.Fileoff != uint64(h.PointerToRawData) {
 		Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
-		Errorexit()
+		errorexit()
 	}
 }
 
@@ -450,9 +451,9 @@
 	nextfileoff = int(PEFILEHEADR)
 
 	// some mingw libs depend on this symbol, for example, FindPESectionByName
-	xdefine("__image_base__", SDATA, PEBASE)
+	xdefine("__image_base__", obj.SDATA, PEBASE)
 
-	xdefine("_image_base__", SDATA, PEBASE)
+	xdefine("_image_base__", obj.SDATA, PEBASE)
 }
 
 func pewrite() {
@@ -473,7 +474,7 @@
 }
 
 func strput(s string) {
-	coutbuf.w.WriteString(s)
+	coutbuf.WriteString(s)
 	Cput(0)
 	// string must be padded to even size
 	if (len(s)+1)%2 != 0 {
@@ -487,7 +488,7 @@
 	dr = nil
 	var m *Imp
 	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-		if !s.Reachable || s.Type != SDYNIMPORT {
+		if !s.Reachable || s.Type != obj.SDYNIMPORT {
 			continue
 		}
 		for d = dr; d != nil; d = d.next {
@@ -529,7 +530,7 @@
 		// Add real symbol name
 		for d := dr; d != nil; d = d.next {
 			for m = d.ms; m != nil; m = m.next {
-				m.s.Type = SDATA
+				m.s.Type = obj.SDATA
 				Symgrow(Ctxt, m.s, int64(Thearch.Ptrsize))
 				dynName := m.s.Extname
 				// only windows/386 requires stdcall decoration
@@ -538,12 +539,12 @@
 				}
 				dynSym := Linklookup(Ctxt, dynName, 0)
 				dynSym.Reachable = true
-				dynSym.Type = SHOSTOBJ
+				dynSym.Type = obj.SHOSTOBJ
 				r := Addrel(m.s)
 				r.Sym = dynSym
 				r.Off = 0
 				r.Siz = uint8(Thearch.Ptrsize)
-				r.Type = R_ADDR
+				r.Type = obj.R_ADDR
 
 				// pre-allocate symtab entries for those symbols
 				dynSym.Dynid = int32(ncoffsym)
@@ -553,10 +554,10 @@
 	} else {
 		dynamic := Linklookup(Ctxt, ".windynamic", 0)
 		dynamic.Reachable = true
-		dynamic.Type = SWINDOWS
+		dynamic.Type = obj.SWINDOWS
 		for d := dr; d != nil; d = d.next {
 			for m = d.ms; m != nil; m = m.next {
-				m.s.Type = SWINDOWS | SSUB
+				m.s.Type = obj.SWINDOWS | obj.SSUB
 				m.s.Sub = dynamic.Sub
 				dynamic.Sub = m.s
 				m.s.Value = dynamic.Size
@@ -711,7 +712,7 @@
 		}
 		if nexport+1 > len(dexport) {
 			Diag("pe dynexport table is full")
-			Errorexit()
+			errorexit()
 		}
 
 		dexport[nexport] = s
@@ -902,7 +903,7 @@
 	rel := Linklookup(Ctxt, ".rel", 0)
 
 	rel.Reachable = true
-	rel.Type = SELFROSECT
+	rel.Type = obj.SELFROSECT
 
 	initdynimport()
 	initdynexport()
@@ -954,7 +955,7 @@
 
 	if coffsym != nil {
 		// only windows/386 requires underscore prefix on external symbols
-		if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == SHOSTOBJ || s.Cgoexport != 0) && s.Name == s.Extname {
+		if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == obj.SHOSTOBJ || s.Cgoexport != 0) && s.Name == s.Extname {
 			s.Name = "_" + s.Name
 		}
 		cs := &coffsym[ncoffsym]
@@ -964,7 +965,7 @@
 		}
 		// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
 		// it still belongs to the .data section, not the .bss section.
-		if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != SDATA && Linkmode == LinkExternal {
+		if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal {
 			cs.value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
 			cs.sect = bsssect
 		} else if uint64(s.Value) >= Segdata.Vaddr {
@@ -1096,13 +1097,9 @@
 func Asmbpe() {
 	switch Thearch.Thechar {
 	default:
-		Diag("unknown PE architecture")
-		Errorexit()
-		fallthrough
-
+		Exitf("unknown PE architecture: %v", Thearch.Thechar)
 	case '6':
 		fh.Machine = IMAGE_FILE_MACHINE_AMD64
-
 	case '8':
 		fh.Machine = IMAGE_FILE_MACHINE_I386
 	}
@@ -1228,12 +1225,13 @@
 	// for other threads we specify stack size in runtime explicitly
 	// (runtime knows whether cgo is enabled or not).
 	// If you change stack reserve sizes here,
-	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c as well.
+	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c and correspondent
+	// CreateThread parameter in runtime.newosproc as well.
 	if !iscgo {
-		oh64.SizeOfStackReserve = 0x00010000
-		oh.SizeOfStackReserve = 0x00010000
-		oh64.SizeOfStackCommit = 0x0000ffff
-		oh.SizeOfStackCommit = 0x0000ffff
+		oh64.SizeOfStackReserve = 0x00020000
+		oh.SizeOfStackReserve = 0x00020000
+		oh64.SizeOfStackCommit = 0x00001000
+		oh.SizeOfStackCommit = 0x00001000
 	} else {
 		oh64.SizeOfStackReserve = 0x00200000
 		oh.SizeOfStackReserve = 0x00100000
diff --git a/src/cmd/internal/ld/pobj.go b/src/cmd/internal/ld/pobj.go
index 221f2b0..8568744 100644
--- a/src/cmd/internal/ld/pobj.go
+++ b/src/cmd/internal/ld/pobj.go
@@ -38,6 +38,8 @@
 	"strings"
 )
 
+var pkglistfornote []byte
+
 // Reading object files.
 
 func Ldmain() {
@@ -47,7 +49,7 @@
 	Ctxt.Diag = Diag
 	Ctxt.Bso = &Bso
 
-	Bso = *Binitw(os.Stdout)
+	Bso = *obj.Binitw(os.Stdout)
 	Debug = [128]int{}
 	nerrors = 0
 	outfile = ""
@@ -75,16 +77,16 @@
 	if Thearch.Thechar == '6' {
 		obj.Flagcount("8", "assume 64-bit addresses", &Debug['8'])
 	}
-	obj.Flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo)
+	obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
 	obj.Flagcount("C", "check Go calls to C code", &Debug['C'])
-	obj.Flagint64("D", "addr: data address", &INITDAT)
-	obj.Flagstr("E", "sym: entry symbol", &INITENTRY)
+	obj.Flagint64("D", "set data segment `address`", &INITDAT)
+	obj.Flagstr("E", "set `entry` symbol name", &INITENTRY)
 	if Thearch.Thechar == '5' {
 		obj.Flagcount("G", "debug pseudo-ops", &Debug['G'])
 	}
-	obj.Flagfn1("I", "interp: set ELF interp", setinterp)
-	obj.Flagfn1("L", "dir: add dir to library path", Lflag)
-	obj.Flagfn1("H", "head: header type", setheadtype)
+	obj.Flagfn1("I", "use `linker` as ELF dynamic linker", setinterp)
+	obj.Flagfn1("L", "add specified `directory` to library path", Lflag)
+	obj.Flagfn1("H", "set header `type`", setheadtype)
 	obj.Flagcount("K", "add stack underflow checks", &Debug['K'])
 	if Thearch.Thechar == '5' {
 		obj.Flagcount("M", "disable software div/mod", &Debug['M'])
@@ -94,32 +96,35 @@
 	if Thearch.Thechar == '5' {
 		obj.Flagcount("P", "debug code generation", &Debug['P'])
 	}
-	obj.Flagint32("R", "rnd: address rounding", &INITRND)
+	obj.Flagint32("R", "set address rounding `quantum`", &INITRND)
 	obj.Flagcount("nil", "check type signatures", &Debug['S'])
-	obj.Flagint64("T", "addr: text address", &INITTEXT)
+	obj.Flagint64("T", "set text segment `address`", &INITTEXT)
 	obj.Flagfn0("V", "print version and exit", doversion)
 	obj.Flagcount("W", "disassemble input", &Debug['W'])
-	obj.Flagfn1("X", "name value: define string data", addstrdata1)
+	obj.Flagfn1("X", "set the value of a string variable; the next two arguments are its name and value", addstrdata1)
 	obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
 	obj.Flagcount("a", "disassemble output", &Debug['a'])
+	flag.Var(&Buildmode, "buildmode", "set build `mode`")
 	obj.Flagcount("c", "dump call graph", &Debug['c'])
 	obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
-	obj.Flagstr("extld", "ld: linker to run in external mode", &extld)
-	obj.Flagstr("extldflags", "ldflags: flags for external linker", &extldflags)
+	obj.Flagstr("extld", "use `linker` when linking in external mode", &extld)
+	obj.Flagstr("extldflags", "pass `flags` to external linker", &extldflags)
 	obj.Flagcount("f", "ignore version mismatch", &Debug['f'])
 	obj.Flagcount("g", "disable go package data checks", &Debug['g'])
-	obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
-	obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
-	obj.Flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode)
+	obj.Flagstr("installsuffix", "set package directory `suffix`", &flag_installsuffix)
+	obj.Flagstr("k", "set field tracking `symbol`", &tracksym)
+	obj.Flagfn1("linkmode", "set link `mode` (internal, external, auto)", setlinkmode)
+	flag.BoolVar(&Linkshared, "linkshared", false, "link against installed Go shared libraries")
 	obj.Flagcount("n", "dump symbol table", &Debug['n'])
-	obj.Flagstr("o", "outfile: set output file", &outfile)
-	obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
+	obj.Flagstr("o", "write output to `file`", &outfile)
+	flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
 	obj.Flagcount("race", "enable race detector", &flag_race)
 	obj.Flagcount("s", "disable symbol table", &Debug['s'])
+	var flagShared int
 	if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
-		obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &Flag_shared)
+		obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
 	}
-	obj.Flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir)
+	obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir)
 	obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
 	obj.Flagcount("v", "print link trace", &Debug['v'])
 	obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
@@ -135,19 +140,27 @@
 			i++
 		}
 	}
-	obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
-	obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
+	obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
+	obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
+	obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
 	obj.Flagparse(usage)
 	startProfile()
 	Ctxt.Bso = &Bso
 	Ctxt.Debugvlog = int32(Debug['v'])
+	if flagShared != 0 {
+		if Buildmode == BuildmodeExe {
+			Buildmode = BuildmodeCShared
+		} else if Buildmode != BuildmodeCShared {
+			Exitf("-shared and -buildmode=%s are incompatible", Buildmode.String())
+		}
+	}
 
-	if flag.NArg() != 1 {
+	if Buildmode != BuildmodeShared && flag.NArg() != 1 {
 		usage()
 	}
 
 	if outfile == "" {
-		if HEADTYPE == Hwindows {
+		if HEADTYPE == obj.Hwindows {
 			outfile = fmt.Sprintf("%c.out.exe", Thearch.Thechar)
 		} else {
 			outfile = fmt.Sprintf("%c.out", Thearch.Thechar)
@@ -166,12 +179,32 @@
 
 	Thearch.Archinit()
 
+	if Linkshared && !Iself {
+		Exitf("-linkshared can only be used on elf systems")
+	}
+
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
 	}
-	Bflush(&Bso)
+	Bso.Flush()
 
-	addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
+	if Buildmode == BuildmodeShared {
+		for i := 0; i < flag.NArg(); i++ {
+			arg := flag.Arg(i)
+			parts := strings.SplitN(arg, "=", 2)
+			var pkgpath, file string
+			if len(parts) == 1 {
+				pkgpath, file = "main", arg
+			} else {
+				pkgpath, file = parts[0], parts[1]
+			}
+			pkglistfornote = append(pkglistfornote, pkgpath...)
+			pkglistfornote = append(pkglistfornote, '\n')
+			addlibpath(Ctxt, "command line", "command line", file, pkgpath, "")
+		}
+	} else {
+		addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main", "")
+	}
 	loadlib()
 
 	if Thearch.Thechar == '5' {
@@ -187,11 +220,11 @@
 	callgraph()
 
 	doelf()
-	if HEADTYPE == Hdarwin {
+	if HEADTYPE == obj.Hdarwin {
 		domacho()
 	}
 	dostkcheck()
-	if HEADTYPE == Hwindows {
+	if HEADTYPE == obj.Hwindows {
 		dope()
 	}
 	addexport()
@@ -207,13 +240,14 @@
 	Thearch.Asmb()
 	undef()
 	hostlink()
+	archive()
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime())
 		fmt.Fprintf(&Bso, "%d symbols\n", Ctxt.Nsymbol)
 		fmt.Fprintf(&Bso, "%d liveness data\n", liveness)
 	}
 
-	Bflush(&Bso)
+	Bso.Flush()
 
-	Errorexit()
+	errorexit()
 }
diff --git a/src/cmd/internal/ld/sym.go b/src/cmd/internal/ld/sym.go
index d0a80e6..652109d 100644
--- a/src/cmd/internal/ld/sym.go
+++ b/src/cmd/internal/ld/sym.go
@@ -33,10 +33,10 @@
 
 import (
 	"cmd/internal/obj"
-	"fmt"
 	"log"
 	"os"
 	"path/filepath"
+	"strconv"
 )
 
 func yy_isalpha(c int) bool {
@@ -47,26 +47,26 @@
 	name string
 	val  int
 }{
-	{"darwin", Hdarwin},
-	{"dragonfly", Hdragonfly},
-	{"elf", Helf},
-	{"freebsd", Hfreebsd},
-	{"linux", Hlinux},
-	{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
-	{"nacl", Hnacl},
-	{"netbsd", Hnetbsd},
-	{"openbsd", Hopenbsd},
-	{"plan9", Hplan9},
-	{"solaris", Hsolaris},
-	{"windows", Hwindows},
-	{"windowsgui", Hwindows},
+	{"darwin", obj.Hdarwin},
+	{"dragonfly", obj.Hdragonfly},
+	{"elf", obj.Helf},
+	{"freebsd", obj.Hfreebsd},
+	{"linux", obj.Hlinux},
+	{"android", obj.Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
+	{"nacl", obj.Hnacl},
+	{"netbsd", obj.Hnetbsd},
+	{"openbsd", obj.Hopenbsd},
+	{"plan9", obj.Hplan9},
+	{"solaris", obj.Hsolaris},
+	{"windows", obj.Hwindows},
+	{"windowsgui", obj.Hwindows},
 }
 
 func linknew(arch *LinkArch) *Link {
 	ctxt := new(Link)
 	ctxt.Hash = make(map[symVer]*LSym)
 	ctxt.Arch = arch
-	ctxt.Version = HistVersion
+	ctxt.Version = obj.HistVersion
 	ctxt.Goroot = obj.Getgoroot()
 
 	p := obj.Getgoarch()
@@ -92,7 +92,7 @@
 	default:
 		log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
 
-	case Hplan9, Hwindows:
+	case obj.Hplan9, obj.Hwindows:
 		break
 
 		/*
@@ -100,15 +100,15 @@
 		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
 		 * Known to low-level assembly in package runtime and runtime/cgo.
 		 */
-	case Hlinux,
-		Hfreebsd,
-		Hnetbsd,
-		Hopenbsd,
-		Hdragonfly,
-		Hsolaris:
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hdragonfly,
+		obj.Hsolaris:
 		ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
 
-	case Hnacl:
+	case obj.Hnacl:
 		switch ctxt.Arch.Thechar {
 		default:
 			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
@@ -127,19 +127,22 @@
 		 * OS X system constants - offset from 0(GS) to our TLS.
 		 * Explained in ../../runtime/cgo/gcc_darwin_*.c.
 		 */
-	case Hdarwin:
+	case obj.Hdarwin:
 		switch ctxt.Arch.Thechar {
 		default:
 			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
 
+		case '5':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
 		case '6':
 			ctxt.Tlsoffset = 0x8a0
 
+		case '7':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
 		case '8':
 			ctxt.Tlsoffset = 0x468
-
-		case '5':
-			ctxt.Tlsoffset = 0 // dummy value, not needed
 		}
 	}
 
@@ -205,16 +208,13 @@
 	return _lookup(ctxt, name, v, 0)
 }
 
-var headstr_buf string
-
 func Headstr(v int) string {
 	for i := 0; i < len(headers); i++ {
 		if v == headers[i].val {
 			return headers[i].name
 		}
 	}
-	headstr_buf = fmt.Sprintf("%d", v)
-	return headstr_buf
+	return strconv.Itoa(v)
 }
 
 func headtype(name string) int {
diff --git a/src/cmd/internal/ld/symtab.go b/src/cmd/internal/ld/symtab.go
index d667d1c..d6e79dc 100644
--- a/src/cmd/internal/ld/symtab.go
+++ b/src/cmd/internal/ld/symtab.go
@@ -30,7 +30,10 @@
 
 package ld
 
-import "strings"
+import (
+	"cmd/internal/obj"
+	"strings"
+)
 
 // Symbol table.
 
@@ -40,8 +43,13 @@
 		putelfstr("")
 	}
 
-	// Rewrite · to . for ASCII-only tools like DTrace (sigh)
-	s = strings.Replace(s, "·", ".", -1)
+	// When dynamically linking, we create LSym's by reading the names from
+	// the symbol tables of the shared libraries and so the names need to
+	// match exactly.  Tools like DTrace will have to wait for now.
+	if !DynlinkingGo() {
+		// Rewrite · to . for ASCII-only tools like DTrace (sigh)
+		s = strings.Replace(s, "·", ".", -1)
+	}
 
 	n := len(s) + 1
 	for len(Elfstrdat)+n > cap(Elfstrdat) {
@@ -98,7 +106,9 @@
 		type_ = STT_OBJECT
 
 	case 'U':
-		type_ = STT_NOTYPE
+		// ElfType is only set for symbols read from Go shared libraries, but
+		// for other symbols it is left as STT_NOTYPE which is fine.
+		type_ = int(x.ElfType)
 
 	case 't':
 		type_ = STT_TLS
@@ -110,7 +120,7 @@
 	}
 
 	var elfshnum int
-	if xo.Type == SDYNIMPORT || xo.Type == SHOSTOBJ {
+	if xo.Type == obj.SDYNIMPORT || xo.Type == obj.SHOSTOBJ {
 		elfshnum = SHN_UNDEF
 	} else {
 		if xo.Sect == nil {
@@ -118,19 +128,19 @@
 			Diag("missing section in putelfsym")
 			return
 		}
-		if (xo.Sect.(*Section)).Elfsect == nil {
+		if xo.Sect.(*Section).Elfsect == nil {
 			Ctxt.Cursym = x
 			Diag("missing ELF section in putelfsym")
 			return
 		}
-		elfshnum = ((xo.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum
+		elfshnum = xo.Sect.(*Section).Elfsect.(*ElfShdr).shnum
 	}
 
 	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
 	// maybe one day STB_WEAK.
 	bind := STB_GLOBAL
 
-	if ver != 0 || (x.Type&SHIDDEN != 0) {
+	if ver != 0 || (x.Type&obj.SHIDDEN != 0) || x.Local {
 		bind = STB_LOCAL
 	}
 
@@ -138,7 +148,8 @@
 	// to get the exported symbols put into the dynamic symbol table.
 	// To avoid filling the dynamic table with lots of unnecessary symbols,
 	// mark all Go symbols local (not global) in the final executable.
-	if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
+	// But when we're dynamically linking, we need all those global symbols.
+	if !DynlinkingGo() && Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
 		bind = STB_LOCAL
 	}
 
@@ -148,10 +159,10 @@
 
 	off := putelfstr(s)
 	if Linkmode == LinkExternal && elfshnum != SHN_UNDEF {
-		addr -= int64((xo.Sect.(*Section)).Vaddr)
+		addr -= int64(xo.Sect.(*Section).Vaddr)
 	}
 	other := STV_DEFAULT
-	if x.Type&SHIDDEN != 0 {
+	if x.Type&obj.SHIDDEN != 0 {
 		other = STV_HIDDEN
 	}
 	putelfsyment(off, addr, size, bind<<4|type_&0xf, elfshnum, other)
@@ -167,11 +178,9 @@
 
 func putelfsymshndx(sympos int64, shndx int) {
 	here := Cpos()
-	switch Thearch.Thechar {
-	case '6':
+	if elf64 {
 		Cseek(sympos + 6)
-
-	default:
+	} else {
 		Cseek(sympos + 14)
 	}
 
@@ -208,7 +217,7 @@
 		'Z',
 		'm':
 		l := 4
-		if HEADTYPE == Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
+		if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
 			Lputb(uint32(addr >> 32))
 			l = 8
 		}
@@ -290,55 +299,60 @@
 
 	// Define these so that they'll get put into the symbol table.
 	// data.c:/^address will provide the actual values.
-	xdefine("runtime.text", STEXT, 0)
+	xdefine("runtime.text", obj.STEXT, 0)
 
-	xdefine("runtime.etext", STEXT, 0)
-	xdefine("runtime.typelink", SRODATA, 0)
-	xdefine("runtime.etypelink", SRODATA, 0)
-	xdefine("runtime.rodata", SRODATA, 0)
-	xdefine("runtime.erodata", SRODATA, 0)
-	xdefine("runtime.noptrdata", SNOPTRDATA, 0)
-	xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
-	xdefine("runtime.data", SDATA, 0)
-	xdefine("runtime.edata", SDATA, 0)
-	xdefine("runtime.bss", SBSS, 0)
-	xdefine("runtime.ebss", SBSS, 0)
-	xdefine("runtime.noptrbss", SNOPTRBSS, 0)
-	xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
-	xdefine("runtime.end", SBSS, 0)
-	xdefine("runtime.epclntab", SRODATA, 0)
-	xdefine("runtime.esymtab", SRODATA, 0)
+	xdefine("runtime.etext", obj.STEXT, 0)
+	xdefine("runtime.typelink", obj.SRODATA, 0)
+	xdefine("runtime.etypelink", obj.SRODATA, 0)
+	xdefine("runtime.rodata", obj.SRODATA, 0)
+	xdefine("runtime.erodata", obj.SRODATA, 0)
+	xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0)
+	xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0)
+	xdefine("runtime.data", obj.SDATA, 0)
+	xdefine("runtime.edata", obj.SDATA, 0)
+	xdefine("runtime.bss", obj.SBSS, 0)
+	xdefine("runtime.ebss", obj.SBSS, 0)
+	xdefine("runtime.noptrbss", obj.SNOPTRBSS, 0)
+	xdefine("runtime.enoptrbss", obj.SNOPTRBSS, 0)
+	xdefine("runtime.end", obj.SBSS, 0)
+	xdefine("runtime.epclntab", obj.SRODATA, 0)
+	xdefine("runtime.esymtab", obj.SRODATA, 0)
 
 	// garbage collection symbols
 	s := Linklookup(Ctxt, "runtime.gcdata", 0)
 
-	s.Type = SRODATA
+	s.Type = obj.SRODATA
 	s.Size = 0
 	s.Reachable = true
-	xdefine("runtime.egcdata", SRODATA, 0)
+	xdefine("runtime.egcdata", obj.SRODATA, 0)
 
 	s = Linklookup(Ctxt, "runtime.gcbss", 0)
-	s.Type = SRODATA
+	s.Type = obj.SRODATA
 	s.Size = 0
 	s.Reachable = true
-	xdefine("runtime.egcbss", SRODATA, 0)
+	xdefine("runtime.egcbss", obj.SRODATA, 0)
 
 	// pseudo-symbols to mark locations of type, string, and go string data.
-	s = Linklookup(Ctxt, "type.*", 0)
+	var symtype *LSym
+	if !DynlinkingGo() {
+		s = Linklookup(Ctxt, "type.*", 0)
 
-	s.Type = STYPE
-	s.Size = 0
-	s.Reachable = true
-	symtype := s
+		s.Type = obj.STYPE
+		s.Size = 0
+		s.Reachable = true
+		symtype = s
+	}
 
 	s = Linklookup(Ctxt, "go.string.*", 0)
-	s.Type = SGOSTRING
+	s.Type = obj.SGOSTRING
+	s.Local = true
 	s.Size = 0
 	s.Reachable = true
 	symgostring := s
 
 	s = Linklookup(Ctxt, "go.func.*", 0)
-	s.Type = SGOFUNC
+	s.Type = obj.SGOFUNC
+	s.Local = true
 	s.Size = 0
 	s.Reachable = true
 	symgofunc := s
@@ -346,44 +360,49 @@
 	symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
 
 	symt = Linklookup(Ctxt, "runtime.symtab", 0)
-	symt.Type = SSYMTAB
+	symt.Local = true
+	symt.Type = obj.SSYMTAB
 	symt.Size = 0
 	symt.Reachable = true
 
+	ntypelinks := 0
+
 	// assign specific types so that they sort together.
 	// within a type they sort by size, so the .* symbols
 	// just defined above will be first.
 	// hide the specific symbols.
 	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-		if !s.Reachable || s.Special != 0 || s.Type != SRODATA {
+		if !s.Reachable || s.Special != 0 || s.Type != obj.SRODATA {
 			continue
 		}
-		if strings.HasPrefix(s.Name, "type.") {
-			s.Type = STYPE
+
+		if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() {
+			s.Type = obj.STYPE
 			s.Hide = 1
 			s.Outer = symtype
 		}
 
 		if strings.HasPrefix(s.Name, "go.typelink.") {
-			s.Type = STYPELINK
+			ntypelinks++
+			s.Type = obj.STYPELINK
 			s.Hide = 1
 			s.Outer = symtypelink
 		}
 
 		if strings.HasPrefix(s.Name, "go.string.") {
-			s.Type = SGOSTRING
+			s.Type = obj.SGOSTRING
 			s.Hide = 1
 			s.Outer = symgostring
 		}
 
 		if strings.HasPrefix(s.Name, "go.func.") {
-			s.Type = SGOFUNC
+			s.Type = obj.SGOFUNC
 			s.Hide = 1
 			s.Outer = symgofunc
 		}
 
 		if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
-			s.Type = SGOFUNC
+			s.Type = obj.SGOFUNC
 			s.Hide = 1
 			s.Outer = symgofunc
 			s.Align = 4
@@ -394,21 +413,30 @@
 	// 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.
-	moduledata := Linklookup(Ctxt, "runtime.themoduledata", 0)
-	moduledata.Type = SNOPTRDATA
+	// This code uses several global variables that are set by pcln.go:pclntab.
+	moduledata := Linklookup(Ctxt, "runtime.firstmoduledata", 0)
+	moduledata.Type = obj.SNOPTRDATA
 	moduledata.Size = 0 // truncate symbol back to 0 bytes to reinitialize
 	moduledata.Reachable = true
-	// Three slices (pclntable, ftab, filetab), uninitalized
-	moduledata.Size += int64((3 * 3 * Thearch.Ptrsize))
-	Symgrow(Ctxt, moduledata, moduledata.Size)
-	// Three uintptrs, initialized
+	moduledata.Local = true
+	// The pclntab slice
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0))
-	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.epclntab", 0))
+	adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
+	adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
+	// The ftab slice
+	Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabPclntabOffset))
+	adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
+	adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
+	// The filetab slice
+	Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset))
+	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile))
+	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile))
+	// findfunctab
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
-	// 2 more uintptrs (minpc, maxpc), uninitalized
-	moduledata.Size += int64(2 * Thearch.Ptrsize)
-	Symgrow(Ctxt, moduledata, moduledata.Size)
-	// more initialized uintptrs
+	// minpc, maxpc
+	Addaddr(Ctxt, moduledata, pclntabFirstFunc)
+	Addaddrplus(Ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size)
+	// pointers to specific parts of the module
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.text", 0))
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etext", 0))
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrdata", 0))
@@ -422,6 +450,22 @@
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0))
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0))
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
+	// The typelinks slice
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
-	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypelink", 0))
+	adduint(Ctxt, moduledata, uint64(ntypelinks))
+	adduint(Ctxt, moduledata, uint64(ntypelinks))
+	// 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
+	// compiler-provided size, so read it from the type data.
+	moduledatatype := Linkrlookup(Ctxt, "type.runtime.moduledata", 0)
+	moduledata.Size = decodetype_size(moduledatatype)
+	Symgrow(Ctxt, moduledata, moduledata.Size)
+
+	lastmoduledatap := Linklookup(Ctxt, "runtime.lastmoduledatap", 0)
+	if lastmoduledatap.Type != obj.SDYNIMPORT {
+		lastmoduledatap.Type = obj.SNOPTRDATA
+		lastmoduledatap.Size = 0 // overwrite existing value
+		Addaddr(Ctxt, lastmoduledatap, moduledata)
+	}
 }
diff --git a/src/cmd/internal/ld/util.go b/src/cmd/internal/ld/util.go
index 8c37cab..f38f05c 100644
--- a/src/cmd/internal/ld/util.go
+++ b/src/cmd/internal/ld/util.go
@@ -5,12 +5,11 @@
 package ld
 
 import (
-	"bufio"
 	"bytes"
 	"encoding/binary"
-	"io"
 	"log"
 	"os"
+	"runtime"
 	"runtime/pprof"
 	"strings"
 	"time"
@@ -24,18 +23,6 @@
 	return string(x)
 }
 
-func plan9quote(s string) string {
-	if s == "" {
-		return "'" + strings.Replace(s, "'", "''", -1) + "'"
-	}
-	for i := 0; i < len(s); i++ {
-		if s[i] <= ' ' || s[i] == '\'' {
-			return "'" + strings.Replace(s, "'", "''", -1) + "'"
-		}
-	}
-	return s
-}
-
 func tokenize(s string) []string {
 	var f []string
 	for {
@@ -87,170 +74,6 @@
 	return s
 }
 
-type Biobuf struct {
-	unget    [2]int
-	numUnget int
-	f        *os.File
-	r        *bufio.Reader
-	w        *bufio.Writer
-	linelen  int
-}
-
-func Bopenw(name string) (*Biobuf, error) {
-	f, err := os.Create(name)
-	if err != nil {
-		return nil, err
-	}
-	return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
-}
-
-func Bopenr(name string) (*Biobuf, error) {
-	f, err := os.Open(name)
-	if err != nil {
-		return nil, err
-	}
-	return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
-}
-
-func Binitw(w *os.File) *Biobuf {
-	return &Biobuf{w: bufio.NewWriter(w), f: w}
-}
-
-func (b *Biobuf) Write(p []byte) (int, error) {
-	return b.w.Write(p)
-}
-
-func Bwritestring(b *Biobuf, p string) (int, error) {
-	return b.w.WriteString(p)
-}
-
-func Bseek(b *Biobuf, offset int64, whence int) int64 {
-	if b.w != nil {
-		if err := b.w.Flush(); err != nil {
-			log.Fatalf("writing output: %v", err)
-		}
-	} else if b.r != nil {
-		if whence == 1 {
-			offset -= int64(b.r.Buffered())
-		}
-	}
-	off, err := b.f.Seek(offset, whence)
-	if err != nil {
-		log.Panicf("seeking in output [%d %d %p]: %v", offset, whence, b.f, err)
-	}
-	if b.r != nil {
-		b.r.Reset(b.f)
-	}
-	return off
-}
-
-func Boffset(b *Biobuf) int64 {
-	if b.w != nil {
-		if err := b.w.Flush(); err != nil {
-			log.Fatalf("writing output: %v", err)
-		}
-	}
-	off, err := b.f.Seek(0, 1)
-	if err != nil {
-		log.Fatalf("seeking in output [0, 1]: %v", err)
-	}
-	if b.r != nil {
-		off -= int64(b.r.Buffered())
-	}
-	return off
-}
-
-func (b *Biobuf) Flush() error {
-	return b.w.Flush()
-}
-
-func Bwrite(b *Biobuf, p []byte) (int, error) {
-	return b.w.Write(p)
-}
-
-func Bputc(b *Biobuf, c byte) {
-	b.w.WriteByte(c)
-}
-
-const Beof = -1
-
-func Bread(b *Biobuf, p []byte) int {
-	if b.numUnget > 0 {
-		Bseek(b, -int64(b.numUnget), 1)
-		b.numUnget = 0
-	}
-	n, err := io.ReadFull(b.r, p)
-	if n == 0 {
-		if err != nil && err != io.EOF {
-			n = -1
-		}
-	}
-	return n
-}
-
-func Bgetc(b *Biobuf) int {
-	if b.numUnget > 0 {
-		b.numUnget--
-		return int(b.unget[b.numUnget])
-	}
-	c, err := b.r.ReadByte()
-	r := int(c)
-	if err != nil {
-		r = -1
-	}
-	b.unget[1] = b.unget[0]
-	b.unget[0] = r
-	return r
-}
-
-func Bgetrune(b *Biobuf) int {
-	if b.numUnget > 0 {
-		Bseek(b, -int64(b.numUnget), 1)
-		b.numUnget = 0
-	}
-	r, _, err := b.r.ReadRune()
-	if err != nil {
-		return -1
-	}
-	return int(r)
-}
-
-func Bungetrune(b *Biobuf) {
-	b.r.UnreadRune()
-}
-
-func (b *Biobuf) Read(p []byte) (int, error) {
-	return b.r.Read(p)
-}
-
-func Brdline(b *Biobuf, delim int) string {
-	if b.numUnget > 0 {
-		Bseek(b, -int64(b.numUnget), 1)
-		b.numUnget = 0
-	}
-	s, err := b.r.ReadBytes(byte(delim))
-	if err != nil {
-		log.Fatalf("reading input: %v", err)
-	}
-	b.linelen = len(s)
-	return string(s)
-}
-
-func Brdstr(b *Biobuf, delim int, cut int) string {
-	if b.numUnget > 0 {
-		Bseek(b, -int64(b.numUnget), 1)
-		b.numUnget = 0
-	}
-	s, err := b.r.ReadString(byte(delim))
-	if err != nil {
-		log.Fatalf("reading input: %v", err)
-	}
-	if len(s) > 0 && cut > 0 {
-		s = s[:len(s)-1]
-	}
-	return s
-}
-
 func Access(name string, mode int) int {
 	if mode != 0 {
 		panic("bad access")
@@ -262,30 +85,6 @@
 	return 0
 }
 
-func Blinelen(b *Biobuf) int {
-	return b.linelen
-}
-
-func Bungetc(b *Biobuf) {
-	b.numUnget++
-}
-
-func Bflush(b *Biobuf) error {
-	return b.w.Flush()
-}
-
-func Bterm(b *Biobuf) error {
-	var err error
-	if b.w != nil {
-		err = b.w.Flush()
-	}
-	err1 := b.f.Close()
-	if err == nil {
-		err = err1
-	}
-	return err
-}
-
 // strings.Compare, introduced in Go 1.5.
 func stringsCompare(a, b string) int {
 	if a == b {
@@ -312,8 +111,11 @@
 	os.Exit(code)
 }
 
-var cpuprofile string
-var memprofile string
+var (
+	cpuprofile     string
+	memprofile     string
+	memprofilerate int64
+)
 
 func startProfile() {
 	if cpuprofile != "" {
@@ -327,11 +129,15 @@
 		AtExit(pprof.StopCPUProfile)
 	}
 	if memprofile != "" {
+		if memprofilerate != 0 {
+			runtime.MemProfileRate = int(memprofilerate)
+		}
 		f, err := os.Create(memprofile)
 		if err != nil {
 			log.Fatalf("%v", err)
 		}
 		AtExit(func() {
+			runtime.GC() // profile all outstanding allocations
 			if err := pprof.WriteHeapProfile(f); err != nil {
 				log.Fatalf("%v", err)
 			}
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index 527474f..6207c73 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -1524,7 +1524,7 @@
 
 	case 0: /* pseudo ops */
 		if false { /*debug['G']*/
-			fmt.Printf("%x: %s: arm %d\n", uint32(p.Pc), p.From.Sym.Name, p.From.Sym.Fnptr)
+			fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
 		}
 
 	case 1: /* op R,[R],R */
@@ -1673,8 +1673,6 @@
 				if ctxt.Flag_shared != 0 {
 					rel.Add += ctxt.Pc - p.Pcrel.Pc - 8 - int64(rel.Siz)
 				}
-				rel.Xadd = rel.Add
-				rel.Xsym = rel.Sym
 			} else if ctxt.Flag_shared != 0 {
 				rel.Type = obj.R_PCREL
 				rel.Add += ctxt.Pc - p.Pcrel.Pc - 8
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 793a2b6..c73c146 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -112,12 +112,6 @@
 			i32 := math.Float32bits(f32)
 			literal := fmt.Sprintf("$f32.%08x", i32)
 			s := obj.Linklookup(ctxt, literal, 0)
-			if s.Type == 0 {
-				s.Type = obj.SRODATA
-				obj.Adduint32(ctxt, s, i32)
-				s.Reachable = 0
-			}
-
 			p.From.Type = obj.TYPE_MEM
 			p.From.Sym = s
 			p.From.Name = obj.NAME_EXTERN
@@ -129,12 +123,6 @@
 			i64 := math.Float64bits(p.From.Val.(float64))
 			literal := fmt.Sprintf("$f64.%016x", i64)
 			s := obj.Linklookup(ctxt, literal, 0)
-			if s.Type == 0 {
-				s.Type = obj.SRODATA
-				obj.Adduint64(ctxt, s, i64)
-				s.Reachable = 0
-			}
-
 			p.From.Type = obj.TYPE_MEM
 			p.From.Sym = s
 			p.From.Name = obj.NAME_EXTERN
@@ -182,11 +170,6 @@
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	autosize := int32(0)
 
-	if ctxt.Symmorestack[0] == nil {
-		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
-		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
-	}
-
 	ctxt.Cursym = cursym
 
 	if cursym.Text == nil || cursym.Text.Link == nil {
@@ -355,7 +338,7 @@
 			if autosize == 0 && cursym.Text.Mark&LEAF == 0 {
 				if ctxt.Debugvlog != 0 {
 					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
-					obj.Bflush(ctxt.Bso)
+					ctxt.Bso.Flush()
 				}
 
 				cursym.Text.Mark |= LEAF
@@ -369,7 +352,7 @@
 			}
 
 			if p.From3.Offset&obj.NOSPLIT == 0 {
-				p = stacksplit(ctxt, p, autosize, cursym.Text.From3.Offset&obj.NEEDCTXT == 0) // emit split check
+				p = stacksplit(ctxt, p, autosize) // emit split check
 			}
 
 			// MOVW.W		R14,$-autosize(SP)
@@ -720,7 +703,7 @@
 	}
 }
 
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt bool) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	// MOVW			g_stackguard(g), R1
 	p = obj.Appendp(ctxt, p)
 
@@ -830,8 +813,10 @@
 	p.To.Type = obj.TYPE_BRANCH
 	if ctxt.Cursym.Cfunc != 0 {
 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
+	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
 	} else {
-		p.To.Sym = ctxt.Symmorestack[bool2int(noctxt)]
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
 	}
 
 	// BLS	start
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index e35a99e..6e00cb5 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -258,17 +258,19 @@
 	{AWORD, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0},
 	{AWORD, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0},
 	{AMOVW, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+	{AMOVW, C_VCONADDR, C_NONE, C_REG, 68, 8, 0, 0, 0},
 	{AMOVD, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
-	{AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AMOVH, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AMOVD, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AMOVB, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
-	{AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
-	{AMOVH, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
-	{AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
-	{AMOVD, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
+	{AMOVD, C_VCONADDR, C_NONE, C_REG, 68, 8, 0, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVB, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVBU, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVH, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVW, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVD, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
 	{AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
 	{AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
 	{AMADD, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
@@ -447,10 +449,10 @@
 	{AFMOVS, C_LOREG, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
 	{AFMOVD, C_LAUTO, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
 	{AFMOVD, C_LOREG, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
-	{AFMOVS, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AFMOVS, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM, 0},
-	{AFMOVD, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
-	{AFMOVD, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM, 0},
+	{AFMOVS, C_FREG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AFMOVS, C_ADDR, C_NONE, C_FREG, 65, 12, 0, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AFMOVD, C_ADDR, C_NONE, C_FREG, 65, 12, 0, 0, 0},
 	{AFADDS, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
 	{AFADDS, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0},
 	{AFADDS, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0},
@@ -829,7 +831,7 @@
 
 func ispcdisp(v int32) int {
 	/* pc-relative addressing will reach? */
-	return bool2int(v >= -0xfffff && v <= 0xfffff && (v&3) == 0)
+	return obj.Bool2int(v >= -0xfffff && v <= 0xfffff && (v&3) == 0)
 }
 
 func isaddcon(v int64) int {
@@ -840,14 +842,14 @@
 	if (v & 0xFFF) == 0 {
 		v >>= 12
 	}
-	return bool2int(v <= 0xFFF)
+	return obj.Bool2int(v <= 0xFFF)
 }
 
 func isbitcon(v uint64) int {
 	/*  fancy bimm32 or bimm64? */
 	// TODO(aram):
 	return 0
-	// return bool2int(findmask(v) != nil || (v>>32) == 0 && findmask(v|(v<<32)) != nil)
+	// return obj.Bool2int(findmask(v) != nil || (v>>32) == 0 && findmask(v|(v<<32)) != nil)
 }
 
 func autoclass(l int64) int {
@@ -1176,12 +1178,7 @@
 		}
 
 	case C_VCON:
-		if b == C_VCONADDR {
-			return true
-		} else {
-			return cmp(C_LCON, b)
-		}
-		fallthrough
+		return cmp(C_LCON, b)
 
 	case C_LACON:
 		if b == C_AACON {
@@ -2113,7 +2110,7 @@
 		}
 
 		rt := int(p.To.Reg)
-		o1 |= (uint32(r&31) << 16) | (uint32(cond) << 12) | (uint32(rf&31) << 5) | uint32(rt&31)
+		o1 |= (uint32(rf&31) << 16) | (uint32(cond&31) << 12) | (uint32(r&31) << 5) | uint32(rt&31)
 
 	case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
 		nzcv := int(p.To.Offset)
@@ -2191,7 +2188,7 @@
 	case 24: /* mov/mvn Rs,Rd -> add $0,Rs,Rd or orr Rs,ZR,Rd */
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
-		s := bool2int(rf == REGSP || rt == REGSP)
+		s := obj.Bool2int(rf == REGSP || rt == REGSP)
 		if p.As == AMVN || p.As == AMVNW {
 			if s != 0 {
 				ctxt.Diag("illegal SP reference\n%v", p)
@@ -2724,21 +2721,27 @@
 		}
 
 		/* reloc ops */
-	case 64: /* movT R,addr */
-		o1 = omovlit(ctxt, AMOVD, p, &p.To, REGTMP)
+	case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
+		o1 = ADR(1, 0, REGTMP)
+		o2 = opirr(ctxt, AADD) | REGTMP&31<<5 | REGTMP&31
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 8
+		rel.Sym = p.To.Sym
+		rel.Add = p.To.Offset
+		rel.Type = obj.R_ADDRARM64
+		o3 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), 0, REGTMP, int(p.From.Reg))
 
-		if !(o1 != 0) {
-			break
-		}
-		o2 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), 0, REGTMP, int(p.From.Reg))
-
-	case 65: /* movT addr,R */
-		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
-
-		if !(o1 != 0) {
-			break
-		}
-		o2 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), 0, REGTMP, int(p.To.Reg))
+	case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
+		o1 = ADR(1, 0, REGTMP)
+		o2 = opirr(ctxt, AADD) | REGTMP&31<<5 | REGTMP&31
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 8
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRARM64
+		o3 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), 0, REGTMP, int(p.To.Reg))
 
 	case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */
 		v := int32(p.From.Offset)
@@ -2767,6 +2770,19 @@
 		}
 		o1 |= uint32(int64(2<<30|5<<27|((uint32(v)/8)&0x7f)<<15) | p.From.Offset<<10 | int64(uint32(p.To.Reg&31)<<5) | int64(p.From.Reg&31))
 
+	case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */
+		if p.As == AMOVW {
+			ctxt.Diag("invalid load of 32-bit address: %v", p)
+		}
+		o1 = ADR(1, 0, uint32(p.To.Reg))
+		o2 = opirr(ctxt, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31)
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 8
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRARM64
+
 	// This is supposed to be something that stops execution.
 	// It's not supposed to be reached, ever, but if it is, we'd
 	// like to be able to tell how we got there.  Assemble as
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 52eef3f..b8d930b 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -49,7 +49,7 @@
 	ACMNW: ACMPW,
 }
 
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt int) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	// MOV	g_stackguard(g), R1
 	p = obj.Appendp(ctxt, p)
 
@@ -186,8 +186,10 @@
 	p.To.Type = obj.TYPE_BRANCH
 	if ctxt.Cursym.Cfunc != 0 {
 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
+	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
 	} else {
-		p.To.Sym = ctxt.Symmorestack[noctxt]
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
 	}
 
 	// B	start
@@ -465,11 +467,6 @@
 }
 
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	if ctxt.Symmorestack[0] == nil {
-		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
-		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
-	}
-
 	ctxt.Cursym = cursym
 
 	if cursym.Text == nil || cursym.Text.Link == nil {
@@ -488,7 +485,7 @@
 	 * strip NOPs
 	 * expand RET
 	 */
-	obj.Bflush(ctxt.Bso)
+	ctxt.Bso.Flush()
 	q := (*obj.Prog)(nil)
 	var q1 *obj.Prog
 	for p := cursym.Text; p != nil; p = p.Link {
@@ -578,12 +575,12 @@
 				if ctxt.Debugvlog != 0 {
 					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name)
 				}
-				obj.Bflush(ctxt.Bso)
+				ctxt.Bso.Flush()
 				cursym.Text.Mark |= LEAF
 			}
 
 			if !(p.From3.Offset&obj.NOSPLIT != 0) {
-				p = stacksplit(ctxt, p, ctxt.Autosize, bool2int(cursym.Text.From3.Offset&obj.NEEDCTXT == 0)) // emit split check
+				p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check
 			}
 
 			aoffset = ctxt.Autosize
@@ -781,7 +778,6 @@
 			}
 
 			p.As = obj.ARET
-			p.Lineno = p.Lineno
 			p.To.Type = obj.TYPE_MEM
 			p.To.Offset = 0
 			p.To.Reg = REGLINK
@@ -811,6 +807,7 @@
 	ADWORD: true,
 	ABL:    true,
 	AB:     true,
+	ASVC:   true,
 }
 
 var Linkarm64 = obj.LinkArch{
diff --git a/src/cmd/internal/obj/arm64/util.go b/src/cmd/internal/obj/arm64/util.go
deleted file mode 100644
index 7cb5040..0000000
--- a/src/cmd/internal/obj/arm64/util.go
+++ /dev/null
@@ -1,12 +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 arm64
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index ab3e209..2037af4 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -121,7 +121,6 @@
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
-	s.Reachable = 1
 	if s.Size < off+wid {
 		s.Size = off + wid
 		Symgrow(ctxt, s, s.Size)
@@ -183,7 +182,6 @@
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
-	s.Reachable = 1
 	i := s.Size
 	s.Size += int64(ctxt.Arch.Ptrsize)
 	Symgrow(ctxt, s, s.Size)
@@ -200,7 +198,6 @@
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
-	s.Reachable = 1
 	i := s.Size
 	s.Size += 4
 	Symgrow(ctxt, s, s.Size)
@@ -221,7 +218,6 @@
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
-	s.Reachable = 1
 	if off+int64(ctxt.Arch.Ptrsize) > s.Size {
 		s.Size = off + int64(ctxt.Arch.Ptrsize)
 		Symgrow(ctxt, s, s.Size)
@@ -244,7 +240,6 @@
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
-	s.Reachable = 1
 	i := s.Size
 	s.Size += int64(ctxt.Arch.Ptrsize)
 	Symgrow(ctxt, s, s.Size)
@@ -260,7 +255,6 @@
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
-	s.Reachable = 1
 	i := s.Size
 	s.Size += 4
 	Symgrow(ctxt, s, s.Size)
diff --git a/src/cmd/internal/obj/flag.go b/src/cmd/internal/obj/flag.go
index 3759437..0664f5c 100644
--- a/src/cmd/internal/obj/flag.go
+++ b/src/cmd/internal/obj/flag.go
@@ -93,7 +93,7 @@
 
 func (i *int32Value) Get() interface{} { return int32(*i) }
 
-func (i *int32Value) String() string { return fmt.Sprintf("%v", *i) }
+func (i *int32Value) String() string { return fmt.Sprint(*i) }
 
 type fn0 func()
 
diff --git a/src/cmd/internal/obj/fmt.go b/src/cmd/internal/obj/fmt.go
index b1936ef..1268f42 100644
--- a/src/cmd/internal/obj/fmt.go
+++ b/src/cmd/internal/obj/fmt.go
@@ -15,20 +15,20 @@
 package obj
 
 const (
-	FmtWidth    = 1
-	FmtLeft     = FmtWidth << 1
-	FmtPrec     = FmtLeft << 1
-	FmtSharp    = FmtPrec << 1
-	FmtSpace    = FmtSharp << 1
-	FmtSign     = FmtSpace << 1
-	FmtApost    = FmtSign << 1
-	FmtZero     = FmtApost << 1
-	FmtUnsigned = FmtZero << 1
-	FmtShort    = FmtUnsigned << 1
-	FmtLong     = FmtShort << 1
-	FmtVLong    = FmtLong << 1
-	FmtComma    = FmtVLong << 1
-	FmtByte     = FmtComma << 1
-	FmtLDouble  = FmtByte << 1
-	FmtFlag     = FmtLDouble << 1
+	FmtWidth = 1 << iota
+	FmtLeft
+	FmtPrec
+	FmtSharp
+	FmtSpace
+	FmtSign
+	FmtApost
+	FmtZero
+	FmtUnsigned
+	FmtShort
+	FmtLong
+	FmtVLong
+	FmtComma
+	FmtByte
+	FmtLDouble
+	FmtFlag
 )
diff --git a/src/cmd/internal/obj/go.go b/src/cmd/internal/obj/go.go
index 2b65ee6..24ed07f 100644
--- a/src/cmd/internal/obj/go.go
+++ b/src/cmd/internal/obj/go.go
@@ -6,16 +6,16 @@
 
 import (
 	"fmt"
-	"math"
 	"os"
 	"strings"
 )
 
 // go-specific code shared across loaders (5l, 6l, 8l).
 
-var Framepointer_enabled int
-
-var Fieldtrack_enabled int
+var (
+	Framepointer_enabled int
+	Fieldtrack_enabled   int
+)
 
 // Toolchain experiments.
 // These are controlled by the GOEXPERIMENT environment
@@ -25,14 +25,8 @@
 	name string
 	val  *int
 }{
-	struct {
-		name string
-		val  *int
-	}{"fieldtrack", &Fieldtrack_enabled},
-	struct {
-		name string
-		val  *int
-	}{"framepointer", &Framepointer_enabled},
+	{"fieldtrack", &Fieldtrack_enabled},
+	{"framepointer", &Framepointer_enabled},
 }
 
 func addexp(s string) {
@@ -57,15 +51,6 @@
 	}
 }
 
-// replace all "". with pkg.
-func Expandpkg(t0 string, pkg string) string {
-	return strings.Replace(t0, `"".`, pkg+".", -1)
-}
-
-func double2ieee(ieee *uint64, f float64) {
-	*ieee = math.Float64bits(f)
-}
-
 func Nopout(p *Prog) {
 	p.As = ANOP
 	p.Scond = 0
@@ -82,53 +67,6 @@
 	p.To.Class = 0
 }
 
-/*
- *	bv.c
- */
-
-/*
- *	closure.c
- */
-
-/*
- *	const.c
- */
-
-/*
- *	cplx.c
- */
-
-/*
- *	dcl.c
- */
-
-/*
- *	esc.c
- */
-
-/*
- *	export.c
- */
-
-/*
- *	fmt.c
- */
-
-/*
- *	gen.c
- */
-
-/*
- *	init.c
- */
-
-/*
- *	inl.c
- */
-
-/*
- *	lex.c
- */
 func Expstring() string {
 	buf := "X"
 	for i := range exper {
diff --git a/src/cmd/internal/obj/libc.go b/src/cmd/internal/obj/libc.go
index 204839e..b200b26 100644
--- a/src/cmd/internal/obj/libc.go
+++ b/src/cmd/internal/obj/libc.go
@@ -1,20 +1,12 @@
+// 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 obj
 
 const (
 	AEXIST = 0
+	BOM    = 0xFEFF
 )
 
 var GOEXPERIMENT string
-
-const (
-	OREAD = iota
-	OWRITE
-	ORDWR
-	SIGBUS
-	SIGSEGV
-	NDFLT
-	FPPDBL
-	FPRNR
-	HEADER_IO
-	BOM = 0xFEFF
-)
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 92fd7c4..9f5e87b 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -173,6 +173,9 @@
 	NAME_STATIC
 	NAME_AUTO
 	NAME_PARAM
+	// A reference to name@GOT(SB) is a reference to the entry in the global offset
+	// table for 'name'.
+	NAME_GOTREF
 )
 
 const (
@@ -270,53 +273,36 @@
 	A_ARCHSPECIFIC
 )
 
+// An LSym is the sort of symbol that is written to an object file.
 type LSym struct {
-	Name        string
-	Extname     string
-	Type        int16
-	Version     int16
-	Dupok       uint8
-	Cfunc       uint8
-	External    uint8
-	Nosplit     uint8
-	Reachable   uint8
-	Cgoexport   uint8
-	Special     uint8
-	Stkcheck    uint8
-	Hide        uint8
-	Leaf        uint8
-	Fnptr       uint8
-	Localentry  uint8
-	Seenglobl   uint8
-	Onlist      uint8
-	Printed     uint8
-	Symid       int16
-	Dynid       int32
-	Plt         int32
-	Got         int32
-	Align       int32
-	Elfsym      int32
-	Args        int32
-	Locals      int32
-	Value       int64
-	Size        int64
-	Allsym      *LSym
-	Next        *LSym
-	Sub         *LSym
-	Outer       *LSym
-	Gotype      *LSym
-	Reachparent *LSym
-	Queue       *LSym
-	File        string
-	Dynimplib   string
-	Dynimpvers  string
-	Sect        *struct{}
-	Autom       *Auto
-	Text        *Prog
-	Etext       *Prog
-	Pcln        *Pcln
-	P           []byte
-	R           []Reloc
+	Name      string
+	Type      int16
+	Version   int16
+	Dupok     uint8
+	Cfunc     uint8
+	Nosplit   uint8
+	Leaf      uint8
+	Seenglobl uint8
+	Onlist    uint8
+	// Local means make the symbol local even when compiling Go code to reference Go
+	// symbols in other shared libraries, as in this mode symbols are global by
+	// default. "local" here means in the sense of the dynamic linker, i.e. not
+	// visible outside of the module (shared library or executable) that contains its
+	// definition. (When not compiling to support Go shared libraries, all symbols are
+	// local in this sense unless there is a cgo_export_* directive).
+	Local  bool
+	Args   int32
+	Locals int32
+	Value  int64
+	Size   int64
+	Next   *LSym
+	Gotype *LSym
+	Autom  *Auto
+	Text   *Prog
+	Etext  *Prog
+	Pcln   *Pcln
+	P      []byte
+	R      []Reloc
 }
 
 type Pcln struct {
@@ -374,21 +360,18 @@
 )
 
 type Reloc struct {
-	Off     int32
-	Siz     uint8
-	Done    uint8
-	Type    int32
-	Variant int32
-	Add     int64
-	Xadd    int64
-	Sym     *LSym
-	Xsym    *LSym
+	Off  int32
+	Siz  uint8
+	Type int32
+	Add  int64
+	Sym  *LSym
 }
 
 // Reloc.type
 const (
 	R_ADDR = 1 + iota
 	R_ADDRPOWER
+	R_ADDRARM64
 	R_SIZE
 	R_CALL
 	R_CALLARM
@@ -397,8 +380,23 @@
 	R_CALLPOWER
 	R_CONST
 	R_PCREL
+	// R_TLS (only used on arm currently, and not on android and darwin where tlsg is
+	// a regular variable) resolves to data needed to access the thread-local g. It is
+	// interpreted differently depending on toolchain flags to implement either the
+	// "local exec" or "inital exec" model for tls access.
+	// TODO(mwhudson): change to use R_TLS_LE or R_TLS_IE as appropriate, not having
+	// R_TLS do double duty.
 	R_TLS
+	// R_TLS_LE (only used on 386 and amd64 currently) resolves to the offset of the
+	// thread-local g from the thread local base and is used to implement the "local
+	// exec" model for tls access (r.Sym is not set by the compiler for this case but
+	// is set to Tlsg in the linker when externally linking).
 	R_TLS_LE
+	// R_TLS_IE (only used on 386 and amd64 currently) resolves to the PC-relative
+	// offset to a GOT slot containing the offset the thread-local g from the thread
+	// local base and is used to implemented the "initial exec" model for tls access
+	// (r.Sym is not set by the compiler for this case but is set to Tlsg in the
+	// linker when externally linking).
 	R_TLS_IE
 	R_GOTOFF
 	R_PLT0
@@ -406,17 +404,7 @@
 	R_PLT2
 	R_USEFIELD
 	R_POWER_TOC
-)
-
-// Reloc.variant
-const (
-	RV_NONE = iota
-	RV_POWER_LO
-	RV_POWER_HI
-	RV_POWER_HA
-	RV_POWER_DS
-	RV_CHECK_OVERFLOW = 1 << 8
-	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
+	R_GOTPCREL
 )
 
 type Auto struct {
@@ -438,7 +426,7 @@
 }
 
 // Pcdata iterator.
-//	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
+//      for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
 type Pciter struct {
 	d       Pcdata
 	p       []byte
@@ -459,34 +447,23 @@
 // Link holds the context for writing object code from a compiler
 // to be linker input or for reading that input into the linker.
 type Link struct {
-	Thechar            int32
-	Thestring          string
 	Goarm              int32
 	Headtype           int
 	Arch               *LinkArch
-	Ignore             func(string) int32
 	Debugasm           int32
-	Debugline          int32
-	Debughist          int32
-	Debugread          int32
 	Debugvlog          int32
-	Debugstack         int32
 	Debugzerostack     int32
 	Debugdivmod        int32
-	Debugfloat         int32
 	Debugpcln          int32
 	Flag_shared        int32
-	Iself              int32
+	Flag_dynlink       bool
 	Bso                *Biobuf
 	Pathname           string
 	Windows            int32
-	Trimpath           string
 	Goroot             string
 	Goroot_final       string
 	Enforce_data_order int32
 	Hash               map[SymVer]*LSym
-	Allsym             *LSym
-	Nsymbol            int32
 	LineHist           LineHist
 	Imports            []string
 	Plist              *Plist
@@ -495,7 +472,6 @@
 	Sym_divu           *LSym
 	Sym_mod            *LSym
 	Sym_modu           *LSym
-	Symmorestack       [2]*LSym
 	Tlsg               *LSym
 	Plan9privates      *LSym
 	Curp               *Prog
@@ -513,32 +489,18 @@
 	Autosize           int32
 	Armsize            int32
 	Pc                 int64
-	Libdir             []string
-	Library            []Library
 	Tlsoffset          int
 	Diag               func(string, ...interface{})
 	Mode               int
-	Curauto            *Auto
-	Curhist            *Auto
 	Cursym             *LSym
 	Version            int
 	Textp              *LSym
 	Etextp             *LSym
-	Histdepth          int32
-	Nhistfile          int32
-	Filesyms           *LSym
 }
 
 type SymVer struct {
 	Name    string
-	Version int
-}
-
-type Library struct {
-	Objref string
-	Srcref string
-	File   string
-	Pkg    string
+	Version int // TODO: make int16 to match LSym.Version?
 }
 
 // LinkArch is the definition of a single architecture.
@@ -572,14 +534,6 @@
 	Hwindows
 )
 
-const (
-	LinkAuto = 0 + iota
-	LinkInternal
-	LinkExternal
-)
-
-var linkbasepointer int
-
 type Plist struct {
 	Name    *LSym
 	Firstpc *Prog
@@ -592,13 +546,11 @@
  */
 func Linknewplist(ctxt *Link) *Plist {
 	pl := new(Plist)
-	*pl = Plist{}
 	if ctxt.Plist == nil {
 		ctxt.Plist = pl
 	} else {
 		ctxt.Plast.Link = pl
 	}
 	ctxt.Plast = pl
-
 	return pl
 }
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 1f68578..35a9ef6 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -400,7 +400,11 @@
 	wrint(b, int64(s.Type))
 	wrstring(b, s.Name)
 	wrint(b, int64(s.Version))
-	wrint(b, int64(s.Dupok))
+	flags := int64(s.Dupok)
+	if s.Local {
+		flags |= 2
+	}
+	wrint(b, flags)
 	wrint(b, s.Size)
 	wrsym(b, s.Gotype)
 	wrdata(b, s.P)
@@ -413,9 +417,9 @@
 		wrint(b, int64(r.Siz))
 		wrint(b, int64(r.Type))
 		wrint(b, r.Add)
-		wrint(b, r.Xadd)
+		wrint(b, 0) // Xadd, ignored
 		wrsym(b, r.Sym)
-		wrsym(b, r.Xsym)
+		wrsym(b, nil) // Xsym, ignored
 	}
 
 	if s.Type == STEXT {
@@ -463,18 +467,21 @@
 	}
 }
 
+// Reusable buffer to avoid allocations.
+// This buffer was responsible for 15% of gc's allocations.
+var varintbuf [10]uint8
+
 func wrint(b *Biobuf, sval int64) {
 	var v uint64
-	var buf [10]uint8
 	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
-	p := buf[:]
+	p := varintbuf[:]
 	for v = uv; v >= 0x80; v >>= 7 {
 		p[0] = uint8(v | 0x80)
 		p = p[1:]
 	}
 	p[0] = uint8(v)
 	p = p[1:]
-	Bwrite(b, buf[:len(buf)-len(p)])
+	b.Write(varintbuf[:len(varintbuf)-len(p)])
 }
 
 func wrstring(b *Biobuf, s string) {
@@ -490,7 +497,7 @@
 
 func wrdata(b *Biobuf, v []byte) {
 	wrint(b, int64(len(v)))
-	Bwrite(b, v)
+	b.Write(v)
 }
 
 func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
@@ -514,7 +521,3 @@
 	wrstring(b, s.Name)
 	wrint(b, int64(s.Version))
 }
-
-var startmagic string = "\x00\x00go13ld"
-
-var endmagic string = "\xff\xffgo13ld"
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index e05061f..6d7db42 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -115,11 +115,6 @@
 }
 
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	if ctxt.Symmorestack[0] == nil {
-		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
-		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
-	}
-
 	// TODO(minux): add morestack short-cuts with small fixed frame-size.
 	ctxt.Cursym = cursym
 
@@ -142,7 +137,7 @@
 	if ctxt.Debugvlog != 0 {
 		fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
 	}
-	obj.Bflush(ctxt.Bso)
+	ctxt.Bso.Flush()
 
 	var q *obj.Prog
 	var q1 *obj.Prog
@@ -328,7 +323,7 @@
 			p.To.Offset = int64(autosize) - 8
 
 			if p.From3.Offset&obj.NOSPLIT == 0 {
-				p = stacksplit(ctxt, p, autosize, cursym.Text.From3.Offset&obj.NEEDCTXT == 0) // emit split check
+				p = stacksplit(ctxt, p, autosize) // emit split check
 			}
 
 			q = p
@@ -351,7 +346,7 @@
 			} else if cursym.Text.Mark&LEAF == 0 {
 				if ctxt.Debugvlog != 0 {
 					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
-					obj.Bflush(ctxt.Bso)
+					ctxt.Bso.Flush()
 				}
 
 				cursym.Text.Mark |= LEAF
@@ -628,7 +623,7 @@
 		q = p;
 	}
 */
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt bool) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	// MOVD	g_stackguard(g), R3
 	p = obj.Appendp(ctxt, p)
 
@@ -757,8 +752,10 @@
 	p.To.Type = obj.TYPE_BRANCH
 	if ctxt.Cursym.Cfunc != 0 {
 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
+	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
 	} else {
-		p.To.Sym = ctxt.Symmorestack[bool2int(noctxt)]
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
 	}
 
 	// BR	start
diff --git a/src/cmd/internal/obj/ppc64/util.go b/src/cmd/internal/obj/ppc64/util.go
deleted file mode 100644
index 0df4af7..0000000
--- a/src/cmd/internal/obj/ppc64/util.go
+++ /dev/null
@@ -1,12 +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 ppc64
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/internal/obj/stack.go b/src/cmd/internal/obj/stack.go
index b8d0350..87698b3 100644
--- a/src/cmd/internal/obj/stack.go
+++ b/src/cmd/internal/obj/stack.go
@@ -1,3 +1,7 @@
+// Copyright 2011 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.
+
 // Inferno utils/5l/span.c
 // http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
 //
@@ -30,12 +34,6 @@
 
 package obj
 
-// Instruction layout.
-
-// Copyright 2011 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.
-
 // For the linkers. Must match Go definitions.
 // TODO(rsc): Share Go definitions with linkers directly.
 
@@ -43,7 +41,7 @@
 	STACKSYSTEM = 0
 	StackSystem = STACKSYSTEM
 	StackBig    = 4096
-	StackGuard  = 640 + StackSystem
+	StackGuard  = 640*stackGuardMultiplier + StackSystem
 	StackSmall  = 128
 	StackLimit  = StackGuard - StackSystem - StackSmall
 )
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 3568a5c..37bb40b 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -32,73 +32,30 @@
 package obj
 
 import (
-	"fmt"
 	"log"
 	"os"
 	"path/filepath"
 	"runtime"
+	"strconv"
 )
 
-func yy_isalpha(c int) bool {
-	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
-}
-
 var headers = []struct {
 	name string
 	val  int
 }{
-	struct {
-		name string
-		val  int
-	}{"darwin", Hdarwin},
-	struct {
-		name string
-		val  int
-	}{"dragonfly", Hdragonfly},
-	struct {
-		name string
-		val  int
-	}{"elf", Helf},
-	struct {
-		name string
-		val  int
-	}{"freebsd", Hfreebsd},
-	struct {
-		name string
-		val  int
-	}{"linux", Hlinux},
-	struct {
-		name string
-		val  int
-	}{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
-	struct {
-		name string
-		val  int
-	}{"nacl", Hnacl},
-	struct {
-		name string
-		val  int
-	}{"netbsd", Hnetbsd},
-	struct {
-		name string
-		val  int
-	}{"openbsd", Hopenbsd},
-	struct {
-		name string
-		val  int
-	}{"plan9", Hplan9},
-	struct {
-		name string
-		val  int
-	}{"solaris", Hsolaris},
-	struct {
-		name string
-		val  int
-	}{"windows", Hwindows},
-	struct {
-		name string
-		val  int
-	}{"windowsgui", Hwindows},
+	{"darwin", Hdarwin},
+	{"dragonfly", Hdragonfly},
+	{"elf", Helf},
+	{"freebsd", Hfreebsd},
+	{"linux", Hlinux},
+	{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
+	{"nacl", Hnacl},
+	{"netbsd", Hnetbsd},
+	{"openbsd", Hopenbsd},
+	{"plan9", Hplan9},
+	{"solaris", Hsolaris},
+	{"windows", Hwindows},
+	{"windowsgui", Hwindows},
 }
 
 func headtype(name string) int {
@@ -110,16 +67,13 @@
 	return -1
 }
 
-var headstr_buf string
-
 func Headstr(v int) string {
 	for i := 0; i < len(headers); i++ {
 		if v == headers[i].val {
 			return headers[i].name
 		}
 	}
-	headstr_buf = fmt.Sprintf("%d", v)
-	return headstr_buf
+	return strconv.Itoa(v)
 }
 
 func Linknew(arch *LinkArch) *Link {
@@ -197,14 +151,17 @@
 		default:
 			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
 
+		case '5':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
 		case '6':
 			ctxt.Tlsoffset = 0x8a0
 
+		case '7':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
 		case '8':
 			ctxt.Tlsoffset = 0x468
-
-		case '5':
-			ctxt.Tlsoffset = 0 // dummy value, not needed
 		}
 	}
 
@@ -221,46 +178,31 @@
 	return ctxt
 }
 
-func linknewsym(ctxt *Link, symb string, v int) *LSym {
-	s := new(LSym)
-	*s = LSym{}
-
-	s.Dynid = -1
-	s.Plt = -1
-	s.Got = -1
-	s.Name = symb
-	s.Type = 0
-	s.Version = int16(v)
-	s.Value = 0
-	s.Size = 0
-	ctxt.Nsymbol++
-
-	s.Allsym = ctxt.Allsym
-	ctxt.Allsym = s
-
-	return s
-}
-
-func _lookup(ctxt *Link, symb string, v int, creat int) *LSym {
+func _lookup(ctxt *Link, symb string, v int, create bool) *LSym {
 	s := ctxt.Hash[SymVer{symb, v}]
-	if s != nil || creat == 0 {
+	if s != nil || !create {
 		return s
 	}
 
-	s = linknewsym(ctxt, symb, v)
-	s.Extname = s.Name
+	s = &LSym{
+		Name:    symb,
+		Type:    0,
+		Version: int16(v),
+		Value:   0,
+		Size:    0,
+	}
 	ctxt.Hash[SymVer{symb, v}] = s
 
 	return s
 }
 
 func Linklookup(ctxt *Link, name string, v int) *LSym {
-	return _lookup(ctxt, name, v, 1)
+	return _lookup(ctxt, name, v, true)
 }
 
 // read-only lookup
 func linkrlookup(ctxt *Link, name string, v int) *LSym {
-	return _lookup(ctxt, name, v, 0)
+	return _lookup(ctxt, name, v, false)
 }
 
 func Linksymfmt(s *LSym) string {
diff --git a/src/cmd/internal/obj/textflag.go b/src/cmd/internal/obj/textflag.go
index e0e641d..b5d27a6 100644
--- a/src/cmd/internal/obj/textflag.go
+++ b/src/cmd/internal/obj/textflag.go
@@ -30,4 +30,7 @@
 
 	// This function uses its incoming context register.
 	NEEDCTXT = 64
+
+	// When passed to ggloblsym, causes Local to be set to true on the LSym it creates.
+	LOCAL = 128
 )
diff --git a/src/cmd/internal/obj/typekind.go b/src/cmd/internal/obj/typekind.go
index f8e302b..2193271 100644
--- a/src/cmd/internal/obj/typekind.go
+++ b/src/cmd/internal/obj/typekind.go
@@ -1,13 +1,9 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2012 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 obj
 
-// Copyright 2012 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.
-
 // Must match runtime and reflect.
 // Included by cmd/gc.
 
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index b0d10b5..b0b2091 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -28,12 +28,10 @@
 }
 
 type Biobuf struct {
-	unget    [2]int
-	numUnget int
-	f        *os.File
-	r        *bufio.Reader
-	w        *bufio.Writer
-	linelen  int
+	f       *os.File
+	r       *bufio.Reader
+	w       *bufio.Writer
+	linelen int
 }
 
 func Bopenw(name string) (*Biobuf, error) {
@@ -85,12 +83,17 @@
 }
 
 func Boffset(b *Biobuf) int64 {
-	if err := b.w.Flush(); err != nil {
-		log.Fatalf("writing output: %v", err)
+	if b.w != nil {
+		if err := b.w.Flush(); err != nil {
+			log.Fatalf("writing output: %v", err)
+		}
 	}
 	off, err := b.f.Seek(0, 1)
 	if err != nil {
-		log.Fatalf("seeking in output: %v", err)
+		log.Fatalf("seeking in output [0, 1]: %v", err)
+	}
+	if b.r != nil {
+		off -= int64(b.r.Buffered())
 	}
 	return off
 }
@@ -99,10 +102,6 @@
 	return b.w.Flush()
 }
 
-func Bwrite(b *Biobuf, p []byte) (int, error) {
-	return b.w.Write(p)
-}
-
 func Bputc(b *Biobuf, c byte) {
 	b.w.WriteByte(c)
 }
@@ -120,18 +119,11 @@
 }
 
 func Bgetc(b *Biobuf) int {
-	if b.numUnget > 0 {
-		b.numUnget--
-		return int(b.unget[b.numUnget])
-	}
 	c, err := b.r.ReadByte()
-	r := int(c)
 	if err != nil {
-		r = -1
+		return -1
 	}
-	b.unget[1] = b.unget[0]
-	b.unget[0] = r
-	return r
+	return int(c)
 }
 
 func Bgetrune(b *Biobuf) int {
@@ -150,6 +142,10 @@
 	return b.r.Read(p)
 }
 
+func (b *Biobuf) Peek(n int) ([]byte, error) {
+	return b.r.Peek(n)
+}
+
 func Brdline(b *Biobuf, delim int) string {
 	s, err := b.r.ReadBytes(byte(delim))
 	if err != nil {
@@ -185,14 +181,6 @@
 	return b.linelen
 }
 
-func Bungetc(b *Biobuf) {
-	b.numUnget++
-}
-
-func Bflush(b *Biobuf) error {
-	return b.w.Flush()
-}
-
 func Bterm(b *Biobuf) error {
 	var err error
 	if b.w != nil {
@@ -379,7 +367,7 @@
 			break
 		}
 
-		str = fmt.Sprintf("%v", Rconv(int(a.Reg)))
+		str = Rconv(int(a.Reg))
 		if a.Name != TYPE_NONE || a.Sym != nil {
 			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
 		}
@@ -388,9 +376,9 @@
 		if a.Sym != nil {
 			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
 		} else if p != nil && p.Pcond != nil {
-			str = fmt.Sprintf("%d", p.Pcond.Pc)
+			str = fmt.Sprint(p.Pcond.Pc)
 		} else if a.Val != nil {
-			str = fmt.Sprintf("%d", a.Val.(*Prog).Pc)
+			str = fmt.Sprint(a.Val.(*Prog).Pc)
 		} else {
 			str = fmt.Sprintf("%d(PC)", a.Offset)
 		}
@@ -467,7 +455,7 @@
 	case NAME_NONE:
 		switch {
 		case a.Reg == REG_NONE:
-			str = fmt.Sprintf("%d", a.Offset)
+			str = fmt.Sprint(a.Offset)
 		case a.Offset == 0:
 			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
 		case a.Offset != 0:
@@ -477,6 +465,9 @@
 	case NAME_EXTERN:
 		str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
 
+	case NAME_GOTREF:
+		str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
+
 	case NAME_STATIC:
 		str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
 
@@ -638,3 +629,10 @@
 	"VARDEF",
 	"VARKILL",
 }
+
+func Bool2int(b bool) int {
+	if b {
+		return 1
+	}
+	return 0
+}
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 997e920..0c0cc04 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2028,6 +2028,7 @@
 	case obj.TYPE_ADDR:
 		switch a.Name {
 		case obj.NAME_EXTERN,
+			obj.NAME_GOTREF,
 			obj.NAME_STATIC:
 			if a.Sym != nil && isextern(a.Sym) || p.Mode == 32 {
 				return Yi32
@@ -2437,6 +2438,7 @@
 
 	switch a.Name {
 	case obj.NAME_STATIC,
+		obj.NAME_GOTREF,
 		obj.NAME_EXTERN:
 		s := a.Sym
 		if r == nil {
@@ -2444,7 +2446,10 @@
 			log.Fatalf("reloc")
 		}
 
-		if isextern(s) || p.Mode != 64 {
+		if a.Name == obj.NAME_GOTREF {
+			r.Siz = 4
+			r.Type = obj.R_GOTPCREL
+		} else if isextern(s) || p.Mode != 64 {
 			r.Siz = 4
 			r.Type = obj.R_ADDR
 		} else {
@@ -2455,11 +2460,6 @@
 		r.Off = -1 // caller must fill in
 		r.Sym = s
 		r.Add = a.Offset
-		if s.Type == obj.STLSBSS {
-			r.Xadd = r.Add - int64(r.Siz)
-			r.Type = obj.R_TLS
-			r.Xsym = s
-		}
 
 		return 0
 	}
@@ -2519,6 +2519,7 @@
 		base := int(a.Reg)
 		switch a.Name {
 		case obj.NAME_EXTERN,
+			obj.NAME_GOTREF,
 			obj.NAME_STATIC:
 			if !isextern(a.Sym) && p.Mode == 64 {
 				goto bad
@@ -2564,6 +2565,7 @@
 	base = int(a.Reg)
 	switch a.Name {
 	case obj.NAME_STATIC,
+		obj.NAME_GOTREF,
 		obj.NAME_EXTERN:
 		if a.Sym == nil {
 			ctxt.Diag("bad addr: %v", p)
@@ -2582,7 +2584,10 @@
 
 	ctxt.Rexflag |= regrex[base]&Rxb | rex
 	if base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS {
-		if (a.Sym == nil || !isextern(a.Sym)) && base == REG_NONE && (a.Name == obj.NAME_STATIC || a.Name == obj.NAME_EXTERN) || p.Mode != 64 {
+		if (a.Sym == nil || !isextern(a.Sym)) && base == REG_NONE && (a.Name == obj.NAME_STATIC || a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_GOTREF) || p.Mode != 64 {
+			if a.Name == obj.NAME_GOTREF && (a.Offset != 0 || a.Index != 0 || a.Scale != 0) {
+				ctxt.Diag("%v has offset against gotref", p)
+			}
 			ctxt.Andptr[0] = byte(0<<6 | 5<<0 | r<<3)
 			ctxt.Andptr = ctxt.Andptr[1:]
 			goto putrelv
@@ -2622,7 +2627,7 @@
 	if REG_AX <= base && base <= REG_R15 {
 		if a.Index == REG_TLS && ctxt.Flag_shared == 0 {
 			rel = obj.Reloc{}
-			rel.Type = obj.R_TLS_IE
+			rel.Type = obj.R_TLS_LE
 			rel.Siz = 4
 			rel.Sym = nil
 			rel.Add = int64(v)
@@ -2911,7 +2916,6 @@
 }
 
 var bpduff2 = []byte{
-	0x90,
 	0x48, 0x8b, 0x6d, 0x00, // MOVQ 0(BP), BP
 }
 
@@ -2981,7 +2985,7 @@
 	f3t := int(p.F3t) * Ymax
 	tt := int(p.Tt) * Ymax
 
-	xo := bool2int(o.op[0] == 0x0f)
+	xo := obj.Bool2int(o.op[0] == 0x0f)
 	z := 0
 	var a *obj.Addr
 	var l int
@@ -3441,6 +3445,10 @@
 					log.Fatalf("bad code")
 				}
 
+				if yt.zcase == Zcallduff && ctxt.Flag_dynlink {
+					ctxt.Diag("directly calling duff when dynamically linking Go")
+				}
+
 				if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
 					// Maintain BP around call, since duffcopy/duffzero can't do it
 					// (the call jumps into the middle of the function).
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 3d9a4be..7a4fc12 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -38,7 +38,7 @@
 	"math"
 )
 
-func canuselocaltls(ctxt *obj.Link) bool {
+func canuse1insntls(ctxt *obj.Link) bool {
 	if ctxt.Arch.Regsize == 4 {
 		switch ctxt.Headtype {
 		case obj.Hlinux,
@@ -92,29 +92,36 @@
 	// if the linker needs to adjust the offset, it can. For example:
 	//
 	//         MOVQ TLS, AX
-	//         MOVQ 8(AX)(TLS*1), CX // load m into CX
+	//         MOVQ 0(AX)(TLS*1), CX // load g into CX
 	//
 	// On systems that support direct access to the TLS memory, this
 	// pair of instructions can be reduced to a direct TLS memory reference:
 	//
-	//         MOVQ 8(TLS), CX // load m into CX
+	//         MOVQ 0(TLS), CX // load g into CX
 	//
-	// The 2-instruction and 1-instruction forms correspond roughly to
-	// ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
+	// The 2-instruction and 1-instruction forms correspond to the two code
+	// sequences for loading a TLS variable in the local exec model given in "ELF
+	// Handling For Thread-Local Storage".
 	//
-	// We applies this rewrite on systems that support the 1-instruction form.
-	// The decision is made using only the operating system (and probably
-	// the -shared flag, eventually), not the link mode. If some link modes
-	// on a particular operating system require the 2-instruction form,
-	// then all builds for that operating system will use the 2-instruction
-	// form, so that the link mode decision can be delayed to link time.
+	// We apply this rewrite on systems that support the 1-instruction form.
+	// The decision is made using only the operating system and the -shared flag,
+	// not the link mode. If some link modes on a particular operating system
+	// require the 2-instruction form, then all builds for that operating system
+	// will use the 2-instruction form, so that the link mode decision can be
+	// delayed to link time.
 	//
 	// In this way, all supported systems use identical instructions to
 	// access TLS, and they are rewritten appropriately first here in
 	// liblink and then finally using relocations in the linker.
+	//
+	// When -shared is passed, we leave the code in the 2-instruction form but
+	// assemble (and relocate) them in different ways to generate the initial
+	// exec code sequence. It's a bit of a fluke that this is possible without
+	// rewriting the instructions more comprehensively, and it only does because
+	// we only support a single TLS variable (g).
 
-	if canuselocaltls(ctxt) {
-		// Reduce TLS initial exec model to TLS local exec model.
+	if canuse1insntls(ctxt) {
+		// Reduce 2-instruction sequence to 1-instruction sequence.
 		// Sequences like
 		//	MOVQ TLS, BX
 		//	... off(BX)(TLS*1) ...
@@ -140,13 +147,12 @@
 			p.To.Index = REG_NONE
 		}
 	} else {
-		// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
-		// The instruction
-		//	MOVQ off(TLS), BX
-		// becomes the sequence
+		// load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it
+		// as the 2-instruction sequence if necessary.
+		//	MOVQ 0(TLS), BX
+		// becomes
 		//	MOVQ TLS, BX
-		//	MOVQ off(BX)(TLS*1), BX
-		// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
+		//	MOVQ 0(BX)(TLS*1), BX
 		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
 			q := obj.Appendp(ctxt, p)
 			q.As = p.As
@@ -243,15 +249,10 @@
 			i32 := math.Float32bits(f32)
 			literal := fmt.Sprintf("$f32.%08x", i32)
 			s := obj.Linklookup(ctxt, literal, 0)
-			if s.Type == 0 {
-				s.Type = obj.SRODATA
-				obj.Adduint32(ctxt, s, i32)
-				s.Reachable = 0
-			}
-
 			p.From.Type = obj.TYPE_MEM
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Sym = s
+			p.From.Sym.Local = true
 			p.From.Offset = 0
 		}
 
@@ -287,18 +288,119 @@
 			i64 := math.Float64bits(p.From.Val.(float64))
 			literal := fmt.Sprintf("$f64.%016x", i64)
 			s := obj.Linklookup(ctxt, literal, 0)
-			if s.Type == 0 {
-				s.Type = obj.SRODATA
-				obj.Adduint64(ctxt, s, i64)
-				s.Reachable = 0
-			}
-
 			p.From.Type = obj.TYPE_MEM
 			p.From.Name = obj.NAME_EXTERN
 			p.From.Sym = s
+			p.From.Sym.Local = true
 			p.From.Offset = 0
 		}
 	}
+
+	if ctxt.Flag_dynlink && (p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO) {
+		var sym *obj.LSym
+		if p.As == obj.ADUFFZERO {
+			sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+		} else {
+			sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+		}
+		offset := p.To.Offset
+		p.As = AMOVQ
+		p.From.Type = obj.TYPE_MEM
+		p.From.Name = obj.NAME_GOTREF
+		p.From.Sym = sym
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R15
+		p.To.Offset = 0
+		p.To.Sym = nil
+		p1 := obj.Appendp(ctxt, p)
+		p1.As = AADDQ
+		p1.From.Type = obj.TYPE_CONST
+		p1.From.Offset = offset
+		p1.To.Type = obj.TYPE_REG
+		p1.To.Reg = REG_R15
+		p2 := obj.Appendp(ctxt, p1)
+		p2.As = obj.ACALL
+		p2.To.Type = obj.TYPE_REG
+		p2.To.Reg = REG_R15
+	}
+
+	if ctxt.Flag_dynlink {
+		if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+			p.As = AMOVQ
+			p.From.Type = obj.TYPE_ADDR
+		}
+		if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+			if p.As != AMOVQ {
+				ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
+			}
+			if p.To.Type != obj.TYPE_REG {
+				ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
+			}
+			p.From.Type = obj.TYPE_MEM
+			p.From.Name = obj.NAME_GOTREF
+			if p.From.Offset != 0 {
+				q := obj.Appendp(ctxt, p)
+				q.As = AADDQ
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = p.From.Offset
+				q.To = p.To
+				p.From.Offset = 0
+			}
+		}
+		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 {
+				ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
+			}
+			source = &p.From
+		} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+			source = &p.To
+		} else {
+			return
+		}
+		if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+			return
+		}
+		if source.Type != obj.TYPE_MEM {
+			ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		}
+		p1 := obj.Appendp(ctxt, p)
+		p2 := obj.Appendp(ctxt, p1)
+
+		p1.As = AMOVQ
+		p1.From.Type = obj.TYPE_MEM
+		p1.From.Sym = source.Sym
+		p1.From.Name = obj.NAME_GOTREF
+		p1.To.Type = obj.TYPE_REG
+		p1.To.Reg = REG_R15
+
+		p2.As = p.As
+		p2.From = p.From
+		p2.To = p.To
+		if p.From.Name == obj.NAME_EXTERN {
+			p2.From.Reg = REG_R15
+			p2.From.Name = obj.NAME_NONE
+			p2.From.Sym = nil
+		} else if p.To.Name == obj.NAME_EXTERN {
+			p2.To.Reg = REG_R15
+			p2.To.Name = obj.NAME_NONE
+			p2.To.Sym = nil
+		} else {
+			return
+		}
+		l := p.Link
+		l2 := p2.Link
+		*p = *p1
+		*p1 = *p2
+		p.Link = l
+		p1.Link = l2
+	}
 }
 
 func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
@@ -337,10 +439,6 @@
 	if ctxt.Tlsg == nil {
 		ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0)
 	}
-	if ctxt.Symmorestack[0] == nil {
-		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
-		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
-	}
 
 	if ctxt.Headtype == obj.Hplan9 && ctxt.Plan9privates == nil {
 		ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
@@ -402,7 +500,7 @@
 
 	var q *obj.Prog
 	if cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
-		p = stacksplit(ctxt, p, autoffset, int32(textarg), cursym.Text.From3.Offset&obj.NEEDCTXT == 0, &q) // emit split check
+		p = stacksplit(ctxt, p, autoffset, int32(textarg), &q) // emit split check
 	}
 
 	if autoffset != 0 {
@@ -759,7 +857,7 @@
 // Returns last new instruction.
 // On return, *jmpok is the instruction that should jump
 // to the stack frame allocation if no split is needed.
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32, noctxt bool, jmpok **obj.Prog) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32, jmpok **obj.Prog) *obj.Prog {
 	cmp := ACMPQ
 	lea := ALEAQ
 	mov := AMOVQ
@@ -885,8 +983,10 @@
 	p.To.Type = obj.TYPE_BRANCH
 	if ctxt.Cursym.Cfunc != 0 {
 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
+	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
 	} else {
-		p.To.Sym = ctxt.Symmorestack[bool2int(noctxt)]
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
 	}
 
 	p = obj.Appendp(ctxt, p)
diff --git a/src/cmd/internal/obj/x86/obj6_test.go b/src/cmd/internal/obj/x86/obj6_test.go
new file mode 100644
index 0000000..b4526fc
--- /dev/null
+++ b/src/cmd/internal/obj/x86/obj6_test.go
@@ -0,0 +1,172 @@
+package x86_test
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"go/build"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+const testdata = `
+MOVQ AX, AX -> MOVQ AX, AX
+
+LEAQ name(SB), AX -> MOVQ name@GOT(SB), AX
+LEAQ name+10(SB), AX -> MOVQ name@GOT(SB), AX; ADDQ $10, AX
+MOVQ $name(SB), AX -> MOVQ name@GOT(SB), AX
+MOVQ $name+10(SB), AX -> MOVQ name@GOT(SB), AX; ADDQ $10, AX
+
+MOVQ name(SB), AX -> MOVQ name@GOT(SB), R15; MOVQ (R15), AX
+MOVQ name+10(SB), AX -> MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX
+
+CMPQ name(SB), $0 -> MOVQ name@GOT(SB), R15; CMPQ (R15), $0
+
+MOVQ $1, name(SB) -> MOVQ name@GOT(SB), R15; MOVQ $1, (R15)
+MOVQ $1, name+10(SB) -> MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15)
+`
+
+type ParsedTestData struct {
+	input              string
+	marks              []int
+	marker_to_input    map[int][]string
+	marker_to_expected map[int][]string
+	marker_to_output   map[int][]string
+}
+
+const marker_start = 1234
+
+func parseTestData(t *testing.T) *ParsedTestData {
+	r := &ParsedTestData{}
+	scanner := bufio.NewScanner(strings.NewReader(testdata))
+	r.marker_to_input = make(map[int][]string)
+	r.marker_to_expected = make(map[int][]string)
+	marker := marker_start
+	input_insns := []string{}
+	for scanner.Scan() {
+		line := scanner.Text()
+		if len(strings.TrimSpace(line)) == 0 {
+			continue
+		}
+		parts := strings.Split(line, "->")
+		if len(parts) != 2 {
+			t.Fatalf("malformed line %v", line)
+		}
+		r.marks = append(r.marks, marker)
+		marker_insn := fmt.Sprintf("MOVQ $%d, AX", marker)
+		input_insns = append(input_insns, marker_insn)
+		for _, input_insn := range strings.Split(parts[0], ";") {
+			input_insns = append(input_insns, input_insn)
+			r.marker_to_input[marker] = append(r.marker_to_input[marker], normalize(input_insn))
+		}
+		for _, expected_insn := range strings.Split(parts[1], ";") {
+			r.marker_to_expected[marker] = append(r.marker_to_expected[marker], normalize(expected_insn))
+		}
+		marker++
+	}
+	r.input = "TEXT ·foo(SB),$0\n" + strings.Join(input_insns, "\n") + "\n"
+	return r
+}
+
+var spaces_re *regexp.Regexp = regexp.MustCompile("\\s+")
+var marker_re *regexp.Regexp = regexp.MustCompile("MOVQ \\$([0-9]+), AX")
+
+func normalize(s string) string {
+	return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ")
+}
+
+func asmOutput(t *testing.T, s string) []byte {
+	tmpdir, err := ioutil.TempDir("", "progedittest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+	tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer tmpfile.Close()
+	_, err = tmpfile.WriteString(s)
+	if err != nil {
+		t.Fatal(err)
+	}
+	gofolder := filepath.Join(build.Default.GOROOT, "bin")
+	if gobin := os.Getenv("GOBIN"); len(gobin) != 0 {
+		gofolder = gobin
+	}
+
+	cmd := exec.Command(
+		filepath.Join(gofolder, "go"), "tool", "asm", "-S", "-dynlink",
+		"-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())
+
+	var env []string
+	for _, v := range os.Environ() {
+		if !strings.HasPrefix(v, "GOARCH=") {
+			env = append(env, v)
+		}
+	}
+	cmd.Env = append(env, "GOARCH=amd64")
+	asmout, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("error %s output %s", err, asmout)
+	}
+	return asmout
+}
+
+func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) {
+	scanner := bufio.NewScanner(bytes.NewReader(asmout))
+	marker := regexp.MustCompile("MOVQ \\$([0-9]+), AX")
+	mark := -1
+	td.marker_to_output = make(map[int][]string)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if line[0] != '\t' {
+			continue
+		}
+		parts := strings.SplitN(line, "\t", 3)
+		if len(parts) != 3 {
+			continue
+		}
+		n := normalize(parts[2])
+		mark_matches := marker.FindStringSubmatch(n)
+		if mark_matches != nil {
+			mark, _ = strconv.Atoi(mark_matches[1])
+			if _, ok := td.marker_to_input[mark]; !ok {
+				t.Fatalf("unexpected marker %d", mark)
+			}
+		} else if mark != -1 {
+			td.marker_to_output[mark] = append(td.marker_to_output[mark], n)
+		}
+	}
+}
+
+func TestDynlink(t *testing.T) {
+	iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
+	if runtime.GOOS == "nacl" || runtime.GOOS == "android" || iOS {
+		t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
+	}
+	testdata := parseTestData(t)
+	asmout := asmOutput(t, testdata.input)
+	parseOutput(t, testdata, asmout)
+	for _, m := range testdata.marks {
+		i := strings.Join(testdata.marker_to_input[m], "; ")
+		o := strings.Join(testdata.marker_to_output[m], "; ")
+		e := strings.Join(testdata.marker_to_expected[m], "; ")
+		if o != e {
+			if o == i {
+				t.Errorf("%s was unchanged; should have become %s", i, e)
+			} else {
+				t.Errorf("%s became %s; should have become %s", i, o, e)
+			}
+		} else if i != e {
+			t.Logf("%s correctly became %s", i, o)
+		}
+	}
+}
diff --git a/src/cmd/internal/obj/x86/util.go b/src/cmd/internal/obj/x86/util.go
deleted file mode 100644
index dceedf8..0000000
--- a/src/cmd/internal/obj/x86/util.go
+++ /dev/null
@@ -1,12 +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 x86
-
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
diff --git a/src/cmd/link/load.go b/src/cmd/link/load.go
index ca0c24c..50602b8 100644
--- a/src/cmd/link/load.go
+++ b/src/cmd/link/load.go
@@ -6,7 +6,10 @@
 
 package main
 
-import "os"
+import (
+	"cmd/internal/obj"
+	"os"
+)
 
 // load allocates segment images, populates them with data
 // read from package files, and applies relocations to the data.
@@ -73,17 +76,6 @@
 	}
 }
 
-// TODO(rsc): Define full enumeration for relocation types.
-const (
-	R_ADDR    = 1
-	R_SIZE    = 2
-	R_CALL    = 3
-	R_CALLARM = 4
-	R_CALLIND = 5
-	R_CONST   = 6
-	R_PCREL   = 7
-)
-
 // relocateSym applies relocations to sym's data.
 func (p *Prog) relocateSym(sym *Sym, data []byte) {
 	for i := range sym.Reloc {
@@ -97,9 +89,9 @@
 		switch r.Type {
 		default:
 			p.errorf("%v: unknown relocation type %d", sym, r.Type)
-		case R_ADDR, R_CALLIND:
+		case obj.R_ADDR, obj.R_CALLIND:
 			// ok
-		case R_PCREL, R_CALL:
+		case obj.R_PCREL, obj.R_CALL:
 			val -= sym.Addr + Addr(r.Offset+r.Size)
 		}
 		frag := data[r.Offset : r.Offset+r.Size]
diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go
index 2d13178..7f8bf52 100644
--- a/src/cmd/link/pclntab.go
+++ b/src/cmd/link/pclntab.go
@@ -8,6 +8,7 @@
 
 import (
 	"cmd/internal/goobj"
+	"cmd/internal/obj"
 	"encoding/binary"
 	"os"
 	"sort"
@@ -371,7 +372,7 @@
 		Size:   b.ptrsize,
 		Sym:    sym,
 		Add:    int(symoff),
-		Type:   R_ADDR,
+		Type:   obj.R_ADDR,
 	})
 	return off + b.ptrsize
 }
diff --git a/src/cmd/link/testdata/Makefile b/src/cmd/link/testdata/Makefile
index e9651a0..83e8a05 100644
--- a/src/cmd/link/testdata/Makefile
+++ b/src/cmd/link/testdata/Makefile
@@ -9,7 +9,7 @@
 all: $(ALL)
 
 %.6: %.s
-	GOARCH=amd64 GOOS=darwin go tool 6a -trimpath=$(shell pwd) $*.s
+	GOARCH=amd64 GOOS=darwin go tool asm -I $(shell go env GOROOT)/pkg/include -trimpath=$(shell pwd) $*.s
 
 pclntab.s: genpcln.go
 	go run genpcln.go >pclntab.s
diff --git a/src/cmd/link/testdata/autosection.6 b/src/cmd/link/testdata/autosection.6
index 386f422..34aa5d3 100644
--- a/src/cmd/link/testdata/autosection.6
+++ b/src/cmd/link/testdata/autosection.6
Binary files differ
diff --git a/src/cmd/link/testdata/autoweak.6 b/src/cmd/link/testdata/autoweak.6
index 5d74d4e..a86b841 100644
--- a/src/cmd/link/testdata/autoweak.6
+++ b/src/cmd/link/testdata/autoweak.6
Binary files differ
diff --git a/src/cmd/link/testdata/dead.6 b/src/cmd/link/testdata/dead.6
index 9540adc..5e9b09c 100644
--- a/src/cmd/link/testdata/dead.6
+++ b/src/cmd/link/testdata/dead.6
Binary files differ
diff --git a/src/cmd/link/testdata/hello.6 b/src/cmd/link/testdata/hello.6
index 67983f1..890cbbd 100644
--- a/src/cmd/link/testdata/hello.6
+++ b/src/cmd/link/testdata/hello.6
Binary files differ
diff --git a/src/cmd/link/testdata/layout.6 b/src/cmd/link/testdata/layout.6
index db24ef3..748c836 100644
--- a/src/cmd/link/testdata/layout.6
+++ b/src/cmd/link/testdata/layout.6
Binary files differ
diff --git a/src/cmd/link/testdata/link.hello.darwin.amd64 b/src/cmd/link/testdata/link.hello.darwin.amd64
index 0bd475d..4c62eb1 100644
--- a/src/cmd/link/testdata/link.hello.darwin.amd64
+++ b/src/cmd/link/testdata/link.hello.darwin.amd64
@@ -6,23 +6,23 @@
 *
 00000060  00 00 00 00 00 00 00 00  19 00 00 00 38 01 00 00  |............8...|
 00000070  5f 5f 54 45 58 54 00 00  00 00 00 00 00 00 00 00  |__TEXT..........|
-00000080  00 10 00 00 00 00 00 00  b0 10 00 00 00 00 00 00  |................|
-00000090  00 00 00 00 00 00 00 00  b0 10 00 00 00 00 00 00  |................|
+00000080  00 10 00 00 00 00 00 00  c0 10 00 00 00 00 00 00  |................|
+00000090  00 00 00 00 00 00 00 00  c0 10 00 00 00 00 00 00  |................|
 000000a0  07 00 00 00 05 00 00 00  03 00 00 00 00 00 00 00  |................|
 000000b0  5f 5f 74 65 78 74 00 00  00 00 00 00 00 00 00 00  |__text..........|
 000000c0  5f 5f 54 45 58 54 00 00  00 00 00 00 00 00 00 00  |__TEXT..........|
-000000d0  00 20 00 00 00 00 00 00  20 00 00 00 00 00 00 00  |. ...... .......|
+000000d0  00 20 00 00 00 00 00 00  30 00 00 00 00 00 00 00  |. ......0.......|
 000000e0  00 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000000f0  00 04 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000100  5f 5f 72 6f 64 61 74 61  00 00 00 00 00 00 00 00  |__rodata........|
 00000110  5f 5f 54 45 58 54 00 00  00 00 00 00 00 00 00 00  |__TEXT..........|
-00000120  20 20 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |  ..............|
-00000130  20 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  | ...............|
+00000120  30 20 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |0 ..............|
+00000130  30 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |0...............|
 *
 00000150  5f 5f 66 75 6e 63 74 61  62 00 00 00 00 00 00 00  |__functab.......|
 00000160  5f 5f 54 45 58 54 00 00  00 00 00 00 00 00 00 00  |__TEXT..........|
-00000170  20 20 00 00 00 00 00 00  90 00 00 00 00 00 00 00  |  ..............|
-00000180  20 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  | ...............|
+00000170  30 20 00 00 00 00 00 00  90 00 00 00 00 00 00 00  |0 ..............|
+00000180  30 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |0...............|
 *
 000001a0  19 00 00 00 98 00 00 00  5f 5f 44 41 54 41 00 00  |........__DATA..|
 000001b0  00 00 00 00 00 00 00 00  00 30 00 00 00 00 00 00  |.........0......|
@@ -38,17 +38,18 @@
 *
 000002c0  00 00 00 00 00 00 00 00  00 20 00 00 00 00 00 00  |......... ......|
 *
-00001000  bf 01 00 00 00 be 00 30  00 00 ba 0c 00 00 00 b8  |.......0........|
-00001010  04 00 00 02 0f 05 31 ff  b8 01 00 00 02 0f 05 c3  |......1.........|
-00001020  fb ff ff ff 00 00 01 08  01 00 00 00 00 00 00 00  |................|
-00001030  00 20 00 00 00 00 00 00  30 00 00 00 00 00 00 00  |. ......0.......|
-00001040  20 20 00 00 00 00 00 00  80 00 00 00 00 00 00 00  |  ..............|
-00001050  00 20 00 00 00 00 00 00  58 00 00 00 00 00 00 80  |. ......X.......|
-00001060  08 00 00 00 60 00 00 00  63 00 00 00 66 00 00 00  |....`...c...f...|
-00001070  00 00 00 00 00 00 00 00  5f 72 74 30 5f 67 6f 00  |........_rt0_go.|
-00001080  02 20 00 04 20 00 06 05  02 05 02 05 02 05 02 02  |. .. ...........|
-00001090  02 02 02 05 02 02 02 01  00 00 00 00 00 00 00 00  |................|
-000010a0  02 00 00 00 88 00 00 00  68 65 6c 6c 6f 2e 73 00  |........hello.s.|
+00001000  bf 01 00 00 00 8d 35 f5  0f 00 00 ba 0c 00 00 00  |......5.........|
+00001010  b8 04 00 00 02 0f 05 31  ff b8 01 00 00 02 0f 05  |.......1........|
+00001020  c3 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00001030  fb ff ff ff 00 00 01 08  01 00 00 00 00 00 00 00  |................|
+00001040  00 20 00 00 00 00 00 00  30 00 00 00 00 00 00 00  |. ......0.......|
+00001050  30 20 00 00 00 00 00 00  80 00 00 00 00 00 00 00  |0 ..............|
+00001060  00 20 00 00 00 00 00 00  58 00 00 00 00 00 00 80  |. ......X.......|
+00001070  08 00 00 00 60 00 00 00  63 00 00 00 66 00 00 00  |....`...c...f...|
+00001080  00 00 00 00 00 00 00 00  5f 72 74 30 5f 67 6f 00  |........_rt0_go.|
+00001090  02 30 00 04 30 00 06 05  02 06 02 05 02 05 02 02  |.0..0...........|
+000010a0  02 02 02 05 02 02 02 10  00 00 00 00 00 00 00 00  |................|
+000010b0  02 00 00 00 88 00 00 00  68 65 6c 6c 6f 2e 73 00  |........hello.s.|
 *
 00002000  68 65 6c 6c 6f 20 77 6f  72 6c 64 0a              |hello world.|
 0000200c
diff --git a/src/cmd/link/testdata/pclntab.6 b/src/cmd/link/testdata/pclntab.6
index 9e7f9af..8156698 100644
--- a/src/cmd/link/testdata/pclntab.6
+++ b/src/cmd/link/testdata/pclntab.6
Binary files differ
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index 3081921..155d103 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -59,8 +59,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 1846272..e0859b1 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -19,8 +19,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
@@ -125,5 +126,9 @@
 	case "arm64":
 		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
 	}
+	// TODO(jsing): Renable once openbsd/arm has external linking support.
+	if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
+		t.Skip("skipping on openbsd/arm, no support for external linking, issue 10619")
+	}
 	testDisasm(t, "-ldflags=-linkmode=external")
 }
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index c472c57..9c33f4f 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -203,8 +203,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
@@ -244,8 +245,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
diff --git a/src/cmd/pprof/internal/driver/driver.go b/src/cmd/pprof/internal/driver/driver.go
index 9703baf..acb29d1 100644
--- a/src/cmd/pprof/internal/driver/driver.go
+++ b/src/cmd/pprof/internal/driver/driver.go
@@ -1013,6 +1013,10 @@
 		w = outputFile
 	}
 
+	if prof.Empty() {
+		return fmt.Errorf("profile is empty")
+	}
+
 	value, stype, unit := sampleFormat(prof, f)
 	o.SampleType = stype
 	rpt := report.New(prof, *o, value, unit)
diff --git a/src/cmd/pprof/internal/profile/profile.go b/src/cmd/pprof/internal/profile/profile.go
index 7ee58ee..5eb641f 100644
--- a/src/cmd/pprof/internal/profile/profile.go
+++ b/src/cmd/pprof/internal/profile/profile.go
@@ -565,3 +565,8 @@
 	}
 	return nil
 }
+
+// Empty returns true if the profile contains no samples.
+func (p *Profile) Empty() bool {
+	return len(p.Sample) == 0
+}
diff --git a/src/cmd/pprof/internal/profile/profile_test.go b/src/cmd/pprof/internal/profile/profile_test.go
new file mode 100644
index 0000000..09b11a4
--- /dev/null
+++ b/src/cmd/pprof/internal/profile/profile_test.go
@@ -0,0 +1,24 @@
+// 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 profile
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestEmptyProfile(t *testing.T) {
+	var buf bytes.Buffer
+	p, err := Parse(&buf)
+	if err != nil {
+		t.Error("Want no error, got", err)
+	}
+	if p == nil {
+		t.Fatal("Want a valid profile, got <nil>")
+	}
+	if !p.Empty() {
+		t.Errorf("Profile should be empty, got %#v", p)
+	}
+}
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index 16a20ae..02cd0a5 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -323,7 +323,7 @@
 
 func (ctx *traceContext) time(ev *trace.Event) int64 {
 	if ev.Ts < ctx.startTime || ev.Ts > ctx.endTime {
-		fmt.Printf("ts=%v startTime=%v endTime\n", ev.Ts, ctx.startTime, ctx.endTime)
+		fmt.Printf("ts=%v startTime=%v endTime=%v\n", ev.Ts, ctx.startTime, ctx.endTime)
 		panic("timestamp is outside of trace range")
 	}
 	// NOTE: trace viewer wants timestamps in microseconds and it does not
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 68e59e5..5c7b0b7 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -507,29 +507,6 @@
 		errorf("unexpected EOF before %%")
 	}
 
-	// put out non-literal terminals
-	for i := TOKSTART; i <= ntokens; i++ {
-		// non-literals
-		if !tokset[i].noconst {
-			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
-		}
-	}
-
-	// put out names of token names
-	ftable.WriteRune('\n')
-	fmt.Fprintf(ftable, "var %sToknames = []string{\n", prefix)
-	for i := TOKSTART; i <= ntokens; i++ {
-		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
-	}
-	fmt.Fprintf(ftable, "}\n")
-
-	// put out names of state names
-	fmt.Fprintf(ftable, "var %sStatenames = []string{", prefix)
-	//	for i:=TOKSTART; i<=ntokens; i++ {
-	//		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
-	//	}
-	fmt.Fprintf(ftable, "}\n")
-
 	fmt.Fprintf(fcode, "switch %snt {\n", prefix)
 
 	moreprod()
@@ -660,9 +637,6 @@
 			if tempty != nontrst[curprod[0]-NTBASE].value {
 				lerrorf(ruleline, "default action causes potential type clash")
 			}
-			fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
-			fmt.Fprintf(fcode, "\n\t\t%sVAL.%v = %sS[%spt-0].%v",
-				prefix, typeset[tempty], prefix, prefix, typeset[tempty])
 		}
 		moreprod()
 		prdptr[nprod] = make([]int, mem)
@@ -679,6 +653,29 @@
 
 	fmt.Fprintf(fcode, "\n\t}")
 
+	// put out non-literal terminals
+	for i := TOKSTART; i <= ntokens; i++ {
+		// non-literals
+		if !tokset[i].noconst {
+			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
+		}
+	}
+
+	// put out names of token names
+	ftable.WriteRune('\n')
+	fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
+	for i := 1; i <= ntokens; i++ {
+		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
+	}
+	fmt.Fprintf(ftable, "}\n")
+
+	// put out names of state names
+	fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
+	//	for i:=TOKSTART; i<=ntokens; i++ {
+	//		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
+	//	}
+	fmt.Fprintf(ftable, "}\n")
+
 	ftable.WriteRune('\n')
 	fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
 	fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
@@ -2156,7 +2153,7 @@
 	if !lflag {
 		fmt.Fprintf(ftable, "\n//line yacctab:1")
 	}
-	fmt.Fprintf(ftable, "\nvar %sExca = []int{\n", prefix)
+	fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
 
 	noset := mkset()
 
@@ -2892,7 +2889,7 @@
 	arout("Tok2", temp1, c+1)
 
 	// table 3 has everything else
-	fmt.Fprintf(ftable, "var %sTok3 = []int{\n\t", prefix)
+	fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix)
 	c = 0
 	for i = 1; i <= ntokens; i++ {
 		j = tokset[i].value
@@ -2937,7 +2934,7 @@
 
 func arout(s string, v []int, n int) {
 	s = prefix + s
-	fmt.Fprintf(ftable, "var %v = []int{\n", s)
+	fmt.Fprintf(ftable, "var %v = [...]int{\n", s)
 	for i := 0; i < n; i++ {
 		if i%10 == 0 {
 			fmt.Fprintf(ftable, "\n\t")
@@ -3198,7 +3195,10 @@
 var yaccpartext = `
 /*	parser for yacc output	*/
 
-var $$Debug = 0
+var (
+	$$Debug        = 0
+	$$ErrorVerbose = false
+)
 
 type $$Lexer interface {
 	Lex(lval *$$SymType) int
@@ -3212,6 +3212,7 @@
 
 type $$ParserImpl struct {
 	lookahead func() int
+	state     func() int
 }
 
 func (p *$$ParserImpl) Lookahead() int {
@@ -3221,6 +3222,7 @@
 func $$NewParser() $$Parser {
 	p := &$$ParserImpl{
 		lookahead: func() int { return -1 },
+		state:     func() int { return -1 },
 	}
 	return p
 }
@@ -3228,10 +3230,9 @@
 const $$Flag = -1000
 
 func $$Tokname(c int) string {
-	// 4 is TOKSTART above
-	if c >= 4 && c-4 < len($$Toknames) {
-		if $$Toknames[c-4] != "" {
-			return $$Toknames[c-4]
+	if c >= 1 && c-1 < len($$Toknames) {
+		if $$Toknames[c-1] != "" {
+			return $$Toknames[c-1]
 		}
 	}
 	return __yyfmt__.Sprintf("tok-%v", c)
@@ -3246,6 +3247,63 @@
 	return __yyfmt__.Sprintf("state-%v", s)
 }
 
+func $$ErrorMessage(state, lookAhead int) string {
+	const TOKSTART = 4
+
+	if !$$ErrorVerbose {
+		return "syntax error"
+	}
+	res := "syntax error: unexpected " + $$Tokname(lookAhead)
+
+	// To match Bison, suggest at most four expected tokens.
+	expected := make([]int, 0, 4)
+
+	// Look for shiftable tokens.
+	base := $$Pact[state]
+	for tok := TOKSTART; tok-1 < len($$Toknames); tok++ {
+		if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok {
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+	}
+
+	if $$Def[state] == -2 {
+		i := 0
+		for $$Exca[i] != -1 || $$Exca[i+1] != state {
+			i += 2
+		}
+
+		// Look for tokens that we accept or reduce.
+		for i += 2; $$Exca[i] >= 0; i += 2 {
+			tok := $$Exca[i]
+			if tok < TOKSTART || $$Exca[i+1] == 0 {
+				continue
+			}
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+
+		// If the default action is to accept or reduce, give up.
+		if $$Exca[i+1] != 0 {
+			return res
+		}
+	}
+
+	for i, tok := range expected {
+		if i == 0 {
+			res += ", expecting "
+		} else {
+			res += " or "
+		}
+		res += $$Tokname(tok)
+	}
+	return res
+}
+
 func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) {
 	token = 0
 	char = lex.Lex(lval)
@@ -3297,9 +3355,11 @@
 	$$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.
+		$$state = -1
 		$$char = -1
 		$$token = -1
 	}()
@@ -3382,7 +3442,7 @@
 		/* error ... attempt to resume parsing */
 		switch Errflag {
 		case 0: /* brand new error */
-			$$lex.Error("syntax error")
+			$$lex.Error($$ErrorMessage($$state, $$token))
 			Nerrs++
 			if $$Debug >= 1 {
 				__yyfmt__.Printf("%s", $$Statname($$state))
diff --git a/src/compress/flate/flate_test.go b/src/compress/flate/flate_test.go
index 0687663..06d35a0 100644
--- a/src/compress/flate/flate_test.go
+++ b/src/compress/flate/flate_test.go
@@ -10,6 +10,8 @@
 
 import (
 	"bytes"
+	"io/ioutil"
+	"strings"
 	"testing"
 )
 
@@ -30,9 +32,8 @@
 	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8}
-	h := new(huffmanDecoder)
-	ok := h.init(bits)
-	if ok == true {
+	var h huffmanDecoder
+	if h.init(bits) {
 		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
 	}
 }
@@ -41,9 +42,8 @@
 func TestIssue5962(t *testing.T) {
 	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0,
 		5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11}
-	h := new(huffmanDecoder)
-	ok := h.init(bits)
-	if ok == true {
+	var h huffmanDecoder
+	if h.init(bits) {
 		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
 	}
 }
@@ -52,7 +52,7 @@
 func TestIssue6255(t *testing.T) {
 	bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11}
 	bits2 := []int{11, 13}
-	h := new(huffmanDecoder)
+	var h huffmanDecoder
 	if !h.init(bits1) {
 		t.Fatalf("Given sequence of bits is good and should succeed.")
 	}
@@ -60,3 +60,59 @@
 		t.Fatalf("Given sequence of bits is bad and should not succeed.")
 	}
 }
+
+func TestInvalidEncoding(t *testing.T) {
+	// Initialize Huffman decoder to recognize "0".
+	var h huffmanDecoder
+	if !h.init([]int{1}) {
+		t.Fatal("Failed to initialize Huffman decoder")
+	}
+
+	// Initialize decompressor with invalid Huffman coding.
+	var f decompressor
+	f.r = bytes.NewReader([]byte{0xff})
+
+	_, err := f.huffSym(&h)
+	if err == nil {
+		t.Fatal("Should have rejected invalid bit sequence")
+	}
+}
+
+func TestInvalidBits(t *testing.T) {
+	oversubscribed := []int{1, 2, 3, 4, 4, 5}
+	incomplete := []int{1, 2, 4, 4}
+	var h huffmanDecoder
+	if h.init(oversubscribed) {
+		t.Fatal("Should reject oversubscribed bit-length set")
+	}
+	if h.init(incomplete) {
+		t.Fatal("Should reject incomplete bit-length set")
+	}
+}
+
+func TestDegenerateHuffmanCoding(t *testing.T) {
+	const (
+		want = "abcabc"
+		// This compressed form has a dynamic Huffman block, even though a
+		// sensible encoder would use a literal data block, as the latter is
+		// shorter. Still, it is a valid flate compression of "abcabc". It has
+		// a degenerate Huffman table with only one coded value: the one
+		// non-literal back-ref copy of the first "abc" to the second "abc".
+		//
+		// To verify that this is decompressible with zlib (the C library),
+		// it's easy to use the Python wrapper library:
+		// >>> import zlib
+		// >>> compressed = "\x0c\xc2...etc...\xff\xff"
+		// >>> zlib.decompress(compressed, -15) # negative means no GZIP header.
+		// 'abcabc'
+		compressed = "\x0c\xc2\x01\x0d\x00\x00\x00\x82\xb0\xac\x4a\xff\x0e\xb0\x7d\x27" +
+			"\x06\x00\x00\xff\xff"
+	)
+	b, err := ioutil.ReadAll(NewReader(strings.NewReader(compressed)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got := string(b); got != want {
+		t.Fatalf("got %q, want %q", got, want)
+	}
+}
diff --git a/src/compress/flate/gen.go b/src/compress/flate/gen.go
index 6288ecd..eeafa84 100644
--- a/src/compress/flate/gen.go
+++ b/src/compress/flate/gen.go
@@ -46,6 +46,15 @@
 
 // Initialize Huffman decoding tables from array of code lengths.
 func (h *huffmanDecoder) init(bits []int) bool {
+	// Sanity enables additional runtime tests during Huffman
+	// table construction.  It's intended to be used during
+	// development to supplement the currently ad-hoc unit tests.
+	const sanity = false
+
+	if h.min != 0 {
+		*h = huffmanDecoder{}
+	}
+
 	// Count number of codes of each length,
 	// compute min and max length.
 	var count [maxCodeLen]int
@@ -66,33 +75,41 @@
 		return false
 	}
 
-	h.min = min
-	var linkBits uint
-	var numLinks int
-	if max > huffmanChunkBits {
-		linkBits = uint(max) - huffmanChunkBits
-		numLinks = 1 << linkBits
-		h.linkMask = uint32(numLinks - 1)
-	}
 	code := 0
 	var nextcode [maxCodeLen]int
 	for i := min; i <= max; i++ {
-		if i == huffmanChunkBits+1 {
-			// create link tables
-			link := code >> 1
-			h.links = make([][]uint32, huffmanNumChunks-link)
-			for j := uint(link); j < huffmanNumChunks; j++ {
-				reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-				reverse >>= uint(16 - huffmanChunkBits)
-				off := j - uint(link)
-				h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i))
-				h.links[off] = make([]uint32, 1<<linkBits)
-			}
-		}
-		n := count[i]
-		nextcode[i] = code
-		code += n
 		code <<= 1
+		nextcode[i] = code
+		code += count[i]
+	}
+
+	// Check that the coding is complete (i.e., that we've
+	// assigned all 2-to-the-max possible bit sequences).
+	// Exception: To be compatible with zlib, we also need to
+	// accept degenerate single-code codings.  See also
+	// TestDegenerateHuffmanCoding.
+	if code != 1<<uint(max) && !(code == 1 && max == 1) {
+		return false
+	}
+
+	h.min = min
+	if max > huffmanChunkBits {
+		numLinks := 1 << (uint(max) - huffmanChunkBits)
+		h.linkMask = uint32(numLinks - 1)
+
+		// create link tables
+		link := nextcode[huffmanChunkBits+1] >> 1
+		h.links = make([][]uint32, huffmanNumChunks-link)
+		for j := uint(link); j < huffmanNumChunks; j++ {
+			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+			reverse >>= uint(16 - huffmanChunkBits)
+			off := j - uint(link)
+			if sanity && h.chunks[reverse] != 0 {
+				panic("impossible: overwriting existing chunk")
+			}
+			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
+			h.links[off] = make([]uint32, numLinks)
+		}
 	}
 
 	for i, n := range bits {
@@ -105,17 +122,60 @@
 		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
-			for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) {
+			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
+				// We should never need to overwrite
+				// an existing chunk.  Also, 0 is
+				// never a valid chunk, because the
+				// lower 4 "count" bits should be
+				// between 1 and 15.
+				if sanity && h.chunks[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				h.chunks[off] = chunk
 			}
 		} else {
-			linktab := h.links[h.chunks[reverse&(huffmanNumChunks-1)]>>huffmanValueShift]
+			j := reverse & (huffmanNumChunks - 1)
+			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
+				// Longer codes should have been
+				// associated with a link table above.
+				panic("impossible: not an indirect chunk")
+			}
+			value := h.chunks[j] >> huffmanValueShift
+			linktab := h.links[value]
 			reverse >>= huffmanChunkBits
-			for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
+			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
+				if sanity && linktab[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				linktab[off] = chunk
 			}
 		}
 	}
+
+	if sanity {
+		// Above we've sanity checked that we never overwrote
+		// an existing entry.  Here we additionally check that
+		// we filled the tables completely.
+		for i, chunk := range h.chunks {
+			if chunk == 0 {
+				// As an exception, in the degenerate
+				// single-code case, we allow odd
+				// chunks to be missing.
+				if code == 1 && i%2 == 1 {
+					continue
+				}
+				panic("impossible: missing chunk")
+			}
+		}
+		for _, linktab := range h.links {
+			for _, chunk := range linktab {
+				if chunk == 0 {
+					panic("impossible: missing chunk")
+				}
+			}
+		}
+	}
+
 	return true
 }
 
@@ -138,6 +198,9 @@
 		bits[i] = 8
 	}
 	h.init(bits[:])
+	if h.links != nil {
+		log.Fatal("Unexpected links table in fixed Huffman decoder")
+	}
 
 	var buf bytes.Buffer
 
diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go
index 76519bb..6f88159 100644
--- a/src/compress/flate/inflate.go
+++ b/src/compress/flate/inflate.go
@@ -102,6 +102,11 @@
 
 // Initialize Huffman decoding tables from array of code lengths.
 func (h *huffmanDecoder) init(bits []int) bool {
+	// Sanity enables additional runtime tests during Huffman
+	// table construction.  It's intended to be used during
+	// development to supplement the currently ad-hoc unit tests.
+	const sanity = false
+
 	if h.min != 0 {
 		*h = huffmanDecoder{}
 	}
@@ -126,36 +131,41 @@
 		return false
 	}
 
-	h.min = min
-	var linkBits uint
-	var numLinks int
-	if max > huffmanChunkBits {
-		linkBits = uint(max) - huffmanChunkBits
-		numLinks = 1 << linkBits
-		h.linkMask = uint32(numLinks - 1)
-	}
 	code := 0
 	var nextcode [maxCodeLen]int
 	for i := min; i <= max; i++ {
-		if i == huffmanChunkBits+1 {
-			// create link tables
-			link := code >> 1
-			if huffmanNumChunks < link {
-				return false
-			}
-			h.links = make([][]uint32, huffmanNumChunks-link)
-			for j := uint(link); j < huffmanNumChunks; j++ {
-				reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-				reverse >>= uint(16 - huffmanChunkBits)
-				off := j - uint(link)
-				h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i))
-				h.links[off] = make([]uint32, 1<<linkBits)
-			}
-		}
-		n := count[i]
-		nextcode[i] = code
-		code += n
 		code <<= 1
+		nextcode[i] = code
+		code += count[i]
+	}
+
+	// Check that the coding is complete (i.e., that we've
+	// assigned all 2-to-the-max possible bit sequences).
+	// Exception: To be compatible with zlib, we also need to
+	// accept degenerate single-code codings.  See also
+	// TestDegenerateHuffmanCoding.
+	if code != 1<<uint(max) && !(code == 1 && max == 1) {
+		return false
+	}
+
+	h.min = min
+	if max > huffmanChunkBits {
+		numLinks := 1 << (uint(max) - huffmanChunkBits)
+		h.linkMask = uint32(numLinks - 1)
+
+		// create link tables
+		link := nextcode[huffmanChunkBits+1] >> 1
+		h.links = make([][]uint32, huffmanNumChunks-link)
+		for j := uint(link); j < huffmanNumChunks; j++ {
+			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+			reverse >>= uint(16 - huffmanChunkBits)
+			off := j - uint(link)
+			if sanity && h.chunks[reverse] != 0 {
+				panic("impossible: overwriting existing chunk")
+			}
+			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
+			h.links[off] = make([]uint32, numLinks)
+		}
 	}
 
 	for i, n := range bits {
@@ -168,21 +178,60 @@
 		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
-			for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) {
+			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
+				// We should never need to overwrite
+				// an existing chunk.  Also, 0 is
+				// never a valid chunk, because the
+				// lower 4 "count" bits should be
+				// between 1 and 15.
+				if sanity && h.chunks[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				h.chunks[off] = chunk
 			}
 		} else {
-			value := h.chunks[reverse&(huffmanNumChunks-1)] >> huffmanValueShift
-			if value >= uint32(len(h.links)) {
-				return false
+			j := reverse & (huffmanNumChunks - 1)
+			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
+				// Longer codes should have been
+				// associated with a link table above.
+				panic("impossible: not an indirect chunk")
 			}
+			value := h.chunks[j] >> huffmanValueShift
 			linktab := h.links[value]
 			reverse >>= huffmanChunkBits
-			for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
+			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
+				if sanity && linktab[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				linktab[off] = chunk
 			}
 		}
 	}
+
+	if sanity {
+		// Above we've sanity checked that we never overwrote
+		// an existing entry.  Here we additionally check that
+		// we filled the tables completely.
+		for i, chunk := range h.chunks {
+			if chunk == 0 {
+				// As an exception, in the degenerate
+				// single-code case, we allow odd
+				// chunks to be missing.
+				if code == 1 && i%2 == 1 {
+					continue
+				}
+				panic("impossible: missing chunk")
+			}
+		}
+		for _, linktab := range h.links {
+			for _, chunk := range linktab {
+				if chunk == 0 {
+					panic("impossible: missing chunk")
+				}
+			}
+		}
+	}
+
 	return true
 }
 
@@ -655,12 +704,12 @@
 		if n > huffmanChunkBits {
 			chunk = h.links[chunk>>huffmanValueShift][(f.b>>huffmanChunkBits)&h.linkMask]
 			n = uint(chunk & huffmanCountMask)
+		}
+		if n <= f.nb {
 			if n == 0 {
 				f.err = CorruptInputError(f.roffset)
 				return 0, f.err
 			}
-		}
-		if n <= f.nb {
 			f.b >>= n
 			f.nb -= n
 			return int(chunk >> huffmanValueShift), nil
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index 396bb5c..f3b84e1 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -308,7 +308,8 @@
 	return ret
 }
 
-// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil.
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair.
+// It is an error if the point is not on the curve. On error, x = nil.
 func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
 	byteLen := (curve.Params().BitSize + 7) >> 3
 	if len(data) != 1+2*byteLen {
@@ -319,6 +320,9 @@
 	}
 	x = new(big.Int).SetBytes(data[1 : 1+byteLen])
 	y = new(big.Int).SetBytes(data[1+byteLen:])
+	if !curve.Params().IsOnCurve(x, y) {
+		x, y = nil, nil
+	}
 	return
 }
 
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
index 4dc27c9..7e27913 100644
--- a/src/crypto/elliptic/elliptic_test.go
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -19,6 +19,19 @@
 	}
 }
 
+func TestOffCurve(t *testing.T) {
+	p224 := P224()
+	x, y := new(big.Int).SetInt64(1), new(big.Int).SetInt64(1)
+	if p224.IsOnCurve(x, y) {
+		t.Errorf("FAIL: point off curve is claimed to be on the curve")
+	}
+	b := Marshal(p224, x, y)
+	x1, y1 := Unmarshal(p224, b)
+	if x1 != nil || y1 != nil {
+		t.Errorf("FAIL: unmarshalling a point not on the curve succeeded")
+	}
+}
+
 type baseMultTest struct {
 	k    string
 	x, y string
diff --git a/src/crypto/rand/rand_linux.go b/src/crypto/rand/rand_linux.go
index 8cb59c7..7d6d9e8 100644
--- a/src/crypto/rand/rand_linux.go
+++ b/src/crypto/rand/rand_linux.go
@@ -5,7 +5,7 @@
 package rand
 
 import (
-	"internal/syscall"
+	"internal/syscall/unix"
 	"sync"
 )
 
@@ -25,7 +25,7 @@
 	// - the machine has no entropy available (early boot + no hardware
 	//   entropy source?) and we want to avoid blocking later.
 	var buf [1]byte
-	n, err := syscall.GetRandom(buf[:], syscall.GRND_NONBLOCK)
+	n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK)
 	useSyscall = n == 1 && err == nil
 }
 
@@ -34,6 +34,6 @@
 	if !useSyscall {
 		return false
 	}
-	n, err := syscall.GetRandom(p, 0)
+	n, err := unix.GetRandom(p, 0)
 	return n == len(p) && err == nil
 }
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index b315436..a5fed29 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -5,7 +5,6 @@
 package tls
 
 import (
-	"crypto"
 	"crypto/aes"
 	"crypto/cipher"
 	"crypto/des"
@@ -49,6 +48,9 @@
 	// suiteTLS12 indicates that the cipher suite should only be advertised
 	// and accepted when using TLS 1.2.
 	suiteTLS12
+	// suiteSHA384 indicates that the cipher suite uses SHA384 as the
+	// handshake hash.
+	suiteSHA384
 	// suiteDefaultOff indicates that this cipher suite is not included by
 	// default.
 	suiteDefaultOff
@@ -64,31 +66,30 @@
 	ivLen  int
 	ka     func(version uint16) keyAgreement
 	// flags is a bitmask of the suite* values, above.
-	flags     int
-	cipher    func(key, iv []byte, isRead bool) interface{}
-	mac       func(version uint16, macKey []byte) macFunction
-	aead      func(key, fixedNonce []byte) cipher.AEAD
-	tls12Hash crypto.Hash
+	flags  int
+	cipher func(key, iv []byte, isRead bool) interface{}
+	mac    func(version uint16, macKey []byte) macFunction
+	aead   func(key, fixedNonce []byte) cipher.AEAD
 }
 
 var cipherSuites = []*cipherSuite{
 	// Ciphersuite order is chosen so that ECDHE comes before plain RSA
 	// and RC4 comes before AES (because of the Lucky13 attack).
-	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA256},
-	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA256},
-	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA384},
-	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA384},
-	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil, crypto.SHA256},
-	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil, crypto.SHA256},
-	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil, crypto.SHA256},
+	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
 }
 
 func cipherRC4(key, iv []byte, isRead bool) interface{} {
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index 584a361..12500ab 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -8,7 +8,9 @@
 	"container/list"
 	"crypto"
 	"crypto/rand"
+	"crypto/sha512"
 	"crypto/x509"
+	"errors"
 	"fmt"
 	"io"
 	"math/big"
@@ -73,6 +75,7 @@
 	extensionSupportedPoints     uint16 = 11
 	extensionSignatureAlgorithms uint16 = 13
 	extensionALPN                uint16 = 16
+	extensionSCT                 uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
 	extensionSessionTicket       uint16 = 35
 	extensionNextProtoNeg        uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo   uint16 = 0xff01
@@ -138,34 +141,31 @@
 	hash, signature uint8
 }
 
-// supportedSKXSignatureAlgorithms contains the signature and hash algorithms
-// that the code advertises as supported in a TLS 1.2 ClientHello.
-var supportedSKXSignatureAlgorithms = []signatureAndHash{
+// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2
+// CertificateRequest.
+var supportedSignatureAlgorithms = []signatureAndHash{
 	{hashSHA256, signatureRSA},
 	{hashSHA256, signatureECDSA},
+	{hashSHA384, signatureRSA},
+	{hashSHA384, signatureECDSA},
 	{hashSHA1, signatureRSA},
 	{hashSHA1, signatureECDSA},
 }
 
-// supportedClientCertSignatureAlgorithms contains the signature and hash
-// algorithms that the code advertises as supported in a TLS 1.2
-// CertificateRequest.
-var supportedClientCertSignatureAlgorithms = []signatureAndHash{
-	{hashSHA256, signatureRSA},
-	{hashSHA256, signatureECDSA},
-}
-
 // ConnectionState records basic TLS details about the connection.
 type ConnectionState struct {
-	Version                    uint16                // TLS version used by the connection (e.g. VersionTLS12)
-	HandshakeComplete          bool                  // TLS handshake is complete
-	DidResume                  bool                  // connection resumes a previous TLS connection
-	CipherSuite                uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
-	NegotiatedProtocol         string                // negotiated next protocol (from Config.NextProtos)
-	NegotiatedProtocolIsMutual bool                  // negotiated protocol was advertised by server
-	ServerName                 string                // server name requested by client, if any (server side only)
-	PeerCertificates           []*x509.Certificate   // certificate chain presented by remote peer
-	VerifiedChains             [][]*x509.Certificate // verified chains built from PeerCertificates
+	Version                     uint16                // TLS version used by the connection (e.g. VersionTLS12)
+	HandshakeComplete           bool                  // TLS handshake is complete
+	DidResume                   bool                  // connection resumes a previous TLS connection
+	CipherSuite                 uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
+	NegotiatedProtocol          string                // negotiated next protocol (from Config.NextProtos)
+	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server
+	ServerName                  string                // server name requested by client, if any (server side only)
+	PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
+	VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
+	SignedCertificateTimestamps [][]byte              // SCTs from the server, if any
+	OCSPResponse                []byte                // stapled OCSP response from server, if any
 
 	// TLSUnique contains the "tls-unique" channel binding value (see RFC
 	// 5929, section 3). For resumed sessions this value will be nil
@@ -266,10 +266,12 @@
 	NameToCertificate map[string]*Certificate
 
 	// GetCertificate returns a Certificate based on the given
-	// ClientHelloInfo. If GetCertificate is nil or returns nil, then the
-	// certificate is retrieved from NameToCertificate. If
-	// NameToCertificate is nil, the first element of Certificates will be
-	// used.
+	// ClientHelloInfo. It will only be called if the client supplies SNI
+	// information or if Certificates is empty.
+	//
+	// If GetCertificate is nil or returns nil, then the certificate is
+	// retrieved from NameToCertificate. If NameToCertificate is nil, the
+	// first element of Certificates will be used.
 	GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
 
 	// RootCAs defines the set of root certificate authorities
@@ -345,6 +347,38 @@
 	CurvePreferences []CurveID
 
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
+
+	// mutex protects sessionTicketKeys
+	mutex sync.RWMutex
+	// sessionTicketKeys contains zero or more ticket keys. If the length
+	// is zero, SessionTicketsDisabled must be true. The first key is used
+	// for new tickets and any subsequent keys can be used to decrypt old
+	// tickets.
+	sessionTicketKeys []ticketKey
+}
+
+// ticketKeyNameLen is the number of bytes of identifier that is prepended to
+// an encrypted session ticket in order to identify the key used to encrypt it.
+const ticketKeyNameLen = 16
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+	// keyName is an opaque byte string that serves to identify the session
+	// ticket key. It's exposed as plaintext in every session ticket.
+	keyName [ticketKeyNameLen]byte
+	aesKey  [16]byte
+	hmacKey [16]byte
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+	hashed := sha512.Sum512(b[:])
+	copy(key.keyName[:], hashed[:ticketKeyNameLen])
+	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
+	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+	return key
 }
 
 func (c *Config) serverInit() {
@@ -352,16 +386,51 @@
 		return
 	}
 
-	// If the key has already been set then we have nothing to do.
+	alreadySet := false
 	for _, b := range c.SessionTicketKey {
 		if b != 0 {
+			alreadySet = true
+			break
+		}
+	}
+
+	if !alreadySet {
+		if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+			c.SessionTicketsDisabled = true
 			return
 		}
 	}
 
-	if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
-		c.SessionTicketsDisabled = true
+	c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+}
+
+func (c *Config) ticketKeys() []ticketKey {
+	c.mutex.RLock()
+	// c.sessionTicketKeys is constant once created. SetSessionTicketKeys
+	// will only update it by replacing it with a new value.
+	ret := c.sessionTicketKeys
+	c.mutex.RUnlock()
+	return ret
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server. The first
+// key will be used when creating new tickets, while all keys can be used for
+// decrypting tickets. It is safe to call this function while the server is
+// running in order to rotate the session ticket keys. The function will panic
+// if keys is empty.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+	if len(keys) == 0 {
+		panic("tls: keys must have at least one key")
 	}
+
+	newKeys := make([]ticketKey, len(keys))
+	for i, bytes := range keys {
+		newKeys[i] = ticketKeyFromBytes(bytes)
+	}
+
+	c.mutex.Lock()
+	c.sessionTicketKeys = newKeys
+	c.mutex.Unlock()
 }
 
 func (c *Config) rand() io.Reader {
@@ -429,13 +498,18 @@
 // getCertificate returns the best certificate for the given ClientHelloInfo,
 // defaulting to the first element of c.Certificates.
 func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
-	if c.GetCertificate != nil {
+	if c.GetCertificate != nil &&
+		(len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
 		cert, err := c.GetCertificate(clientHello)
 		if cert != nil || err != nil {
 			return cert, err
 		}
 	}
 
+	if len(c.Certificates) == 0 {
+		return nil, errors.New("crypto/tls: no certificates configured")
+	}
+
 	if len(c.Certificates) == 1 || c.NameToCertificate == nil {
 		// There's only one choice, so no point doing any work.
 		return &c.Certificates[0], nil
@@ -489,14 +563,17 @@
 type Certificate struct {
 	Certificate [][]byte
 	// PrivateKey contains the private key corresponding to the public key
-	// in Leaf. For a server, this must be a *rsa.PrivateKey or
-	// *ecdsa.PrivateKey. For a client doing client authentication, this
-	// can be any type that implements crypto.Signer (which includes RSA
-	// and ECDSA private keys).
+	// in Leaf. For a server, this must implement crypto.Signer and/or
+	// crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client
+	// (performing client authentication), this must be a crypto.Signer
+	// with an RSA or ECDSA PublicKey.
 	PrivateKey crypto.PrivateKey
 	// OCSPStaple contains an optional OCSP response which will be served
 	// to clients that request it.
 	OCSPStaple []byte
+	// SignedCertificateTimestamps contains an optional list of Signed
+	// Certificate Timestamps which will be served to clients that request it.
+	SignedCertificateTimestamps [][]byte
 	// Leaf is the parsed form of the leaf certificate, which may be
 	// initialized using x509.ParseCertificate to reduce per-handshake
 	// processing for TLS clients doing client authentication. If nil, the
@@ -623,3 +700,12 @@
 func unexpectedMessageError(wanted, got interface{}) error {
 	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
 }
+
+func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool {
+	for _, s := range sigHashes {
+		if s == sigHash {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index db47879..cad47185 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -35,7 +35,8 @@
 	handshakeComplete bool
 	didResume         bool // whether this connection was a session resumption
 	cipherSuite       uint16
-	ocspResponse      []byte // stapled OCSP response
+	ocspResponse      []byte   // stapled OCSP response
+	scts              [][]byte // signed certificate timestamps from server
 	peerCertificates  []*x509.Certificate
 	// verifiedChains contains the certificate chains that we built, as
 	// opposed to the ones presented by the server.
@@ -993,6 +994,8 @@
 		state.PeerCertificates = c.peerCertificates
 		state.VerifiedChains = c.verifiedChains
 		state.ServerName = c.serverName
+		state.SignedCertificateTimestamps = c.scts
+		state.OCSPResponse = c.ocspResponse
 		if !c.didResume {
 			state.TLSUnique = c.firstFinished[:]
 		}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 3ebf7db..6b09264 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -54,6 +54,7 @@
 		compressionMethods:  []uint8{compressionNone},
 		random:              make([]byte, 32),
 		ocspStapling:        true,
+		scts:                true,
 		serverName:          c.config.ServerName,
 		supportedCurves:     c.config.curvePreferences(),
 		supportedPoints:     []uint8{pointFormatUncompressed},
@@ -88,7 +89,7 @@
 	}
 
 	if hello.vers >= VersionTLS12 {
-		hello.signatureAndHashes = supportedSKXSignatureAlgorithms
+		hello.signatureAndHashes = supportedSignatureAlgorithms
 	}
 
 	var session *ClientSessionState
@@ -168,18 +169,26 @@
 		serverHello:  serverHello,
 		hello:        hello,
 		suite:        suite,
-		finishedHash: newFinishedHash(c.vers, suite.tls12Hash),
+		finishedHash: newFinishedHash(c.vers, suite),
 		session:      session,
 	}
 
-	hs.finishedHash.Write(hs.hello.marshal())
-	hs.finishedHash.Write(hs.serverHello.marshal())
-
 	isResume, err := hs.processServerHello()
 	if err != nil {
 		return err
 	}
 
+	// No signatures of the handshake are needed in a resumption.
+	// Otherwise, in a full handshake, if we don't have any certificates
+	// configured then we will never send a CertificateVerify message and
+	// thus no signatures are needed in that case either.
+	if isResume || len(c.config.Certificates) == 0 {
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+
+	hs.finishedHash.Write(hs.hello.marshal())
+	hs.finishedHash.Write(hs.serverHello.marshal())
+
 	if isResume {
 		if err := hs.establishKeys(); err != nil {
 			return err
@@ -423,7 +432,6 @@
 	}
 
 	if chainToSend != nil {
-		var signed []byte
 		certVerify := &certificateVerifyMsg{
 			hasSignatureAndHash: c.vers >= VersionTLS12,
 		}
@@ -433,31 +441,42 @@
 			c.sendAlert(alertInternalError)
 			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
 		}
+
+		var signatureType uint8
 		switch key.Public().(type) {
 		case *ecdsa.PublicKey:
-			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
-			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
-			certVerify.signatureAndHash.signature = signatureECDSA
-			certVerify.signatureAndHash.hash = hashId
+			signatureType = signatureECDSA
 		case *rsa.PublicKey:
-			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
-			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
-			certVerify.signatureAndHash.signature = signatureRSA
-			certVerify.signatureAndHash.hash = hashId
+			signatureType = signatureRSA
 		default:
-			err = fmt.Errorf("tls: unknown client certificate key type: %T", key)
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key)
 		}
+
+		certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType)
 		if err != nil {
 			c.sendAlert(alertInternalError)
-			return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
+			return err
 		}
-		certVerify.signature = signed
+		digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
 
 		hs.finishedHash.Write(certVerify.marshal())
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
 	}
 
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite.tls12Hash, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+
+	hs.finishedHash.discardHandshakeBuffer()
+
 	return nil
 }
 
@@ -465,7 +484,7 @@
 	c := hs.c
 
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, hs.suite.tls12Hash, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 	var clientCipher, serverCipher interface{}
 	var clientHash, serverHash macFunction
 	if hs.suite.cipher != nil {
@@ -522,6 +541,7 @@
 		c.clientProtocol = hs.serverHello.alpnProtocol
 		c.clientProtocolFallback = false
 	}
+	c.scts = hs.serverHello.scts
 
 	if hs.serverResumedSession() {
 		// Restore masterSecret and peerCerts from previous state
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 7388d29..5fc57b0 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -9,6 +9,8 @@
 	"crypto/ecdsa"
 	"crypto/rsa"
 	"crypto/x509"
+	"encoding/base64"
+	"encoding/binary"
 	"encoding/pem"
 	"fmt"
 	"io"
@@ -49,6 +51,10 @@
 	// key, if not nil, contains either a *rsa.PrivateKey or
 	// *ecdsa.PrivateKey which is the private key for the reference server.
 	key interface{}
+	// extensions, if not nil, contains a list of extension data to be returned
+	// from the ServerHello. The data should be in standard TLS format with
+	// a 2-byte uint16 type, 2-byte data length, followed by the extension data.
+	extensions [][]byte
 	// validate, if not nil, is a function that will be called with the
 	// ConnectionState of the resulting connection. It returns a non-nil
 	// error if the ConnectionState is unacceptable.
@@ -111,6 +117,19 @@
 	const serverPort = 24323
 	command = append(command, "-accept", strconv.Itoa(serverPort))
 
+	if len(test.extensions) > 0 {
+		var serverInfo bytes.Buffer
+		for _, ext := range test.extensions {
+			pem.Encode(&serverInfo, &pem.Block{
+				Type:  fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)),
+				Bytes: ext,
+			})
+		}
+		serverInfoPath := tempFile(serverInfo.String())
+		defer os.Remove(serverInfoPath)
+		command = append(command, "-serverinfo", serverInfoPath)
+	}
+
 	cmd := exec.Command(command[0], command[1:]...)
 	stdin = blockingSource(make(chan bool))
 	cmd.Stdin = stdin
@@ -193,7 +212,7 @@
 		}
 		if test.validate != nil {
 			if err := test.validate(client.ConnectionState()); err != nil {
-				t.Logf("validate callback returned error: %s", err)
+				t.Errorf("validate callback returned error: %s", err)
 			}
 		}
 		client.Close()
@@ -394,7 +413,7 @@
 	}
 
 	testResumeState := func(test string, didResume bool) {
-		hs, err := testHandshake(clientConfig, serverConfig)
+		_, hs, err := testHandshake(clientConfig, serverConfig)
 		if err != nil {
 			t.Fatalf("%s: handshake failed: %s", test, err)
 		}
@@ -403,15 +422,38 @@
 		}
 	}
 
-	testResumeState("Handshake", false)
-	testResumeState("Resume", true)
-
-	if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
-		t.Fatalf("Failed to invalidate SessionTicketKey")
+	getTicket := func() []byte {
+		return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket
 	}
+	randomKey := func() [32]byte {
+		var k [32]byte
+		if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil {
+			t.Fatalf("Failed to read new SessionTicketKey: %s", err)
+		}
+		return k
+	}
+
+	testResumeState("Handshake", false)
+	ticket := getTicket()
+	testResumeState("Resume", true)
+	if !bytes.Equal(ticket, getTicket()) {
+		t.Fatal("first ticket doesn't match ticket after resumption")
+	}
+
+	key2 := randomKey()
+	serverConfig.SetSessionTicketKeys([][32]byte{key2})
+
 	testResumeState("InvalidSessionTicketKey", false)
 	testResumeState("ResumeAfterInvalidSessionTicketKey", true)
 
+	serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2})
+	ticket = getTicket()
+	testResumeState("KeyChange", true)
+	if bytes.Equal(ticket, getTicket()) {
+		t.Fatal("new ticket wasn't included while resuming")
+	}
+	testResumeState("KeyChangeFinish", true)
+
 	clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
 	testResumeState("DifferentCipherSuite", false)
 	testResumeState("DifferentCipherSuiteRecovers", true)
@@ -507,3 +549,41 @@
 	}
 	runClientTestTLS12(t, test)
 }
+
+// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443`
+const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0="
+
+func TestHandshakClientSCTs(t *testing.T) {
+	config := *testConfig
+
+	scts, err := base64.StdEncoding.DecodeString(sctsBase64)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	test := &clientTest{
+		name: "SCT",
+		// Note that this needs OpenSSL 1.0.2 because that is the first
+		// version that supports the -serverinfo flag.
+		command:    []string{"openssl", "s_server"},
+		config:     &config,
+		extensions: [][]byte{scts},
+		validate: func(state ConnectionState) error {
+			expectedSCTs := [][]byte{
+				scts[8:125],
+				scts[127:245],
+				scts[247:],
+			}
+			if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) {
+				return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs))
+			}
+			for i, expected := range expectedSCTs {
+				if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) {
+					return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected)
+				}
+			}
+			return nil
+		},
+	}
+	runClientTestTLS12(t, test)
+}
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index 9532508..b794f05 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -16,6 +16,7 @@
 	nextProtoNeg        bool
 	serverName          string
 	ocspStapling        bool
+	scts                bool
 	supportedCurves     []CurveID
 	supportedPoints     []uint8
 	ticketSupported     bool
@@ -40,6 +41,7 @@
 		m.nextProtoNeg == m1.nextProtoNeg &&
 		m.serverName == m1.serverName &&
 		m.ocspStapling == m1.ocspStapling &&
+		m.scts == m1.scts &&
 		eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
 		bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
 		m.ticketSupported == m1.ticketSupported &&
@@ -99,6 +101,9 @@
 		}
 		numExtensions++
 	}
+	if m.scts {
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -271,6 +276,13 @@
 		lengths[0] = byte(stringsLength >> 8)
 		lengths[1] = byte(stringsLength)
 	}
+	if m.scts {
+		// https://tools.ietf.org/html/rfc6962#section-3.3.1
+		z[0] = byte(extensionSCT >> 8)
+		z[1] = byte(extensionSCT)
+		// zero uint16 for the zero-length extension_data
+		z = z[4:]
+	}
 
 	m.raw = x
 
@@ -326,6 +338,7 @@
 	m.sessionTicket = nil
 	m.signatureAndHashes = nil
 	m.alpnProtocols = nil
+	m.scts = false
 
 	if len(data) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -453,6 +466,11 @@
 				m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
 				d = d[stringLen:]
 			}
+		case extensionSCT:
+			m.scts = true
+			if length != 0 {
+				return false
+			}
 		}
 		data = data[length:]
 	}
@@ -470,6 +488,7 @@
 	nextProtoNeg        bool
 	nextProtos          []string
 	ocspStapling        bool
+	scts                [][]byte
 	ticketSupported     bool
 	secureRenegotiation bool
 	alpnProtocol        string
@@ -481,6 +500,15 @@
 		return false
 	}
 
+	if len(m.scts) != len(m1.scts) {
+		return false
+	}
+	for i, sct := range m.scts {
+		if !bytes.Equal(sct, m1.scts[i]) {
+			return false
+		}
+	}
+
 	return bytes.Equal(m.raw, m1.raw) &&
 		m.vers == m1.vers &&
 		bytes.Equal(m.random, m1.random) &&
@@ -530,6 +558,14 @@
 		extensionsLength += 2 + 1 + alpnLen
 		numExtensions++
 	}
+	sctLen := 0
+	if len(m.scts) > 0 {
+		for _, sct := range m.scts {
+			sctLen += len(sct) + 2
+		}
+		extensionsLength += 2 + sctLen
+		numExtensions++
+	}
 
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
@@ -605,6 +641,23 @@
 		copy(z[7:], []byte(m.alpnProtocol))
 		z = z[7+alpnLen:]
 	}
+	if sctLen > 0 {
+		z[0] = byte(extensionSCT >> 8)
+		z[1] = byte(extensionSCT)
+		l := sctLen + 2
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z[4] = byte(sctLen >> 8)
+		z[5] = byte(sctLen)
+
+		z = z[6:]
+		for _, sct := range m.scts {
+			z[0] = byte(len(sct) >> 8)
+			z[1] = byte(len(sct))
+			copy(z[2:], sct)
+			z = z[len(sct)+2:]
+		}
+	}
 
 	m.raw = x
 
@@ -634,6 +687,7 @@
 	m.nextProtoNeg = false
 	m.nextProtos = nil
 	m.ocspStapling = false
+	m.scts = nil
 	m.ticketSupported = false
 	m.alpnProtocol = ""
 
@@ -706,6 +760,34 @@
 			}
 			d = d[1:]
 			m.alpnProtocol = string(d)
+		case extensionSCT:
+			d := data[:length]
+
+			if len(d) < 2 {
+				return false
+			}
+			l := int(d[0])<<8 | int(d[1])
+			d = d[2:]
+			if len(d) != l {
+				return false
+			}
+			if l == 0 {
+				continue
+			}
+
+			m.scts = make([][]byte, 0, 3)
+			for len(d) != 0 {
+				if len(d) < 2 {
+					return false
+				}
+				sctLen := int(d[0])<<8 | int(d[1])
+				d = d[2:]
+				if len(d) < sctLen {
+					return false
+				}
+				m.scts = append(m.scts, d[:sctLen])
+				d = d[sctLen:]
+			}
 		}
 		data = data[length:]
 	}
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index a96e95c..95d825b 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -136,12 +136,15 @@
 		}
 	}
 	if rand.Intn(10) > 5 {
-		m.signatureAndHashes = supportedSKXSignatureAlgorithms
+		m.signatureAndHashes = supportedSignatureAlgorithms
 	}
 	m.alpnProtocols = make([]string, rand.Intn(5))
 	for i := range m.alpnProtocols {
 		m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand)
 	}
+	if rand.Intn(10) > 5 {
+		m.scts = true
+	}
 
 	return reflect.ValueOf(m)
 }
@@ -172,6 +175,14 @@
 	}
 	m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
 
+	if rand.Intn(10) > 5 {
+		numSCTs := rand.Intn(4)
+		m.scts = make([][]byte, numSCTs)
+		for i := range m.scts {
+			m.scts[i] = randomBytes(rand.Intn(500), rand)
+		}
+	}
+
 	return reflect.ValueOf(m)
 }
 
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index c7c1f1e..accfa6f 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -25,6 +25,8 @@
 	suite           *cipherSuite
 	ellipticOk      bool
 	ecdsaOk         bool
+	rsaDecryptOk    bool
+	rsaSignOk       bool
 	sessionState    *sessionState
 	finishedHash    finishedHash
 	masterSecret    []byte
@@ -47,8 +49,6 @@
 	if err != nil {
 		return err
 	}
-	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite.tls12Hash)
-	hs.finishedHash.Write(hs.clientHello.marshal())
 
 	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
 	if isResume {
@@ -59,6 +59,14 @@
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
+		// ticketSupported is set in a resumption handshake if the
+		// ticket from the client was encrypted with an old session
+		// ticket key and thus a refreshed ticket should be sent.
+		if hs.hello.ticketSupported {
+			if err := hs.sendSessionTicket(); err != nil {
+				return err
+			}
+		}
 		if err := hs.sendFinished(c.firstFinished[:]); err != nil {
 			return err
 		}
@@ -179,25 +187,39 @@
 		}
 	}
 
-	if len(config.Certificates) == 0 {
+	if hs.cert, err = config.getCertificate(&ClientHelloInfo{
+		CipherSuites:    hs.clientHello.cipherSuites,
+		ServerName:      hs.clientHello.serverName,
+		SupportedCurves: hs.clientHello.supportedCurves,
+		SupportedPoints: hs.clientHello.supportedPoints,
+	}); err != nil {
 		c.sendAlert(alertInternalError)
-		return false, errors.New("tls: no certificates configured")
+		return false, err
 	}
-	hs.cert = &config.Certificates[0]
-	if len(hs.clientHello.serverName) > 0 {
-		chi := &ClientHelloInfo{
-			CipherSuites:    hs.clientHello.cipherSuites,
-			ServerName:      hs.clientHello.serverName,
-			SupportedCurves: hs.clientHello.supportedCurves,
-			SupportedPoints: hs.clientHello.supportedPoints,
-		}
-		if hs.cert, err = config.getCertificate(chi); err != nil {
-			c.sendAlert(alertInternalError)
-			return false, err
-		}
+	if hs.clientHello.scts {
+		hs.hello.scts = hs.cert.SignedCertificateTimestamps
 	}
 
-	_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+	if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
+		switch priv.Public().(type) {
+		case *ecdsa.PublicKey:
+			hs.ecdsaOk = true
+		case *rsa.PublicKey:
+			hs.rsaSignOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
+		}
+	}
+	if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
+		switch priv.Public().(type) {
+		case *rsa.PublicKey:
+			hs.rsaDecryptOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
+		}
+	}
 
 	if hs.checkForResumption() {
 		return true, nil
@@ -213,7 +235,7 @@
 	}
 
 	for _, id := range preferenceList {
-		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
+		if hs.setCipherSuite(id, supportedList, c.vers) {
 			break
 		}
 	}
@@ -272,8 +294,7 @@
 	}
 
 	// Check that we also support the ciphersuite from the session.
-	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk)
-	if hs.suite == nil {
+	if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) {
 		return false
 	}
 
@@ -296,6 +317,10 @@
 	// We echo the client's session ID in the ServerHello to let it know
 	// that we're doing a resumption.
 	hs.hello.sessionId = hs.clientHello.sessionId
+	hs.hello.ticketSupported = hs.sessionState.usedOldKey
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.discardHandshakeBuffer()
+	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
@@ -320,6 +345,14 @@
 
 	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
 	hs.hello.cipherSuite = hs.suite.id
+
+	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
+	if config.ClientAuth == NoClientCert {
+		// No need to keep a full record of the handshake if client
+		// certificates won't be used.
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
@@ -356,7 +389,7 @@
 		}
 		if c.vers >= VersionTLS12 {
 			certReq.hasSignatureAndHash = true
-			certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms
+			certReq.signatureAndHashes = supportedSignatureAlgorithms
 		}
 
 		// An empty list of certificateAuthorities signals to
@@ -420,6 +453,13 @@
 	}
 	hs.finishedHash.Write(ckx.marshal())
 
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+
 	// If we received a client cert in response to our certificate request message,
 	// the client will send us a certificateVerifyMsg immediately after the
 	// clientKeyExchangeMsg.  This message is a digest of all preceding
@@ -437,8 +477,31 @@
 			return unexpectedMessageError(certVerify, msg)
 		}
 
+		// Determine the signature type.
+		var signatureAndHash signatureAndHash
+		if certVerify.hasSignatureAndHash {
+			signatureAndHash = certVerify.signatureAndHash
+			if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) {
+				return errors.New("tls: unsupported hash function for client certificate")
+			}
+		} else {
+			// Before TLS 1.2 the signature algorithm was implicit
+			// from the key type, and only one hash per signature
+			// algorithm was possible. Leave the hash as zero.
+			switch pub.(type) {
+			case *ecdsa.PublicKey:
+				signatureAndHash.signature = signatureECDSA
+			case *rsa.PublicKey:
+				signatureAndHash.signature = signatureRSA
+			}
+		}
+
 		switch key := pub.(type) {
 		case *ecdsa.PublicKey:
+			if signatureAndHash.signature != signatureECDSA {
+				err = errors.New("bad signature type for client's ECDSA certificate")
+				break
+			}
 			ecdsaSig := new(ecdsaSignature)
 			if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil {
 				break
@@ -447,28 +510,34 @@
 				err = errors.New("ECDSA signature contained zero or negative values")
 				break
 			}
-			digest, _, _ := hs.finishedHash.hashForClientCertificate(signatureECDSA)
-			if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
-				err = errors.New("ECDSA verification failure")
+			var digest []byte
+			if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil {
 				break
 			}
+			if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
+				err = errors.New("ECDSA verification failure")
+			}
 		case *rsa.PublicKey:
-			digest, hashFunc, _ := hs.finishedHash.hashForClientCertificate(signatureRSA)
+			if signatureAndHash.signature != signatureRSA {
+				err = errors.New("bad signature type for client's RSA certificate")
+				break
+			}
+			var digest []byte
+			var hashFunc crypto.Hash
+			if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil {
+				break
+			}
 			err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature)
 		}
 		if err != nil {
 			c.sendAlert(alertBadCertificate)
-			return errors.New("could not validate signature of connection nonces: " + err.Error())
+			return errors.New("tls: could not validate signature of connection nonces: " + err.Error())
 		}
 
 		hs.finishedHash.Write(certVerify.marshal())
 	}
-	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
-	if err != nil {
-		c.sendAlert(alertHandshakeFailure)
-		return err
-	}
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite.tls12Hash, preMasterSecret, hs.clientHello.random, hs.hello.random)
+
+	hs.finishedHash.discardHandshakeBuffer()
 
 	return nil
 }
@@ -477,7 +546,7 @@
 	c := hs.c
 
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, hs.suite.tls12Hash, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 
 	var clientCipher, serverCipher interface{}
 	var clientHash, serverHash macFunction
@@ -649,9 +718,10 @@
 	return nil, nil
 }
 
-// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
-// is acceptable to use.
-func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
+// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
+// suite if that cipher suite is acceptable to use.
+// It returns a bool indicating if the suite was set.
+func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool {
 	for _, supported := range supportedCipherSuites {
 		if id == supported {
 			var candidate *cipherSuite
@@ -667,18 +737,26 @@
 			}
 			// Don't select a ciphersuite which we can't
 			// support for this client.
-			if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
-				continue
-			}
-			if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
+			if candidate.flags&suiteECDHE != 0 {
+				if !hs.ellipticOk {
+					continue
+				}
+				if candidate.flags&suiteECDSA != 0 {
+					if !hs.ecdsaOk {
+						continue
+					}
+				} else if !hs.rsaSignOk {
+					continue
+				}
+			} else if !hs.rsaDecryptOk {
 				continue
 			}
 			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
 				continue
 			}
-			return candidate
+			hs.suite = candidate
+			return true
 		}
 	}
-
-	return nil
+	return false
 }
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index af5cadb..bbf105d 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -63,6 +63,10 @@
 	testConfig.BuildNameToCertificate()
 }
 
+func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
+	testClientHelloFailure(t, serverConfig, m, "")
+}
+
 func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
 	// Create in-memory network connection,
 	// send message to server.  Should return
@@ -78,7 +82,11 @@
 	}()
 	err := Server(s, serverConfig).Handshake()
 	s.Close()
-	if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
+	if len(expectedSubStr) == 0 {
+		if err != nil && err != io.EOF {
+			t.Errorf("Got error: %s; expected to succeed", err, expectedSubStr)
+		}
+	} else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
 		t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
 	}
 }
@@ -126,6 +134,55 @@
 	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
 }
 
+func TestDontSelectECDSAWithRSAKey(t *testing.T) {
+	// Test that, even when both sides support an ECDSA cipher suite, it
+	// won't be selected if the server's private key doesn't support it.
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+		compressionMethods: []uint8{0},
+		supportedCurves:    []CurveID{CurveP256},
+		supportedPoints:    []uint8{pointFormatUncompressed},
+	}
+	serverConfig := *testConfig
+	serverConfig.CipherSuites = clientHello.cipherSuites
+	serverConfig.Certificates = make([]Certificate, 1)
+	serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+	serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+	serverConfig.BuildNameToCertificate()
+	// First test that it *does* work when the server's key is ECDSA.
+	testClientHello(t, &serverConfig, clientHello)
+
+	// Now test that switching to an RSA key causes the expected error (and
+	// not an internal error about a signing failure).
+	serverConfig.Certificates = testConfig.Certificates
+	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestDontSelectRSAWithECDSAKey(t *testing.T) {
+	// Test that, even when both sides support an RSA cipher suite, it
+	// won't be selected if the server's private key doesn't support it.
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+		compressionMethods: []uint8{0},
+		supportedCurves:    []CurveID{CurveP256},
+		supportedPoints:    []uint8{pointFormatUncompressed},
+	}
+	serverConfig := *testConfig
+	serverConfig.CipherSuites = clientHello.cipherSuites
+	// First test that it *does* work when the server's key is RSA.
+	testClientHello(t, &serverConfig, clientHello)
+
+	// Now test that switching to an ECDSA key causes the expected error
+	// (and not an internal error about a signing failure).
+	serverConfig.Certificates = make([]Certificate, 1)
+	serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+	serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+	serverConfig.BuildNameToCertificate()
+	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
 func TestRenegotiationExtension(t *testing.T) {
 	clientHello := &clientHelloMsg{
 		vers:                VersionTLS12,
@@ -246,19 +303,20 @@
 	}
 }
 
-func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) {
+func testHandshake(clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) {
 	c, s := net.Pipe()
 	done := make(chan bool)
 	go func() {
 		cli := Client(c, clientConfig)
 		cli.Handshake()
+		clientState = cli.ConnectionState()
 		c.Close()
 		done <- true
 	}()
 	server := Server(s, serverConfig)
 	err = server.Handshake()
 	if err == nil {
-		state = server.ConnectionState()
+		serverState = server.ConnectionState()
 	}
 	s.Close()
 	<-done
@@ -273,7 +331,7 @@
 	clientConfig := &Config{
 		InsecureSkipVerify: true,
 	}
-	state, err := testHandshake(clientConfig, serverConfig)
+	state, _, err := testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -292,7 +350,7 @@
 		CipherSuites:       []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA},
 		InsecureSkipVerify: true,
 	}
-	state, err := testHandshake(clientConfig, serverConfig)
+	state, _, err := testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -302,7 +360,7 @@
 	}
 
 	serverConfig.PreferServerCipherSuites = true
-	state, err = testHandshake(clientConfig, serverConfig)
+	state, _, err = testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -311,6 +369,33 @@
 	}
 }
 
+func TestSCTHandshake(t *testing.T) {
+	expected := [][]byte{[]byte("certificate"), []byte("transparency")}
+	serverConfig := &Config{
+		Certificates: []Certificate{{
+			Certificate:                 [][]byte{testRSACertificate},
+			PrivateKey:                  testRSAPrivateKey,
+			SignedCertificateTimestamps: expected,
+		}},
+	}
+	clientConfig := &Config{
+		InsecureSkipVerify: true,
+	}
+	_, state, err := testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	actual := state.SignedCertificateTimestamps
+	if len(actual) != len(expected) {
+		t.Fatalf("got %d scts, want %d", len(actual), len(expected))
+	}
+	for i, sct := range expected {
+		if !bytes.Equal(sct, actual[i]) {
+			t.Fatalf("SCT #%d was %x, but expected %x", i, actual[i], sct)
+		}
+	}
+}
+
 // Note: see comment in handshake_test.go for details of how the reference
 // tests work.
 
@@ -328,9 +413,6 @@
 	expectedPeerCerts []string
 	// config, if not nil, contains a custom Config to use for this test.
 	config *Config
-	// expectAlert, if true, indicates that a fatal alert should be returned
-	// when handshaking with the server.
-	expectAlert bool
 	// expectHandshakeErrorIncluding, when not empty, contains a string
 	// that must be a substring of the error resulting from the handshake.
 	expectHandshakeErrorIncluding string
@@ -455,9 +537,7 @@
 	if !write {
 		flows, err := test.loadData()
 		if err != nil {
-			if !test.expectAlert {
-				t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
-			}
+			t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
 		}
 		for i, b := range flows {
 			if i%2 == 0 {
@@ -466,17 +546,11 @@
 			}
 			bb := make([]byte, len(b))
 			n, err := io.ReadFull(clientConn, bb)
-			if test.expectAlert {
-				if err == nil {
-					t.Fatal("Expected read failure but read succeeded")
-				}
-			} else {
-				if err != nil {
-					t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
-				}
-				if !bytes.Equal(b, bb) {
-					t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
-				}
+			if err != nil {
+				t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
+			}
+			if !bytes.Equal(b, bb) {
+				t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
 			}
 		}
 		clientConn.Close()
@@ -678,7 +752,7 @@
 		return cert, nil
 	}
 	test := &serverTest{
-		name:    "SNI",
+		name:    "SNI-GetCertificate",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
 		config:  &config,
 	}
@@ -696,7 +770,7 @@
 		return nil, nil
 	}
 	test := &serverTest{
-		name:    "SNI",
+		name:    "SNI-GetCertificateNotFound",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
 		config:  &config,
 	}
@@ -706,18 +780,50 @@
 // TestHandshakeServerSNICertForNameError tests to make sure that errors in
 // GetCertificate result in a tls alert.
 func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
-	config := *testConfig
+	const errMsg = "TestHandshakeServerSNIGetCertificateError error"
 
-	config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
-		return nil, fmt.Errorf("Test error in GetCertificate")
+	serverConfig := *testConfig
+	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+		return nil, errors.New(errMsg)
 	}
-	test := &serverTest{
-		name:        "SNI",
-		command:     []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
-		config:      &config,
-		expectAlert: true,
+
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+		serverName:         "test",
 	}
-	runServerTestTLS12(t, test)
+	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+}
+
+// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
+// the case that Certificates is empty, even without SNI.
+func TestHandshakeServerEmptyCertificates(t *testing.T) {
+	const errMsg = "TestHandshakeServerEmptyCertificates error"
+
+	serverConfig := *testConfig
+	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+		return nil, errors.New(errMsg)
+	}
+	serverConfig.Certificates = nil
+
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+	}
+	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+
+	// With an empty Certificates and a nil GetCertificate, the server
+	// should always return a “no certificates” error.
+	serverConfig.GetCertificate = nil
+
+	clientHello = &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+	}
+	testClientHelloFailure(t, &serverConfig, clientHello, "no certificates")
 }
 
 // TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 0974fc6..b9f86d2 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -11,7 +11,6 @@
 	"crypto/md5"
 	"crypto/rsa"
 	"crypto/sha1"
-	"crypto/sha256"
 	"crypto/x509"
 	"encoding/asn1"
 	"errors"
@@ -31,12 +30,6 @@
 }
 
 func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
-	preMasterSecret := make([]byte, 48)
-	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
-	if err != nil {
-		return nil, err
-	}
-
 	if len(ckx.ciphertext) < 2 {
 		return nil, errClientKeyExchange
 	}
@@ -49,8 +42,12 @@
 		}
 		ciphertext = ckx.ciphertext[2:]
 	}
-
-	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
+	priv, ok := cert.PrivateKey.(crypto.Decrypter)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+	}
+	// Perform contant time RSA PKCS#1 v1.5 decryption
+	preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
 	if err != nil {
 		return nil, err
 	}
@@ -110,30 +107,26 @@
 	return md5sha1
 }
 
-// sha256Hash implements TLS 1.2's hash function.
-func sha256Hash(slices [][]byte) []byte {
-	h := sha256.New()
-	for _, slice := range slices {
-		h.Write(slice)
-	}
-	return h.Sum(nil)
-}
-
 // hashForServerKeyExchange hashes the given slices and returns their digest
-// and the identifier of the hash function used. The hashFunc argument is only
-// used for >= TLS 1.2 and precisely identifies the hash function to use.
-func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
+// and the identifier of the hash function used. The sigAndHash argument is
+// only used for >= TLS 1.2 and precisely identifies the hash function to use.
+func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
 	if version >= VersionTLS12 {
-		switch hashFunc {
-		case hashSHA256:
-			return sha256Hash(slices), crypto.SHA256, nil
-		case hashSHA1:
-			return sha1Hash(slices), crypto.SHA1, nil
-		default:
-			return nil, crypto.Hash(0), errors.New("tls: unknown hash function used by peer")
+		if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
+			return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer")
 		}
+		hashFunc, err := lookupTLSHash(sigAndHash.hash)
+		if err != nil {
+			return nil, crypto.Hash(0), err
+		}
+		h := hashFunc.New()
+		for _, slice := range slices {
+			h.Write(slice)
+		}
+		digest := h.Sum(nil)
+		return digest, hashFunc, nil
 	}
-	if sigType == signatureECDSA {
+	if sigAndHash.signature == signatureECDSA {
 		return sha1Hash(slices), crypto.SHA1, nil
 	}
 	return md5SHA1Hash(slices), crypto.MD5SHA1, nil
@@ -142,20 +135,19 @@
 // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
 // ServerKeyExchange given the signature type being used and the client's
 // advertised list of supported signature and hash combinations.
-func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
-	if len(clientSignatureAndHashes) == 0 {
+func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) {
+	if len(clientList) == 0 {
 		// If the client didn't specify any signature_algorithms
 		// extension then we can assume that it supports SHA1. See
 		// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
 		return hashSHA1, nil
 	}
 
-	for _, sigAndHash := range clientSignatureAndHashes {
+	for _, sigAndHash := range clientList {
 		if sigAndHash.signature != sigType {
 			continue
 		}
-		switch sigAndHash.hash {
-		case hashSHA1, hashSHA256:
+		if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
 			return sigAndHash.hash, nil
 		}
 	}
@@ -228,41 +220,42 @@
 	serverECDHParams[3] = byte(len(ecdhePublic))
 	copy(serverECDHParams[4:], ecdhePublic)
 
-	var tls12HashId uint8
+	sigAndHash := signatureAndHash{signature: ka.sigType}
+
 	if ka.version >= VersionTLS12 {
-		if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
+		if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
 			return nil, err
 		}
 	}
 
-	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams)
+	digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams)
 	if err != nil {
 		return nil, err
 	}
+
+	priv, ok := cert.PrivateKey.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
+	}
 	var sig []byte
 	switch ka.sigType {
 	case signatureECDSA:
-		privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+		_, ok := priv.Public().(*ecdsa.PublicKey)
 		if !ok {
-			return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
+			return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
 		}
-		r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
-		if err != nil {
-			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
-		}
-		sig, err = asn1.Marshal(ecdsaSignature{r, s})
 	case signatureRSA:
-		privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
+		_, ok := priv.Public().(*rsa.PublicKey)
 		if !ok {
-			return nil, errors.New("ECDHE RSA requires a RSA server private key")
-		}
-		sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
-		if err != nil {
-			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+			return nil, errors.New("ECDHE RSA requires a RSA server key")
 		}
 	default:
 		return nil, errors.New("unknown ECDHE signature algorithm")
 	}
+	sig, err = priv.Sign(config.rand(), digest, hashFunc)
+	if err != nil {
+		return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+	}
 
 	skx := new(serverKeyExchangeMsg)
 	sigAndHashLen := 0
@@ -273,8 +266,8 @@
 	copy(skx.key, serverECDHParams)
 	k := skx.key[len(serverECDHParams):]
 	if ka.version >= VersionTLS12 {
-		k[0] = tls12HashId
-		k[1] = ka.sigType
+		k[0] = sigAndHash.hash
+		k[1] = sigAndHash.signature
 		k = k[2:]
 	}
 	k[0] = byte(len(sig) >> 8)
@@ -335,15 +328,14 @@
 		return errServerKeyExchange
 	}
 
-	var tls12HashId uint8
+	sigAndHash := signatureAndHash{signature: ka.sigType}
 	if ka.version >= VersionTLS12 {
 		// handle SignatureAndHashAlgorithm
-		var sigAndHash []uint8
-		sigAndHash, sig = sig[:2], sig[2:]
-		if sigAndHash[1] != ka.sigType {
+		sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]}
+		if sigAndHash.signature != ka.sigType {
 			return errServerKeyExchange
 		}
-		tls12HashId = sigAndHash[0]
+		sig = sig[2:]
 		if len(sig) < 2 {
 			return errServerKeyExchange
 		}
@@ -354,7 +346,7 @@
 	}
 	sig = sig[2:]
 
-	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams)
+	digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams)
 	if err != nil {
 		return err
 	}
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index d2f9e28..6127c1c 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -9,8 +9,10 @@
 	"crypto/hmac"
 	"crypto/md5"
 	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"errors"
 	"hash"
-	"strconv"
 )
 
 // Split a premaster secret in two as specified in RFC 4346, section 5.
@@ -64,14 +66,14 @@
 	}
 }
 
-// prf12New returns a function implementing the TLS 1.2 pseudo-random function,
-// as defined in RFC 5246, section 5, using the given hash.
-func prf12New(tls12Hash crypto.Hash) func(result, secret, label, seed []byte) {
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
+func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
 	return func(result, secret, label, seed []byte) {
 		labelAndSeed := make([]byte, len(label)+len(seed))
 		copy(labelAndSeed, label)
 		copy(labelAndSeed[len(label):], seed)
-		pHash(result, secret, labelAndSeed, tls12Hash.New)
+
+		pHash(result, secret, labelAndSeed, hashFunc)
 	}
 }
 
@@ -119,41 +121,49 @@
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
 
-func prfForVersion(version uint16, tls12Hash crypto.Hash) func(result, secret, label, seed []byte) {
+func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
 	switch version {
 	case VersionSSL30:
-		return prf30
+		return prf30, crypto.Hash(0)
 	case VersionTLS10, VersionTLS11:
-		return prf10
+		return prf10, crypto.Hash(0)
 	case VersionTLS12:
-		return prf12New(tls12Hash)
+		if suite.flags&suiteSHA384 != 0 {
+			return prf12(sha512.New384), crypto.SHA384
+		}
+		return prf12(sha256.New), crypto.SHA256
 	default:
 		panic("unknown version")
 	}
 }
 
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+	prf, _ := prfAndHashForVersion(version, suite)
+	return prf
+}
+
 // masterFromPreMasterSecret generates the master secret from the pre-master
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
-func masterFromPreMasterSecret(version uint16, tls12Hash crypto.Hash, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], clientRandom)
 	copy(seed[len(clientRandom):], serverRandom)
 	masterSecret := make([]byte, masterSecretLength)
-	prfForVersion(version, tls12Hash)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
 	return masterSecret
 }
 
 // keysFromMasterSecret generates the connection keys from the master
 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
 // RFC 2246, section 6.3.
-func keysFromMasterSecret(version uint16, tls12Hash crypto.Hash, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], serverRandom)
 	copy(seed[len(serverRandom):], clientRandom)
 
 	n := 2*macLen + 2*keyLen + 2*ivLen
 	keyMaterial := make([]byte, n)
-	prfForVersion(version, tls12Hash)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
 	clientMAC = keyMaterial[:macLen]
 	keyMaterial = keyMaterial[macLen:]
 	serverMAC = keyMaterial[:macLen]
@@ -168,30 +178,53 @@
 	return
 }
 
-func newFinishedHash(version uint16, tls12Hash crypto.Hash) finishedHash {
-	if version >= VersionTLS12 {
-		return finishedHash{tls12Hash.New(), tls12Hash.New(), tls12Hash, nil, nil, version, prfForVersion(version, tls12Hash)}
+// lookupTLSHash looks up the corresponding crypto.Hash for a given
+// TLS hash identifier.
+func lookupTLSHash(hash uint8) (crypto.Hash, error) {
+	switch hash {
+	case hashSHA1:
+		return crypto.SHA1, nil
+	case hashSHA256:
+		return crypto.SHA256, nil
+	case hashSHA384:
+		return crypto.SHA384, nil
+	default:
+		return 0, errors.New("tls: unsupported hash algorithm")
 	}
-	return finishedHash{sha1.New(), sha1.New(), crypto.MD5SHA1, md5.New(), md5.New(), version, prfForVersion(version, tls12Hash)}
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+	var buffer []byte
+	if version == VersionSSL30 || version >= VersionTLS12 {
+		buffer = []byte{}
+	}
+
+	prf, hash := prfAndHashForVersion(version, cipherSuite)
+	if hash != 0 {
+		return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
+	}
+
+	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
 }
 
 // A finishedHash calculates the hash of a set of handshake messages suitable
 // for including in a Finished message.
 type finishedHash struct {
 	client hash.Hash
-
-	server     hash.Hash
-	serverHash crypto.Hash
+	server hash.Hash
 
 	// Prior to TLS 1.2, an additional MD5 hash is required.
 	clientMD5 hash.Hash
 	serverMD5 hash.Hash
 
+	// In TLS 1.2, a full buffer is sadly required.
+	buffer []byte
+
 	version uint16
 	prf     func(result, secret, label, seed []byte)
 }
 
-func (h finishedHash) Write(msg []byte) (n int, err error) {
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
 	h.client.Write(msg)
 	h.server.Write(msg)
 
@@ -199,14 +232,29 @@
 		h.clientMD5.Write(msg)
 		h.serverMD5.Write(msg)
 	}
+
+	if h.buffer != nil {
+		h.buffer = append(h.buffer, msg...)
+	}
+
 	return len(msg), nil
 }
 
+func (h finishedHash) Sum() []byte {
+	if h.version >= VersionTLS12 {
+		return h.client.Sum(nil)
+	}
+
+	out := make([]byte, 0, md5.Size+sha1.Size)
+	out = h.clientMD5.Sum(out)
+	return h.client.Sum(out)
+}
+
 // finishedSum30 calculates the contents of the verify_data member of a SSLv3
 // Finished message given the MD5 and SHA1 hashes of a set of handshake
 // messages.
-func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
-	md5.Write(magic[:])
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
+	md5.Write(magic)
 	md5.Write(masterSecret)
 	md5.Write(ssl30Pad1[:])
 	md5Digest := md5.Sum(nil)
@@ -217,7 +265,7 @@
 	md5.Write(md5Digest)
 	md5Digest = md5.Sum(nil)
 
-	sha1.Write(magic[:])
+	sha1.Write(magic)
 	sha1.Write(masterSecret)
 	sha1.Write(ssl30Pad1[:40])
 	sha1Digest := sha1.Sum(nil)
@@ -241,19 +289,11 @@
 // Finished message.
 func (h finishedHash) clientSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic)
+		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	if h.version >= VersionTLS12 {
-		seed := h.client.Sum(nil)
-		h.prf(out, masterSecret, clientFinishedLabel, seed)
-	} else {
-		seed := make([]byte, 0, md5.Size+sha1.Size)
-		seed = h.clientMD5.Sum(seed)
-		seed = h.client.Sum(seed)
-		h.prf(out, masterSecret, clientFinishedLabel, seed)
-	}
+	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
 	return out
 }
 
@@ -261,48 +301,67 @@
 // Finished message.
 func (h finishedHash) serverSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic)
+		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	if h.version >= VersionTLS12 {
-		seed := h.server.Sum(nil)
-		h.prf(out, masterSecret, serverFinishedLabel, seed)
-	} else {
-		seed := make([]byte, 0, md5.Size+sha1.Size)
-		seed = h.serverMD5.Sum(seed)
-		seed = h.server.Sum(seed)
-		h.prf(out, masterSecret, serverFinishedLabel, seed)
-	}
+	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
 	return out
 }
 
+// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a
+// client's CertificateVerify with, or an error if none can be found.
+func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
+	if h.version < VersionTLS12 {
+		// Nothing to negotiate before TLS 1.2.
+		return signatureAndHash{signature: sigType}, nil
+	}
+
+	for _, v := range serverList {
+		if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) {
+			return v, nil
+		}
+	}
+	return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate")
+}
+
 // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
 // id suitable for signing by a TLS client certificate.
-func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) {
-	if h.version >= VersionTLS12 {
-		digest := h.server.Sum(nil)
-		return digest, h.serverHash, tls12HashID(h.serverHash)
-	}
-	if sigType == signatureECDSA {
-		digest := h.server.Sum(nil)
-		return digest, crypto.SHA1, hashSHA1
+func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) {
+	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
+		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
 	}
 
-	digest := make([]byte, 0, 36)
-	digest = h.serverMD5.Sum(digest)
-	digest = h.server.Sum(digest)
-	return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */
+	if h.version == VersionSSL30 {
+		if signatureAndHash.signature != signatureRSA {
+			return nil, 0, errors.New("tls: unsupported signature type for client certificate")
+		}
+
+		md5Hash := md5.New()
+		md5Hash.Write(h.buffer)
+		sha1Hash := sha1.New()
+		sha1Hash.Write(h.buffer)
+		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
+	}
+	if h.version >= VersionTLS12 {
+		hashAlg, err := lookupTLSHash(signatureAndHash.hash)
+		if err != nil {
+			return nil, 0, err
+		}
+		hash := hashAlg.New()
+		hash.Write(h.buffer)
+		return hash.Sum(nil), hashAlg, nil
+	}
+
+	if signatureAndHash.signature == signatureECDSA {
+		return h.server.Sum(nil), crypto.SHA1, nil
+	}
+
+	return h.Sum(), crypto.MD5SHA1, nil
 }
 
-// tls12HashID returns the HashAlgorithm id corresponding to the hash h, as
-// specified in RFC 5246, section A.4.1.
-func tls12HashID(h crypto.Hash) uint8 {
-	switch h {
-	case crypto.SHA256:
-		return hashSHA256
-	case crypto.SHA384:
-		return hashSHA384
-	}
-	panic("tls12HashID called with unknown hash " + strconv.Itoa(int(h)))
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+	h.buffer = nil
 }
diff --git a/src/crypto/tls/prf_test.go b/src/crypto/tls/prf_test.go
index 1d21741..0a1b1bc 100644
--- a/src/crypto/tls/prf_test.go
+++ b/src/crypto/tls/prf_test.go
@@ -5,7 +5,6 @@
 package tls
 
 import (
-	"crypto"
 	"encoding/hex"
 	"testing"
 )
@@ -36,7 +35,7 @@
 
 type testKeysFromTest struct {
 	version                    uint16
-	hash                       crypto.Hash
+	suite                      *cipherSuite
 	preMasterSecret            string
 	clientRandom, serverRandom string
 	masterSecret               string
@@ -51,13 +50,13 @@
 		clientRandom, _ := hex.DecodeString(test.clientRandom)
 		serverRandom, _ := hex.DecodeString(test.serverRandom)
 
-		masterSecret := masterFromPreMasterSecret(test.version, test.hash, in, clientRandom, serverRandom)
+		masterSecret := masterFromPreMasterSecret(test.version, test.suite, in, clientRandom, serverRandom)
 		if s := hex.EncodeToString(masterSecret); s != test.masterSecret {
 			t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret)
 			continue
 		}
 
-		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.hash, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
 		clientMACString := hex.EncodeToString(clientMAC)
 		serverMACString := hex.EncodeToString(serverMAC)
 		clientKeyString := hex.EncodeToString(clientKey)
@@ -71,11 +70,20 @@
 	}
 }
 
+func cipherSuiteById(id uint16) *cipherSuite {
+	for _, cipherSuite := range cipherSuites {
+		if cipherSuite.id == id {
+			return cipherSuite
+		}
+	}
+	panic("ciphersuite not found")
+}
+
 // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
 var testKeysFromTests = []testKeysFromTest{
 	{
 		VersionTLS10,
-		crypto.SHA1,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
 		"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
 		"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -89,7 +97,7 @@
 	},
 	{
 		VersionTLS10,
-		crypto.SHA1,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
 		"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
 		"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -103,7 +111,7 @@
 	},
 	{
 		VersionTLS10,
-		crypto.SHA1,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
@@ -117,7 +125,7 @@
 	},
 	{
 		VersionSSL30,
-		crypto.SHA1,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
index 588090a..4bad786 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 43 60 d4 9a c4  |....Y...U..C`...|
-00000010  28 6c b9 56 de 43 c6 e4  05 f5 ab 71 87 ef ae b8  |(l.V.C.....q....|
-00000020  cf da 13 b5 98 b7 ab cc  35 44 48 20 2c 7f 10 60  |........5DH ,..`|
-00000030  98 a8 13 4d a8 7c d6 45  48 aa c5 aa f2 f7 bb 98  |...M.|.EH.......|
-00000040  53 6e 5d 3f 56 de 17 ba  c9 a8 d1 81 c0 09 00 00  |Sn]?V...........|
+00000000  16 03 01 00 59 02 00 00  55 03 01 c0 e1 5c 5b 45  |....Y...U....\[E|
+00000010  70 fc a1 73 44 e7 69 b6  83 a1 71 bc 03 21 2e cc  |p..sD.i...q..!..|
+00000020  21 7a 28 20 82 6b 2f 77  7d 40 c7 20 0d e4 19 db  |!z( .k/w}@. ....|
+00000030  35 cd 75 a4 e7 e5 6c 3e  c9 d5 fe 9d c5 88 78 7b  |5.u...l>......x{|
+00000040  c4 fc 04 9a c1 10 7a 15  d9 e9 4a 95 c0 09 00 00  |......z...J.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,21 +48,21 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d4 0c 00  00 d0 03 00 17 41 04 ef  |*............A..|
-00000280  89 a9 4f 05 2f ee ee c9  cb 73 d0 57 cc c9 45 ca  |..O./....s.W..E.|
-00000290  d8 61 4d 0d 5b cf 83 c1  19 bd 6d a7 49 de ba 6c  |.aM.[.....m.I..l|
-000002a0  63 b5 88 c9 4d a8 44 9f  f2 ec 3c 88 d6 ec 20 f3  |c...M.D...<... .|
-000002b0  6f 25 cd 99 0a 42 71 19  67 6d dd 65 6a 52 f8 00  |o%...Bq.gm.ejR..|
-000002c0  89 30 81 86 02 41 42 4f  70 eb fa 2a bf 06 0f 16  |.0...ABOp..*....|
-000002d0  62 d8 25 d5 d4 c4 bb 2e  d1 f9 84 3b a0 57 78 7f  |b.%........;.Wx.|
-000002e0  fe 29 50 49 e1 f0 a1 c6  1f 87 98 7f d5 63 b9 72  |.)PI.........c.r|
-000002f0  f5 2f 70 a8 bc 5f 45 22  57 07 99 e1 f8 51 30 b0  |./p.._E"W....Q0.|
-00000300  2f 6e 6d 8c b5 4a 34 02  41 05 86 7d e4 16 b2 bf  |/nm..J4.A..}....|
-00000310  70 de 5a 69 43 6e e2 ec  a2 4f 97 b0 ae 99 07 08  |p.ZiCn...O......|
-00000320  32 d2 9d f4 56 80 71 d7  96 94 36 59 b5 95 7f 10  |2...V.q...6Y....|
-00000330  8a aa a5 90 db cc a3 47  02 53 b1 9e 2d c7 db bc  |.......G.S..-...|
-00000340  58 1d b5 01 07 9c 9c 74  b5 a7 16 03 01 00 0e 0d  |X......t........|
-00000350  00 00 06 03 01 02 40 00  00 0e 00 00 00           |......@......|
+00000270  2a 16 03 01 00 d6 0c 00  00 d2 03 00 17 41 04 01  |*............A..|
+00000280  74 83 af 3a 65 7a ad 1a  63 1f 13 82 9d f4 de 06  |t..:ez..c.......|
+00000290  4e 3a 03 81 61 72 ff f8  58 da 7b f5 81 6d 81 57  |N:..ar..X.{..m.W|
+000002a0  d9 d1 b1 6d e3 97 db 86  72 17 15 18 16 d4 ec 04  |...m....r.......|
+000002b0  32 7c 38 90 6b a4 3c e9  35 79 2d 4c 39 5e 2d 00  |2|8.k.<.5y-L9^-.|
+000002c0  8b 30 81 88 02 42 01 44  78 e1 2a bb 95 f7 45 58  |.0...B.Dx.*...EX|
+000002d0  d4 0d b6 e4 4e ff 48 b3  11 14 ee d5 6c bb 5f 0c  |....N.H.....l._.|
+000002e0  90 b6 ef bc 05 77 f6 05  42 b4 d8 a6 70 e6 8c 90  |.....w..B...p...|
+000002f0  f0 4b 3b c9 d3 4e 0c 85  65 b4 e0 fe b5 10 09 9b  |.K;..N..e.......|
+00000300  e1 08 84 ea 93 96 8e a4  02 42 01 c7 15 ee 9d 98  |.........B......|
+00000310  b7 25 eb 07 ff f6 94 7e  e7 9d a5 17 9e 37 93 40  |.%.....~.....7.@|
+00000320  4c 9f eb 6b a3 7a 57 d8  81 c6 d9 09 34 aa 96 8c  |L..k.zW.....4...|
+00000330  4d 28 2e 9f f7 0b 1c 09  e1 d1 d8 48 6e 8a 8e 9c  |M(.........Hn...|
+00000340  01 4c e7 2d 53 8f 8e 71  61 82 ff ff 16 03 01 00  |.L.-S..qa.......|
+00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........@......|
 >>> Flow 3 (client to server)
 00000000  16 03 01 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -100,30 +101,30 @@
 00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 90 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8c 00 8a 30 81 87  02 42 01 0f 51 63 8f 2e  |.....0...B..Qc..|
-00000270  fa 3a 3a 15 a9 4b 7f 04  c9 23 73 be 44 f5 28 37  |.::..K...#s.D.(7|
-00000280  2c 00 34 20 86 e6 94 00  bf 11 40 ec de a9 54 03  |,.4 ......@...T.|
-00000290  dc 9d 19 67 39 22 5e c4  55 3b f4 b6 9a a8 4f 6e  |...g9"^.U;....On|
-000002a0  21 20 f0 9a 9a 10 a8 01  3a 20 ac 8b 02 41 34 ad  |! ......: ...A4.|
-000002b0  89 da ec cc 8b b7 d7 5a  6c fe 6f 13 fa 58 40 2e  |.......Zl.o..X@.|
-000002c0  a6 bf 32 69 97 a5 21 44  7c 3d d2 51 b3 b3 bb 9c  |..2i..!D|=.Q....|
-000002d0  ed fa 5d bd 09 f3 c0 71  ee 3d 98 24 13 e1 e2 c8  |..]....q.=.$....|
-000002e0  e7 75 fc ac c3 61 9a f3  47 b2 7c 97 01 99 2d 14  |.u...a..G.|...-.|
-000002f0  03 01 00 01 01 16 03 01  00 30 d7 d1 c3 57 a3 f8  |.........0...W..|
-00000300  71 eb 97 9d a8 ac 15 88  f4 b4 f7 e6 8c 2e eb fe  |q...............|
-00000310  25 d1 77 82 20 06 d1 36  20 3d bc 82 ab 30 4d 85  |%.w. ..6 =...0M.|
-00000320  1b 7b c2 9e 60 8f 7e 05  73 3e                    |.{..`.~.s>|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 91 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8d 00 8b 30 81 88  02 42 01 91 2d e9 99 a4  |.....0...B..-...|
+00000270  88 5c 03 9c ea 8b 64 07  f2 c9 e7 ad 5b a3 fb 27  |.\....d.....[..'|
+00000280  fd 19 9b 78 bd 7b 9d 0a  cc 8a 61 c5 83 33 02 29  |...x.{....a..3.)|
+00000290  c3 66 24 9d 5f bc 03 d9  2a 49 aa 59 51 83 49 72  |.f$._...*I.YQ.Ir|
+000002a0  13 be ea 82 5a 5c 09 2f  da 23 bc 18 02 42 01 0d  |....Z\./.#...B..|
+000002b0  a1 15 4d fe 18 ec 90 d5  4e 9a 75 60 05 67 10 5e  |..M.....N.u`.g.^|
+000002c0  3c 34 00 e8 18 33 8f 90  26 2e d3 a9 81 6c 43 17  |<4...3..&....lC.|
+000002d0  80 9e c5 bd 23 c9 24 96  a1 29 23 a4 13 3f ad d2  |....#.$..)#..?..|
+000002e0  45 19 0b 56 56 4b c1 f1  cc 70 c8 af 44 ff 34 96  |E..VVK...p..D.4.|
+000002f0  14 03 01 00 01 01 16 03  01 00 30 c4 0c 67 53 06  |..........0..gS.|
+00000300  49 b3 c9 5c 2e 72 f6 54  ba ad ac a8 80 55 17 01  |I..\.r.T.....U..|
+00000310  5c 44 71 7d ad 15 34 95  9a 7f 7b 95 0e 08 70 ce  |\Dq}..4...{...p.|
+00000320  5a 33 f4 3b 4e 80 06 43  70 93 17                 |Z3.;N..Cp..|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 7a 5e 9e 4b 7d  |..........0z^.K}|
-00000010  44 8f 70 5f fd a9 50 a9  d8 52 cf 89 f9 b0 08 ea  |D.p_..P..R......|
-00000020  bb a2 80 44 73 09 da 81  98 33 b1 44 88 0c ef e3  |...Ds....3.D....|
-00000030  c6 8b 2f 28 9b e1 f7 59  26 9c 54                 |../(...Y&.T|
+00000000  14 03 01 00 01 01 16 03  01 00 30 3b ba 6c 73 ec  |..........0;.ls.|
+00000010  11 5b 44 46 1d bb 31 1b  1b e8 d8 51 4f 95 b0 40  |.[DF..1....QO..@|
+00000020  87 49 33 73 40 98 61 1c  94 02 48 9b 80 d3 6c af  |.I3s@.a...H...l.|
+00000030  e2 31 63 11 a7 c8 db ed  7a a4 4d                 |.1c.....z.M|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 f1 61 1b  1f 1e 91 85 c1 ce 93 38  |.... .a........8|
-00000010  6b d0 ee c5 2e 00 f0 42  e3 a9 f0 82 92 a6 9b df  |k......B........|
-00000020  ac 3c e3 18 aa 17 03 01  00 20 2a 72 5b 1a 57 10  |.<....... *r[.W.|
-00000030  cb 64 c4 5f b2 2d f9 03  41 ca 8d 72 93 f7 ae 19  |.d._.-..A..r....|
-00000040  37 3a 8c d5 f5 ad d8 83  20 9c 15 03 01 00 20 f9  |7:...... ..... .|
-00000050  53 1a 9f 34 27 91 f1 3f  7c 33 eb 1f 5d 0e bc 89  |S..4'..?|3..]...|
-00000060  5e 08 20 9e 5c e4 a0 70  8d 03 63 c6 9a 62 14     |^. .\..p..c..b.|
+00000000  17 03 01 00 20 2e f7 66  f0 ce 50 d7 38 7a d4 fd  |.... ..f..P.8z..|
+00000010  e3 66 b1 76 76 59 ad bc  b0 0a 75 1d f0 92 6e e3  |.f.vvY....u...n.|
+00000020  21 1d 13 dc ad 17 03 01  00 20 f1 b2 0f 3b 26 91  |!........ ...;&.|
+00000030  ed ff 9f fc 41 04 7e 47  17 02 af 0c 2b e8 b7 31  |....A.~G....+..1|
+00000040  ae 29 71 f9 a8 89 84 f3  e8 da 15 03 01 00 20 1f  |.)q........... .|
+00000050  26 64 cf 34 c1 48 6b 79  61 e2 77 57 9d 27 14 45  |&d.4.Hkya.wW.'.E|
+00000060  46 24 ad 2d 35 57 db 2b  32 03 e2 68 b0 1a 5a     |F$.-5W.+2..h..Z|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
index 84632afb..0e420a6 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 8b 2e 89 18 f7  |....Q...M.......|
-00000010  c8 0f 16 f0 81 91 e7 88  7c e8 20 a2 de 0e 28 ce  |........|. ...(.|
-00000020  f3 12 54 68 79 ec b2 05  0b d1 74 20 bc c6 22 fd  |..Thy.....t ..".|
-00000030  45 00 2c a6 bf 65 38 fd  2f 6e 71 9c b8 14 7a 0a  |E.,..e8./nq...z.|
-00000040  5b 8e 71 c9 b6 32 99 41  f7 43 91 ad 00 05 00 00  |[.q..2.A.C......|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 b7 de 52 5a 07  |....Q...M....RZ.|
+00000010  43 b8 72 1d d9 6f 5c a5  70 da ee 27 b7 a9 50 9d  |C.r..o\.p..'..P.|
+00000020  e7 75 ad 61 a5 2f 69 47  2a d8 2e 20 a8 b0 64 6b  |.u.a./iG*.. ..dk|
+00000030  4d 25 ec 50 2b 8e a7 9b  0c f9 f5 3c 62 96 a3 53  |M%.P+......<b..S|
+00000040  a7 4b af 33 1e e7 f8 43  b9 be 6e e7 00 05 00 00  |.K.3...C..n.....|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -101,25 +102,25 @@
 00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
 00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
 00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
-00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 90 0f  |..C.0oUN.p......|
-000002a0  00 00 8c 00 8a 30 81 87  02 41 59 10 98 e1 27 39  |.....0...AY...'9|
-000002b0  62 42 32 98 8d 04 14 6a  95 27 b0 3b 62 46 f3 8e  |bB2....j.'.;bF..|
-000002c0  5a 86 28 4f 3d a8 49 44  85 d8 8d 02 15 52 72 4f  |Z.(O=.ID.....RrO|
-000002d0  87 4c 16 73 98 f6 6f 93  bb 9a c3 11 be 7f 35 81  |.L.s..o.......5.|
-000002e0  52 9f 17 6e 10 5e 33 ad  c9 24 ad 02 42 01 c3 cb  |R..n.^3..$..B...|
-000002f0  e7 4f a9 c5 b1 5f ab c7  d2 42 92 05 a0 9b ca a6  |.O..._...B......|
-00000300  33 ad 5c bd 22 94 c2 f7  d3 b4 3a 25 ae b4 bc c4  |3.\.".....:%....|
-00000310  f3 b6 38 8a a2 aa e7 e8  55 d9 8a 32 1f c7 05 a0  |..8.....U..2....|
-00000320  55 58 46 aa 78 37 d8 c6  57 bc 9b 2a 31 b4 15 14  |UXF.x7..W..*1...|
-00000330  03 01 00 01 01 16 03 01  00 24 fd 98 09 ef 50 d2  |.........$....P.|
-00000340  a5 90 9c 55 eb aa 67 33  24 a3 1e db 4b 2e 6b cb  |...U..g3$...K.k.|
-00000350  b5 17 8b c0 c1 2e a6 c6  49 7d 84 0c d7 96        |........I}....|
+00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 91 0f  |..C.0oUN.p......|
+000002a0  00 00 8d 00 8b 30 81 88  02 42 00 b5 1a 9d 48 90  |.....0...B....H.|
+000002b0  2f d9 1a 04 66 f7 3b 4d  d7 ae d9 1e dd 3c fa 24  |/...f.;M.....<.$|
+000002c0  0f 24 97 b2 61 46 16 d9  a0 35 f9 f7 54 45 92 fd  |.$..aF...5..TE..|
+000002d0  10 56 ab 26 d7 b5 10 80  8b 88 95 ef c6 73 1c d2  |.V.&.........s..|
+000002e0  ff e9 20 cd 18 a8 40 c4  4d 83 c2 e2 02 42 01 8c  |.. ...@.M....B..|
+000002f0  d2 13 4c cc e5 38 37 17  6c 83 d6 ad c1 dc af ec  |..L..87.l.......|
+00000300  8d 06 75 b8 08 ad 56 4a  8f b9 03 59 80 f8 81 d4  |..u...VJ...Y....|
+00000310  f3 91 89 eb 9c 27 5d e1  dc 6d ef d6 20 da e7 9c  |.....']..m.. ...|
+00000320  71 75 cb 2a f9 e4 05 46  c8 85 ca 7b 9c 97 e8 6d  |qu.*...F...{...m|
+00000330  14 03 01 00 01 01 16 03  01 00 24 9f 67 4e 22 04  |..........$.gN".|
+00000340  10 f4 28 55 3e 50 88 90  61 07 42 29 f5 9b f5 32  |..(U>P..a.B)...2|
+00000350  16 3d ea c1 8f aa a1 4c  b5 72 26 d8 32 cd 50     |.=.....L.r&.2.P|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 b3 e4 bb 70 4b  |..........$...pK|
-00000010  21 71 de 80 27 48 7f 15  60 23 65 a5 3f 94 b3 e7  |!q..'H..`#e.?...|
-00000020  91 3a fe 4c 70 60 22 6c  67 ca 85 85 23 f4 83     |.:.Lp`"lg...#..|
+00000000  14 03 01 00 01 01 16 03  01 00 24 df 8d f1 07 6d  |..........$....m|
+00000010  63 39 fc ba b1 67 3b 68  85 b9 37 7d d3 67 19 76  |c9...g;h..7}.g.v|
+00000020  34 a4 1b 86 31 bd fe 06  72 00 d8 2b f2 65 3d     |4...1...r..+.e=|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a d6 19 a3  b8 82 ff dc 69 4f ee 36  |............iO.6|
-00000010  2b 95 c8 c0 e6 d8 84 ea  e7 d9 40 39 10 ba 33 15  |+.........@9..3.|
-00000020  03 01 00 16 85 1b 41 3b  e8 71 07 3c 6e 9f b9 e0  |......A;.q.<n...|
-00000030  0d 67 77 d8 b2 84 9f 76  05 9e                    |.gw....v..|
+00000000  17 03 01 00 1a 60 cc 81  4f 8b 73 b3 7f 34 bf f1  |.....`..O.s..4..|
+00000010  7c d8 32 0a ef 2a 26 f9  b8 69 84 83 48 21 ee 15  ||.2..*&..i..H!..|
+00000020  03 01 00 16 23 7a 0c 65  3a 66 1a 75 03 e4 85 3f  |....#z.e:f.u...?|
+00000030  83 cd 55 70 99 f4 44 dc  67 ba                    |..Up..D.g.|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
index 9dfec4d..7e33edc 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 60 fd 2a c3 90  |....Y...U..`.*..|
-00000010  e3 1d e7 96 4a e7 2c d3  c7 35 80 67 7f 7e 57 8f  |....J.,..5.g.~W.|
-00000020  f1 9c 65 35 36 cd e3 98  ae ed 1e 20 58 3f 0d 2f  |..e56...... X?./|
-00000030  77 10 eb 1a b6 03 96 09  f3 6d 22 9f 4b 96 21 06  |w........m".K.!.|
-00000040  84 d2 da 9a 14 09 b4 d8  be 62 45 91 c0 09 00 00  |.........bE.....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 dc a9 22 c2 a2  |....Y...U...."..|
+00000010  05 ba c4 66 9a 71 aa 0f  92 6a fc df b0 29 4d 36  |...f.q...j...)M6|
+00000020  39 2e f8 39 ed 8e f6 7f  8f 17 13 20 f8 9c f3 3d  |9..9....... ...=|
+00000030  0a 41 8f 30 c7 5d cd 17  c5 ad 1c 52 45 a3 47 8c  |.A.0.].....RE.G.|
+00000040  07 4c 48 e1 00 2b 32 38  01 c8 79 b7 c0 09 00 00  |.LH..+28..y.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,20 +48,20 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 b2  |*............A..|
-00000280  dd fb 15 7b ac 21 6d 89  5f 18 69 18 d7 b2 ef f7  |...{.!m._.i.....|
-00000290  b6 83 99 2d 06 98 38 72  5b 58 b6 6d 09 d3 00 2e  |...-..8r[X.m....|
-000002a0  a0 06 02 46 4d c6 d0 1f  a8 cb c9 74 7e e1 1e 0d  |...FM......t~...|
-000002b0  f4 36 2b 38 b7 ab 29 bd  39 73 a8 b8 55 2a b1 00  |.6+8..).9s..U*..|
-000002c0  8a 30 81 87 02 41 7d 26  e5 9f 73 c4 eb ea d7 59  |.0...A}&..s....Y|
-000002d0  ab b8 7a b9 b7 f6 70 6d  9e 8b a6 4a c2 fc 73 5a  |..z...pm...J..sZ|
-000002e0  78 2c 27 ef ff 52 91 4a  74 12 43 2f 49 d7 55 18  |x,'..R.Jt.C/I.U.|
-000002f0  9f 72 c6 a6 25 0a 2a 94  47 5d 66 08 13 e8 ef af  |.r..%.*.G]f.....|
-00000300  df 12 fa 70 91 86 87 02  42 00 dc 98 50 24 fa 27  |...p....B...P$.'|
-00000310  95 cb 01 c1 ee e9 18 7e  5b b0 b1 e3 f9 e2 56 ff  |.......~[.....V.|
-00000320  d7 d7 41 f3 f1 b1 28 1f  a1 19 62 29 74 1d 0e 4d  |..A...(...b)t..M|
-00000330  57 3f 99 50 c6 a8 78 57  4d 36 1a 42 6b 64 1c 14  |W?.P..xWM6.Bkd..|
-00000340  e8 36 c6 a8 cc f7 75 f7  f7 7d c9 16 03 01 00 0e  |.6....u..}......|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 89  |*............A..|
+00000280  95 9a 90 82 59 ab 29 bf  10 06 8c 6c 0d 67 cf b1  |....Y.)....l.g..|
+00000290  66 8b 5e 43 b8 46 56 3a  8d 30 92 35 28 82 f2 38  |f.^C.FV:.0.5(..8|
+000002a0  6e 19 5d 37 f0 ab fc 78  15 6a 6a 73 ca dc a6 f2  |n.]7...x.jjs....|
+000002b0  68 5d b3 ab 6d 68 44 3b  80 d2 d9 cd 78 0a ed 00  |h]..mhD;....x...|
+000002c0  8a 30 81 87 02 42 01 80  63 4a 22 4c 8e 66 4e 25  |.0...B..cJ"L.fN%|
+000002d0  e1 86 27 81 de eb b3 a0  c4 dc dc e2 a0 94 2a b6  |..'...........*.|
+000002e0  b3 e9 e7 42 e1 1d 1a c0  43 8d a1 d6 8d 77 84 06  |...B....C....w..|
+000002f0  ba 95 99 e3 54 80 59 4e  3c fb 0c f3 b7 d3 a8 d2  |....T.YN<.......|
+00000300  ce 49 97 fb e2 79 91 93  02 41 2b 2c b7 9f 81 ea  |.I...y...A+,....|
+00000310  de 17 12 af 4d 20 bc a1  43 1d 60 a0 37 52 a2 7b  |....M ..C.`.7R.{|
+00000320  a8 4c de fd 1d fe 37 3b  00 23 61 ce d2 80 47 43  |.L....7;.#a...GC|
+00000330  b0 3a f3 1f aa c7 07 b1  68 5b d8 f3 03 a9 56 5c  |.:......h[....V\|
+00000340  63 ef 83 1d 9c 9c 8d 29  81 e9 3b 16 03 01 00 0e  |c......)..;.....|
 00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |.......@......|
 >>> Flow 3 (client to server)
 00000000  16 03 01 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
@@ -100,29 +101,29 @@
 00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 01 00 86  |..h.A.Vk.Z......|
-00000250  0f 00 00 82 00 80 1c 5e  19 d9 f9 4f 97 8d 92 a5  |.......^...O....|
-00000260  73 87 be 46 df 6b 39 be  2c f2 13 73 da a4 04 47  |s..F.k9.,..s...G|
-00000270  44 11 72 6f ea a9 2d ea  fc 6a aa e4 e5 85 d3 60  |D.ro..-..j.....`|
-00000280  3c aa 2f 81 dd bc 4f 7b  bb 77 58 f7 78 15 6f 21  |<./...O{.wX.x.o!|
-00000290  7c c4 bb 95 af 85 49 ab  3f 68 cf bd 18 be e1 3e  ||.....I.?h.....>|
-000002a0  9e 59 64 47 39 37 d5 cf  ba 84 44 2a 4b 8b 2d cb  |.YdG97....D*K.-.|
-000002b0  36 24 87 c4 c5 ba 96 91  b2 b3 d0 30 87 b3 7e 2d  |6$.........0..~-|
-000002c0  8f 51 0e 47 af c6 0c 33  48 fd 37 d8 bb f2 95 2c  |.Q.G...3H.7....,|
-000002d0  72 ca c6 3c ab 8d 14 03  01 00 01 01 16 03 01 00  |r..<............|
-000002e0  30 52 e6 b2 ba 4c be e7  e9 ad bf 9b 86 2d fb 90  |0R...L.......-..|
-000002f0  1c 90 86 55 7e 3e 75 63  df 38 54 d6 20 25 37 ae  |...U~>uc.8T. %7.|
-00000300  ab 4f ab 85 84 03 61 f7  eb 56 bd 1a 17 f3 da f6  |.O....a..V......|
-00000310  6d                                                |m|
+00000250  0f 00 00 82 00 80 0e 80  9c 3a 6e 40 51 09 39 d4  |.........:n@Q.9.|
+00000260  40 58 10 da 7f 32 12 08  9e f0 4d 9a d7 20 a2 9c  |@X...2....M.. ..|
+00000270  b0 95 3a 33 4e f8 b1 a3  74 62 ab 51 7d 23 d4 32  |..:3N...tb.Q}#.2|
+00000280  a2 af b8 5a 3b b0 23 e4  7a f1 eb 4d b7 bb 23 d5  |...Z;.#.z..M..#.|
+00000290  a9 0d b4 81 d2 b4 45 bd  15 52 ad 58 da 92 a2 c4  |......E..R.X....|
+000002a0  30 66 87 f2 ae c5 e4 8c  fa ba a0 40 76 b8 3f 72  |0f.........@v.?r|
+000002b0  2a d9 95 2a 2d c6 05 3c  1e 2f 11 ef c5 3c 11 e4  |*..*-..<./...<..|
+000002c0  be 5a de 37 43 7f 74 52  6e ee 3c 39 cc f1 14 05  |.Z.7C.tRn.<9....|
+000002d0  2d 91 c2 3d c4 7c 14 03  01 00 01 01 16 03 01 00  |-..=.|..........|
+000002e0  30 cd 3c 92 f8 b9 36 7a  e7 8a fb 0f 2f b8 2c 7b  |0.<...6z..../.,{|
+000002f0  10 59 45 14 0a b0 6a 8c  31 b2 89 5b ac 19 dc 12  |.YE...j.1..[....|
+00000300  73 8c 8c 10 49 5a bf 9f  bc 58 82 32 11 ba c5 38  |s...IZ...X.2...8|
+00000310  ff                                                |.|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 ae 6b 02 f3 d5  |..........0.k...|
-00000010  ff 91 fb 05 87 22 c6 f7  ac a8 83 d8 2a 10 89 69  |....."......*..i|
-00000020  e8 16 83 a9 5c 64 14 d2  15 40 94 ac 14 15 8f 75  |....\d...@.....u|
-00000030  27 19 a7 75 e9 8d e7 48  8b 62 0c                 |'..u...H.b.|
+00000000  14 03 01 00 01 01 16 03  01 00 30 da 45 99 fe 52  |..........0.E..R|
+00000010  4f cd d0 e6 30 19 f4 bd  80 6d 5c 8a 72 03 d3 88  |O...0....m\.r...|
+00000020  38 63 e9 c9 39 ee ab 3f  52 26 84 b0 4d cb 5c a4  |8c..9..?R&..M.\.|
+00000030  0d 51 c7 47 48 43 3a bf  89 c7 13                 |.Q.GHC:....|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 09 0e f5  bb d9 7a 54 db 9e e6 22  |.... .....zT..."|
-00000010  ea 9d 98 7e e6 af ba b1  dc c3 55 ad cc 4a f0 fa  |...~......U..J..|
-00000020  0d 3a 9f 49 80 17 03 01  00 20 d0 96 b0 1d 37 42  |.:.I..... ....7B|
-00000030  0d 03 64 1d 87 24 84 ff  f1 62 28 e3 6b 86 a1 54  |..d..$...b(.k..T|
-00000040  f2 65 5e ae 01 db 59 77  b1 c3 15 03 01 00 20 a0  |.e^...Yw...... .|
-00000050  88 b0 60 07 a6 05 13 dd  cd f4 7c e7 57 09 b1 98  |..`.......|.W...|
-00000060  bf b1 93 f1 02 cb 86 67  36 c5 e2 a8 81 c8 8f     |.......g6......|
+00000000  17 03 01 00 20 4d d9 1d  0d 3d 8b 73 91 b9 4e 5e  |.... M...=.s..N^|
+00000010  35 71 4f 67 79 d2 f7 39  35 ea 23 d0 6d 64 de a5  |5qOgy..95.#.md..|
+00000020  59 fb 75 1f c9 17 03 01  00 20 ba bd 3c b4 d7 be  |Y.u...... ..<...|
+00000030  24 64 68 1e 8c b2 bf 6f  78 9f ad 7f fa dd 89 a6  |$dh....ox.......|
+00000040  f9 e7 5e 70 db e9 db 3a  62 b2 15 03 01 00 20 2a  |..^p...:b..... *|
+00000050  82 f4 8b 45 fc 76 35 6c  54 48 62 2f 52 55 f2 d9  |...E.v5lTHb/RU..|
+00000060  99 b2 b5 2d 5f a0 05 ab  f1 93 58 75 4a 87 35     |...-_.....XuJ.5|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
index 776b3d6..9b1a553 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 ba 22 84 d4 ec  |....Q...M..."...|
-00000010  cb 49 cc 28 17 ea 00 19  6f 89 6f 4a c7 36 32 f2  |.I.(....o.oJ.62.|
-00000020  db da de 60 a7 93 b9 4e  64 9e ee 20 48 76 9f d5  |...`...Nd.. Hv..|
-00000030  c9 8a 74 95 ef 4b 7c 92  fd da 04 88 76 d3 6f 5a  |..t..K|.....v.oZ|
-00000040  b5 7f fa f3 3a d0 c3 b2  b1 19 09 a6 00 05 00 00  |....:...........|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 90 e6 e1 c6 bd  |....Q...M.......|
+00000010  86 08 db 33 94 f3 bd 0b  2d fc e0 ba 89 a7 c5 66  |...3....-......f|
+00000020  a5 19 78 33 2b b9 c4 22  d8 e0 63 20 2e 85 53 25  |..x3+.."..c ..S%|
+00000030  f2 22 e3 ca 79 94 9e 50  00 13 da 9d 21 33 49 27  |."..y..P....!3I'|
+00000040  9b 44 c5 10 bc e8 44 01  04 31 02 81 00 05 00 00  |.D....D..1......|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -101,24 +102,24 @@
 00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 01 00 86  |5..C.0oUN.p.....|
-00000290  0f 00 00 82 00 80 20 f0  61 14 6c 45 b1 29 c0 56  |...... .a.lE.).V|
-000002a0  9d 26 45 01 50 d5 56 04  6d cd 66 79 81 e0 cf 5c  |.&E.P.V.m.fy...\|
-000002b0  ee bc 39 f0 a1 a1 3a 43  9d 1f 8f a2 52 6e 5c 77  |..9...:C....Rn\w|
-000002c0  90 2e b3 56 37 ec 78 bd  79 53 a2 a4 8e 7d 49 13  |...V7.x.yS...}I.|
-000002d0  3a cb 88 0c d4 d8 9d d9  33 ef 47 dd d8 08 64 4a  |:.......3.G...dJ|
-000002e0  69 33 84 c4 c4 78 59 6b  84 50 70 2c d9 f8 8a 39  |i3...xYk.Pp,...9|
-000002f0  37 78 3c b4 c3 70 73 8d  ff aa be 8e 93 54 05 7d  |7x<..ps......T.}|
-00000300  a2 cd 8b ef 8c 8c 64 7a  b3 2a af 3e 20 67 a1 7b  |......dz.*.> g.{|
-00000310  a3 07 3b f1 d3 88 14 03  01 00 01 01 16 03 01 00  |..;.............|
-00000320  24 93 a0 0a 95 c2 ee 2c  4b 92 f2 09 e0 a6 80 c8  |$......,K.......|
-00000330  95 fb b1 ef a0 41 bb 27  e6 ad c9 d2 11 29 8a e4  |.....A.'.....)..|
-00000340  1e 9a d6 92 2b                                    |....+|
+00000290  0f 00 00 82 00 80 10 19  57 14 c3 ee 2d da cb de  |........W...-...|
+000002a0  f3 70 c5 62 91 2f ad 62  dd 10 f1 65 20 a2 cf d5  |.p.b./.b...e ...|
+000002b0  cd 6d 5f e4 b3 3e 38 e8  d0 1a f7 f0 e7 7e b6 5d  |.m_..>8......~.]|
+000002c0  c3 6c ad f6 0d 05 1e 41  35 2d 04 15 3c 36 96 00  |.l.....A5-..<6..|
+000002d0  e8 02 b2 01 b8 9f 21 4b  34 85 ef 5e 4c 87 ef 49  |......!K4..^L..I|
+000002e0  df d1 9a b6 b2 bd b8 90  fd 3f 31 93 0c dc c7 18  |.........?1.....|
+000002f0  ff f6 76 bd 5b 74 76 b3  62 87 6a df ff 63 15 d5  |..v.[tv.b.j..c..|
+00000300  94 d5 fe fd 4c 12 df f1  35 07 f1 8a f1 77 7a 35  |....L...5....wz5|
+00000310  cd 99 1d 2a d7 9a 14 03  01 00 01 01 16 03 01 00  |...*............|
+00000320  24 8d db 0c 87 b5 df fd  68 de fe 46 3e e4 41 b5  |$.......h..F>.A.|
+00000330  19 64 68 3c c4 e2 2b 43  50 e4 ee 52 75 34 d3 c1  |.dh<..+CP..Ru4..|
+00000340  51 18 c0 b2 5f                                    |Q..._|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 a4 54 34 b8 11  |..........$.T4..|
-00000010  2b ad bc 55 7d 8b 71 e3  c5 7a a1 9b 0b 7f c3 48  |+..U}.q..z.....H|
-00000020  69 32 5a 8d 0a f4 43 a0  c6 b7 e8 7d a4 f4 62     |i2Z...C....}..b|
+00000000  14 03 01 00 01 01 16 03  01 00 24 0b a4 04 46 60  |..........$...F`|
+00000010  15 fb 9a 9f 47 51 6d b4  4b c6 e7 2a 1b 98 b4 8a  |....GQm.K..*....|
+00000020  8a 1a 03 cf f4 16 7d 80  70 27 e5 e8 d5 9f ad     |......}.p'.....|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 26 c4 9a  35 54 80 41 f6 28 6b 0e  |.....&..5T.A.(k.|
-00000010  d9 e2 3d 37 ad fa db 91  3b fc 1b 5b 82 da 72 15  |..=7....;..[..r.|
-00000020  03 01 00 16 99 b3 54 b5  20 f4 3e bf e2 00 0e 4e  |......T. .>....N|
-00000030  2a 1e 37 55 56 c2 3b 30  62 20                    |*.7UV.;0b |
+00000000  17 03 01 00 1a 6f 84 50  27 c7 f1 aa b0 04 7d 80  |.....o.P'.....}.|
+00000010  6d a7 20 8a 73 cf d9 de  9a d6 f5 e9 36 13 7c 15  |m. .s.......6.|.|
+00000020  03 01 00 16 e8 0b e0 a6  3b 1e 21 24 65 4e 49 b2  |........;.!$eNI.|
+00000030  2d a3 41 2b 98 23 4e d5  4b fd                    |-.A+.#N.K.|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
index f678012..937c290 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 49 fe 00 1f fb  |....Y...U..I....|
-00000010  be ed 3e 36 55 b8 01 4b  a0 ea 7f e4 0e db 8a d0  |..>6U..K........|
-00000020  70 b3 0f 51 47 f3 d6 bd  1f f0 fa 20 60 0c b2 85  |p..QG...... `...|
-00000030  e3 f3 b9 90 25 e5 35 d2  9a 75 31 86 d6 7e 6c b6  |....%.5..u1..~l.|
-00000040  75 96 1c 35 54 10 3a 79  85 7d 3c ce c0 09 00 00  |u..5T.:y.}<.....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 f5 8f 8d 8e ca  |....Y...U.......|
+00000010  30 6b fe 63 c9 84 57 c0  f1 c8 a5 d8 10 56 14 62  |0k.c..W......V.b|
+00000020  c8 02 b2 89 21 5c 09 67  86 d8 9b 20 dc 3f 55 54  |....!\.g... .?UT|
+00000030  33 29 47 45 d3 e0 87 1a  4b 1b 75 30 89 e0 4d 01  |3)GE....K.u0..M.|
+00000040  a1 6a 46 f7 8f 23 d6 74  fd 90 2f 53 c0 09 00 00  |.jF..#.t../S....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,20 +48,20 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 f3  |*............A..|
-00000280  35 bb 79 ff 75 d2 57 d2  e8 8f ac b5 4b 39 ae fa  |5.y.u.W.....K9..|
-00000290  d4 22 b0 74 57 c3 55 aa  cd 26 b8 e0 8c f9 35 85  |.".tW.U..&....5.|
-000002a0  da 55 95 e0 cd e1 49 2c  ff 4b 20 de 88 de c2 4c  |.U....I,.K ....L|
-000002b0  36 e3 ca c6 69 cc 04 c6  ca 99 52 60 7f b4 cb 00  |6...i.....R`....|
-000002c0  8a 30 81 87 02 42 01 e0  54 72 b0 6b 7e 33 73 68  |.0...B..Tr.k~3sh|
-000002d0  8f 3f 81 4b c5 4c a7 bd  78 01 f4 15 54 1a 23 3a  |.?.K.L..x...T.#:|
-000002e0  dd 58 90 a9 27 5d b0 06  fa e5 b8 e7 f5 aa e8 0a  |.X..']..........|
-000002f0  fe 16 14 5e b8 0d 13 9e  8f 5a 29 a8 e2 c4 fd 34  |...^.....Z)....4|
-00000300  78 89 44 42 24 98 d9 24  02 41 2a b0 f6 1a f8 9d  |x.DB$..$.A*.....|
-00000310  60 8a 5f 3e f2 d4 cd bd  d2 73 6f 83 cf b4 87 1d  |`._>.....so.....|
-00000320  29 e5 e2 f0 d5 0c 49 96  82 2f bf ce ab b2 bd e7  |).....I../......|
-00000330  6a ab 1b fe 1a 32 94 43  55 5c b1 76 61 e4 00 c1  |j....2.CU\.va...|
-00000340  f3 cf b2 74 fe b6 a1 ac  f8 1f 11 16 03 01 00 04  |...t............|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 22  |*............A."|
+00000280  8a 47 c6 d3 7a c4 30 a4  8e 41 11 ac b3 2d 2f 45  |.G..z.0..A...-/E|
+00000290  61 54 9b 1f 2e 03 5d 50  eb fc 5b 44 a0 a7 48 78  |aT....]P..[D..Hx|
+000002a0  ce 14 d5 39 a7 c4 ed f5  4d 8f da 9d 71 52 69 70  |...9....M...qRip|
+000002b0  7e 52 29 ad 80 8a 19 ad  4c 5d 1c f1 22 7e 1a 00  |~R).....L].."~..|
+000002c0  8a 30 81 87 02 42 00 97  8b 6d f7 87 c1 a9 a6 55  |.0...B...m.....U|
+000002d0  0f 61 c2 f2 e1 05 26 a8  83 16 1c 0b 69 3b 95 57  |.a....&.....i;.W|
+000002e0  76 5b eb 45 7a bd 6a f1  3e a0 93 49 fa 74 32 fd  |v[.Ez.j.>..I.t2.|
+000002f0  dc 20 3a bb e3 ee 6d b8  56 aa e9 d2 7d 6a ec b7  |. :...m.V...}j..|
+00000300  0a bd aa dc d7 b0 69 65  02 41 4d 19 61 16 d8 5f  |......ie.AM.a.._|
+00000310  1d c1 32 25 15 26 eb 88  5b c1 dd 9a 12 40 fa f1  |..2%.&..[....@..|
+00000320  81 5e 7d b8 2b 6e 60 63  1a 9e 86 cb d5 64 96 d4  |.^}.+n`c.....d..|
+00000330  75 fc 02 33 e0 66 60 b2  40 47 cf e6 6d 25 9c 83  |u..3.f`.@G..m%..|
+00000340  23 d3 4b e2 eb ac f1 56  44 f8 3f 16 03 01 00 04  |#.K....VD.?.....|
 00000350  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
 00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
@@ -68,20 +69,20 @@
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 01 00 30 fd 33  1e 7c cb c1 58 78 d3 ab  |.....0.3.|..Xx..|
-00000060  d9 a0 1b d8 d2 e6 1d ff  f0 4e 07 9f e5 dc eb be  |.........N......|
-00000070  b9 49 b6 d9 26 53 96 c4  70 f1 ea 01 ec c9 49 2f  |.I..&S..p.....I/|
-00000080  63 9e ed c1 d3 16                                 |c.....|
+00000050  01 16 03 01 00 30 cc 86  f1 7e 6e a8 c9 b5 02 5f  |.....0...~n...._|
+00000060  fb b2 3b ea 74 bf a8 da  e4 6a 69 50 a2 5a 78 4f  |..;.t....jiP.ZxO|
+00000070  35 e1 cc 87 c3 fb 1f 5e  f6 a4 5c 63 cc 59 12 3e  |5......^..\c.Y.>|
+00000080  07 c3 a8 d7 87 ba                                 |......|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 b9 bc fb cc 21  |..........0....!|
-00000010  b7 06 cd 88 a4 f5 36 c9  ef 0a 77 fe 11 25 30 83  |......6...w..%0.|
-00000020  a7 34 9b 1e bb 67 80 89  3c 43 a9 4d b6 70 fd cf  |.4...g..<C.M.p..|
-00000030  f6 86 7e ba 09 26 19 2f  25 9e 3a                 |..~..&./%.:|
+00000000  14 03 01 00 01 01 16 03  01 00 30 e8 b6 20 b9 c1  |..........0.. ..|
+00000010  07 38 38 bb 42 b2 b2 a1  c5 8d 92 62 db 67 ab fc  |.88.B......b.g..|
+00000020  f6 64 3f 71 83 1d a0 86  bb 2d e3 4f 65 d5 44 52  |.d?q.....-.Oe.DR|
+00000030  4d f5 62 80 3c af 95 87  19 7c 20                 |M.b.<....| |
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 aa 90 92  5c a6 07 91 99 3e 54 0b  |.... ...\....>T.|
-00000010  dd 9c 59 4a 9e 91 f9 4f  e4 fb 14 9e 65 18 ef 1a  |..YJ...O....e...|
-00000020  8c ad a7 d4 b9 17 03 01  00 20 d7 73 8a 1a fe cb  |......... .s....|
-00000030  fd f7 fc 3e 03 5e 2f 03  97 12 a2 a9 31 df e4 76  |...>.^/.....1..v|
-00000040  88 c4 32 5a 90 6e bb 40  49 5c 15 03 01 00 20 c1  |..2Z.n.@I\.... .|
-00000050  92 ce bd 9e 23 50 8e da  96 d4 98 98 bc 18 e6 e7  |....#P..........|
-00000060  33 74 be 8b b7 d8 d4 19  62 1d e8 f1 4c fd 1c     |3t......b...L..|
+00000000  17 03 01 00 20 bd 65 61  28 e5 ea 1b 81 db 75 92  |.... .ea(.....u.|
+00000010  ad a7 3b 01 a3 23 0e 3b  60 10 8a 1e 04 91 fb 9e  |..;..#.;`.......|
+00000020  7a cf 1f cf 9c 17 03 01  00 20 87 9c dc ed 0d 08  |z........ ......|
+00000030  56 40 23 8b c5 2c d8 7e  42 82 3c 0a c9 f3 77 6d  |V@#..,.~B.<...wm|
+00000040  8d 9a 30 d1 9c c4 ae 04  fb b7 15 03 01 00 20 f7  |..0........... .|
+00000050  f0 12 0d e5 03 c1 80 4e  7e 21 d7 75 55 1c 91 89  |.......N~!.uU...|
+00000060  e7 e1 45 fc 7d d8 fc b1  d0 e7 dc e2 4c ba f4     |..E.}.......L..|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
index 84e0268..f8183f1 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 52 5c cd ba 77  |....Y...U..R\..w|
-00000010  cd 8e 48 de c2 b6 d7 eb  88 c2 e3 b3 8e fd 36 37  |..H...........67|
-00000020  71 c6 79 43 89 13 48 99  98 dc 78 20 cd 26 72 7b  |q.yC..H...x .&r{|
-00000030  84 c3 dd 55 e3 83 99 af  da 65 a7 5f 10 ef 8b 3a  |...U.....e._...:|
-00000040  4c 59 7b 11 d6 6a 61 68  d6 20 3c 3e c0 13 00 00  |LY{..jah. <>....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 5c 69 d0 60 d6  |....Y...U..\i.`.|
+00000010  b3 f4 23 19 5e 3e 26 d8  29 ea c3 94 e4 ed 51 f6  |..#.^>&.).....Q.|
+00000020  58 a2 e3 9c 79 a1 0b 6d  29 90 32 20 23 5b 47 b1  |X...y..m).2 #[G.|
+00000030  8f 22 bc 06 aa ee f7 c3  97 ca 93 df b1 90 7d b4  |."............}.|
+00000040  8c c0 d9 54 35 ca 5b 11  98 37 84 ea c0 13 00 00  |...T5.[..7......|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
@@ -58,40 +59,40 @@
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 01 00 cb 0c 00  00 c7 03 00 17 41 04 25  |.............A.%|
-00000330  0b 65 90 de 1c eb d0 7c  fe cb 71 2c 62 dd f9 7c  |.e.....|..q,b..||
-00000340  bd bc f5 bd a9 79 df a1  38 36 2a 98 7b 5d ce 17  |.....y..86*.{]..|
-00000350  67 a7 71 b9 9e 0a f2 02  f4 f3 19 a6 96 bc 53 45  |g.q...........SE|
-00000360  2e e0 df f1 e6 50 8b a2  36 a1 e9 59 1e d2 8f 00  |.....P..6..Y....|
-00000370  80 5a c1 19 13 94 5e ee  89 33 4a 22 e6 5d fa bc  |.Z....^..3J".]..|
-00000380  78 20 f2 5d 73 39 c9 84  1f e0 de 77 99 72 2b 77  |x .]s9.....w.r+w|
-00000390  58 f2 b6 a7 6e 3d e3 f9  95 b6 23 6e 27 36 45 f7  |X...n=....#n'6E.|
-000003a0  75 87 ff 4a 49 e1 d0 ea  83 52 97 b1 77 c6 00 8e  |u..JI....R..w...|
-000003b0  62 af 4f d0 cd 5e a4 9b  2f 72 ca dc 87 96 6b 73  |b.O..^../r....ks|
-000003c0  08 2c a5 75 d8 9d d5 a3  ba 25 45 78 07 db f1 86  |.,.u.....%Ex....|
-000003d0  08 4a 56 26 9d da f6 10  43 74 c1 93 ae 89 17 f1  |.JV&....Ct......|
-000003e0  1c 22 10 15 30 81 47 78  25 de fe 30 6d da 7d 0f  |."..0.Gx%..0m.}.|
-000003f0  36 16 03 01 00 04 0e 00  00 00                    |6.........|
+00000320  d9 16 03 01 00 cb 0c 00  00 c7 03 00 17 41 04 a6  |.............A..|
+00000330  57 60 8d 63 4e 4d 3f 48  e0 5d ad 9a 9c f7 e6 8c  |W`.cNM?H.]......|
+00000340  00 18 9c eb 34 ea f0 5c  d5 77 3f af 81 a9 50 d9  |....4..\.w?...P.|
+00000350  05 cf b9 bf 88 5c 70 29  24 61 6f d8 77 11 21 57  |.....\p)$ao.w.!W|
+00000360  a0 4d e1 4b 8e 55 06 50  7f a2 30 c1 c2 b9 c6 00  |.M.K.U.P..0.....|
+00000370  80 68 7c e4 1a bc a4 1e  16 b9 3e 4a 59 39 a9 54  |.h|.......>JY9.T|
+00000380  6f c7 17 b2 f5 af b5 73  5b db cc 71 f2 1b aa dc  |o......s[..q....|
+00000390  9d 64 3c 0f 82 e6 da 1a  6b 96 19 e2 f0 15 b0 df  |.d<.....k.......|
+000003a0  8a 2d 96 09 63 52 f6 53  ef 12 d4 3b 35 b7 0b 43  |.-..cR.S...;5..C|
+000003b0  2c 6e 58 4c c8 2f b8 55  84 89 c9 39 81 7a 7a 7d  |,nXL./.U...9.zz}|
+000003c0  88 68 db eb d7 81 aa 2e  b2 25 ba 98 6c 46 b7 85  |.h.......%..lF..|
+000003d0  8a 21 17 b9 36 23 c0 84  94 af 3b 9b 04 5d ec 31  |.!..6#....;..].1|
+000003e0  f5 75 84 d8 77 d7 80 37  ae c3 5c 26 41 f6 72 af  |.u..w..7..\&A.r.|
+000003f0  88 16 03 01 00 04 0e 00  00 00                    |..........|
 >>> Flow 3 (client to server)
 00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 01 00 30 fa 12  bd 34 6f ca 53 e6 9a 77  |.....0...4o.S..w|
-00000060  ec 0c de 3e 96 ab fe ac  52 7b 04 61 21 29 ab 86  |...>....R{.a!)..|
-00000070  7a 0b 4f 4b 9a f2 2d fe  89 96 07 a5 20 38 71 8b  |z.OK..-..... 8q.|
-00000080  2e 76 9c 4e de 26                                 |.v.N.&|
+00000050  01 16 03 01 00 30 d2 5b  27 5a f5 64 49 31 d5 aa  |.....0.['Z.dI1..|
+00000060  a3 72 ae c9 af 0b aa 75  af ac f3 45 f4 e3 03 fa  |.r.....u...E....|
+00000070  e8 97 88 7b 51 a9 ae 61  40 c8 11 74 3e d8 9a b6  |...{Q..a@..t>...|
+00000080  e7 6a 5e 71 84 7e                                 |.j^q.~|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 54 5d dc 18 0e  |..........0T]...|
-00000010  76 37 48 8c 06 e6 6c 26  6d af 3d 57 fa 57 4f 6b  |v7H...l&m.=W.WOk|
-00000020  3d 00 e5 d6 81 ac 86 ae  1c 82 9c 08 4d 37 fd fc  |=...........M7..|
-00000030  27 d4 38 1e 28 8e 2b 0e  50 23 80                 |'.8.(.+.P#.|
+00000000  14 03 01 00 01 01 16 03  01 00 30 8d 63 fc 58 2e  |..........0.c.X.|
+00000010  50 f7 60 2c 9f 5a 8e 58  29 6c a6 3a 8d 2b a7 2b  |P.`,.Z.X)l.:.+.+|
+00000020  1c 12 8a 53 3f d5 60 79  12 c3 78 e3 aa 50 15 45  |...S?.`y..x..P.E|
+00000030  07 da 2d c7 a9 c3 45 07  48 00 78                 |..-...E.H.x|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 28 98 f6  dd a7 6f 74 c6 5c 6d 54  |.... (....ot.\mT|
-00000010  8a 69 99 c8 db 88 73 9e  94 a6 d7 81 9e be 5f ba  |.i....s......._.|
-00000020  9e 6d 46 72 be 17 03 01  00 20 a9 d1 38 e1 eb 0f  |.mFr..... ..8...|
-00000030  7a fd c7 81 12 8b 5e 8e  4e e8 e2 8b 40 af 74 e3  |z.....^.N...@.t.|
-00000040  80 6d 52 40 13 d5 d4 a0  d9 29 15 03 01 00 20 7c  |.mR@.....).... ||
-00000050  3f d7 27 13 2b d5 41 4e  17 93 10 79 20 f2 f6 21  |?.'.+.AN...y ..!|
-00000060  c7 21 08 f4 bc 5f 97 61  46 2e 4f 35 86 15 79     |.!..._.aF.O5..y|
+00000000  17 03 01 00 20 40 91 8d  e6 95 2f 97 c8 0c 94 5c  |.... @..../....\|
+00000010  46 a7 d3 31 82 3d dc 7e  86 5b dd df 3f 3b 5b 9c  |F..1.=.~.[..?;[.|
+00000020  d5 0d 52 5a 53 17 03 01  00 20 1d 18 da 6b e8 66  |..RZS.... ...k.f|
+00000030  ce 58 18 81 4b 69 8c f6  db 1a ee d0 78 fb f5 68  |.X..Ki......x..h|
+00000040  2c 99 48 47 65 15 2a ae  ff 4e 15 03 01 00 20 68  |,.HGe.*..N.... h|
+00000050  aa 7f 75 33 45 7a 1a 33  18 35 5a 5b 14 b0 f6 83  |..u3Ez.3.5Z[....|
+00000060  97 85 3f b2 dc 78 68 eb  43 ef 92 7f 38 bd f8     |..?..xh.C...8..|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
index b707012..b5deaeb 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 5c 40 79 8d 40  |....Q...M..\@y.@|
-00000010  c0 fd 1f 3c 2d 85 e1 19  12 c8 dc 95 8a 52 44 a5  |...<-........RD.|
-00000020  3a c1 9a 41 9a 72 9d cf  d8 8e 3c 20 76 d2 7d 3d  |:..A.r....< v.}=|
-00000030  b9 0f a9 b0 05 a6 c7 ac  53 7a fa 0f 7a d5 25 ec  |........Sz..z.%.|
-00000040  51 5f fb da a4 9e f2 45  10 40 38 13 00 05 00 00  |Q_.....E.@8.....|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 a9 b0 bf 24 3f  |....Q...M.....$?|
+00000010  98 c6 0f 83 23 2b b6 e4  3f d5 5b 10 9a 6f b8 63  |....#+..?.[..o.c|
+00000020  4c 3c d6 4d 05 c0 08 85  f7 72 72 20 ab 85 8c ff  |L<.M.....rr ....|
+00000030  f7 bb 95 ab 69 37 3d b6  79 cb 46 ad 4e 22 e7 c6  |....i7=.y.F.N"..|
+00000040  a5 9b 72 92 32 ff a5 f7  ed dc 30 41 00 05 00 00  |..r.2.....0A....|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -69,15 +70,15 @@
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 01 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 01 00 24 c0 e9  f1 c2 c5 a1 75 6b b8 84  |.....$......uk..|
-000000a0  cf d8 46 e6 e1 d4 a0 65  d9 89 29 55 91 4c 38 5e  |..F....e..)U.L8^|
-000000b0  8c 90 ac 2e db 28 68 e6  00 b4                    |.....(h...|
+00000090  01 16 03 01 00 24 4d 1d  d7 8c d6 c7 65 a6 ce af  |.....$M.....e...|
+000000a0  e7 59 0d 7e dc d9 96 1c  ed 9c 57 94 84 b8 3f b5  |.Y.~......W...?.|
+000000b0  34 e1 61 a5 61 f3 5d 09  bc ff                    |4.a.a.]...|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 20 d1 dd c0 6f  |..........$ ...o|
-00000010  2c f2 1e 30 c6 8c 59 e9  5b 31 e6 a6 ce ea 57 06  |,..0..Y.[1....W.|
-00000020  59 39 a2 b9 78 6e a4 fc  cb 0c 9c 26 05 3b 16     |Y9..xn.....&.;.|
+00000000  14 03 01 00 01 01 16 03  01 00 24 13 81 89 61 5c  |..........$...a\|
+00000010  fb 0a 9c a1 4b db 94 6b  8b 41 6e 63 d6 aa db 88  |....K..k.Anc....|
+00000020  03 b7 b5 19 b8 12 cf 5e  17 54 79 2f 03 91 7e     |.......^.Ty/..~|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 25 ef 34  80 3d 18 91 ae ba 40 79  |.....%.4.=....@y|
-00000010  0e 2e 59 ac 30 0d 47 77  bd 61 b8 16 a7 08 b0 15  |..Y.0.Gw.a......|
-00000020  03 01 00 16 54 73 7f 48  c4 49 55 97 2a 2d 00 71  |....Ts.H.IU.*-.q|
-00000030  fc 82 c8 7a 63 2a ea 9e  8d 6f                    |...zc*...o|
+00000000  17 03 01 00 1a b3 2b da  ce 45 ec b2 9d 3b 18 d9  |......+..E...;..|
+00000010  7a cb 99 ea ff 4d 91 b5  48 df 6f 8b 2f 85 c7 15  |z....M..H.o./...|
+00000020  03 01 00 16 19 1c 72 74  36 cf 22 0f a0 a7 18 96  |......rt6.".....|
+00000030  3a 67 cb 22 16 f1 a8 7b  57 37                    |:g."...{W7|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
index 5d2528a..a4a2930 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 48 99 38 25 1c  |....Y...U..H.8%.|
-00000010  df 79 d9 78 68 90 92 ad  3f e7 a0 38 b2 d8 ab 50  |.y.xh...?..8...P|
-00000020  2c fb b0 16 00 5a 5c 87  a6 dc 16 20 70 3f 2a fd  |,....Z\.... p?*.|
-00000030  ef 14 aa 68 d5 08 c4 1e  4c 04 7a 08 63 ec cb 0d  |...h....L.z.c...|
-00000040  1f 2b 08 17 f2 29 7c da  a3 d0 6f 07 c0 09 00 00  |.+...)|...o.....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 5a 52 92 23 05  |....Y...U..ZR.#.|
+00000010  58 68 b2 1e 77 a2 a8 16  e9 88 85 ea 38 b3 63 c2  |Xh..w.......8.c.|
+00000020  40 f8 de 37 3c d4 b9 51  11 2d d1 20 12 fd 95 b3  |@..7<..Q.-. ....|
+00000030  2a 54 40 c0 23 3a 4e 4e  f6 7b f8 77 04 6e e7 d7  |*T@.#:NN.{.w.n..|
+00000040  3b 9a 45 32 e0 af df aa  ff bf 78 8b c0 09 00 00  |;.E2......x.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  02 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,21 +48,21 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 02 00 d6 0c 00  00 d2 03 00 17 41 04 5f  |*............A._|
-00000280  ea cb dd 6a 2c 16 40 15  d1 e7 ea 41 19 08 5d 1c  |...j,.@....A..].|
-00000290  e8 f2 f2 75 84 96 f5 d4  c8 5b fd 4b ba 3b 79 8c  |...u.....[.K.;y.|
-000002a0  86 a3 2a ce 77 2d 97 ea  39 3d 52 8e a4 c7 da bd  |..*.w-..9=R.....|
-000002b0  52 68 46 b4 f2 ba 1f 73  30 29 2f 29 d4 82 66 00  |RhF....s0)/)..f.|
-000002c0  8b 30 81 88 02 42 00 c3  d3 8d 5e f9 a8 03 27 d8  |.0...B....^...'.|
-000002d0  be 19 80 53 8e 5a 58 4f  13 2a 04 25 8c 73 71 9a  |...S.ZXO.*.%.sq.|
-000002e0  15 7e 05 09 d4 a2 8d 3e  16 0e 2d a8 73 97 bc 1a  |.~.....>..-.s...|
-000002f0  b4 48 81 f0 c9 2a e7 c2  39 13 5d 25 3e b1 82 d1  |.H...*..9.]%>...|
-00000300  cf 3e 46 f5 f6 f8 e3 e2  02 42 01 a2 ba f5 05 eb  |.>F......B......|
-00000310  84 26 34 06 f2 85 ae e0  54 95 cd f9 8a 2e 01 a5  |.&4.....T.......|
-00000320  65 d0 ab da cd ec 33 7a  12 51 1c 75 3f 4f be 7f  |e.....3z.Q.u?O..|
-00000330  f7 a6 02 81 2e 6d 3b 58  d6 5f 2d 53 d0 43 61 2d  |.....m;X._-S.Ca-|
-00000340  0c d8 7d e5 08 48 48 da  51 47 8b a5 16 03 02 00  |..}..HH.QG......|
-00000350  04 0e 00 00 00                                    |.....|
+00000270  2a 16 03 02 00 d5 0c 00  00 d1 03 00 17 41 04 c3  |*............A..|
+00000280  55 86 65 95 83 02 4b 69  6e 95 f4 52 46 83 21 86  |U.e...Kin..RF.!.|
+00000290  9e 99 cf 81 d9 b8 20 7a  87 b3 07 48 14 04 20 d9  |...... z...H.. .|
+000002a0  6c 2e 22 5a b5 b4 ef de  15 b3 08 ef 1e 18 ea 67  |l."Z...........g|
+000002b0  eb 45 fd e1 27 43 ed 41  ea 05 7e f3 f9 ee 23 00  |.E..'C.A..~...#.|
+000002c0  8a 30 81 87 02 42 00 b0  9c 06 85 83 b2 bf 42 22  |.0...B........B"|
+000002d0  6e 57 7a 31 fe a9 d9 28  be 0a a9 80 49 a2 14 c1  |nWz1...(....I...|
+000002e0  a9 99 76 b7 f9 76 d0 3c  d3 0c c7 42 34 d7 94 a9  |..v..v.<...B4...|
+000002f0  15 66 7e 6b 83 6e b2 b4  5b 22 c9 4e a0 96 db 2b  |.f~k.n..[".N...+|
+00000300  ad 77 33 1e 4a 5c 2f 2e  02 41 26 0c 1a 5a b4 07  |.w3.J\/..A&..Z..|
+00000310  95 99 ec 0b 5b 2e bb db  0e d5 26 c4 b3 eb c2 30  |....[.....&....0|
+00000320  b0 7b c1 07 97 a0 99 3f  db 4e b0 c4 b8 bb 5e be  |.{.....?.N....^.|
+00000330  2a e4 b3 a4 5c ad d1 d7  7a 2d fb ae 73 ee 0c 1e  |*...\...z-..s...|
+00000340  3b 64 e1 74 14 bc c0 1e  8b f3 26 16 03 02 00 04  |;d.t......&.....|
+00000350  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
 00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -69,21 +70,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 20 a1  aa ad 8d db ed 19 63 64  |...... .......cd|
-00000070  60 73 8a 59 0d 59 81 51  b8 44 7b c8 86 ac fe db  |`s.Y.Y.Q.D{.....|
-00000080  9f da 5e af fd 54 a3 6e  c6 f0 d6 45 fe 93 70 f1  |..^..T.n...E..p.|
-00000090  45 99 06 3e 6a 28                                 |E..>j(|
+00000060  00 00 00 00 00 00 33 07  8a af e1 94 ef f9 08 3a  |......3........:|
+00000070  33 5f b3 e6 42 07 85 af  40 e2 8b 34 53 62 1a 10  |3_..B...@..4Sb..|
+00000080  bb 08 7e 75 d4 21 12 2d  54 87 33 1c 4e 13 27 72  |..~u.!.-T.3.N.'r|
+00000090  3f 9e 9f cc de 47                                 |?....G|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 b7 6f dc 1c 48  |..........@.o..H|
-00000010  cc 3d ac 1d 6b b2 bc 9c  dd 25 02 9d b0 77 8d ca  |.=..k....%...w..|
-00000020  5a 4c d6 d3 c0 e0 a6 8c  03 00 e5 85 3a 2f 5e df  |ZL..........:/^.|
-00000030  17 5b 9a 2e e3 54 20 60  fe 39 ef 51 23 bc 13 ea  |.[...T `.9.Q#...|
-00000040  86 6f 4f e5 8c 5f a0 3e  ae e9 69                 |.oO.._.>..i|
+00000000  14 03 02 00 01 01 16 03  02 00 40 4f 47 0d 43 54  |..........@OG.CT|
+00000010  50 69 3a c8 21 a6 6e 28  78 cc 01 b4 5d eb f7 2b  |Pi:.!.n(x...]..+|
+00000020  8b 7e 26 6e cf 56 98 65  ad bf 0f a0 b4 67 13 70  |.~&n.V.e.....g.p|
+00000030  de b5 b5 91 df d6 df 8c  53 c6 54 3d 5d 98 e4 25  |........S.T=]..%|
+00000040  47 a0 0f 91 c7 08 96 17  48 bd 0f                 |G.......H..|
 >>> Flow 5 (client to server)
 00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 31 e9 1b  b8 b7 ed a1 dd 34 87 9c  |.....1.......4..|
-00000020  3c 8a 0d 41 8c d3 3f 0e  54 62 d5 31 07 4a a5 8f  |<..A..?.Tb.1.J..|
-00000030  0e 07 3d da 91 15 03 02  00 30 00 00 00 00 00 00  |..=......0......|
-00000040  00 00 00 00 00 00 00 00  00 00 d2 62 91 56 10 c8  |...........b.V..|
-00000050  c9 f8 25 3f ef ab b1 a7  88 a6 85 2b 1b 02 47 36  |..%?.......+..G6|
-00000060  3a 08 b0 63 da c1 cb ea  11 2c                    |:..c.....,|
+00000010  00 00 00 00 00 4e fe 12  d7 4b d7 3f 86 5a 2c f6  |.....N...K.?.Z,.|
+00000020  86 03 2a bd 1a 98 d7 bb  9f 59 6c 6d 4d 57 b0 50  |..*......YlmMW.P|
+00000030  d6 97 7e d4 b6 15 03 02  00 30 00 00 00 00 00 00  |..~......0......|
+00000040  00 00 00 00 00 00 00 00  00 00 65 8b b5 ae 86 90  |..........e.....|
+00000050  00 4e 1e 3f bc ac ed 49  f4 5e 73 49 e6 d8 37 83  |.N.?...I.^sI..7.|
+00000060  cf 4f e5 7b 5e c9 1d c8  c9 dc                    |.O.{^.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
index 23d9771..103f1d8 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 95 77 16 4d 9c  |....Y...U...w.M.|
-00000010  0c e7 a4 de e2 49 a2 28  d5 5b ec 44 24 89 7c 47  |.....I.(.[.D$.|G|
-00000020  f2 a6 03 d4 76 08 92 99  5f 3f af 20 f9 55 14 a9  |....v..._?. .U..|
-00000030  de 8c 1a 77 37 9c 1b d9  95 30 e6 25 93 9a 3f 6f  |...w7....0.%..?o|
-00000040  cc c0 27 4c 4a cd 61 eb  53 a0 b2 59 c0 13 00 00  |..'LJ.a.S..Y....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 e3 ed 49 27 a3  |....Y...U....I'.|
+00000010  28 c5 8c 30 27 c2 ed 57  9b f7 37 a1 6d 2b 88 c2  |(..0'..W..7.m+..|
+00000020  df a7 2d 01 01 00 9a 09  da c2 1f 20 ee 33 87 03  |..-........ .3..|
+00000030  28 93 1c 16 99 5b b1 e0  bf 87 e8 77 4a 72 c9 92  |(....[.....wJr..|
+00000040  8a bc b2 3e 24 e1 f6 e8  f4 3f a2 24 c0 13 00 00  |...>$....?.$....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  02 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
@@ -58,20 +59,20 @@
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 02 00 cb 0c 00  00 c7 03 00 17 41 04 cc  |.............A..|
-00000330  93 4b 67 67 12 37 c6 c4  77 3d 6b 3e ce 16 04 82  |.Kgg.7..w=k>....|
-00000340  09 9d b0 bc 67 a8 43 e8  06 ab 9d 8b dd fe ad 00  |....g.C.........|
-00000350  9e 32 19 f3 5f d8 2d de  18 76 1d 46 18 f1 1f ac  |.2.._.-..v.F....|
-00000360  19 79 9b 6c 5b c8 92 d4  6b 91 e9 58 f7 92 b6 00  |.y.l[...k..X....|
-00000370  80 0c d6 d5 6c 2c 89 fa  8b a6 59 f8 48 cb f2 9d  |....l,....Y.H...|
-00000380  02 61 b0 2d 83 5e e6 5f  41 b9 91 96 30 fb 09 85  |.a.-.^._A...0...|
-00000390  4f 9f ea 92 1a dc a2 c3  59 49 6c 46 85 91 b0 2f  |O.......YIlF.../|
-000003a0  80 47 bc f2 ab 3a 0c 33  5f 46 ef fb bf 2e b7 14  |.G...:.3_F......|
-000003b0  03 ae 6d ac d6 3f 7f 0c  8e c8 18 c3 0d fd ba f3  |..m..?..........|
-000003c0  dd b1 8b a8 c9 ed 53 7c  9c d2 31 91 cc 05 2a f1  |......S|..1...*.|
-000003d0  86 f3 79 c8 d0 55 0d 9d  80 fd 0f 6f 1a 15 c4 dd  |..y..U.....o....|
-000003e0  f3 37 41 2e 4f 51 10 27  80 11 82 c4 a8 4b 7f a3  |.7A.OQ.'.....K..|
-000003f0  e2 16 03 02 00 04 0e 00  00 00                    |..........|
+00000320  d9 16 03 02 00 cb 0c 00  00 c7 03 00 17 41 04 f7  |.............A..|
+00000330  75 c1 b9 58 a0 7d 50 48  e9 85 79 db 89 76 4c d7  |u..X.}PH..y..vL.|
+00000340  84 5b 94 9a 15 d8 92 32  74 d2 3e ce 76 5a bd 0e  |.[.....2t.>.vZ..|
+00000350  24 e7 a6 d0 77 5d 8e 3d  9f 94 7a ea 15 46 3c 5c  |$...w].=..z..F<\|
+00000360  61 28 76 4a ff 81 97 2b  3a 0c b7 aa b4 0e cb 00  |a(vJ...+:.......|
+00000370  80 19 00 a8 fe 0a ea 35  30 51 a3 77 37 08 68 10  |.......50Q.w7.h.|
+00000380  5a e9 07 2d 83 67 77 4c  3a 25 14 1c 5b c1 2e 80  |Z..-.gwL:%..[...|
+00000390  30 6d ba 26 c1 f9 c6 3e  fc 55 34 8c d2 9f 2b a6  |0m.&...>.U4...+.|
+000003a0  46 0c 9d 58 2c 9c 2b ce  6f 03 d7 49 4e df 21 ce  |F..X,.+.o..IN.!.|
+000003b0  3f 8b 19 fe 3e 71 23 51  c3 ec 30 c8 3e 3c 3c 50  |?...>q#Q..0.><<P|
+000003c0  da 08 52 c0 10 9f e3 4a  be e0 97 aa de 5e 13 22  |..R....J.....^."|
+000003d0  b2 77 ee 5d 2d d4 ff fb  7f c3 1e e7 51 fe fc 4b  |.w.]-.......Q..K|
+000003e0  56 5b 8f 50 ad cc 34 7a  a9 dd 24 0a d0 c7 b9 bf  |V[.P..4z..$.....|
+000003f0  1a 16 03 02 00 04 0e 00  00 00                    |..........|
 >>> Flow 3 (client to server)
 00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -79,21 +80,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 cc 4d  33 16 3b 7e 8d 15 6f cf  |.......M3.;~..o.|
-00000070  00 7b e2 5c 00 34 5e 53  30 92 2c 0b 5f 5a df bc  |.{.\.4^S0.,._Z..|
-00000080  05 a1 eb e5 9b 2b 2a 94  26 60 57 cd 81 74 9f 31  |.....+*.&`W..t.1|
-00000090  55 64 b5 52 89 c8                                 |Ud.R..|
+00000060  00 00 00 00 00 00 1e 0b  cd 40 fa 0f ed fa 55 74  |.........@....Ut|
+00000070  4e ad 10 d1 b5 e1 41 8c  c0 93 81 38 f3 83 f1 37  |N.....A....8...7|
+00000080  6a d4 6c ea ba 5b 9e 38  d3 c1 bb 41 45 fb f0 48  |j.l..[.8...AE..H|
+00000090  c1 06 31 64 e0 65                                 |..1d.e|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 10 4d 3e ad a3  |..........@.M>..|
-00000010  6a c6 06 43 7f 5a b6 99  b0 70 22 fe dc 8e a9 a0  |j..C.Z...p".....|
-00000020  9e 0a 8f 0d ed d6 de 8d  16 18 df f9 cc 81 55 a5  |..............U.|
-00000030  56 6b 00 81 c1 8f eb 29  cb 46 16 e5 0f 10 9f 57  |Vk.....).F.....W|
-00000040  b9 28 6e c1 51 d7 c2 e3  46 ee 0b                 |.(n.Q...F..|
+00000000  14 03 02 00 01 01 16 03  02 00 40 17 d1 79 f8 e0  |..........@..y..|
+00000010  d4 40 15 85 df 4d a6 d5  60 90 1f d6 52 58 e7 ae  |.@...M..`...RX..|
+00000020  05 eb a2 ea ed c9 be ae  b5 54 39 de 05 66 27 67  |.........T9..f'g|
+00000030  59 07 03 e7 10 f9 3f da  d8 85 8b 2f 7b 33 9f f5  |Y.....?..../{3..|
+00000040  43 50 b9 9c 6e dd 01 ae  d8 c9 1d                 |CP..n......|
 >>> Flow 5 (client to server)
 00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 9e 9c cb  3c 7c b9 d9 03 1b b9 2c  |........<|.....,|
-00000020  6b e8 d9 eb 9a 9d 29 5f  00 77 a2 f5 b7 cc 0e f1  |k.....)_.w......|
-00000030  78 cb 5d 3f e0 15 03 02  00 30 00 00 00 00 00 00  |x.]?.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 ca af f9 d3 73 44  |..............sD|
-00000050  f2 43 cc ad 30 5c 41 d4  c8 03 bc 77 96 76 ef 8d  |.C..0\A....w.v..|
-00000060  3c 61 3c bf f3 ae 0d 41  80 96                    |<a<....A..|
+00000010  00 00 00 00 00 65 81 63  71 55 1c 46 8a 60 46 d9  |.....e.cqU.F.`F.|
+00000020  7d 71 a2 62 b8 a8 3b 06  3d a2 f4 53 a4 46 a8 9e  |}q.b..;.=..S.F..|
+00000030  b7 89 8a 42 ce 15 03 02  00 30 00 00 00 00 00 00  |...B.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 7a 78 a4 e7 2f 40  |..........zx../@|
+00000050  df 42 9b 76 7a 45 0a 86  40 af 3c 40 c6 69 ba e1  |.B.vzE..@.<@.i..|
+00000060  23 82 fa 44 fd 73 fc 5b  f7 b9                    |#..D.s.[..|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
index a0d2c62..729391f 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 51 02 00 00  4d 03 02 4d 2e 22 e8 40  |....Q...M..M.".@|
-00000010  e2 be 4a dd cc 74 ce 49  40 04 76 fa 30 11 04 64  |..J..t.I@.v.0..d|
-00000020  d3 d8 28 cc ef cb 1b 08  70 ca 28 20 74 90 27 2e  |..(.....p.( t.'.|
-00000030  c7 bb 53 66 93 49 da 00  d9 96 06 cf ac 08 40 66  |..Sf.I........@f|
-00000040  41 eb 6e c8 32 2d 10 a6  42 7b 0d 5e 00 05 00 00  |A.n.2-..B{.^....|
+00000000  16 03 02 00 51 02 00 00  4d 03 02 7e 38 ae 3c 50  |....Q...M..~8.<P|
+00000010  03 96 3d 54 2f cd 86 21  98 7f 87 43 d8 58 aa a3  |..=T/..!...C.X..|
+00000020  d5 9f e7 25 a6 ab 34 7f  10 5f 99 20 56 c5 a8 dd  |...%..4.._. V...|
+00000030  37 17 0d 51 f1 0d c4 4e  76 0f 01 26 56 c9 0c 20  |7..Q...Nv..&V.. |
+00000040  28 ef cd ac 38 ea d3 7f  6f aa 7c b8 00 05 00 00  |(...8...o.|.....|
 00000050  05 ff 01 00 01 00 16 03  02 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -69,15 +70,15 @@
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 02 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 02 00 24 2b 06  10 fe 60 26 58 7d 59 47  |.....$+...`&X}YG|
-000000a0  83 2d 84 43 e3 8d fe ab  e6 c0 3b b8 68 78 e3 73  |.-.C......;.hx.s|
-000000b0  6c 59 d8 53 86 81 42 69  22 74                    |lY.S..Bi"t|
+00000090  01 16 03 02 00 24 b9 df  85 a1 6d a7 14 b5 bc f5  |.....$....m.....|
+000000a0  c2 1d 40 fc 1e 19 f2 36  2d ec 6b 59 c5 6d ae c7  |..@....6-.kY.m..|
+000000b0  1c ad 7e a3 5b 4d 12 e5  58 5a                    |..~.[M..XZ|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 24 62 dc 82 ed 69  |..........$b...i|
-00000010  cc e2 19 72 9c 1b 84 15  77 d8 a0 35 7d b7 47 55  |...r....w..5}.GU|
-00000020  95 4f 67 ad f1 8f 91 01  c0 31 2f 54 64 40 35     |.Og......1/Td@5|
+00000000  14 03 02 00 01 01 16 03  02 00 24 a3 f3 22 a8 32  |..........$..".2|
+00000010  63 c3 88 5c 0f fb 2d 47  21 0d 62 e2 db aa ed ae  |c..\..-G!.b.....|
+00000020  b6 5f e3 c8 98 fc 91 5e  04 83 cf c3 21 17 ce     |._.....^....!..|
 >>> Flow 5 (client to server)
-00000000  17 03 02 00 1a 63 52 52  39 6a 98 7a a8 41 cd b4  |.....cRR9j.z.A..|
-00000010  e4 de 75 32 76 9a ee 44  96 d0 e9 66 b8 0a b5 15  |..u2v..D...f....|
-00000020  03 02 00 16 9f 06 3f 07  78 12 b7 70 db 48 fc ef  |......?.x..p.H..|
-00000030  ff 6e a7 4f e5 82 7f 0c  f2 35                    |.n.O.....5|
+00000000  17 03 02 00 1a f1 e4 46  c7 14 91 4b c6 25 fd aa  |.......F...K.%..|
+00000010  5d dd 3f 61 ac 9c 79 68  bc e6 0f a1 e4 f3 73 15  |].?a..yh......s.|
+00000020  03 02 00 16 6b 8d 23 3c  99 b4 c2 23 3c 27 fd 41  |....k.#<...#<'.A|
+00000030  cc 04 e5 fc e7 f9 d9 81  0a b8                    |..........|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN b/src/crypto/tls/testdata/Client-TLSv12-ALPN
index a30f1a2..9ecb065 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -1,20 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 91 01 00 00  8d 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 99 01 00 00  95 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 46  |...../.5.......F|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 4e  |...../.5.......N|
 00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
 00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
-00000070  0d 00 0a 00 08 04 01 04  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 10 00 10 00 0e  06 70 72 6f 74 6f 32 06  |.........proto2.|
-00000090  70 72 6f 74 6f 31                                 |proto1|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 10  00 10 00 0e 06 70 72 6f  |.............pro|
+00000090  74 6f 32 06 70 72 6f 74  6f 31 00 12 00 00        |to2.proto1....|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 66 02 00 00  62 03 03 7e 48 0b 4a 89  |....f...b..~H.J.|
-00000010  d3 3a a1 8a 8c 8b 11 bb  ea c5 21 5c df 3c 81 2b  |.:........!\.<.+|
-00000020  c5 c0 7c f9 fd d7 cb 10  1b dd d4 20 b4 8a a5 07  |..|........ ....|
-00000030  32 e7 04 9c 1c 73 87 cd  e3 ae ff 8b 5c d7 56 6c  |2....s......\.Vl|
-00000040  03 24 7d 35 4c ad 31 52  c3 cd 5c b0 c0 2f 00 00  |.$}5L.1R..\../..|
+00000000  16 03 03 00 66 02 00 00  62 03 03 56 83 34 0f 9e  |....f...b..V.4..|
+00000010  dd 02 1c 4f 4f 09 d0 2c  df e6 c1 d2 4a c0 6a e7  |...OO..,....J.j.|
+00000020  1e 65 51 c2 42 01 05 70  4a 6c 97 20 0f a8 fb d8  |.eQ.B..pJl. ....|
+00000030  2f 0f 75 21 17 f8 dd 63  28 4a 18 f6 b1 e5 6f 7c  |/.u!...c(J....o||
+00000040  1d 09 d4 13 bf 66 3a bd  c5 48 14 fc c0 2f 00 00  |.....f:..H.../..|
 00000050  1a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 10  |................|
 00000060  00 09 00 07 06 70 72 6f  74 6f 31 16 03 03 02 be  |.....proto1.....|
 00000070  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
@@ -61,19 +61,19 @@
 00000300  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
 00000310  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
 00000320  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
-00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 36 ae 35 52  |..........A.6.5R|
-00000340  e2 d1 7b 5f 96 91 06 73  30 0c c8 cb 42 e3 95 11  |..{_...s0...B...|
-00000350  52 02 5a 8a 8a a4 b3 f9  03 f0 6d 8b 23 3e 73 44  |R.Z.......m.#>sD|
-00000360  2d 3e fb 05 ac c2 0a f4  96 07 58 aa fc 9f f4 8b  |->........X.....|
-00000370  38 af 46 6a a6 87 b7 6d  65 eb 75 17 04 01 00 80  |8.Fj...me.u.....|
-00000380  44 0d 99 2f 79 3d 66 0b  7c 76 f8 95 14 78 90 f9  |D../y=f.|v...x..|
-00000390  ee bb 74 9b 01 25 62 a3  58 d6 8d 4b 43 0a 18 16  |..t..%b.X..KC...|
-000003a0  4d 44 fa 01 13 de 32 36  16 6a 4d 9a 6d ab dd e5  |MD....26.jM.m...|
-000003b0  a8 9d 9e 4a f8 18 fd da  95 99 02 20 29 b3 79 f6  |...J....... ).y.|
-000003c0  c7 c4 eb 81 45 ef 20 5f  2b ed 5f 72 a5 5f 99 0b  |....E. _+._r._..|
-000003d0  54 25 0d db 11 7f 64 ec  5a 2f 38 c7 74 29 77 f0  |T%....d.Z/8.t)w.|
-000003e0  4b 9c 92 72 02 4c f3 bf  ee ba e1 51 fb b4 ac e6  |K..r.L.....Q....|
-000003f0  0c 4c 19 bc 9a b7 e9 fd  8a 86 bf 37 d5 0b 1d 2a  |.L.........7...*|
+00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 85 b7 f7 7c  |..........A....||
+00000340  49 4e 97 14 07 51 bc 56  2d 3f cf 1d 29 08 ac 6a  |IN...Q.V-?..)..j|
+00000350  b4 e7 0d 62 d8 fd 4d 03  29 0d f8 6c 36 6f 4d 5f  |...b..M.)..l6oM_|
+00000360  b7 5a 8e 37 3e c2 d9 dc  f4 15 52 e9 87 71 0f e5  |.Z.7>.....R..q..|
+00000370  4e a6 88 0e 54 35 e0 8b  50 91 e1 c4 04 01 00 80  |N...T5..P.......|
+00000380  51 eb f8 d6 52 ba f5 b5  0a 22 5f 91 fe f7 ee 43  |Q...R...."_....C|
+00000390  f8 af 52 b6 27 2c fc 14  e2 fb 41 61 ff 7c b9 be  |..R.',....Aa.|..|
+000003a0  f9 78 be dc 18 32 8c 4d  ef 46 c0 5a a7 91 6a 1b  |.x...2.M.F.Z..j.|
+000003b0  47 78 46 39 47 81 8a 2d  b4 cb fd bb 44 3e a7 b7  |GxF9G..-....D>..|
+000003c0  cc 4e df 17 7b 2b 38 49  fa 9d 9f 4e cd ed f2 16  |.N..{+8I...N....|
+000003d0  03 d9 68 cf c9 5a 08 32  f8 ed 02 30 54 61 f6 c0  |..h..Z.2...0Ta..|
+000003e0  f6 78 bc ad 04 9c 8e 90  7d 3d f5 35 86 aa 6e e9  |.x......}=.5..n.|
+000003f0  a2 9a d3 86 27 9f 2d 6e  ea 6e ad 82 0e aa ef 97  |....'.-n.n......|
 00000400  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
@@ -81,17 +81,17 @@
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 27 e5  |.....(........'.|
-00000060  ee c8 9a 3e d6 70 d6 1a  1b ad d2 1a 88 be 77 fd  |...>.p........w.|
-00000070  bc e2 33 13 22 52 df be  67 30 da 10 5c cf        |..3."R..g0..\.|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 47 18  |.....(........G.|
+00000060  39 03 93 d9 5b 27 29 70  52 68 15 79 f2 60 e6 58  |9...[')pRh.y.`.X|
+00000070  d9 98 cd ce a1 8f 4d ee  2c f0 34 9f fa 73        |......M.,.4..s|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 81 ad 88 a5 2e  |..........(.....|
-00000010  1f 26 3c 53 16 a7 d4 c2  13 08 52 6e ac 3b 00 9d  |.&<S......Rn.;..|
-00000020  d9 ee d4 93 86 3f 8a 0e  d8 06 d9 61 a6 6f bf f9  |.....?.....a.o..|
-00000030  a9 1f fe                                          |...|
+00000000  14 03 03 00 01 01 16 03  03 00 28 39 76 15 70 f1  |..........(9v.p.|
+00000010  73 c9 9a 1e 76 40 bc de  de 49 be 3e 10 4d 6a 42  |s...v@...I.>.MjB|
+00000020  1b 9b bd 07 6b 19 ff f9  2c 19 3c c8 e7 06 fa c8  |....k...,.<.....|
+00000030  3d 52 b4                                          |=R.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 ab b6 ac  |................|
-00000010  55 5d 72 b0 7a a1 0e 17  8d 1b 71 77 79 ef 32 6b  |U]r.z.....qwy.2k|
-00000020  4e c2 df 15 03 03 00 1a  00 00 00 00 00 00 00 02  |N...............|
-00000030  34 1e 22 35 71 60 cd cf  75 2b 73 94 b6 5f 09 1d  |4."5q`..u+s.._..|
-00000040  1b b5                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 14 96 ec  |................|
+00000010  f4 bb ae 45 81 0c 39 10  e2 3a 91 51 04 2c 01 a8  |...E..9..:.Q.,..|
+00000020  8b a3 25 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..%.............|
+00000030  fe 1a 53 01 17 ad a1 30  0a 73 17 9f 39 b4 30 ac  |..S....0.s..9.0.|
+00000040  91 ee                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
index 57f2f36..a22ffae 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -1,19 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 8a 01 00 00  86 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 92 01 00 00  8e 03 03 00 00 00 00 00  |................|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 3f  |...../.5.......?|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 47  |...../.5.......G|
 00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
 00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
-00000070  0d 00 0a 00 08 04 01 04  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 10 00 09 00 07  06 70 72 6f 74 6f 33     |.........proto3|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 10  00 09 00 07 06 70 72 6f  |.............pro|
+00000090  74 6f 33 00 12 00 00                              |to3....|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 f0 ff a6 91 ca  |....Y...U.......|
-00000010  e9 d7 bc 31 4c 5e 15 b0  24 41 78 17 87 a8 1c 7d  |...1L^..$Ax....}|
-00000020  eb bd 28 f6 57 7f 01 ab  b4 02 a7 20 38 08 43 7e  |..(.W...... 8.C~|
-00000030  ca 3c 5f ba 62 bb b0 10  30 f3 f2 03 68 ef 01 43  |.<_.b...0...h..C|
-00000040  3b 70 2c 37 80 fe 1c af  bc f5 db 60 c0 2f 00 00  |;p,7.......`./..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 94 d7 79 73 82  |....Y...U....ys.|
+00000010  87 7c 85 6e 8a 1b 7d bf  69 c9 98 0c 44 bd f6 78  |.|.n..}.i...D..x|
+00000020  d2 80 dc d8 7d 80 bb 91  4b d4 ed 20 fe 9f 2f 7b  |....}...K.. ../{|
+00000030  f2 1a 44 36 cd ce af f1  b5 01 8a ac 18 e4 2b 23  |..D6..........+#|
+00000040  a8 ab 1a 32 23 8b 0b e2  81 a8 0a 40 c0 2f 00 00  |...2#......@./..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
@@ -59,37 +60,37 @@
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 4e  |.............A.N|
-00000330  38 ec 28 ce cb f6 6b 74  96 74 92 46 9a 41 4a 02  |8.(...kt.t.F.AJ.|
-00000340  33 cb f0 d9 24 20 fd e0  d4 8b 24 b2 1f 24 ac 38  |3...$ ....$..$.8|
-00000350  79 cc ec ff 25 c9 30 f6  85 84 51 ee cb 59 8b 0d  |y...%.0...Q..Y..|
-00000360  e2 38 3d e0 24 83 84 da  ef 67 f5 f7 8a 0a c0 04  |.8=.$....g......|
-00000370  01 00 80 82 72 af cb 74  fb 8c 02 d5 d4 d9 26 04  |....r..t......&.|
-00000380  06 59 64 f0 50 ce cf ed  15 b4 24 95 47 8a c6 17  |.Yd.P.....$.G...|
-00000390  b0 da a4 13 20 88 e9 b8  ef cd b2 f1 35 5a 88 81  |.... .......5Z..|
-000003a0  19 03 ee f4 74 a2 23 27  bc e9 bf f2 06 06 58 f3  |....t.#'......X.|
-000003b0  ef b6 5e de 76 58 8c ec  a6 d0 d3 1e 44 ec ac 61  |..^.vX......D..a|
-000003c0  62 91 a6 9e 36 ef 64 e9  a5 2e e8 88 69 30 0f b3  |b...6.d.....i0..|
-000003d0  84 0a b4 d1 3b a5 fe 9e  96 1a ad 7b 8a 24 7e a7  |....;......{.$~.|
-000003e0  af 5b 6d 11 be 1f 2b 7a  5f 62 f7 ae be 2e 99 ec  |.[m...+z_b......|
-000003f0  05 b6 7c 16 03 03 00 04  0e 00 00 00              |..|.........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 7d  |.............A.}|
+00000330  75 a5 53 0b a5 4d a6 81  e0 df c4 11 c9 b5 31 ba  |u.S..M........1.|
+00000340  9f 7b 51 04 57 c6 e0 b9  b0 bc 4f bc 71 74 8a 2e  |.{Q.W.....O.qt..|
+00000350  d1 f6 39 36 94 4e c7 d3  a7 1b 2c b5 55 04 71 01  |..96.N....,.U.q.|
+00000360  9e 2b 42 1e 8b a4 40 b2  13 4f 03 1f 51 9e 5c 04  |.+B...@..O..Q.\.|
+00000370  01 00 80 68 05 c7 4a ca  df 00 85 2b 53 f7 4f c3  |...h..J....+S.O.|
+00000380  b4 0f e8 f7 b8 30 b7 36  56 65 7b 03 6a 72 f1 aa  |.....0.6Ve{.jr..|
+00000390  54 30 90 9e c7 dc fc 03  96 15 70 67 13 12 a4 f4  |T0........pg....|
+000003a0  42 f0 f9 a1 48 c0 44 44  77 0e ea fd cb b5 6e 19  |B...H.DDw.....n.|
+000003b0  89 94 a7 12 67 87 47 19  c3 00 2d c4 9b d4 dc 66  |....g.G...-....f|
+000003c0  fa ca d7 97 79 9b 28 7f  74 d4 37 c0 06 63 d4 9e  |....y.(.t.7..c..|
+000003d0  a1 53 16 5a 8e d7 a5 cc  90 4d 63 f9 0c 18 85 7f  |.S.Z.....Mc.....|
+000003e0  0e 35 3a 49 73 88 82 51  41 e5 2d 58 aa 38 3e bd  |.5:Is..QA.-X.8>.|
+000003f0  3d d8 da 16 03 03 00 04  0e 00 00 00              |=...........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 d4 91  |.....(..........|
-00000060  e7 17 05 14 7a ce cf 0c  3b c1 a6 a7 4a 57 70 9a  |....z...;...JWp.|
-00000070  cf 0e ec 59 19 d3 ba 90  97 51 8b 60 8e 03        |...Y.....Q.`..|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 a8 da  |.....(..........|
+00000060  74 a6 d0 a5 26 86 f3 5f  89 a4 af ac 9c 1a 01 1f  |t...&.._........|
+00000070  89 8a 1c fc cf 68 3e a5  a3 20 1a b3 78 af        |.....h>.. ..x.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 55 64 22 e3 20  |..........(Ud". |
-00000010  eb 69 63 44 b4 68 89 29  d6 c8 83 d8 6c 30 2f af  |.icD.h.)....l0/.|
-00000020  2a 86 b0 ea ce 57 b8 9c  69 9a e3 fe 86 7e 0a bf  |*....W..i....~..|
-00000030  08 f1 fe                                          |...|
+00000000  14 03 03 00 01 01 16 03  03 00 28 1a f2 a9 e8 71  |..........(....q|
+00000010  b2 a6 ca 36 4a ea 55 f6  20 03 fd f7 90 c3 af 30  |...6J.U. ......0|
+00000020  d3 29 c3 d7 1b d6 4d 3e  61 55 94 0d 4e 3e 83 1a  |.)....M>aU..N>..|
+00000030  97 dd 19                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 29 39 41  |.............)9A|
-00000010  c4 ff e3 3e 38 bf 06 09  d2 d9 05 84 66 60 58 e8  |...>8.......f`X.|
-00000020  3a 74 f5 15 03 03 00 1a  00 00 00 00 00 00 00 02  |:t..............|
-00000030  b4 1f e4 7b 84 1e 87 57  97 f6 f2 12 df 40 85 fe  |...{...W.....@..|
-00000040  d0 d1                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 94 5b 5e  |..............[^|
+00000010  51 a1 52 ee 19 78 78 ef  12 0d 9c 66 bf e2 48 cb  |Q.R..xx....f..H.|
+00000020  f6 00 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  cd 5d 31 58 d9 5a 12 65  5b c6 7e 4e e2 04 e7 1d  |.]1X.Z.e[.~N....|
+00000040  b1 4c                                             |.L|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
index 7871a05..1470ba7 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 e1 64 a4 cd 65  |....Y...U...d..e|
-00000010  5a 19 5f 07 68 cb af f2  74 76 a2 99 18 e4 9e 00  |Z._.h...tv......|
-00000020  6a 72 6b 84 dd 1c ec cd  64 45 34 20 96 c3 54 88  |jrk.....dE4 ..T.|
-00000030  00 ec aa 32 95 2c ad 08  47 64 fd 2e d4 1f 8e 5e  |...2.,..Gd.....^|
-00000040  ec 39 aa ba 6a 3c 8c c7  a6 63 55 8e c0 09 00 00  |.9..j<...cU.....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 a5 28 60 99 bf  |....Y...U...(`..|
+00000010  c7 54 04 87 60 ad c5 32  f6 bf ed 11 47 de 4d ff  |.T..`..2....G.M.|
+00000020  99 e1 8f 88 f6 af 10 6e  29 74 0a 20 1d 39 cb e0  |.......n)t. .9..|
+00000030  a5 11 fe 8e 23 11 83 c7  a6 53 fc 97 03 9d ff 7c  |....#....S.....||
+00000040  cf 51 ba 41 64 61 38 22  5c c6 4a 04 c0 09 00 00  |.Q.Ada8"\.J.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,24 +48,23 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 bb  |*............A..|
-00000280  6d 5c 62 98 a7 6c bd f1  9b 4b 09 16 31 59 6a 51  |m\b..l...K..1YjQ|
-00000290  83 c8 9f 75 9c f8 09 b0  ee 39 01 e3 7a 25 9d 66  |...u.....9..z%.f|
-000002a0  fe 14 14 15 45 1b 51 a4  47 fe 1e 58 01 28 96 13  |....E.Q.G..X.(..|
-000002b0  2a 0e 0b 40 b2 22 db 2f  e6 f4 88 0a 58 92 10 04  |*..@."./....X...|
-000002c0  03 00 8b 30 81 88 02 42  01 13 f5 38 52 04 f7 3b  |...0...B...8R..;|
-000002d0  55 96 ef 39 77 be 4f 85  07 18 e9 47 49 b4 bb 57  |U..9w.O....GI..W|
-000002e0  c9 c0 93 2e 9e b2 5e 3f  14 ce 43 f0 93 b5 a4 66  |......^?..C....f|
-000002f0  8c fe 3a 06 fc a7 bb 9d  87 46 b8 20 1f 0a 31 c6  |..:......F. ..1.|
-00000300  80 b0 2d fa e5 06 5f 78  b2 da 02 42 01 c0 bd 12  |..-..._x...B....|
-00000310  5b ec 79 dd bf a4 54 f1  3b a8 b8 9a 50 ac a9 7c  |[.y...T.;...P..||
-00000320  d2 a6 b5 dd 84 ee dd eb  3e c7 52 1c 65 ac 1e 37  |........>.R.e..7|
-00000330  4f a8 87 fa 05 8a a4 69  c9 59 53 65 ee 8e 4c 1b  |O......i.YSe..L.|
-00000340  6c d0 88 b8 65 de 85 f8  fe f9 27 96 b8 c0 16 03  |l...e.....'.....|
-00000350  03 00 2e 0d 00 00 26 03  01 02 40 00 1e 06 01 06  |......&...@.....|
-00000360  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
-00000370  01 03 02 03 03 02 01 02  02 02 03 00 00 0e 00 00  |................|
-00000380  00                                                |.|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 c4  |*............A..|
+00000280  0a 40 05 84 eb 90 3c 13  d0 90 af 69 fa 5c 20 75  |.@....<....i.\ u|
+00000290  e1 9b f2 30 f7 df cc 75  2c 35 7e 38 16 99 7d 57  |...0...u,5~8..}W|
+000002a0  6d d7 f0 93 2d 1d c8 03  89 6e 52 3b 20 e5 8a 5f  |m...-....nR; .._|
+000002b0  6d ca 6e 6a ca 51 f8 a4  dc 1d ec 3e 73 c9 72 04  |m.nj.Q.....>s.r.|
+000002c0  03 00 8a 30 81 87 02 41  37 bf 0d 1d c1 9a 37 39  |...0...A7.....79|
+000002d0  4d 4a f8 17 50 5d 4c 78  d4 25 99 9d 81 48 98 a8  |MJ..P]Lx.%...H..|
+000002e0  ff 2d 3f 98 4b 9f d8 96  2b fa 37 cc e8 66 25 0e  |.-?.K...+.7..f%.|
+000002f0  d3 5e 53 c5 3b ad 17 3f  21 ce d2 45 d8 93 95 6c  |.^S.;..?!..E...l|
+00000300  25 f9 5a 10 9f 37 c8 14  a6 02 42 00 e6 bd 9a 89  |%.Z..7....B.....|
+00000310  8e 73 40 f4 90 e6 d8 e2  98 51 10 23 fb 98 e5 47  |.s@......Q.#...G|
+00000320  0c 2a 7a 2f 02 66 a8 20  e4 cb 4f ba 14 1d 9e 3a  |.*z/.f. ..O....:|
+00000330  2f 09 47 44 02 e0 9f 30  21 71 f0 99 09 de 23 d2  |/.GD...0!q....#.|
+00000340  f5 f0 b2 93 70 a3 8f 79  b9 4f 88 0b 35 16 03 03  |....p..y.O..5...|
+00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&...@......|
+00000360  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000370  03 02 03 03 02 01 02 02  02 03 00 00 0e 00 00 00  |................|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -103,32 +103,32 @@
 00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 93 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8f 04 03 00 8b 30  81 88 02 42 00 e9 db 80  |.......0...B....|
-00000270  e2 67 5d 00 21 88 67 99  7f df de 90 77 86 1e b7  |.g].!.g.....w...|
-00000280  28 b1 2d 08 8d 02 de 9a  29 2b ca b9 9c 48 ad bd  |(.-.....)+...H..|
-00000290  58 16 68 ad a3 0f 08 4c  01 52 e7 54 97 7c 06 0a  |X.h....L.R.T.|..|
-000002a0  9e c8 97 61 e6 a9 53 62  fb b1 e3 b1 d7 03 02 42  |...a..Sb.......B|
-000002b0  01 f3 99 af dc e6 69 af  1d fb d5 d0 63 bd d1 17  |......i.....c...|
-000002c0  d2 ca a5 10 97 1a 94 93  df c4 94 27 53 77 1a 9e  |...........'Sw..|
-000002d0  9b a5 e6 dd 0d cf 49 46  4c 5b 83 a4 52 f2 8b d6  |......IFL[..R...|
-000002e0  b2 5f 40 e5 c3 d6 7f a2  2c 50 4d 4c 81 54 80 5b  |._@.....,PML.T.[|
-000002f0  72 c7 14 03 03 00 01 01  16 03 03 00 40 00 00 00  |r...........@...|
-00000300  00 00 00 00 00 00 00 00  00 00 00 00 00 96 9f 5a  |...............Z|
-00000310  9c e3 d0 6c 5f 11 c4 cf  e4 34 1a 54 7e dc ec 1d  |...l_....4.T~...|
-00000320  cd 08 eb 5c b4 32 1b d0  e5 12 1f 7a e7 86 16 56  |...\.2.....z...V|
-00000330  a7 10 20 e1 59 31 65 63  12 7d 45 2d 2a           |.. .Y1ec.}E-*|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 92 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8e 05 03 00 8a 30  81 87 02 42 00 cc a4 ad  |.......0...B....|
+00000270  0b ff 09 40 8f 2c a6 37  72 1d f7 d2 19 74 85 ad  |...@.,.7r....t..|
+00000280  ac 33 b0 b8 5b 56 39 cf  b0 ef 46 68 94 39 4c d0  |.3..[V9...Fh.9L.|
+00000290  f4 97 32 10 99 36 c5 95  c8 14 23 37 78 46 5c a9  |..2..6....#7xF\.|
+000002a0  20 95 65 47 ff 54 02 f1  aa 1d d7 bc 39 2d 02 41  | .eG.T......9-.A|
+000002b0  2e f9 d6 8c e8 c5 a9 6f  10 4f d6 5f 4e 88 e9 71  |.......o.O._N..q|
+000002c0  23 5b 6f b8 ab 19 d3 dd  ec f3 32 e3 3b fa 41 a2  |#[o.......2.;.A.|
+000002d0  e8 ae dc 27 8d 4e 79 f4  47 ef c9 8f bf 0b 41 3b  |...'.Ny.G.....A;|
+000002e0  94 16 cb 8f 1e b5 f3 4e  6e 42 46 35 1a 0c ca 79  |.......NnBF5...y|
+000002f0  4b 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |K..........@....|
+00000300  00 00 00 00 00 00 00 00  00 00 00 00 64 1c d9 9f  |............d...|
+00000310  34 ec c2 74 76 7a 9f cf  95 19 be 8d 6a 2f 25 96  |4..tvz......j/%.|
+00000320  df de 18 ca 0e c9 d4 2f  e4 b0 34 10 5b 72 7a 18  |......./..4.[rz.|
+00000330  5c 64 d7 fc 2e 1b 28 10  ae a6 31 e9              |\d....(...1.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 54 bd b1 39 e6  |..........@T..9.|
-00000010  a7 d0 76 5e 7e 91 0d 81  d1 c6 82 05 79 90 24 fc  |..v^~.......y.$.|
-00000020  26 b7 ec e6 b8 72 05 59  bd 00 99 f7 dd f4 44 1e  |&....r.Y......D.|
-00000030  79 4d 6d a1 22 4a e3 2c  41 05 ec 5a f7 32 17 ff  |yMm."J.,A..Z.2..|
-00000040  d3 1b ee 21 71 98 99 b7  85 34 b3                 |...!q....4.|
+00000000  14 03 03 00 01 01 16 03  03 00 40 27 6f 24 a3 0c  |..........@'o$..|
+00000010  6d d7 68 4a fb 43 b0 97  02 6c 22 7e 2f a1 f1 7a  |m.hJ.C...l"~/..z|
+00000020  37 bf 38 82 dc a0 83 24  01 4b c0 4f 15 e1 7c 4c  |7.8....$.K.O..|L|
+00000030  d4 cd b8 e2 71 af f5 20  7d f9 4a 48 4b f0 a1 f3  |....q.. }.JHK...|
+00000040  7b 02 29 18 c0 87 a5 dd  c4 73 8e                 |{.)......s.|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 b9 81 3f  48 14 95 9b 39 85 2a 9e  |.......?H...9.*.|
-00000020  44 ec bb cf c2 29 a9 44  f7 8a 6b 3f 92 13 dd 0e  |D....).D..k?....|
-00000030  c6 6b a1 51 79 15 03 03  00 30 00 00 00 00 00 00  |.k.Qy....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 1c 93 91 23 12 11  |.............#..|
-00000050  cc 30 fb 22 9e 23 b7 60  8a 3d 4c e6 52 2b 3e 6b  |.0.".#.`.=L.R+>k|
-00000060  8e 47 91 b1 68 50 07 8a  d1 6f                    |.G..hP...o|
+00000010  00 00 00 00 00 bf 7a e1  23 0d d0 13 6e 96 81 6d  |......z.#...n..m|
+00000020  32 56 0f 75 7e 01 88 5f  6d e6 d6 ca ec 3c 17 e9  |2V.u~.._m....<..|
+00000030  44 a9 c0 1c a4 15 03 03  00 30 00 00 00 00 00 00  |D........0......|
+00000040  00 00 00 00 00 00 00 00  00 00 76 be 7a 77 29 01  |..........v.zw).|
+00000050  8e 13 02 66 81 43 a0 55  03 35 22 09 de ea 52 bb  |...f.C.U.5"...R.|
+00000060  51 cc c1 09 0e 9b 4d bd  94 85                    |Q.....M...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
index 24c1b9a..95c5782 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 7a 6c c2 d1 69  |....Q...M..zl..i|
-00000010  af 86 6f 03 3c e4 70 ae  03 39 fd c6 3a a9 a4 b2  |..o.<.p..9..:...|
-00000020  96 1e 50 f2 f4 16 50 e4  a2 f2 41 20 f8 83 3b 45  |..P...P...A ..;E|
-00000030  0d 5b 88 bc 87 6c 81 23  e3 1d e0 7e 22 f5 6d 95  |.[...l.#...~".m.|
-00000040  58 63 39 cf 4f 80 80 cc  41 bb b1 4c 00 05 00 00  |Xc9.O...A..L....|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 79 e8 35 e3 d2  |....Q...M..y.5..|
+00000010  c0 5e 39 d1 46 da 9c 94  56 20 e2 06 d6 9b f6 dd  |.^9.F...V ......|
+00000020  4f 7a c1 e8 34 a1 9f 8b  c2 e1 fb 20 66 9c 5a 9a  |Oz..4...... f.Z.|
+00000030  3d 22 ab 8e d8 81 03 94  68 a0 6c 72 d8 23 0b 4b  |="......h.lr.#.K|
+00000040  fe 9d c7 49 a7 7c bd fa  b5 7a 5e 5b 00 05 00 00  |...I.|...z^[....|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -103,26 +104,25 @@
 00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
 00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
 00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
-00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 93 0f  |..C.0oUN.p......|
-000002a0  00 00 8f 04 03 00 8b 30  81 88 02 42 00 87 a3 50  |.......0...B...P|
-000002b0  77 2a 46 97 68 1e ca 47  d2 46 a3 f7 37 e7 1c 3c  |w*F.h..G.F..7..<|
-000002c0  e3 16 dc b9 93 b9 76 af  da 46 b1 da 47 bc 8b 9c  |......v..F..G...|
-000002d0  ff 61 76 45 2b cf a6 85  4a 45 d4 51 98 18 31 c5  |.avE+...JE.Q..1.|
-000002e0  61 54 3b ae 88 ca 56 ac  90 29 de f2 20 a6 02 42  |aT;...V..).. ..B|
-000002f0  01 0d 54 c6 a5 14 c2 c0  83 5d ee 32 d3 c6 05 d7  |..T......].2....|
-00000300  0c 40 42 ca 8a 69 5e cc  9b f5 c4 9b 7c 81 e9 b7  |.@B..i^.....|...|
-00000310  dd 01 c0 e5 93 de 75 d2  6b 26 dd 16 2a ec d0 0e  |......u.k&..*...|
-00000320  50 76 ee 36 ac 42 a3 0b  64 dd 4d 47 18 3e 5c 18  |Pv.6.B..d.MG.>\.|
-00000330  16 3b 14 03 03 00 01 01  16 03 03 00 24 c2 c7 3a  |.;..........$..:|
-00000340  a2 9b 93 ea 75 1c b6 47  60 2e 15 cf b8 63 73 8a  |....u..G`....cs.|
-00000350  2c b8 86 a8 12 1d cb 30  e2 38 fe 0f 02 57 43 f0  |,......0.8...WC.|
-00000360  07                                                |.|
+00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 92 0f  |..C.0oUN.p......|
+000002a0  00 00 8e 05 03 00 8a 30  81 87 02 41 19 c7 50 06  |.......0...A..P.|
+000002b0  42 82 f9 e5 ec 0b f7 65  7e b1 19 53 5f 23 ab 19  |B......e~..S_#..|
+000002c0  54 08 ec d2 a7 22 dd 83  7c 97 76 59 a5 6b f4 1d  |T...."..|.vY.k..|
+000002d0  92 86 34 2d ce 71 bb 01  d2 8a 67 0e a8 fb 51 e4  |..4-.q....g...Q.|
+000002e0  69 9c 27 23 74 b9 fd 6f  b6 5e 48 a0 cc 02 42 01  |i.'#t..o.^H...B.|
+000002f0  50 97 b7 95 14 f4 a6 f2  95 63 17 38 59 a1 51 95  |P........c.8Y.Q.|
+00000300  1e bc 99 fb fd 82 8b ab  cb 4d 8e 17 a9 f8 e9 c2  |.........M......|
+00000310  9b 93 15 02 50 e6 c2 05  54 e7 8a ec 6f 93 1f 79  |....P...T...o..y|
+00000320  8d 67 e7 2d d6 65 ab 97  fd be 20 97 bd 6b c4 fc  |.g.-.e.... ..k..|
+00000330  02 14 03 03 00 01 01 16  03 03 00 24 24 df 52 6e  |...........$$.Rn|
+00000340  c1 35 48 fe 60 77 28 69  36 fe 96 a1 72 db a2 f5  |.5H.`w(i6...r...|
+00000350  d0 b7 c3 d9 67 e5 ee f2  d9 18 bf f0 35 80 06 c2  |....g.......5...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 ca e7 84 5c 1b  |..........$...\.|
-00000010  94 4c d8 78 6f 3f 80 b2  f9 9f fd c5 a5 fd 6f 89  |.L.xo?........o.|
-00000020  d7 50 a1 81 bf d0 9d eb  75 10 69 97 35 74 06     |.P......u.i.5t.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 40 5b dc 01 59  |..........$@[..Y|
+00000010  33 6e 61 5a 6d fc c8 a5  f5 00 9b 55 77 c5 e6 f2  |3naZm......Uw...|
+00000020  c6 5c b6 2f 94 3c 72 5b  b5 0c 3e 78 88 e6 44     |.\./.<r[..>x..D|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a 4a 11 45  18 75 a7 47 d3 36 ad 24  |.....J.E.u.G.6.$|
-00000010  fc d0 68 44 f2 9a 05 54  a2 44 e3 a7 33 74 99 15  |..hD...T.D..3t..|
-00000020  03 03 00 16 d5 d5 75 a9  a9 ef f5 31 50 f7 00 08  |......u....1P...|
-00000030  78 0a 00 1f c8 42 db c7  15 6b                    |x....B...k|
+00000000  17 03 03 00 1a cd 2f 11  b1 3a e4 1c 31 95 9b c4  |....../..:..1...|
+00000010  37 20 9f 03 d3 45 a4 15  e1 09 1e 0c f6 5d d3 15  |7 ...E.......]..|
+00000020  03 03 00 16 d7 f6 a1 d0  ad 41 69 73 c0 40 22 f2  |.........Ais.@".|
+00000030  5f e8 c3 50 f9 35 fc 59  e0 3a                    |_..P.5.Y.:|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
index e7ca34c..52e3bef 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 2d 12 aa 2a 67  |....Y...U..-..*g|
-00000010  e1 6c 55 dc 1c 0b 3f 94  39 7a 2f e3 4e d4 85 cb  |.lU...?.9z/.N...|
-00000020  31 ff da 09 dd e0 92 75  6c e8 0b 20 e1 e7 fc 09  |1......ul.. ....|
-00000030  bd 12 b8 5c b2 54 75 01  7a f5 65 95 d7 87 66 77  |...\.Tu.z.e...fw|
-00000040  03 1f 25 23 cb 39 9f 47  2b 5c fd bd c0 30 00 00  |..%#.9.G+\...0..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 74 fe 19 af 4b  |....Y...U..t...K|
+00000010  f3 d8 92 62 5a df 90 2c  cc 09 fd 79 45 26 cd 52  |...bZ..,...yE&.R|
+00000020  9a e6 da 16 99 fe 1d 91  79 a7 a0 20 b3 13 e9 03  |........y.. ....|
+00000030  52 23 5f f0 55 59 f1 9e  00 a7 77 97 90 ed 2b fb  |R#_.UY....w...+.|
+00000040  9c ab fe b1 db ea 16 95  95 68 b0 e9 c0 30 00 00  |.........h...0..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
@@ -58,20 +59,20 @@
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 99  |.............A..|
-00000330  91 58 07 9b 2b 79 26 ad  cb 37 07 5e f3 e3 75 81  |.X..+y&..7.^..u.|
-00000340  32 50 39 59 a4 7c c0 b8  c2 f4 16 de dc c3 9f ba  |2P9Y.|..........|
-00000350  04 42 a4 15 9c 8f 4e da  35 88 fc e5 b1 03 70 85  |.B....N.5.....p.|
-00000360  64 a3 6e 59 15 8c 92 11  4c 10 d9 90 f4 a9 9b 04  |d.nY....L.......|
-00000370  01 00 80 4e d1 02 4d d0  a7 7d 01 42 7a b6 75 ed  |...N..M..}.Bz.u.|
-00000380  ea 10 a3 66 a2 35 94 2d  2d 7a 32 55 63 23 df 8c  |...f.5.--z2Uc#..|
-00000390  9e ec d2 19 df bb e0 02  70 c0 50 4f 05 d8 ec 1c  |........p.PO....|
-000003a0  40 a1 a5 ae 2c 80 5b 6f  b1 f9 f9 74 20 dc 4f d7  |@...,.[o...t .O.|
-000003b0  23 b3 25 61 a7 5e 76 37  a7 17 f3 54 47 08 d9 2c  |#.%a.^v7...TG..,|
-000003c0  fb ea 4f 56 51 ee 5c cc  2f 4d 80 66 7b 21 78 1d  |..OVQ.\./M.f{!x.|
-000003d0  ef a0 71 96 cc 3d 09 8e  37 fd bc 9f 26 be 75 48  |..q..=..7...&.uH|
-000003e0  b2 a1 39 0e b3 d3 73 f5  f1 68 4f aa 03 92 c0 1f  |..9...s..hO.....|
-000003f0  90 74 a9 16 03 03 00 2e  0d 00 00 26 03 01 02 40  |.t.........&...@|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 22  |.............A."|
+00000330  84 e9 5e 6e 35 92 a3 83  73 0a d6 0d 1a c1 4d ab  |..^n5...s.....M.|
+00000340  1f ab c2 dc 3f 53 a5 7d  38 c0 92 a4 82 e1 3c c5  |....?S.}8.....<.|
+00000350  24 60 20 a5 3b c5 65 ba  9c f1 b9 a5 b9 c2 70 73  |$` .;.e.......ps|
+00000360  19 74 a6 d1 0f 75 b4 75  e0 e8 60 20 e9 23 fe 04  |.t...u.u..` .#..|
+00000370  01 00 80 92 e0 56 3f 48  0d 10 23 48 b5 95 b6 91  |.....V?H..#H....|
+00000380  3e 8a 2e c7 02 e2 85 0e  59 c8 03 24 d9 1a 1a 25  |>.......Y..$...%|
+00000390  8e 12 bb 0b 83 ac 51 36  81 3f bc 0e be b9 3b 1d  |......Q6.?....;.|
+000003a0  67 56 21 4d 24 36 84 05  61 e7 70 60 d5 8e ae 97  |gV!M$6..a.p`....|
+000003b0  b8 3a d3 b1 94 72 52 cd  b0 0d dd 46 b1 15 3b 58  |.:...rR....F..;X|
+000003c0  c1 a4 63 2c 4c 31 f9 c7  4f 27 c1 0f f0 24 36 72  |..c,L1..O'...$6r|
+000003d0  e0 f8 51 12 86 c2 13 ed  6b 84 a8 15 c3 d0 39 55  |..Q.....k.....9U|
+000003e0  a4 60 50 88 c9 1e 60 60  aa 8d a5 31 3e 35 c3 f8  |.`P...``...1>5..|
+000003f0  2c 90 1c 16 03 03 00 2e  0d 00 00 26 03 01 02 40  |,..........&...@|
 00000400  00 1e 06 01 06 02 06 03  05 01 05 02 05 03 04 01  |................|
 00000410  04 02 04 03 03 01 03 02  03 03 02 01 02 02 02 03  |................|
 00000420  00 00 0e 00 00 00                                 |......|
@@ -113,26 +114,26 @@
 00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 03 00 88  |..h.A.Vk.Z......|
-00000250  0f 00 00 84 05 01 00 80  2c 1c b4 c4 d6 73 62 3a  |........,....sb:|
-00000260  86 37 c5 cb 3d 28 5f 3b  7f e2 08 f8 38 ef dc c4  |.7..=(_;....8...|
-00000270  a9 13 b6 82 28 0a 3a 67  48 01 c7 54 1d 4f b4 b4  |....(.:gH..T.O..|
-00000280  4e a8 5b fc b6 9b 27 7c  e3 a6 d7 88 62 2d 2c ca  |N.[...'|....b-,.|
-00000290  35 55 b3 99 ac 4e 28 45  55 29 3e 30 fc 46 6b 86  |5U...N(EU)>0.Fk.|
-000002a0  20 0b b1 d0 7c c5 07 cd  d8 49 5a 88 dd c2 bc 5d  | ...|....IZ....]|
-000002b0  5f ad 52 d8 be 56 e4 fd  f8 ab ef 17 04 08 50 a5  |_.R..V........P.|
-000002c0  2f 52 58 e5 31 51 e4 83  44 41 c0 8e 16 cf 39 4f  |/RX.1Q..DA....9O|
-000002d0  3d de c8 19 1e 5c c3 a7  14 03 03 00 01 01 16 03  |=....\..........|
-000002e0  03 00 28 00 00 00 00 00  00 00 00 2c e0 65 72 59  |..(........,.erY|
-000002f0  1e 0a ff 8b 58 74 14 c8  c5 fa db 08 06 4f a1 d4  |....Xt.......O..|
-00000300  20 cc f4 3e 6a f5 5c 0f  8e 26 1d                 | ..>j.\..&.|
+00000250  0f 00 00 84 05 01 00 80  33 bb 8e 67 64 03 e7 7e  |........3..gd..~|
+00000260  be a5 b1 bc cf 7a 07 24  01 17 c3 3d 4b 72 dd c3  |.....z.$...=Kr..|
+00000270  64 a7 36 e8 49 ab b6 87  ce d6 af 9e 07 22 76 e8  |d.6.I........"v.|
+00000280  0d 44 a3 36 c9 eb a4 49  85 cf 72 67 e8 2a a7 5b  |.D.6...I..rg.*.[|
+00000290  d3 f2 46 af 53 48 c6 13  f7 0b 5b 9c c7 4d 3e 05  |..F.SH....[..M>.|
+000002a0  3c 0f 69 a7 40 3a e8 70  04 01 1c 29 b2 42 0f 5f  |<.i.@:.p...).B._|
+000002b0  1c d5 b7 5c c2 17 07 7f  bd a2 b3 9a 95 81 51 24  |...\..........Q$|
+000002c0  54 5c 42 d6 a4 76 c0 d7  54 d2 11 54 bf fd dc a0  |T\B..v..T..T....|
+000002d0  ee 95 26 64 59 a0 fc 51  14 03 03 00 01 01 16 03  |..&dY..Q........|
+000002e0  03 00 28 00 00 00 00 00  00 00 00 af f4 8a be d9  |..(.............|
+000002f0  ff f1 44 e4 41 ab 9b b3  d8 b0 3d 3f 6b c5 1d b6  |..D.A.....=?k...|
+00000300  1d 9e 35 f5 20 f4 2a af  e8 35 77                 |..5. .*..5w|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 59 f7 e1 f5 7c  |..........(Y...||
-00000010  ef 54 7c ee 08 29 50 82  d2 43 32 f5 c1 bc af 0c  |.T|..)P..C2.....|
-00000020  5f 4f 6e 9a fd 65 8c 4d  ef c4 0e ec 6a ea 46 73  |_On..e.M....j.Fs|
-00000030  e2 9f 4a                                          |..J|
+00000000  14 03 03 00 01 01 16 03  03 00 28 ff 0d 47 63 2b  |..........(..Gc+|
+00000010  bd 00 3a ad 82 e3 a7 b3  b0 84 4a 26 f4 30 78 20  |..:.......J&.0x |
+00000020  80 f2 2b 15 98 61 1c cb  8b 17 67 8a 11 96 aa 93  |..+..a....g.....|
+00000030  68 f7 fb                                          |h..|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 4d b2 6d  |.............M.m|
-00000010  73 75 d3 68 3d a5 7c 98  32 3f b2 4a 47 3f b2 95  |su.h=.|.2?.JG?..|
-00000020  8f cd 99 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
-00000030  91 31 70 57 68 0a e1 e1  1b ca f0 62 ab 22 da 3d  |.1pWh......b.".=|
-00000040  e1 64                                             |.d|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 a6 8d 7b  |...............{|
+00000010  99 5e a2 e1 95 bb 5f e4  01 f4 0e 20 52 b4 64 4e  |.^...._.... R.dN|
+00000020  86 b1 3f 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..?.............|
+00000030  61 98 eb d0 7c ac bd 00  ac 7a e1 32 20 3e 81 b6  |a...|....z.2 >..|
+00000040  9d d5                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
index e770026..23bf29d 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 ef cd 72 a3 35  |....Y...U....r.5|
-00000010  e7 11 9f 67 a4 42 9e 34  03 b4 ab e1 0d 4f a4 09  |...g.B.4.....O..|
-00000020  4e e1 8d 52 d2 d0 0e 0e  f0 7a 74 20 da 3f 9c d8  |N..R.....zt .?..|
-00000030  e3 c6 5c a1 e8 5e a0 48  50 e8 70 aa 96 a7 84 4a  |..\..^.HP.p....J|
-00000040  3a b3 c3 21 24 30 6c 7a  d5 b4 9b 9c c0 09 00 00  |:..!$0lz........|
+00000000  16 03 03 00 59 02 00 00  55 03 03 b3 7f 4e e7 11  |....Y...U....N..|
+00000010  6d bc 56 ec 9c a8 61 08  d6 5a 2a 42 7b f1 94 0a  |m.V...a..Z*B{...|
+00000020  29 35 8b 7e 23 a0 6c 59  23 cf 39 20 84 09 b6 5b  |)5.~#.lY#.9 ...[|
+00000030  2f 46 80 3b 26 92 fd 81  e9 24 8c e2 b8 64 a2 03  |/F.;&....$...d..|
+00000040  3a 68 c3 7b 44 f8 28 41  e2 d3 6c 7c c0 09 00 00  |:h.{D.(A..l|....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,24 +48,23 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 7e  |*............A.~|
-00000280  3b ae 99 3d b7 3b da 7a  44 b1 b3 0d 41 36 c5 47  |;..=.;.zD...A6.G|
-00000290  b2 b9 65 44 79 2a c4 a9  e3 a8 ee 6a 77 3b ee d8  |..eDy*.....jw;..|
-000002a0  ee 11 0a 20 61 9b be 03  54 29 63 b3 fb 91 6f 34  |... a...T)c...o4|
-000002b0  cb ad 6c 5e 00 5f 0a c7  fd 70 d4 d6 de 5a 00 04  |..l^._...p...Z..|
-000002c0  03 00 8b 30 81 88 02 42  00 c2 21 72 c5 61 07 2f  |...0...B..!r.a./|
-000002d0  0e af fd d5 22 43 e5 2e  06 51 29 73 c2 ec 50 34  |...."C...Q)s..P4|
-000002e0  76 ab 67 fe 37 49 68 54  4b 16 d2 7a 4c 04 02 b2  |v.g.7IhTK..zL...|
-000002f0  0a 66 28 fb b5 bf 5b 00  4b dc bf e2 9e 99 a7 0c  |.f(...[.K.......|
-00000300  7c 64 36 79 d6 4e 99 70  5f 97 02 42 01 bb 4b 10  ||d6y.N.p_..B..K.|
-00000310  36 f1 38 c1 42 de e9 68  41 2d 0a 4b 19 eb 3c 6b  |6.8.B..hA-.K..<k|
-00000320  cd 11 3e 20 3f 95 c3 c7  ba 18 0c 4a 6a da 45 77  |..> ?......Jj.Ew|
-00000330  8c 8d f4 01 d3 15 91 3e  64 22 16 bd b5 2a 07 52  |.......>d"...*.R|
-00000340  63 e5 de 0c 22 90 2e 2f  e9 b4 3f ab b8 27 16 03  |c..."../..?..'..|
-00000350  03 00 2e 0d 00 00 26 03  01 02 40 00 1e 06 01 06  |......&...@.....|
-00000360  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
-00000370  01 03 02 03 03 02 01 02  02 02 03 00 00 0e 00 00  |................|
-00000380  00                                                |.|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 0f  |*............A..|
+00000280  4d b0 41 d4 dc 6b 8a 85  52 eb eb 18 4a 8f a7 e6  |M.A..k..R...J...|
+00000290  24 52 e5 86 be 57 d7 0a  e7 23 84 a8 a9 6c 96 08  |$R...W...#...l..|
+000002a0  4b f7 47 32 79 d9 df 81  f6 05 40 63 3b 14 67 3b  |K.G2y.....@c;.g;|
+000002b0  ea 01 a0 0d 43 1a 36 29  b3 51 7a e4 af 1b 67 04  |....C.6).Qz...g.|
+000002c0  03 00 8a 30 81 87 02 42  01 8e 57 8a b8 b7 5b 2f  |...0...B..W...[/|
+000002d0  9c 31 74 d8 7d 68 d7 6e  83 73 5f fb d0 cd de 66  |.1t.}h.n.s_....f|
+000002e0  60 fa 0a 0a 15 0b 30 3b  08 b6 f1 3e 4f 20 13 62  |`.....0;...>O .b|
+000002f0  b5 ff 86 81 dc 42 a1 4c  af c8 ff b3 24 81 d8 e1  |.....B.L....$...|
+00000300  d1 09 0c 32 11 92 5e dd  3f 87 02 41 76 a7 29 48  |...2..^.?..Av.)H|
+00000310  52 68 1c 72 4d d5 39 bf  fa 61 ec b2 27 ce 10 4e  |Rh.rM.9..a..'..N|
+00000320  86 12 3d 1e 04 9c 11 b7  b4 0c cf 98 9d 01 c3 93  |..=.............|
+00000330  cf 83 9e 92 9a ca fd 8f  b1 9f 1b 20 c4 fb a4 46  |........... ...F|
+00000340  60 fc fd d5 33 b0 8f b5  b5 c8 a4 70 c5 16 03 03  |`...3......p....|
+00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&...@......|
+00000360  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000370  03 02 03 03 02 01 02 02  02 03 00 00 0e 00 00 00  |................|
 >>> Flow 3 (client to server)
 00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
 00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
@@ -103,31 +103,31 @@
 00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 03 00 88  |..h.A.Vk.Z......|
-00000250  0f 00 00 84 04 01 00 80  07 7e 14 14 83 b9 d9 52  |.........~.....R|
-00000260  fd db c0 a4 79 37 b7 91  0b bb d6 ab d0 d1 c8 2e  |....y7..........|
-00000270  35 5b 58 3f ce 6b f6 a9  01 95 34 a9 8b da 6b 23  |5[X?.k....4...k#|
-00000280  b7 99 11 75 3e f8 db bc  ab 9b d4 8f 4f 89 12 d9  |...u>.......O...|
-00000290  2d 18 0e 54 2d 61 ff 9a  0e 3d 50 66 1d c2 e0 f6  |-..T-a...=Pf....|
-000002a0  4d 65 ca e2 08 af 29 cf  6d ab 63 72 ad 7c 03 a1  |Me....).m.cr.|..|
-000002b0  1e a1 f4 75 f5 54 58 28  3b 7d f7 21 d5 67 ec 60  |...u.TX(;}.!.g.`|
-000002c0  3b 59 81 ac f5 9a c6 cb  6a af da 7e 29 c4 c2 68  |;Y......j..~)..h|
-000002d0  53 34 aa b8 0e 58 61 24  14 03 03 00 01 01 16 03  |S4...Xa$........|
+00000250  0f 00 00 84 05 01 00 80  02 19 16 cc 97 ad 70 20  |..............p |
+00000260  bd 64 63 dd b6 81 a0 16  b3 46 4b 42 ff 21 58 2c  |.dc......FKB.!X,|
+00000270  bb 2b 4c e1 4e d7 49 4d  5c 7c 63 32 3e ef e6 ad  |.+L.N.IM\|c2>...|
+00000280  85 3f ab b4 5c 2a 37 76  8b 28 56 08 4f 08 b9 51  |.?..\*7v.(V.O..Q|
+00000290  71 14 07 27 47 45 11 a0  03 cf 72 7d 67 ef 31 8d  |q..'GE....r}g.1.|
+000002a0  e7 db 36 76 b1 b3 f4 bf  aa 6c c4 56 94 35 71 e1  |..6v.....l.V.5q.|
+000002b0  dd 88 6d 15 90 c8 70 ad  d8 95 55 42 9b c1 45 19  |..m...p...UB..E.|
+000002c0  36 ce 87 c6 fd 94 8a d4  98 6e ec 18 d5 da 59 54  |6........n....YT|
+000002d0  80 a7 8c 90 ae 55 20 1c  14 03 03 00 01 01 16 03  |.....U .........|
 000002e0  03 00 40 00 00 00 00 00  00 00 00 00 00 00 00 00  |..@.............|
-000002f0  00 00 00 a4 af 4b 95 ec  53 cf 49 8d b4 6c e0 3b  |.....K..S.I..l.;|
-00000300  76 60 23 9b 2a f3 2c 12  61 18 cf 56 7c 1d 8c 01  |v`#.*.,.a..V|...|
-00000310  a8 bb 19 4d 1f ff ff 73  a2 90 e5 87 7b 85 d3 1b  |...M...s....{...|
-00000320  74 6d 36                                          |tm6|
+000002f0  00 00 00 58 fe bc 5c ba  b2 a9 96 77 2f 95 c9 10  |...X..\....w/...|
+00000300  fd 6d fc 6a 88 8c df 82  c3 a4 3d cc 28 f4 bf 7d  |.m.j......=.(..}|
+00000310  4a f8 3d 97 36 e5 a0 76  92 94 da dd cc f5 e4 0e  |J.=.6..v........|
+00000320  7a c4 2c                                          |z.,|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 fb 28 05 0a 99  |..........@.(...|
-00000010  61 d1 c7 52 a7 9e 95 a5  c1 11 3c 81 ee f2 b8 68  |a..R......<....h|
-00000020  a6 35 e2 7e bb 3c e7 7b  61 72 08 29 3a a5 e9 d3  |.5.~.<.{ar.):...|
-00000030  39 9c d2 0f 38 12 9b 92  79 36 58 bc f3 23 85 76  |9...8...y6X..#.v|
-00000040  1c 7b 6c 49 0c bc 00 61  20 1b ff                 |.{lI...a ..|
+00000000  14 03 03 00 01 01 16 03  03 00 40 81 ab 5a 66 a8  |..........@..Zf.|
+00000010  0f a5 d3 07 00 66 45 1f  31 a9 ef f7 a0 d9 23 46  |.....fE.1.....#F|
+00000020  f0 3e 50 18 99 e3 5a bd  eb b7 1d 81 d5 95 d5 ee  |.>P...Z.........|
+00000030  21 31 41 4b 19 92 b5 95  36 da 21 c0 4a 2a a0 1c  |!1AK....6.!.J*..|
+00000040  a3 9f 8e a0 6f 9d 37 5e  12 11 03                 |....o.7^...|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 fa f6 0b  1f f6 28 c7 4c 6c c8 8d  |..........(.Ll..|
-00000020  9c 97 5f 3d 22 bb 45 fc  07 ae 3a 7e 74 01 7c 71  |.._=".E...:~t.|q|
-00000030  39 45 15 d3 c7 15 03 03  00 30 00 00 00 00 00 00  |9E.......0......|
-00000040  00 00 00 00 00 00 00 00  00 00 a1 43 03 79 a4 4e  |...........C.y.N|
-00000050  bd 0f 17 c4 d0 29 1a 8a  dd 7b e7 48 3c e4 4b 8a  |.....)...{.H<.K.|
-00000060  53 3d 1d 18 f9 05 fd 4b  73 4a                    |S=.....KsJ|
+00000010  00 00 00 00 00 a9 51 94  19 72 ab 9f 3e 97 5e 99  |......Q..r..>.^.|
+00000020  2c ec 13 48 3e 10 54 5f  8a 85 88 4d 1a a8 f5 ed  |,..H>.T_...M....|
+00000030  c3 4f a9 59 a3 15 03 03  00 30 00 00 00 00 00 00  |.O.Y.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 25 00 6d 2f a0 f6  |..........%.m/..|
+00000050  ce 8a 30 ba 53 da 97 c6  11 f3 d2 f3 9e 66 d6 dd  |..0.S........f..|
+00000060  19 f3 ee 07 03 d3 e6 f1  30 32                    |........02|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
index 66a661c..ff79aa2 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 32 d8 c5 23 e3  |....Q...M..2..#.|
-00000010  c7 4c d9 e9 d9 bd 1d d4  70 60 df 01 46 dc ca c5  |.L......p`..F...|
-00000020  d3 1b 57 28 f0 c4 4b 1c  b3 8d 13 20 4a b8 d7 eb  |..W(..K.... J...|
-00000030  70 9e e5 6d 6f 8c d4 0d  a4 25 3a ce 91 e0 25 68  |p..mo....%:...%h|
-00000040  6f 25 38 0d 91 57 af 28  39 9c 61 85 00 05 00 00  |o%8..W.(9.a.....|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 b3 b2 22 69 e4  |....Q...M...."i.|
+00000010  1a a1 56 94 26 0c 43 b7  89 0c 34 ce dc 5a c8 ca  |..V.&.C...4..Z..|
+00000020  e2 42 92 5c 75 9a b3 22  22 64 38 20 6d 2c 26 0b  |.B.\u..""d8 m,&.|
+00000030  34 b6 b8 20 36 e2 58 e5  ee 1f e2 9f a0 75 f6 d9  |4.. 6.X......u..|
+00000040  0c e4 39 ce 3c 8e 2e f8  e8 d1 a2 16 00 05 00 00  |..9.<...........|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -103,24 +104,24 @@
 00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 03 00 88  |5..C.0oUN.p.....|
-00000290  0f 00 00 84 04 01 00 80  3a 55 0a c6 97 2d 71 bc  |........:U...-q.|
-000002a0  9d e1 ec 5b cb 3d de 64  8e fd 99 c0 55 1f d5 d1  |...[.=.d....U...|
-000002b0  ae 74 79 b8 1d 25 3e 4d  19 32 62 ca 04 82 f4 3f  |.ty..%>M.2b....?|
-000002c0  7c 2b 7a 82 a6 86 2b d3  ba b0 ad 48 c4 c9 33 e6  ||+z...+....H..3.|
-000002d0  c8 2c 4a 06 75 a6 e7 49  65 53 54 33 27 55 7a 30  |.,J.u..IeST3'Uz0|
-000002e0  55 64 ef a0 d9 96 29 69  3f 90 ba b3 e4 aa 4e 5f  |Ud....)i?.....N_|
-000002f0  1d 00 c2 90 c2 04 f9 9b  7f f1 e5 fd f2 1e 57 fd  |..............W.|
-00000300  fc 0b 70 81 71 9a 43 9b  80 ff 96 42 f5 8d ff 2f  |..p.q.C....B.../|
-00000310  4f d9 48 e2 6e bf 9e f2  14 03 03 00 01 01 16 03  |O.H.n...........|
-00000320  03 00 24 32 b3 61 bd 9a  e1 21 79 60 f0 4b 6c 26  |..$2.a...!y`.Kl&|
-00000330  15 91 14 6d bc 42 9b c0  21 5f 93 2d d0 f7 db 9f  |...m.B..!_.-....|
-00000340  81 60 bd d6 34 fa 31                              |.`..4.1|
+00000290  0f 00 00 84 05 01 00 80  01 24 8d bb 05 61 2d 29  |.........$...a-)|
+000002a0  12 11 90 f5 57 21 be b7  29 76 55 63 94 8e 7b 4d  |....W!..)vUc..{M|
+000002b0  3b 3d 89 5b 1f b9 e1 8c  36 68 6f 31 21 50 af e4  |;=.[....6ho1!P..|
+000002c0  9f ca a5 68 55 b9 eb 36  75 3a 0c be 11 30 28 c8  |...hU..6u:...0(.|
+000002d0  8b 82 93 9a 71 37 4d 4e  4f d2 0c 2f 13 36 ad c3  |....q7MNO../.6..|
+000002e0  df 8a 1b 59 b2 f9 8b a7  74 63 75 4a f4 9d e0 6b  |...Y....tcuJ...k|
+000002f0  42 02 5a a9 6e a4 a8 24  d3 23 f7 09 ee b0 dc c4  |B.Z.n..$.#......|
+00000300  6f 87 58 72 e7 e3 87 b3  6b 15 ba 7f dd 9b 93 91  |o.Xr....k.......|
+00000310  5b 21 a0 31 31 bd 15 b5  14 03 03 00 01 01 16 03  |[!.11...........|
+00000320  03 00 24 fc 0e 7c e8 3e  8b b5 dc c9 3d 38 61 a1  |..$..|.>....=8a.|
+00000330  24 d6 77 1f 06 1f 30 32  ba dd 05 68 45 f1 4f 0d  |$.w...02...hE.O.|
+00000340  2e 24 09 ad c1 e5 b7                              |.$.....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 5c 99 fe 86 6f  |..........$\...o|
-00000010  89 c3 e1 ed 24 1f a5 81  a8 fd 2a 8d 28 01 cd 86  |....$.....*.(...|
-00000020  11 48 5c 13 fe f4 29 dd  ff 15 70 da 68 3b d8     |.H\...)...p.h;.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 d7 b6 b3 0a e6  |..........$.....|
+00000010  86 9a 25 e4 38 de d0 57  ff 93 0b f4 de 76 3d 00  |..%.8..W.....v=.|
+00000020  64 35 cf 70 f6 ea 74 2d  b0 71 2d 92 e2 df eb     |d5.p..t-.q-....|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a a9 5b 30  f3 9d 98 b0 a6 a6 4c 52  |......[0......LR|
-00000010  35 c9 aa 88 24 12 0f b0  53 88 21 8a 39 56 62 15  |5...$...S.!.9Vb.|
-00000020  03 03 00 16 ff 5f 0a cf  48 2a bd 2f e9 db 50 bc  |....._..H*./..P.|
-00000030  11 3c c8 d2 61 69 6c 84  22 bf                    |.<..ail.".|
+00000000  17 03 03 00 1a db bd 43  12 7c b5 83 b5 18 9d 6a  |.......C.|.....j|
+00000010  70 3f 5a eb cb d0 ba d4  03 3e a0 7b 25 f0 41 15  |p?Z......>.{%.A.|
+00000020  03 03 00 16 f8 f2 a3 27  a5 c7 25 d9 6c 08 b1 96  |.......'..%.l...|
+00000030  38 22 38 df 16 fb e2 9f  61 a3                    |8"8.....a.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
index 9ff4d3c..e700e16 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 97 dc 20 65 0f  |....Y...U.... e.|
-00000010  3f 83 4a 55 06 27 32 2f  68 81 f9 4a 6d 0a 8c 3e  |?.JU.'2/h..Jm..>|
-00000020  c0 aa c1 c2 e1 09 a8 a0  a5 e3 42 20 7b ed 80 22  |..........B {.."|
-00000030  22 f9 84 ab 6d f5 63 18  bc f8 dc 7d 13 31 6b 4b  |"...m.c....}.1kK|
-00000040  85 c0 63 8d e5 d8 29 c8  ad 09 d7 b7 c0 09 00 00  |..c...).........|
+00000000  16 03 03 00 59 02 00 00  55 03 03 21 9b eb 15 24  |....Y...U..!...$|
+00000010  46 b6 c1 85 f5 be c5 0d  e2 6b 60 bc ee 73 b1 fb  |F........k`..s..|
+00000020  34 6f f0 b8 f0 9e 1c 26  a4 4b 0f 20 cb 2b 84 a2  |4o.....&.K. .+..|
+00000030  cb a5 48 70 fe 84 25 b0  16 20 14 a1 83 21 fc f9  |..Hp..%.. ...!..|
+00000040  82 fc 9e 1a d1 3b 56 69  ab c5 0e 2c c0 09 00 00  |.....;Vi...,....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,20 +48,20 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 dd  |*............A..|
-00000280  34 64 e4 ba 63 e0 25 f2  6b cd 24 21 58 8b e1 08  |4d..c.%.k.$!X...|
-00000290  eb 09 6f 93 e2 cd 19 13  d0 e6 5a 0c ee 57 b9 ab  |..o.......Z..W..|
-000002a0  21 be 8d b5 47 1e a8 01  a4 de c4 de a7 d5 eb dd  |!...G...........|
-000002b0  d9 bd 66 1a 71 0a b7 a1  3d 10 8e b6 2d 73 ba 04  |..f.q...=...-s..|
-000002c0  03 00 8b 30 81 88 02 42  01 c6 4a 64 2b 66 7f cb  |...0...B..Jd+f..|
-000002d0  28 eb ad 05 d4 86 a0 d6  0f 12 52 03 fc 66 3f 76  |(.........R..f?v|
-000002e0  db 85 8f b4 f1 45 04 f5  10 27 b3 76 62 9a bc 7b  |.....E...'.vb..{|
-000002f0  f9 6e f6 45 fb 15 9c eb  5c 70 ca b2 40 00 f8 18  |.n.E....\p..@...|
-00000300  b9 e4 28 fc e4 b7 d8 15  70 1a 02 42 01 d3 8f 53  |..(.....p..B...S|
-00000310  57 b5 e4 f5 84 97 a2 e9  07 5a f8 67 bd 03 02 6d  |W........Z.g...m|
-00000320  ea 4e 14 da 12 2c d0 7c  89 a0 93 97 46 c9 62 ee  |.N...,.|....F.b.|
-00000330  c0 d3 d6 bf 04 11 af 19  96 6b a9 86 f8 2c 2f ab  |.........k...,/.|
-00000340  89 20 45 94 b6 d1 43 64  fc eb 2e ff 80 37 16 03  |. E...Cd.....7..|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 b6  |*............A..|
+00000280  3f 37 33 68 cb 79 c0 86  f4 9d 12 ac c4 9d 8c 9b  |?73h.y..........|
+00000290  59 1c d4 a9 01 9f 2d cb  80 24 02 ec e0 ff d1 8c  |Y.....-..$......|
+000002a0  bd 82 67 3f 47 58 1a 2e  6b 61 f6 8e 4e 27 7f 49  |..g?GX..ka..N'.I|
+000002b0  b5 45 f1 0b 9a 33 ff 53  ac 65 e2 82 7a 18 5c 04  |.E...3.S.e..z.\.|
+000002c0  03 00 8b 30 81 88 02 42  00 e1 2d ff 5d e7 77 f1  |...0...B..-.].w.|
+000002d0  12 d9 e4 c2 4d cd 9c b5  ee e4 fd 21 b2 d8 53 a9  |....M......!..S.|
+000002e0  42 e7 c5 9b 51 c3 59 37  a5 08 d4 e6 29 12 c5 56  |B...Q.Y7....)..V|
+000002f0  b8 fe f0 bb 77 87 a3 ee  09 b0 8c cd 1c 39 9e b5  |....w........9..|
+00000300  d9 15 63 53 cb d7 f1 55  5b 48 02 42 01 19 10 8a  |..cS...U[H.B....|
+00000310  7a ee 95 b1 77 44 d4 a3  bf d1 f3 f1 b0 d8 c7 7e  |z...wD.........~|
+00000320  42 c0 83 04 f5 f7 9c c0  ce 6a 98 47 9d 21 29 84  |B........j.G.!).|
+00000330  c8 be 6b 67 4e fc c6 26  ec 63 df 00 33 e6 d2 f7  |..kgN..&.c..3...|
+00000340  34 93 85 9b 1b 0f e0 89  42 b6 0b 94 1b 80 16 03  |4.......B.......|
 00000350  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
@@ -69,21 +70,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 21 2a  44 9c f5 f7 b5 0f 43 f4  |......!*D.....C.|
-00000070  19 03 02 64 c0 9a a0 d1  50 89 f2 f2 dd a1 dc 72  |...d....P......r|
-00000080  da 08 d1 5c 75 fa 54 ee  bf c8 76 5f 57 df 62 2b  |...\u.T...v_W.b+|
-00000090  36 48 40 c4 a4 ac                                 |6H@...|
+00000060  00 00 00 00 00 00 50 73  9c 9f a8 d7 78 ac 06 14  |......Ps....x...|
+00000070  8f ae fc fb ef 7d 99 db  b7 c9 91 dd f2 fe da 1b  |.....}..........|
+00000080  aa 9e 7d e4 5c 2f 5f dd  74 aa fe 03 51 e7 cd 98  |..}.\/_.t...Q...|
+00000090  e9 21 19 c9 6f 59                                 |.!..oY|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 72 a7 fe d8 23  |..........@r...#|
-00000010  6a 4f 4c 11 09 5d 0e d3  86 4e d6 e8 96 cb ac 71  |jOL..]...N.....q|
-00000020  68 e2 50 94 eb e4 d2 9b  61 56 e2 17 50 5e fb b2  |h.P.....aV..P^..|
-00000030  fe a0 1f 8d 74 2c c6 d0  ba 5e f7 73 b8 00 8d b5  |....t,...^.s....|
-00000040  57 e1 41 90 21 15 91 6d  69 25 83                 |W.A.!..mi%.|
+00000000  14 03 03 00 01 01 16 03  03 00 40 47 18 b5 1b 75  |..........@G...u|
+00000010  b8 a3 63 ab 77 d3 47 cb  14 26 b4 88 fe 15 db 22  |..c.w.G..&....."|
+00000020  76 3b 25 d3 68 8e f2 a7  d5 03 2b 82 7b b1 0f 10  |v;%.h.....+.{...|
+00000030  49 6a 3d 95 d0 4b 55 0e  14 eb bb a7 34 bb 57 b3  |Ij=..KU.....4.W.|
+00000040  5d fb 7e 15 80 5a fa f3  3a df 90                 |].~..Z..:..|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 80 70 b8  c4 f1 ef 0c 2e 87 5c fc  |......p.......\.|
-00000020  fb 54 19 4d 42 42 09 32  32 dd 54 b9 6e 35 ea 13  |.T.MBB.22.T.n5..|
-00000030  e1 2b 4c 7e e6 15 03 03  00 30 00 00 00 00 00 00  |.+L~.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 3e aa 24 38 78 63  |..........>.$8xc|
-00000050  ae 5c d4 28 2d 3b 7c 1b  66 2f 07 02 00 e1 78 dd  |.\.(-;|.f/....x.|
-00000060  6e 43 e7 23 da 55 55 33  a2 d8                    |nC.#.UU3..|
+00000010  00 00 00 00 00 70 74 e2  60 fc 3a 7a b7 5e 16 07  |.....pt.`.:z.^..|
+00000020  22 92 07 fe 92 53 c4 43  1b 8f 94 07 84 48 2b 50  |"....S.C.....H+P|
+00000030  ab 1d 6d 49 ed 15 03 03  00 30 00 00 00 00 00 00  |..mI.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 ce a8 ba 91 0b e4  |................|
+00000050  8c 38 23 9b 8b 2c 0a 0c  63 79 61 f4 b6 25 f7 41  |.8#..,..cya..%.A|
+00000060  04 9f b0 8f e0 e5 24 44  2f e9                    |......$D/.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
index 9b7d61d..607ecdc 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 c9 39 e6 18 c8  |....Y...U...9...|
-00000010  4a 7f f3 23 75 99 22 80  48 bc e3 a7 eb 49 d5 95  |J..#u.".H....I..|
-00000020  b1 ec 1d 9e 44 09 6e d9  b7 b2 f8 20 30 fd 2b 50  |....D.n.... 0.+P|
-00000030  d2 91 de c3 d0 84 a9 d5  ba c0 45 0f 18 c4 98 73  |..........E....s|
-00000040  4b cf c6 82 dd 88 0d 35  28 8e f8 d3 c0 2b 00 00  |K......5(....+..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 91 8a 4f 94 29  |....Y...U....O.)|
+00000010  32 fa 66 7a 7f b8 a7 04  5c 34 b9 7e 12 83 35 1f  |2.fz....\4.~..5.|
+00000020  93 b0 af e0 9f 71 07 5e  2f d7 ca 20 52 dc 0d e7  |.....q.^/.. R...|
+00000030  f8 16 db 90 9a 78 2f 03  0b f0 ae a7 2f c6 b4 4c  |.....x/...../..L|
+00000040  62 e7 de 32 d5 68 61 f3  07 e4 60 d2 c0 2b 00 00  |b..2.ha...`..+..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,20 +48,20 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 91  |*............A..|
-00000280  d0 f0 1b df 51 57 74 f3  62 ee d5 9e e8 7d bd 65  |....QWt.b....}.e|
-00000290  69 0a 5a 2b 75 c3 3c f7  24 3f 91 26 34 fe d8 8f  |i.Z+u.<.$?.&4...|
-000002a0  fa d3 7e f6 f5 01 89 7b  f5 69 5c c2 52 41 81 93  |..~....{.i\.RA..|
-000002b0  c4 9e 01 5d 96 fa db 41  3d 0b 78 58 ad 29 b5 04  |...]...A=.xX.)..|
-000002c0  03 00 8b 30 81 88 02 42  01 92 7c 0a 7c 79 d1 41  |...0...B..|.|y.A|
-000002d0  98 b7 57 37 10 d9 31 41  2e fe d5 a8 94 26 fa 59  |..W7..1A.....&.Y|
-000002e0  78 bf 15 c0 cf e7 a9 09  a8 6f 97 45 1b 3f e6 60  |x........o.E.?.`|
-000002f0  2d 78 dc ec 99 0f 92 43  64 20 c4 6b 59 16 df 66  |-x.....Cd .kY..f|
-00000300  83 a0 f1 d1 91 c1 8a 29  ce 4d 02 42 01 61 a2 6c  |.......).M.B.a.l|
-00000310  84 58 58 0b 74 fa 9e 4c  33 6a b5 b1 a9 da ad 1c  |.XX.t..L3j......|
-00000320  d9 33 25 91 59 a0 f2 21  ae b1 14 15 4a d1 65 50  |.3%.Y..!....J.eP|
-00000330  0e 1d 1e bc f6 29 da 22  09 20 de 75 30 ac 0a 1e  |.....).". .u0...|
-00000340  7e 46 98 89 dd 6d e4 6a  9b 83 b5 85 f3 74 16 03  |~F...m.j.....t..|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 26  |*............A.&|
+00000280  c1 67 14 4b 9e b0 45 8c  27 bf a3 a2 78 5b 56 ad  |.g.K..E.'...x[V.|
+00000290  d1 21 56 53 df 86 e9 91  de e3 f9 5d e6 f6 5d 79  |.!VS.......]..]y|
+000002a0  11 8b 60 f9 c2 9a c6 3f  6b 72 cd 7c d7 0e 13 64  |..`....?kr.|...d|
+000002b0  af e8 9f 40 35 e6 fb 04  0c 60 aa 19 61 dd 24 04  |...@5....`..a.$.|
+000002c0  03 00 8b 30 81 88 02 42  00 9d e1 02 5d 8b b1 45  |...0...B....]..E|
+000002d0  e5 c7 b6 94 27 df 36 31  fd 5e 47 fe c8 0f 5f 17  |....'.61.^G..._.|
+000002e0  b1 92 56 76 29 45 3d 90  be 91 6e 2c a7 b2 e1 33  |..Vv)E=...n,...3|
+000002f0  3b f9 3c bb 80 58 c2 d8  a8 59 82 16 dc 9e dd 60  |;.<..X...Y.....`|
+00000300  ff 82 b9 0c 5a ca ff f3  02 2c 02 42 00 a4 c0 d3  |....Z....,.B....|
+00000310  aa 1d 69 52 c0 06 fa 93  e8 50 da a4 2f 72 c9 4a  |..iR.....P../r.J|
+00000320  2c 43 7f 95 05 f7 7a f3  4a 2e 2d ce 13 be 80 40  |,C....z.J.-....@|
+00000330  a4 3b b2 f0 73 8d f1 d4  7b a3 ff 01 e1 58 71 31  |.;..s...{....Xq1|
+00000340  fc d8 2f b3 ef 62 2e b7  ac f5 c4 bc b8 68 16 03  |../..b.......h..|
 00000350  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
@@ -68,17 +69,17 @@
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 b0 4d  |.....(.........M|
-00000060  e2 ad 33 40 f2 44 e3 c7  ad a5 c6 c7 e5 00 07 68  |..3@.D.........h|
-00000070  72 80 d5 89 f0 aa 72 2b  36 5a 51 f6 f0 6a        |r.....r+6ZQ..j|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 83 cf  |.....(..........|
+00000060  ef 50 c2 e7 da b9 74 7f  1c e0 b8 fb dc 39 c9 98  |.P....t......9..|
+00000070  0c a3 7d 8c c6 fa 6f f2  ee 44 a0 a0 03 18        |..}...o..D....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 5d b6 1b 59 71  |..........(]..Yq|
-00000010  f0 7a 2c 4f d5 f0 7b a7  ab 56 48 4d b4 f7 5c bc  |.z,O..{..VHM..\.|
-00000020  34 d6 cc 02 4f 1f 45 b2  e9 ff 96 0e a2 47 d6 4e  |4...O.E......G.N|
-00000030  47 83 68                                          |G.h|
+00000000  14 03 03 00 01 01 16 03  03 00 28 73 c4 48 24 3d  |..........(s.H$=|
+00000010  8f 5f f3 8c fc fd 63 be  64 39 d5 56 67 bd d7 c4  |._....c.d9.Vg...|
+00000020  0d 57 88 1a 45 a6 f3 ad  11 b2 5a 41 58 33 f3 d3  |.W..E.....ZAX3..|
+00000030  58 fa 21                                          |X.!|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 2f f1 95  |............./..|
-00000010  75 5e 0d fb 48 9b 40 10  6d bb 81 7e d2 ca 68 ae  |u^..H.@.m..~..h.|
-00000020  84 47 d2 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.G..............|
-00000030  26 87 82 85 fa 5f a2 b2  19 b2 4e 81 f6 0f c6 c5  |&...._....N.....|
-00000040  e0 3e                                             |.>|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 65 5e 55  |.............e^U|
+00000010  32 be 00 77 6e 1d 8e 8f  95 33 24 3d 7a c2 b0 3f  |2..wn....3$=z..?|
+00000020  ca aa 97 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  b2 71 6e 42 6a 0d cf c9  ac 14 a4 b5 9c c9 71 60  |.qnBj.........q`|
+00000040  d7 c2                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
index 068b402..df2f737 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 d2 dd 5a 60 0d  |....Y...U....Z`.|
-00000010  25 72 ed e6 89 6e 4d d8  1c 75 76 e4 37 5f 06 80  |%r...nM..uv.7_..|
-00000020  26 23 48 02 cd c6 b1 e5  59 89 b2 20 99 9e e6 31  |&#H.....Y.. ...1|
-00000030  8f ca b2 aa 68 b2 6b 2e  c0 f3 f8 e9 56 f4 60 90  |....h.k.....V.`.|
-00000040  bb 5d 79 fd 4f f5 71 15  5b e7 31 20 c0 2c 00 00  |.]y.O.q.[.1 .,..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 11 50 81 a7 ef  |....Y...U...P...|
+00000010  3f bd a5 a9 41 11 e6 86  b2 a3 d8 bf 29 c3 d4 f4  |?...A.......)...|
+00000020  b6 20 2d cb 94 1b 0e dd  99 d1 0b 20 78 92 23 31  |. -........ x.#1|
+00000030  e3 fc 99 67 1f fd f3 2a  fc 9c 4c 74 6e 32 e4 f8  |...g...*..Ltn2..|
+00000040  ed 6d 2e 6d ad a9 a9 bf  63 27 7e 44 c0 2c 00 00  |.m.m....c'~D.,..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,38 +48,38 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 16  |*............A..|
-00000280  80 a7 71 18 d7 2e 0e 9b  a0 ae 58 8b ff 56 c5 21  |..q.......X..V.!|
-00000290  44 b1 ff 7e 2a 1a c4 39  91 d8 f5 cb 67 6c eb 24  |D..~*..9....gl.$|
-000002a0  86 e3 2f 79 ca 07 a4 6a  ad 92 3e 36 79 f0 00 25  |../y...j..>6y..%|
-000002b0  b5 b8 31 e5 3c 2e f1 5e  16 23 69 c4 14 a5 93 04  |..1.<..^.#i.....|
-000002c0  03 00 8b 30 81 88 02 42  01 68 cb 9b f4 22 71 10  |...0...B.h..."q.|
-000002d0  c5 5f 02 7c ab b4 db 6e  af 35 89 3b ad 4d 6b 40  |._.|...n.5.;.Mk@|
-000002e0  62 64 8b e5 6c e1 9a bd  21 05 25 cb e9 b4 7a 31  |bd..l...!.%...z1|
-000002f0  2e 63 4f 77 4c 3f ab 7b  67 21 02 ae 8b 0a 7b 7e  |.cOwL?.{g!....{~|
-00000300  f9 0f a8 df b1 14 0e ef  5e 66 02 42 01 c7 50 11  |........^f.B..P.|
-00000310  28 e9 aa 1d ea 52 60 af  37 35 73 13 bd f9 dd 54  |(....R`.75s....T|
-00000320  8e 34 db 9a 78 20 61 d4  6c 7f 72 06 4e 7a 58 07  |.4..x a.l.r.NzX.|
-00000330  d9 87 01 82 b8 dc 39 72  48 41 a4 ef 58 8e dd c6  |......9rHA..X...|
-00000340  8c 0d d3 c1 c6 36 79 e1  d0 78 dd 1c 89 9a 16 03  |.....6y..x......|
-00000350  03 00 04 0e 00 00 00                              |.......|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 fc  |*............A..|
+00000280  e6 25 27 3c 76 10 a8 9e  d3 a4 a8 68 31 06 85 fc  |.%'<v......h1...|
+00000290  35 2a 76 b3 ad 08 c5 70  ed 3d 61 e0 29 cc 47 52  |5*v....p.=a.).GR|
+000002a0  68 21 ab 48 19 f9 28 ba  54 8c 56 8e b0 7d 55 7f  |h!.H..(.T.V..}U.|
+000002b0  75 f5 42 38 61 ff e2 06  98 1a ae fc bc a0 3a 04  |u.B8a.........:.|
+000002c0  03 00 8a 30 81 87 02 42  01 0c b2 7f c9 d3 1b 83  |...0...B........|
+000002d0  1e 24 a3 d7 1c 81 f0 02  ae ed 42 6f e9 d9 91 4d  |.$........Bo...M|
+000002e0  16 5f aa 8e 5a de 3b 00  0e e6 2d fb 05 30 f3 cf  |._..Z.;...-..0..|
+000002f0  31 a2 ec 99 87 ea 42 03  0a 57 82 e5 12 27 98 8a  |1.....B..W...'..|
+00000300  c6 56 4b 9a 0b d7 37 5f  46 50 02 41 57 61 13 3c  |.VK...7_FP.AWa.<|
+00000310  48 d0 b3 b0 d5 21 72 49  80 7b d7 ef 8f 0d a0 c5  |H....!rI.{......|
+00000320  88 a1 5d ca 61 6d fb 8b  51 15 5d e5 a2 61 c4 78  |..].am..Q.]..a.x|
+00000330  8f d9 e3 78 df 7d a0 8f  0c c0 cc 18 36 41 e6 bb  |...x.}......6A..|
+00000340  6d e3 9d 04 c2 c4 d0 66  35 45 9a 08 b2 16 03 03  |m......f5E......|
+00000350  00 04 0e 00 00 00                                 |......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 5f f3  |.....(........_.|
-00000060  89 d5 29 18 bb 58 6f 28  f6 15 46 a2 1b 0a 49 9a  |..)..Xo(..F...I.|
-00000070  66 ab 83 31 36 f7 f6 74  35 45 2e db 80 b9        |f..16..t5E....|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 a3 3f  |.....(.........?|
+00000060  be 65 91 cd fe 37 43 e0  ea 6f 15 9d c2 aa 6a 02  |.e...7C..o....j.|
+00000070  20 b8 bc b5 c8 9a 1c d4  c4 e5 9b 2e 39 e7        | ...........9.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 ef 24 92 74 6b  |..........(.$.tk|
-00000010  d1 a7 26 2a 52 6e 15 70  10 65 e4 a9 89 8d 56 04  |..&*Rn.p.e....V.|
-00000020  29 d1 36 f5 aa 64 9b 34  b9 53 df fa de 47 c4 1b  |).6..d.4.S...G..|
-00000030  36 59 88                                          |6Y.|
+00000000  14 03 03 00 01 01 16 03  03 00 28 7c b7 1f 13 9e  |..........(|....|
+00000010  21 d2 eb db 32 fc 36 d0  53 e1 11 04 ce d0 61 33  |!...2.6.S.....a3|
+00000020  1e 30 3d 91 c3 6a 0d 98  55 f5 e0 5c ca 77 fa 72  |.0=..j..U..\.w.r|
+00000030  63 6a be                                          |cj.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 36 2e 40  |.............6.@|
-00000010  ed b9 f0 05 2e 08 64 28  3a da 3f 4b 80 26 6b e3  |......d(:.?K.&k.|
-00000020  97 0e 43 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..C.............|
-00000030  bd 85 57 7c 08 f1 76 bf  57 16 fe 5f f7 b4 de 43  |..W|..v.W.._...C|
-00000040  64 36                                             |d6|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 d9 db db  |................|
+00000010  4b 3a ae 5c a4 dc 96 33  ed b5 a0 70 64 1f 96 2f  |K:.\...3...pd../|
+00000020  b6 cd 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  18 a0 d1 98 a6 71 c9 56  36 bd 1a 46 4b 5b 45 29  |.....q.V6..FK[E)|
+00000040  1f dd                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
index 3c75161..994ebb1 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 81 ab f4 92 ec  |....Y...U.......|
-00000010  b8 99 85 43 62 31 8e 58  63 c0 04 03 82 b4 f5 49  |...Cb1.Xc......I|
-00000020  d5 2d cd 24 de a0 24 29  39 93 90 20 ad 9c 35 ad  |.-.$..$)9.. ..5.|
-00000030  20 1d 35 0a 6e 29 99 48  72 e6 fc 19 ae e6 7f 4f  | .5.n).Hr......O|
-00000040  47 01 24 f4 9d 9e d7 0e  06 25 a8 93 c0 13 00 00  |G.$......%......|
+00000000  16 03 03 00 59 02 00 00  55 03 03 e6 ae 89 0d 22  |....Y...U......"|
+00000010  e5 e0 cd 57 a3 ca 71 4f  17 2f 64 77 f8 30 89 ef  |...W..qO./dw.0..|
+00000020  e8 19 70 ac dd 2c c5 9f  84 7d 1d 20 1c 59 3c fe  |..p..,...}. .Y<.|
+00000030  a9 ec 10 dd 38 3b 43 fe  6b 09 e5 e4 83 d9 7a 78  |....8;C.k.....zx|
+00000040  86 08 33 da 9b e1 09 d8  c9 07 34 19 c0 13 00 00  |..3.......4.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
 00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
@@ -58,20 +59,20 @@
 000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
 00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
 00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
-00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 a3  |.............A..|
-00000330  b7 75 d0 ba b1 e1 4e aa  08 36 e2 90 52 3c e8 8c  |.u....N..6..R<..|
-00000340  78 54 61 e6 ec 60 ad 95  9b 1e a0 de a4 14 95 31  |xTa..`.........1|
-00000350  fb fc 23 5b e7 22 da 68  a1 c4 68 da 7e 62 08 6e  |..#[.".h..h.~b.n|
-00000360  40 0a 3d ac 28 f2 70 17  44 24 43 b6 12 f0 0e 04  |@.=.(.p.D$C.....|
-00000370  01 00 80 3c 1e 25 16 dc  f0 d0 ac 3e 63 d3 c6 ee  |...<.%.....>c...|
-00000380  ed 1b 1c 8b 9d ec 41 d9  10 56 f6 19 35 61 49 fc  |......A..V..5aI.|
-00000390  e6 03 f5 29 89 a1 61 46  78 0b 9b 4e f9 26 18 58  |...)..aFx..N.&.X|
-000003a0  50 64 c2 a6 fb 61 d0 29  e2 f9 b1 56 07 91 69 8d  |Pd...a.)...V..i.|
-000003b0  ec 69 0e ab 91 70 a9 82  52 4f b1 d8 31 28 e2 49  |.i...p..RO..1(.I|
-000003c0  fa fa 26 c7 f9 cf 30 6e  01 59 3f de 0d 56 c8 9e  |..&...0n.Y?..V..|
-000003d0  ae fd 49 2a 66 a0 bb 0b  b4 f8 02 7f c8 b2 53 14  |..I*f.........S.|
-000003e0  f1 7f a9 3a 02 cd 33 04  cf 73 8b 5a 61 f3 d3 5e  |...:..3..s.Za..^|
-000003f0  24 78 43 16 03 03 00 04  0e 00 00 00              |$xC.........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 77  |.............A.w|
+00000330  87 a7 ad f6 f8 34 82 05  ef bb 14 6d c7 8b 7b 2a  |.....4.....m..{*|
+00000340  4d ca 41 65 58 3c 83 fa  4d ce 0c 74 46 85 fe 38  |M.AeX<..M..tF..8|
+00000350  95 80 ee 7c c2 bf f2 be  a3 c6 bf f3 aa 07 23 40  |...|..........#@|
+00000360  7e cc 74 4a 4e 2e 69 af  6b e0 42 8a fc 41 be 04  |~.tJN.i.k.B..A..|
+00000370  01 00 80 99 ed a8 3a ef  93 1b 4c 17 80 9e cc eb  |......:...L.....|
+00000380  da 39 fb c8 9a 73 e1 96  20 3e 41 fa 8b 1a b1 68  |.9...s.. >A....h|
+00000390  cd 47 bc 4b 7b 0c 14 da  87 d3 36 09 5e 37 33 88  |.G.K{.....6.^73.|
+000003a0  7f 88 07 87 46 ec e5 72  a8 59 92 07 fa 4d 02 dc  |....F..r.Y...M..|
+000003b0  bf 3a f5 e4 77 0b a6 85  ce 43 ee 1b 90 30 7f ec  |.:..w....C...0..|
+000003c0  88 79 f8 88 59 af 6b 7f  2d 88 de 92 cd c8 36 cf  |.y..Y.k.-.....6.|
+000003d0  ba b9 08 6a c4 3d d7 9a  48 50 e1 67 d0 62 a5 b3  |...j.=..HP.g.b..|
+000003e0  b0 5f 2e 16 ee 4d 7d a2  cf d9 93 19 89 b7 64 0f  |._...M}.......d.|
+000003f0  0f 8e 3d 16 03 03 00 04  0e 00 00 00              |..=.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -79,21 +80,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |.....@..........|
-00000060  00 00 00 00 00 00 58 40  67 61 f4 eb d6 54 b5 f4  |......X@ga...T..|
-00000070  08 d8 27 18 ff 7f c5 58  d1 1e 43 d3 92 74 fe a8  |..'....X..C..t..|
-00000080  a6 f8 09 4e 44 0e 0e 6a  3b 72 7e 12 1f b2 bd 9c  |...ND..j;r~.....|
-00000090  f8 f3 c0 f0 4e 5e                                 |....N^|
+00000060  00 00 00 00 00 00 f2 20  58 ec f1 88 a6 26 79 9d  |....... X....&y.|
+00000070  2e 9b 02 b5 5e da e2 c1  c5 8d c8 93 6f 6d 07 4e  |....^.......om.N|
+00000080  fa dd ee cb b1 ae c7 3b  09 b2 cc 64 7a cd 98 91  |.......;...dz...|
+00000090  cb f8 3c 34 3b ed                                 |..<4;.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 ac 13 13 7a 41  |..........@...zA|
-00000010  ef 34 2e 9c 03 52 01 84  6b c3 f4 67 48 f5 32 fb  |.4...R..k..gH.2.|
-00000020  07 b2 6a cf a8 57 c5 7a  16 03 02 b5 9f 90 4c 28  |..j..W.z......L(|
-00000030  65 48 0d e6 43 48 f2 06  22 88 db 90 d9 6e da 07  |eH..CH.."....n..|
-00000040  59 1f 1c 6e af 74 ab 83  68 12 15                 |Y..n.t..h..|
+00000000  14 03 03 00 01 01 16 03  03 00 40 4c a1 8d bd 49  |..........@L...I|
+00000010  33 d3 72 fb 2f 23 7e 11  29 fc d2 ff 9b 67 30 c8  |3.r./#~.)....g0.|
+00000020  be c1 bc 51 6e 92 a5 f4  9d e3 b3 f9 d2 d4 c4 a5  |...Qn...........|
+00000030  83 23 90 b3 17 00 35 18  c5 ef 8b 18 a3 cf ed 9d  |.#....5.........|
+00000040  a9 52 c9 11 0a c9 55 c2  76 df 78                 |.R....U.v.x|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 87 cf e1  7e 13 ec 82 ca 75 e0 4d  |........~....u.M|
-00000020  ca 17 a3 de c0 2a 54 b3  3e 4d cf 73 46 c8 a3 cf  |.....*T.>M.sF...|
-00000030  ad 54 1c 74 46 15 03 03  00 30 00 00 00 00 00 00  |.T.tF....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 d3 9d a4 fd 16 8d  |................|
-00000050  83 1b 7c c2 53 8e 10 7b  e3 3c d5 23 8e c4 9c 74  |..|.S..{.<.#...t|
-00000060  86 9e 66 59 81 41 a1 14  8e 59                    |..fY.A...Y|
+00000010  00 00 00 00 00 60 40 d0  bf 8f ef 05 2b 89 d7 bb  |.....`@.....+...|
+00000020  27 d0 1f b2 cf c3 ff 8e  be 69 16 a9 b3 03 e8 3c  |'........i.....<|
+00000030  30 1d 58 39 4a 15 03 03  00 30 00 00 00 00 00 00  |0.X9J....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 de 61 51 a1 3c fc  |...........aQ.<.|
+00000050  1c 7b e6 f2 7d e0 aa 80  2d 9c e9 22 09 5c dd 8a  |.{..}...-..".\..|
+00000060  55 cc c4 77 34 97 05 88  98 d3                    |U..w4.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
index b3c112e..73e34c0 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
 00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
 00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
-00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 39 d1 22 07 3f  |....Q...M..9.".?|
-00000010  57 87 49 e1 92 8f c8 45  b6 8d 49 f2 dd 91 e0 6f  |W.I....E..I....o|
-00000020  86 cd 38 c4 f5 8f d1 f2  ff 13 19 20 5f 98 f8 87  |..8........ _...|
-00000030  8e 6b 63 53 67 65 88 fc  e4 02 47 4d 0b 52 bc 0c  |.kcSge....GM.R..|
-00000040  8a 08 23 45 74 89 ce 77  ac 15 1c 16 00 05 00 00  |..#Et..w........|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 e8 ae 4c 97 41  |....Q...M....L.A|
+00000010  78 0f 08 84 d4 4a 80 6d  a2 e1 d0 67 40 8f 01 8b  |x....J.m...g@...|
+00000020  20 54 cb 28 16 52 04 fd  3c c2 84 20 30 96 f0 51  | T.(.R..<.. 0..Q|
+00000030  72 86 6a d8 47 b9 47 e3  a4 ad 97 77 a9 77 1a f9  |r.j.G.G....w.w..|
+00000040  ba 63 33 32 4f 43 09 1c  e1 bd 1b 3b 00 05 00 00  |.c32OC.....;....|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -69,15 +70,15 @@
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 03 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 03 00 24 d3 d5  a4 0c ae 33 1e d4 d8 ba  |.....$.....3....|
-000000a0  67 e5 93 31 e2 e9 08 c8  9e 27 d8 9b 20 d5 59 4d  |g..1.....'.. .YM|
-000000b0  d0 f9 d9 bd 82 f7 62 7c  95 0b                    |......b|..|
+00000090  01 16 03 03 00 24 54 8c  7f 71 03 7c 98 e5 97 65  |.....$T..q.|...e|
+000000a0  51 13 b2 9d 4a b8 c9 c1  e6 11 1b 50 c8 1b c0 46  |Q...J......P...F|
+000000b0  a7 cb 13 97 92 a0 51 d4  a9 e5                    |......Q...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 b2 af 7d da e2  |..........$..}..|
-00000010  b4 4f 9e ee 68 d4 bf eb  d3 09 63 de 61 e1 c2 12  |.O..h.....c.a...|
-00000020  ba 56 d8 dc 5f 9e 31 fe  1c d4 70 2a 1a 80 3c     |.V.._.1...p*..<|
+00000000  14 03 03 00 01 01 16 03  03 00 24 37 ca ae 55 79  |..........$7..Uy|
+00000010  e7 0a 70 55 1e d1 76 61  57 46 d2 c0 d0 ed 3d 70  |..pU..vaWF....=p|
+00000020  1f 02 f2 06 5b 3e 50 ec  13 4b 67 e2 7c bd 45     |....[>P..Kg.|.E|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a 43 f5 b5  0e 1b 1f 20 2a 09 27 e5  |.....C..... *.'.|
-00000010  dc 11 cf e6 07 31 2b fc  60 52 86 2b 41 b0 c2 15  |.....1+.`R.+A...|
-00000020  03 03 00 16 6a b9 06 9b  c6 e9 6d ad ed 2d cc 0f  |....j.....m..-..|
-00000030  bc 0a f1 0c 2d 0d 74 29  17 6b                    |....-.t).k|
+00000000  17 03 03 00 1a c4 13 68  ec e0 38 a1 07 35 da d7  |.......h..8..5..|
+00000010  c4 6b f9 5c ed a7 8a cb  96 7a 22 7c ca a5 30 15  |.k.\.....z"|..0.|
+00000020  03 03 00 16 f7 a7 8d 41  b0 c1 4b 61 60 b0 b2 ed  |.......A..Ka`...|
+00000030  4a ab c3 54 d5 20 eb 67  b7 8f                    |J..T. .g..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-SCT b/src/crypto/tls/testdata/Client-TLSv12-SCT
new file mode 100644
index 0000000..826c9f0
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-SCT
@@ -0,0 +1,118 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
+>>> Flow 2 (server to client)
+00000000  16 03 03 01 c6 02 00 01  c2 03 03 1b f6 69 c1 c2  |.............i..|
+00000010  36 77 72 32 69 95 c9 e7  db 9b 5d bd 59 ba 08 02  |6wr2i.....].Y...|
+00000020  1e 76 11 c4 8e 49 08 22  8e 8a 5a 20 44 ec d9 13  |.v...I."..Z D...|
+00000030  23 ad 05 45 48 29 00 c6  11 3d 5a 5c a1 ee 34 2b  |#..EH)...=Z\..4+|
+00000040  58 ef 34 5b 7e 42 08 84  23 66 56 ee c0 2f 00 01  |X.4[~B..#fV../..|
+00000050  7a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 12  |z...............|
+00000060  01 69 01 67 00 75 00 a4  b9 09 90 b4 18 58 14 87  |.i.g.u.......X..|
+00000070  bb 13 a2 cc 67 70 0a 3c  35 98 04 f9 1b df b8 e3  |....gp.<5.......|
+00000080  77 cd 0e c8 0d dc 10 00  00 01 47 97 99 ee 16 00  |w.........G.....|
+00000090  00 04 03 00 46 30 44 02  20 1c 4b 82 5d 95 6e 67  |....F0D. .K.].ng|
+000000a0  5b db 04 95 4b f6 ce f4  32 3e 86 7a 7a 32 ab 18  |[...K...2>.zz2..|
+000000b0  60 74 de 08 da 05 91 4c  2f 02 20 73 54 1b 6e 7f  |`t.....L/. sT.n.|
+000000c0  a1 b0 7d 11 bc e6 f3 85  2f 97 66 1a f7 8a e4 10  |..}...../.f.....|
+000000d0  25 8f 12 f4 6f 39 0f d2  9e 18 f0 00 76 00 68 f6  |%...o9......v.h.|
+000000e0  98 f8 1f 64 82 be 3a 8c  ee b9 28 1d 4c fc 71 51  |...d..:...(.L.qQ|
+000000f0  5d 67 93 d4 44 d1 0a 67  ac bb 4f 4f fb c4 00 00  |]g..D..g..OO....|
+00000100  01 47 97 e1 b5 70 00 00  04 03 00 47 30 45 02 20  |.G...p.....G0E. |
+00000110  32 21 14 38 06 d8 72 2e  00 30 64 1a e2 e8 6d 4e  |2!.8..r..0d...mN|
+00000120  5a e1 d9 42 1e 82 4b 96  25 89 d5 26 13 d3 9c fa  |Z..B..K.%..&....|
+00000130  02 21 00 8f 12 28 64 51  4f 44 d5 8c 18 62 23 b2  |.!...(dQOD...b#.|
+00000140  43 93 33 05 f3 43 55 a1  d9 ee cd c5 71 35 91 dd  |C.3..CU.....q5..|
+00000150  49 d1 0b 00 76 00 ee 4b  bd b7 75 ce 60 ba e1 42  |I...v..K..u.`..B|
+00000160  69 1f ab e1 9e 66 a3 0f  7e 5f b0 72 d8 83 00 c4  |i....f..~_.r....|
+00000170  7b 89 7a a8 fd cb 00 00  01 48 5c 64 8a 87 00 00  |{.z......H\d....|
+00000180  04 03 00 47 30 45 02 20  29 89 d6 b0 53 d3 d2 e9  |...G0E. )...S...|
+00000190  91 bc f1 b5 40 be 1e 2e  e7 5c b4 74 27 ed 8f 9b  |....@....\.t'...|
+000001a0  02 e9 fa c2 4c ba a2 be  02 21 00 af 43 64 52 71  |....L....!..CdRq|
+000001b0  15 29 58 40 91 c7 08 16  96 03 a8 73 a5 65 a0 6c  |.)X@.......s.e.l|
+000001c0  b8 48 56 5a b6 29 83 64  6d 2a 9d 16 03 03 02 be  |.HVZ.).dm*......|
+000001d0  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
+000001e0  02 19 a0 03 02 01 02 02  09 00 85 b0 bb a4 8a 7f  |................|
+000001f0  b8 ca 30 0d 06 09 2a 86  48 86 f7 0d 01 01 05 05  |..0...*.H.......|
+00000200  00 30 45 31 0b 30 09 06  03 55 04 06 13 02 41 55  |.0E1.0...U....AU|
+00000210  31 13 30 11 06 03 55 04  08 13 0a 53 6f 6d 65 2d  |1.0...U....Some-|
+00000220  53 74 61 74 65 31 21 30  1f 06 03 55 04 0a 13 18  |State1!0...U....|
+00000230  49 6e 74 65 72 6e 65 74  20 57 69 64 67 69 74 73  |Internet Widgits|
+00000240  20 50 74 79 20 4c 74 64  30 1e 17 0d 31 30 30 34  | Pty Ltd0...1004|
+00000250  32 34 30 39 30 39 33 38  5a 17 0d 31 31 30 34 32  |24090938Z..11042|
+00000260  34 30 39 30 39 33 38 5a  30 45 31 0b 30 09 06 03  |4090938Z0E1.0...|
+00000270  55 04 06 13 02 41 55 31  13 30 11 06 03 55 04 08  |U....AU1.0...U..|
+00000280  13 0a 53 6f 6d 65 2d 53  74 61 74 65 31 21 30 1f  |..Some-State1!0.|
+00000290  06 03 55 04 0a 13 18 49  6e 74 65 72 6e 65 74 20  |..U....Internet |
+000002a0  57 69 64 67 69 74 73 20  50 74 79 20 4c 74 64 30  |Widgits Pty Ltd0|
+000002b0  81 9f 30 0d 06 09 2a 86  48 86 f7 0d 01 01 01 05  |..0...*.H.......|
+000002c0  00 03 81 8d 00 30 81 89  02 81 81 00 bb 79 d6 f5  |.....0.......y..|
+000002d0  17 b5 e5 bf 46 10 d0 dc  69 be e6 2b 07 43 5a d0  |....F...i..+.CZ.|
+000002e0  03 2d 8a 7a 43 85 b7 14  52 e7 a5 65 4c 2c 78 b8  |.-.zC...R..eL,x.|
+000002f0  23 8c b5 b4 82 e5 de 1f  95 3b 7e 62 a5 2c a5 33  |#........;~b.,.3|
+00000300  d6 fe 12 5c 7a 56 fc f5  06 bf fa 58 7b 26 3f b5  |...\zV.....X{&?.|
+00000310  cd 04 d3 d0 c9 21 96 4a  c7 f4 54 9f 5a bf ef 42  |.....!.J..T.Z..B|
+00000320  71 00 fe 18 99 07 7f 7e  88 7d 7d f1 04 39 c4 a2  |q......~.}}..9..|
+00000330  2e db 51 c9 7c e3 c0 4c  3b 32 66 01 cf af b1 1d  |..Q.|..L;2f.....|
+00000340  b8 71 9a 1d db db 89 6b  ae da 2d 79 02 03 01 00  |.q.....k..-y....|
+00000350  01 a3 81 a7 30 81 a4 30  1d 06 03 55 1d 0e 04 16  |....0..0...U....|
+00000360  04 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
+00000370  d3 26 8e 18 88 39 30 75  06 03 55 1d 23 04 6e 30  |.&...90u..U.#.n0|
+00000380  6c 80 14 b1 ad e2 85 5a  cf cb 28 db 69 ce 23 69  |l......Z..(.i.#i|
+00000390  de d3 26 8e 18 88 39 a1  49 a4 47 30 45 31 0b 30  |..&...9.I.G0E1.0|
+000003a0  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000003b0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000003c0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000003d0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000003e0  74 64 82 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0c 06  |td...........0..|
+000003f0  03 55 1d 13 04 05 30 03  01 01 ff 30 0d 06 09 2a  |.U....0....0...*|
+00000400  86 48 86 f7 0d 01 01 05  05 00 03 81 81 00 08 6c  |.H.............l|
+00000410  45 24 c7 6b b1 59 ab 0c  52 cc f2 b0 14 d7 87 9d  |E$.k.Y..R.......|
+00000420  7a 64 75 b5 5a 95 66 e4  c5 2b 8e ae 12 66 1f eb  |zdu.Z.f..+...f..|
+00000430  4f 38 b3 6e 60 d3 92 fd  f7 41 08 b5 25 13 b1 18  |O8.n`....A..%...|
+00000440  7a 24 fb 30 1d ba ed 98  b9 17 ec e7 d7 31 59 db  |z$.0.........1Y.|
+00000450  95 d3 1d 78 ea 50 56 5c  d5 82 5a 2d 5a 5f 33 c4  |...x.PV\..Z-Z_3.|
+00000460  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
+00000470  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
+00000480  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
+00000490  03 00 cd 0c 00 00 c9 03  00 17 41 04 d7 61 5b 05  |..........A..a[.|
+000004a0  de 22 d3 3d 00 72 a5 be  0a c1 76 94 a1 34 41 6e  |.".=.r....v..4An|
+000004b0  55 f2 74 91 d2 6f 5c 47  87 c8 4b eb ab ab 10 b9  |U.t..o\G..K.....|
+000004c0  f9 0a bc 63 03 5f 90 5b  e3 6f e1 44 97 cc bf d2  |...c._.[.o.D....|
+000004d0  e8 0d f5 9c 2e 9d 07 2c  b2 00 90 0b 04 01 00 80  |.......,........|
+000004e0  67 3d c7 73 42 b9 b2 fd  4b dd 02 57 87 95 20 75  |g=.sB...K..W.. u|
+000004f0  da c1 e7 d3 33 09 01 5d  e9 32 d7 20 7f 92 a9 dd  |....3..].2. ....|
+00000500  bb 17 c5 ee f2 07 b2 04  1d 5e 1f c2 41 66 3f 14  |.........^..Af?.|
+00000510  90 cd 84 ac 49 46 04 3e  ce 89 7d 79 42 2a 8c 56  |....IF.>..}yB*.V|
+00000520  93 d3 9c 3b 57 38 9e 91  af 62 ad 86 40 29 3d 46  |...;W8...b..@)=F|
+00000530  c7 cc f4 3f a1 7d ee 53  3d 94 1c 85 b9 1d a9 5f  |...?.}.S=......_|
+00000540  10 8e ee 38 5e 98 5d 39  31 79 83 cd f9 02 a8 a9  |...8^.]91y......|
+00000550  b8 82 21 33 40 ed 27 54  a3 6e 64 cb e9 ce dd e1  |..!3@.'T.nd.....|
+00000560  16 03 03 00 04 0e 00 00  00                       |.........|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 60 0e  |.....(........`.|
+00000060  49 99 7a 9f 28 6e 46 03  a8 fd 0e b7 ed bb 9c ba  |I.z.(nF.........|
+00000070  07 9c 4d cc 26 2b c2 70  a0 26 38 a0 f2 a0        |..M.&+.p.&8...|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 d2 ef 8f f4 7b  |..........(....{|
+00000010  7a 9b c8 98 a4 36 f2 be  61 46 0e af f4 6f 63 71  |z....6..aF...ocq|
+00000020  6e bd 87 ea 1b f2 95 ad  36 7d a3 52 7f b2 b6 45  |n.......6}.R...E|
+00000030  3f 0b 62                                          |?.b|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 53 a1 85  |.............S..|
+00000010  ce 3c c1 64 39 80 fb db  67 ec 48 20 7f e9 82 f4  |.<.d9...g.H ....|
+00000020  2d 69 0a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |-i..............|
+00000030  ab 78 11 1b 80 55 23 db  07 c5 7f c3 5e 19 d8 b3  |.x...U#.....^...|
+00000040  f8 c6                                             |..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN b/src/crypto/tls/testdata/Server-TLSv12-ALPN
index ca804295..6c7521e 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 78 01 00 01  74 03 03 73 99 93 cd 3d  |....x...t..s...=|
-00000010  e8 60 23 0d 6a e8 f5 e3  46 ca 38 44 85 ca 79 c8  |.`#.j...F.8D..y.|
-00000020  96 be 94 bd 43 d5 14 2b  20 da 5c 00 00 c4 c0 30  |....C..+ .\....0|
+00000000  16 03 01 01 6b 01 00 01  67 03 03 8c 16 4a 54 65  |....k...g....JTe|
+00000010  9f cf 83 7e 6c da 46 9c  79 cd 7f 67 29 e2 55 af  |...~l.F.y..g).U.|
+00000020  c2 d3 24 7b f6 a1 ea 96  43 95 8b 00 00 b6 c0 30  |..${....C......0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
@@ -13,16 +13,15 @@
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
-000000f0  00 ff 01 00 00 87 00 0b  00 04 03 00 01 02 00 0a  |................|
-00000100  00 3a 00 38 00 0e 00 0d  00 19 00 1c 00 0b 00 0c  |.:.8............|
-00000110  00 1b 00 18 00 09 00 0a  00 1a 00 16 00 17 00 08  |................|
-00000120  00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13  |................|
-00000130  00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00  |.............#..|
-00000140  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
-00000150  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
-00000160  02 02 02 03 00 0f 00 01  01 00 10 00 10 00 0e 06  |................|
-00000170  70 72 6f 74 6f 32 06 70  72 6f 74 6f 31           |proto2.proto1|
+000000e0  00 09 00 ff 02 01 00 00  87 00 0b 00 04 03 00 01  |................|
+000000f0  02 00 0a 00 3a 00 38 00  0e 00 0d 00 19 00 1c 00  |....:.8.........|
+00000100  0b 00 0c 00 1b 00 18 00  09 00 0a 00 1a 00 16 00  |................|
+00000110  17 00 08 00 06 00 07 00  14 00 15 00 04 00 05 00  |................|
+00000120  12 00 13 00 01 00 02 00  03 00 0f 00 10 00 11 00  |................|
+00000130  23 00 00 00 0d 00 20 00  1e 06 01 06 02 06 03 05  |#..... .........|
+00000140  01 05 02 05 03 04 01 04  02 04 03 03 01 03 02 03  |................|
+00000150  03 02 01 02 02 02 03 00  0f 00 01 01 00 10 00 10  |................|
+00000160  00 0e 06 70 72 6f 74 6f  32 06 70 72 6f 74 6f 31  |...proto2.proto1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 42 02 00 00  3e 03 03 00 00 00 00 00  |....B...>.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -77,39 +76,40 @@
 00000320  35 75 71 b5 e5 54 5b 12  2e 8f 09 67 fd a7 24 20  |5uq..T[....g..$ |
 00000330  3e b2 56 1c ce 97 28 5e  f8 2b 2d 4f 9e f1 07 9f  |>.V...(^.+-O....|
 00000340  6c 4b 5b 83 56 e2 32 42  e9 58 b6 d7 49 a6 b5 68  |lK[.V.2B.X..I..h|
-00000350  1a 41 03 56 6b dc 5a 89  04 01 00 80 52 f3 4c 3f  |.A.Vk.Z.....R.L?|
-00000360  c4 82 3c 4f 8f dc f5 33  c5 12 41 80 dc ea f2 84  |..<O...3..A.....|
-00000370  cf e4 50 f6 27 90 bb d0  09 ef 9c 9a 34 58 5c 38  |..P.'.......4X\8|
-00000380  53 27 72 e5 07 86 bb 4d  6c 17 6f 79 60 bd ca cb  |S'r....Ml.oy`...|
-00000390  be 05 f1 0c 46 4b 1f 19  74 67 cd d9 64 2a fa 5f  |....FK..tg..d*._|
-000003a0  b8 47 fb 98 47 a9 1f d5  20 95 19 48 70 1a 1c 57  |.G..G... ..Hp..W|
-000003b0  81 46 2a 8c 56 35 69 48  c9 23 a0 4e 7f f0 c0 fc  |.F*.V5iH.#.N....|
-000003c0  eb 28 8a d3 99 45 39 cc  2b 2a 93 1f c3 0b 68 60  |.(...E9.+*....h`|
-000003d0  91 14 5e 6d be e6 40 19  38 76 d1 4c 16 03 03 00  |..^m..@.8v.L....|
+00000350  1a 41 03 56 6b dc 5a 89  05 01 00 80 a5 67 1e 1a  |.A.Vk.Z......g..|
+00000360  58 c6 60 8f d8 74 60 56  f2 7d 60 2d 46 fe e2 a2  |X.`..t`V.}`-F...|
+00000370  cd 0f 07 fb 66 38 e6 99  84 ad f9 d2 b0 00 8a 6f  |....f8.........o|
+00000380  aa 07 95 6b 38 dc a5 a7  29 8e 1a fb f2 50 1c 64  |...k8...)....P.d|
+00000390  e5 c0 c6 c0 90 33 d4 ab  0b 42 0a e5 c9 89 4a 0c  |.....3...B....J.|
+000003a0  00 32 b6 2e 45 e0 5d d5  23 09 29 68 99 43 c3 cb  |.2..E.].#.)h.C..|
+000003b0  4b 5c 0a a2 b3 ac 64 65  76 c6 25 ee 7e 3e 27 d9  |K\....dev.%.~>'.|
+000003c0  91 f6 5b 33 cb e4 ce 74  52 2a c2 d1 d3 e0 44 7d  |..[3...tR*....D}|
+000003d0  a1 4f 15 ad 83 29 3a c6  9f 87 22 6d 16 03 03 00  |.O...):..."m....|
 000003e0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 e2 86 c1 a0 c0  |....F...BA......|
-00000010  45 9a da 1a 70 a1 3e b6  9c b7 2e ec dd 2b 0a c6  |E...p.>......+..|
-00000020  50 59 95 fe 8e 54 83 06  b6 68 42 60 56 de b2 b3  |PY...T...hB`V...|
-00000030  b9 14 f0 e0 e2 2e a3 7f  ec 01 4d 10 8a 43 ab 33  |..........M..C.3|
-00000040  18 f4 b9 5d 6c ae cd 90  3e f4 64 14 03 03 00 01  |...]l...>.d.....|
-00000050  01 16 03 03 00 28 47 e5  15 81 5b f4 a0 6a 61 d6  |.....(G...[..ja.|
-00000060  df 5e 60 f1 d4 dc 55 45  84 0b ef 56 42 0b 42 1d  |.^`...UE...VB.B.|
-00000070  28 b4 90 a6 2a 47 41 97  3b 91 5c 74 ab 02        |(...*GA.;.\t..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 cb 9a 95 ae 57  |....F...BA.....W|
+00000010  6e 67 8a 10 30 60 b4 2c  9e f7 18 bb d1 ad 09 96  |ng..0`.,........|
+00000020  02 e3 48 b1 a3 b8 7d 29  42 2b f7 68 f6 8e 2c f8  |..H...})B+.h..,.|
+00000030  b7 12 5c 9c 08 2a b5 8a  13 b2 4c 08 62 e0 83 c0  |..\..*....L.b...|
+00000040  4a 42 6e 5a 35 24 85 2f  58 6c 8c 14 03 03 00 01  |JBnZ5$./Xl......|
+00000050  01 16 03 03 00 28 3f b4  ed a5 a6 03 e0 db 72 cf  |.....(?.......r.|
+00000060  a7 c1 a1 32 93 38 8c c4  9d c7 07 44 8d 83 78 5f  |...2.8.....D..x_|
+00000070  c1 07 5c 0e b1 a9 5f e3  6d e7 6e 2d 5f d8        |..\..._.m.n-_.|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 8b e4 ef ba 19 39 3a  95 90 2b 6d 0d 59 ac 36  |......9:..+m.Y.6|
-00000030  be 71 eb b4 25 51 86 cc  80 43 ea 60 e0 53 30 ba  |.q..%Q...C.`.S0.|
-00000040  3e b9 c3 29 9b 26 94 5a  43 36 d0 65 be a7 f1 06  |>..).&.ZC6.e....|
-00000050  99 e3 c5 d7 f2 59 23 11  c5 99 27 5c 7f 43 94 0e  |.....Y#...'\.C..|
-00000060  b3 35 7a 66 d9 c4 49 53  2a 28 b6 3d e7 0f c5 d5  |.5zf..IS*(.=....|
-00000070  a2 d8 15 a8 3a 88 f7 14  03 03 00 01 01 16 03 03  |....:...........|
-00000080  00 28 00 00 00 00 00 00  00 00 07 2e 75 1d 9a 12  |.(..........u...|
-00000090  9f e9 7e 0b 42 dd 7b 8e  ae 58 ac 49 78 8d fb 3f  |..~.B.{..X.Ix..?|
-000000a0  21 e8 ef 91 3c 02 a6 23  d5 cc 17 03 03 00 25 00  |!...<..#......%.|
-000000b0  00 00 00 00 00 00 01 bb  04 db f2 86 63 96 01 60  |............c..`|
-000000c0  bb f4 68 f9 50 2a f0 15  82 f8 a1 73 bf cd 5f 4d  |..h.P*.....s.._M|
-000000d0  1a 73 67 91 15 03 03 00  1a 00 00 00 00 00 00 00  |.sg.............|
-000000e0  02 02 79 34 67 e2 67 d5  52 59 91 76 90 10 c8 41  |..y4g.g.RY.v...A|
-000000f0  c5 56 c9                                          |.V.|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f ec 80 83 61 69 c5 a3  b0 d3 be 06 98 78 ef 8e  |o...ai.......x..|
+00000040  7e 7c 3a 28 a1 54 e5 e3  51 bf f1 ef 57 0a fd b9  |~|:(.T..Q...W...|
+00000050  fb 02 61 ed 27 2b cf fc  0c d9 eb 7a 9e 79 a5 02  |..a.'+.....z.y..|
+00000060  8a 84 f2 26 b2 33 94 03  f7 13 3c da f7 16 f1 f5  |...&.3....<.....|
+00000070  74 95 9d d2 20 05 ab d3  cb 62 af 5a 97 d1 99 bd  |t... ....b.Z....|
+00000080  e5 70 48 36 73 bf 2e 14  03 03 00 01 01 16 03 03  |.pH6s...........|
+00000090  00 28 00 00 00 00 00 00  00 00 fd fc dc fd c2 ee  |.(..............|
+000000a0  29 c8 b9 87 fc d1 fc ae  8b 71 24 20 75 35 eb a9  |)........q$ u5..|
+000000b0  df 54 72 2c 6e 53 f7 9b  25 c9 17 03 03 00 25 00  |.Tr,nS..%.....%.|
+000000c0  00 00 00 00 00 00 01 91  5a 43 e7 eb f1 72 f5 fa  |........ZC...r..|
+000000d0  6d c0 c1 63 47 2e c9 11  d7 20 2d db 0c 98 08 46  |m..cG.... -....F|
+000000e0  7b c8 d7 0e 15 03 03 00  1a 00 00 00 00 00 00 00  |{...............|
+000000f0  02 a0 60 01 85 aa 70 e8  3a ff 89 fc 06 ac 58 a1  |..`...p.:.....X.|
+00000100  43 6e ba                                          |Cn.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
index 54f2fe8..40c2b01 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 78 01 00 01  74 03 03 ba 93 c5 44 7d  |....x...t.....D}|
-00000010  cf bf e3 d4 ad 9a ff 3a  48 ec 46 11 1a e5 68 87  |.......:H.F...h.|
-00000020  d1 f0 3b 7c da 86 b9 8f  5d a7 59 00 00 c4 c0 30  |..;|....].Y....0|
+00000000  16 03 01 01 6b 01 00 01  67 03 03 0e ea ae 76 69  |....k...g.....vi|
+00000010  53 2e 97 2f e1 d5 74 fb  93 5c 6a 5a 65 bd 15 c5  |S../..t..\jZe...|
+00000020  7d 41 4c 5e 71 9a 46 9f  cc 59 0a 00 00 b6 c0 30  |}AL^q.F..Y.....0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
@@ -13,16 +13,15 @@
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
-000000f0  00 ff 01 00 00 87 00 0b  00 04 03 00 01 02 00 0a  |................|
-00000100  00 3a 00 38 00 0e 00 0d  00 19 00 1c 00 0b 00 0c  |.:.8............|
-00000110  00 1b 00 18 00 09 00 0a  00 1a 00 16 00 17 00 08  |................|
-00000120  00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13  |................|
-00000130  00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00  |.............#..|
-00000140  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
-00000150  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
-00000160  02 02 02 03 00 0f 00 01  01 00 10 00 10 00 0e 06  |................|
-00000170  70 72 6f 74 6f 32 06 70  72 6f 74 6f 31           |proto2.proto1|
+000000e0  00 09 00 ff 02 01 00 00  87 00 0b 00 04 03 00 01  |................|
+000000f0  02 00 0a 00 3a 00 38 00  0e 00 0d 00 19 00 1c 00  |....:.8.........|
+00000100  0b 00 0c 00 1b 00 18 00  09 00 0a 00 1a 00 16 00  |................|
+00000110  17 00 08 00 06 00 07 00  14 00 15 00 04 00 05 00  |................|
+00000120  12 00 13 00 01 00 02 00  03 00 0f 00 10 00 11 00  |................|
+00000130  23 00 00 00 0d 00 20 00  1e 06 01 06 02 06 03 05  |#..... .........|
+00000140  01 05 02 05 03 04 01 04  02 04 03 03 01 03 02 03  |................|
+00000150  03 02 01 02 02 02 03 00  0f 00 01 01 00 10 00 10  |................|
+00000160  00 0e 06 70 72 6f 74 6f  32 06 70 72 6f 74 6f 31  |...proto2.proto1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -76,39 +75,40 @@
 00000310  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000320  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000330  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
-00000340  a6 b5 68 1a 41 03 56 6b  dc 5a 89 04 01 00 80 52  |..h.A.Vk.Z.....R|
-00000350  78 35 42 fa 35 a6 19 22  d1 03 f4 ed 65 31 ff fe  |x5B.5.."....e1..|
-00000360  d6 83 d5 db a1 6b 7d 88  2f 53 7a e8 2a cf a7 e4  |.....k}./Sz.*...|
-00000370  83 0f e7 b6 60 60 91 65  ee ce b0 e9 5c bb 8c fd  |....``.e....\...|
-00000380  10 5e c7 17 cb 1b bc db  19 59 23 5d 76 3a f8 87  |.^.......Y#]v:..|
-00000390  d8 2d a7 a2 d8 7b cc e5  f8 82 7c ed bf 08 c4 67  |.-...{....|....g|
-000003a0  c5 f6 a6 5a 2f 9f 59 cb  62 f6 b4 f3 3c d6 f5 dc  |...Z/.Y.b...<...|
-000003b0  20 27 d9 14 36 5c a9 8d  f6 7b c2 db 9f 84 fc 0d  | '..6\...{......|
-000003c0  d3 3a d2 bf 4a 3b 3c 3e  13 eb f9 03 d2 cf 6f 16  |.:..J;<>......o.|
+00000340  a6 b5 68 1a 41 03 56 6b  dc 5a 89 05 01 00 80 b3  |..h.A.Vk.Z......|
+00000350  74 f2 d1 0e 38 f2 b2 92  da 2c 48 c7 3f 6a d3 02  |t...8....,H.?j..|
+00000360  60 58 11 9c 08 e4 4c a5  89 c6 94 10 2d 74 3d f4  |`X....L.....-t=.|
+00000370  fd 0b 5b 5c ec 9c 89 00  da db 11 84 28 0f ca 43  |..[\........(..C|
+00000380  6a a7 f7 9c b0 2f 7d a8  6a c5 a1 d1 64 0a a2 04  |j..../}.j...d...|
+00000390  36 3f eb f1 cd d6 91 bc  45 fd e9 7c ac ff 9e 49  |6?......E..|...I|
+000003a0  e3 f1 f4 64 d7 ed 6c 0b  ac a7 7e d8 16 8d d6 d8  |...d..l...~.....|
+000003b0  01 d1 24 ef b7 db 47 ed  42 b1 4f a3 89 ac ad 74  |..$...G.B.O....t|
+000003c0  c1 fe 29 9a 59 78 b6 cb  c2 07 32 76 8b 8f 5c 16  |..).Yx....2v..\.|
 000003d0  03 03 00 04 0e 00 00 00                           |........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 f2 52 42 97 0a  |....F...BA..RB..|
-00000010  df a1 e0 cb 4e 5e 3c e5  45 0e de b3 eb 3d cd c2  |....N^<.E....=..|
-00000020  78 77 ff ec 6e 74 c2 e5  9e 89 58 6f 2b bc 41 5b  |xw..nt....Xo+.A[|
-00000030  d5 8f d0 ea ce c6 c9 11  74 0a c1 33 2a 52 c2 30  |........t..3*R.0|
-00000040  73 08 5f 20 f2 0a 45 95  81 a8 eb 14 03 03 00 01  |s._ ..E.........|
-00000050  01 16 03 03 00 28 52 9e  4c 11 49 07 9f b5 4b 2f  |.....(R.L.I...K/|
-00000060  45 79 0c d9 cb ae 45 7d  17 1e c2 5a d3 ea bd 8b  |Ey....E}...Z....|
-00000070  0d 94 b1 40 a2 56 6e a5  f8 a2 5b f8 63 73        |...@.Vn...[.cs|
+00000000  16 03 03 00 46 10 00 00  42 41 04 3a 5c 78 52 d4  |....F...BA.:\xR.|
+00000010  63 c4 7d 04 76 71 2a db  9d c2 f7 71 10 4c d3 2f  |c.}.vq*....q.L./|
+00000020  35 9e 35 21 93 d0 ca 00  e7 35 ca 8d 18 d8 ad 07  |5.5!.....5......|
+00000030  9b ca e2 34 bf 84 5e 2a  51 08 01 98 66 5d 5a 94  |...4..^*Q...f]Z.|
+00000040  28 06 b4 bd 2b 47 05 16  d1 15 04 14 03 03 00 01  |(...+G..........|
+00000050  01 16 03 03 00 28 db 5d  dd 42 7a 90 10 bd 7d c9  |.....(.].Bz...}.|
+00000060  ab d5 9b a9 28 03 13 b9  c7 8d fa 49 81 3d 14 a2  |....(......I.=..|
+00000070  f5 b1 14 d9 26 52 ee 29  15 b5 3c d9 d6 a6        |....&R.)..<...|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 8b e4 ef ba f6 cb 68  be 7f f0 66 1a c6 3c c6  |.......h...f..<.|
-00000030  ee 5f 60 3a 62 20 c5 e8  ea 99 92 84 c1 45 a1 76  |._`:b .......E.v|
-00000040  7c a7 f2 cd 40 72 9b 38  51 77 f2 ae 54 dd 67 37  ||...@r.8Qw..T.g7|
-00000050  f8 98 43 2e 55 59 23 3b  50 26 87 ca 6b 2d 45 d6  |..C.UY#;P&..k-E.|
-00000060  3c 85 29 f4 52 58 83 98  ae ad a9 64 8b d1 cc 9c  |<.).RX.....d....|
-00000070  88 3f a8 f9 d2 d3 33 14  03 03 00 01 01 16 03 03  |.?....3.........|
-00000080  00 28 00 00 00 00 00 00  00 00 84 6d 6d 57 fb dc  |.(.........mmW..|
-00000090  09 54 c4 9a fc d7 dd 45  f5 c3 57 fd e9 16 76 ab  |.T.....E..W...v.|
-000000a0  a8 85 eb 34 e7 21 30 85  56 ed 17 03 03 00 25 00  |...4.!0.V.....%.|
-000000b0  00 00 00 00 00 00 01 05  62 69 79 cb c0 74 ad 64  |........biy..t.d|
-000000c0  0a 0c 2a 10 2a b7 8e e2  92 6e 12 3b d7 64 df d7  |..*.*....n.;.d..|
-000000d0  4f da 52 c6 15 03 03 00  1a 00 00 00 00 00 00 00  |O.R.............|
-000000e0  02 b9 dc 49 b9 2a 12 58  3a 4b 4c e0 c8 b2 e9 d9  |...I.*.X:KL.....|
-000000f0  dc 48 17                                          |.H.|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f ec 80 83 61 32 9c da  f8 14 9d 56 31 08 89 38  |o...a2.....V1..8|
+00000040  f5 fc dc 73 bf c6 bc 1d  48 7c 64 41 71 7c b7 2b  |...s....H|dAq|.+|
+00000050  4a b5 2f d5 1b bf 21 e0  56 29 bd e9 e5 d0 80 ab  |J./...!.V)......|
+00000060  d1 d9 d9 81 77 33 94 45  2e 27 4c 22 e3 2b 1f 33  |....w3.E.'L".+.3|
+00000070  96 86 9d 0c 70 ad 1e 56  50 14 11 b6 b1 40 7e f5  |....p..VP....@~.|
+00000080  44 27 70 61 52 d0 66 14  03 03 00 01 01 16 03 03  |D'paR.f.........|
+00000090  00 28 00 00 00 00 00 00  00 00 5a e0 b2 53 80 89  |.(........Z..S..|
+000000a0  40 81 02 bc 62 d0 83 7f  fb 95 52 98 4d 2d 7f 70  |@...b.....R.M-.p|
+000000b0  2e 76 43 2b 60 3c fd 4b  0e e4 17 03 03 00 25 00  |.vC+`<.K......%.|
+000000c0  00 00 00 00 00 00 01 e9  04 b5 f5 92 e7 ac 20 e5  |.............. .|
+000000d0  1c 88 5c c3 c4 21 87 cf  3a 81 04 2e 50 70 c7 20  |..\..!..:...Pp. |
+000000e0  3b e5 e7 21 15 03 03 00  1a 00 00 00 00 00 00 00  |;..!............|
+000000f0  02 8a 92 dd 25 70 1b 32  86 22 d0 29 79 ff 06 f4  |....%p.2.".)y...|
+00000100  c3 82 9f                                          |...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
index cc06d5f..160bf83 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 61 01 00 01  5d 03 03 47 c5 84 0f 55  |....a...]..G...U|
-00000010  83 4d 4a 1c 48 51 15 e4  74 72 84 70 2f 24 e9 ab  |.MJ.HQ..tr.p/$..|
-00000020  42 1e 01 e1 85 27 2f b5  c1 43 14 00 00 c4 c0 30  |B....'/..C.....0|
+00000000  16 03 01 01 53 01 00 01  4f 03 03 0b 19 5d 5b 51  |....S...O....][Q|
+00000010  85 cc 1a 6b 6e 46 0d 63  07 9e 68 f0 36 e1 50 1e  |...knF.c..h.6.P.|
+00000020  e0 f5 28 24 ab 7e bf 5a  4d 4b f6 00 00 b6 c0 30  |..($.~.ZMK.....0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
@@ -13,15 +13,14 @@
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
-000000f0  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
-00000100  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
-00000110  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
-00000120  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
-00000130  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
-00000140  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
-00000150  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
-00000160  03 00 0f 00 01 01                                 |......|
+000000e0  00 09 00 ff 02 01 00 00  6f 00 0b 00 04 03 00 01  |........o.......|
+000000f0  02 00 0a 00 3a 00 38 00  0e 00 0d 00 19 00 1c 00  |....:.8.........|
+00000100  0b 00 0c 00 1b 00 18 00  09 00 0a 00 1a 00 16 00  |................|
+00000110  17 00 08 00 06 00 07 00  14 00 15 00 04 00 05 00  |................|
+00000120  12 00 13 00 01 00 02 00  03 00 0f 00 10 00 11 00  |................|
+00000130  0d 00 20 00 1e 06 01 06  02 06 03 05 01 05 02 05  |.. .............|
+00000140  03 04 01 04 02 04 03 03  01 03 02 03 03 02 01 02  |................|
+00000150  02 02 03 00 0f 00 01 01                           |........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -64,38 +63,38 @@
 00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000290  41 03 56 6b dc 5a 89 04  03 00 8a 30 81 87 02 42  |A.Vk.Z.....0...B|
-000002a0  00 e5 db 39 b2 73 2b 4b  19 66 d6 d6 de d2 ed ae  |...9.s+K.f......|
-000002b0  0c ac 74 96 12 b2 e0 87  73 7c 63 18 8c 58 3f 56  |..t.....s|c..X?V|
-000002c0  4c fe 0f a5 2d b9 b8 1c  7d 4d 49 b9 ca f0 52 01  |L...-...}MI...R.|
-000002d0  12 e2 a9 54 9f 4d ab b7  93 71 3c 1b 96 b0 87 8b  |...T.M...q<.....|
-000002e0  87 c3 02 41 79 c3 50 88  2f 9a b8 a3 f0 14 63 ee  |...Ay.P./.....c.|
-000002f0  d6 76 dd d4 1d 1c ce 4c  ba 53 40 ac 01 d9 62 a7  |.v.....L.S@...b.|
-00000300  bc ee 66 67 fc da f4 b3  0f fd 50 5d 31 0e 2d 41  |..fg......P]1.-A|
-00000310  64 d5 51 30 a3 0e ee 20  f9 9d 0e 11 df 68 a6 f4  |d.Q0... .....h..|
-00000320  54 d4 54 7a 05 16 03 03  00 04 0e 00 00 00        |T.Tz..........|
+00000290  41 03 56 6b dc 5a 89 05  03 00 8a 30 81 87 02 42  |A.Vk.Z.....0...B|
+000002a0  01 c0 83 f1 6b 74 4d 1f  f5 51 d3 df 44 27 ee 1b  |....ktM..Q..D'..|
+000002b0  32 e8 93 a5 e5 9c c7 df  8e 82 bf c1 0a 4a 52 df  |2............JR.|
+000002c0  b8 f3 53 15 88 a1 c0 ae  0a b6 f9 35 ca 6f 52 a1  |..S........5.oR.|
+000002d0  de 45 5d 4d 96 6e 9e b6  10 a1 e8 8d 2b 93 e3 9d  |.E]M.n......+...|
+000002e0  85 30 02 41 6d 41 10 65  8a d3 fe a7 9c 4e 06 a4  |.0.AmA.e.....N..|
+000002f0  8e aa 9f af e8 ec 49 f1  2c 2b 72 62 df 2f d7 ef  |......I.,+rb./..|
+00000300  da b1 b2 a3 d6 29 dc 7a  8b 11 b7 28 01 f2 6e 89  |.....).z...(..n.|
+00000310  20 dc f6 44 65 56 00 b2  4d c5 46 54 ea a4 09 bc  | ..DeV..M.FT....|
+00000320  23 94 d3 52 c1 16 03 03  00 04 0e 00 00 00        |#..R..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 00 a1 de 66 1d  |....F...BA....f.|
-00000010  05 57 3b d2 0e 5f ba 4d  e9 b7 93 0a 3e bd 25 98  |.W;.._.M....>.%.|
-00000020  76 a4 8a c9 d3 c8 04 85  f6 8d 4f 3e 32 4c 25 cb  |v.........O>2L%.|
-00000030  b5 57 86 b5 04 9d f6 ba  f3 17 c8 43 cb eb 8b d0  |.W.........C....|
-00000040  ed 99 23 c7 4d 63 95 e2  cd 52 ba 14 03 03 00 01  |..#.Mc...R......|
-00000050  01 16 03 03 00 40 33 b4  f5 4a 64 88 ef dc b6 e5  |.....@3..Jd.....|
-00000060  b6 1e 40 3e 64 5a 2c 11  97 69 4c b6 7a 4c 9a 8a  |..@>dZ,..iL.zL..|
-00000070  71 f2 60 e9 39 db 96 2a  a3 33 1b 7f 43 15 8b 99  |q.`.9..*.3..C...|
-00000080  0b 52 c2 92 86 fe 57 0d  da fe 62 44 89 ce 65 4f  |.R....W...bD..eO|
-00000090  a5 8d 29 8e 10 50                                 |..)..P|
+00000000  16 03 03 00 46 10 00 00  42 41 04 a0 ef 6e 6e 4f  |....F...BA...nnO|
+00000010  3f ac d1 89 57 cf 8e da  25 46 b5 50 51 68 bc 06  |?...W...%F.PQh..|
+00000020  6a b6 0b a5 82 c3 3d c3  d2 d6 70 ac 32 35 bf 62  |j.....=...p.25.b|
+00000030  e9 6f 8f a6 8b 89 68 04  a3 57 0b 7b 2b 33 a3 01  |.o....h..W.{+3..|
+00000040  b1 7e d3 7b 04 6c 68 b8  bc da ff 14 03 03 00 01  |.~.{.lh.........|
+00000050  01 16 03 03 00 40 04 25  dd 22 f7 7a 2b 55 0d f9  |.....@.%.".z+U..|
+00000060  cc 9c 3d 59 bc 4b 99 86  99 5f c2 75 fd 62 d7 6e  |..=Y.K..._.u.b.n|
+00000070  78 89 90 af 61 59 0f d3  7b 1a 3f 3b 87 09 b5 7c  |x...aY..{.?;...||
+00000080  fd 75 cc 5c f0 41 80 03  8c 7a 1d b0 50 34 32 95  |.u.\.A...z..P42.|
+00000090  8d 74 95 f9 54 cc                                 |.t..T.|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 29 56 67 0c 28  |...........)Vg.(|
-00000020  ca 74 e1 ae c6 e2 30 3b  f2 8b f0 fd c2 eb 11 c0  |.t....0;........|
-00000030  0e 50 eb d8 4e de e3 32  6b 69 77 d8 d7 bd 94 30  |.P..N..2kiw....0|
-00000040  1e bf 03 f0 31 98 d8 07  c0 27 4b 17 03 03 00 40  |....1....'K....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 bf e6 3e cf 4a  |.............>.J|
+00000020  ab 55 af 47 2b fe 01 8e  4a 9e 95 e5 39 16 b1 17  |.U.G+...J...9...|
+00000030  66 93 20 80 5a e9 cc f1  16 79 4f 37 20 60 40 c7  |f. .Z....yO7 `@.|
+00000040  c3 91 28 14 9d 35 02 72  df 66 17 17 03 03 00 40  |..(..5.r.f.....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  97 7f df af a3 9e cc a1  64 5f ab 91 8a 6f fd 19  |........d_...o..|
-00000070  be 94 95 6d bb de 12 a9  54 10 b5 95 f3 68 77 73  |...m....T....hws|
-00000080  14 09 b7 3b ca b8 88 6d  fd 0a 2d 24 c1 94 ce ce  |...;...m..-$....|
+00000060  ac 56 df 2e 4d 72 cb cf  8a 5e e7 36 8b 12 12 f3  |.V..Mr...^.6....|
+00000070  f8 31 9a 81 b9 2a 75 00  7f c7 2c 3b 86 bf 54 ac  |.1...*u...,;..T.|
+00000080  76 97 d8 e2 c5 a4 d3 2d  15 64 5e 8a 0e c9 46 f5  |v......-.d^...F.|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 04 6d b7  9e 15 51 c7 f8 de ab d0  |......m...Q.....|
-000000b0  a0 45 7f 4f bc 59 73 45  e9 a8 b1 0e 9b c3 36 c7  |.E.O.YsE......6.|
-000000c0  cb db 55 19 db                                    |..U..|
+000000a0  00 00 00 00 00 9e e7 4b  50 d0 7c a9 dd 0c 3f 9b  |.......KP.|...?.|
+000000b0  04 c9 f5 f0 88 e3 84 c0  69 05 c2 c0 83 43 5a 8c  |........i....CZ.|
+000000c0  be e4 c4 35 f0                                    |...5.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
index 0d9bb0c..f25f3e7 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 61 01 00 01  5d 03 03 17 83 43 01 d8  |....a...]....C..|
-00000010  14 04 ed 55 41 35 99 cd  f6 50 e6 47 10 60 7d d9  |...UA5...P.G.`}.|
-00000020  d1 f4 0f a1 bf 27 ab 0c  44 56 a5 00 00 c4 c0 30  |.....'..DV.....0|
+00000000  16 03 01 01 53 01 00 01  4f 03 03 66 97 e7 64 f3  |....S...O..f..d.|
+00000010  e7 d2 ba ba 31 f5 d6 ce  50 c7 48 2e 80 48 f1 1f  |....1...P.H..H..|
+00000020  6a a0 f1 da 7b 7b 45 ac  ad e9 73 00 00 b6 c0 30  |j...{{E...s....0|
 00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
 00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
 00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
@@ -13,15 +13,14 @@
 000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
 000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
 000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 14 00 11 00 0e  00 0b 00 08 00 06 00 03  |................|
-000000f0  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
-00000100  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
-00000110  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
-00000120  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
-00000130  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
-00000140  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
-00000150  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
-00000160  03 00 0f 00 01 01                                 |......|
+000000e0  00 09 00 ff 02 01 00 00  6f 00 0b 00 04 03 00 01  |........o.......|
+000000f0  02 00 0a 00 3a 00 38 00  0e 00 0d 00 19 00 1c 00  |....:.8.........|
+00000100  0b 00 0c 00 1b 00 18 00  09 00 0a 00 1a 00 16 00  |................|
+00000110  17 00 08 00 06 00 07 00  14 00 15 00 04 00 05 00  |................|
+00000120  12 00 13 00 01 00 02 00  03 00 0f 00 10 00 11 00  |................|
+00000130  0d 00 20 00 1e 06 01 06  02 06 03 05 01 05 02 05  |.. .............|
+00000140  03 04 01 04 02 04 03 03  01 03 02 03 03 02 01 02  |................|
+00000150  02 02 03 00 0f 00 01 01                           |........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -75,38 +74,38 @@
 00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000340  41 03 56 6b dc 5a 89 04  01 00 80 7f 65 76 11 35  |A.Vk.Z......ev.5|
-00000350  e1 9c c6 0c 21 41 d6 b4  22 2f a3 02 57 5c 40 5c  |....!A.."/..W\@\|
-00000360  2e 0c 5f 07 01 d1 78 29  a3 7b 65 37 1c c6 51 a8  |.._...x).{e7..Q.|
-00000370  e1 70 b4 73 9a cf 37 73  c8 ce 7c 8b 60 9e 0f e4  |.p.s..7s..|.`...|
-00000380  d7 2e 2a a8 fd 5a 0c 8a  e7 e0 4c ca 0b 28 6d ea  |..*..Z....L..(m.|
-00000390  39 da 9f ac 6c 23 f0 c6  fe 21 a8 ad fb e8 c9 6d  |9...l#...!.....m|
-000003a0  96 86 75 4d 88 f0 e8 71  e0 dc 32 b9 81 f9 f3 fe  |..uM...q..2.....|
-000003b0  64 e1 34 62 dc e2 0a 21  a3 7e 70 0d b0 f3 9d 13  |d.4b...!.~p.....|
-000003c0  5c 81 58 24 97 a9 fb 1d  99 60 a7 16 03 03 00 04  |\.X$.....`......|
+00000340  41 03 56 6b dc 5a 89 05  01 00 80 32 97 6b fe 26  |A.Vk.Z.....2.k.&|
+00000350  2f 9d b8 7d 5e cd 30 1b  24 e8 e5 d7 fd 35 7b 7b  |/..}^.0.$....5{{|
+00000360  43 23 64 ea 69 a8 30 7d  72 f4 bf 02 f5 6d bd 7e  |C#d.i.0}r....m.~|
+00000370  52 98 a2 a8 f4 43 6e 9f  bc 02 2e 5f 08 21 6e b2  |R....Cn...._.!n.|
+00000380  63 d7 63 4a b8 74 57 52  6c 04 a1 b1 1d 2c 1b ab  |c.cJ.tWRl....,..|
+00000390  ff ba e8 cf 04 eb 18 66  4d 4b 62 b8 27 e3 24 9b  |.......fMKb.'.$.|
+000003a0  5f 73 19 dc 5c 20 75 c5  e3 09 bc 00 34 75 c8 fe  |_s..\ u.....4u..|
+000003b0  b2 83 83 0f 0a b3 64 d7  52 97 d2 34 54 cf 54 88  |......d.R..4T.T.|
+000003c0  fa d7 0b cf 56 91 de 96  2f 35 de 16 03 03 00 04  |....V.../5......|
 000003d0  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 27 9e 27 b7 bf  |....F...BA.'.'..|
-00000010  b1 a9 b0 5b 7d 1c 9a 02  51 6e 03 ba 60 5a a2 50  |...[}...Qn..`Z.P|
-00000020  17 a6 2a e4 02 cd 6f ed  a2 97 49 49 0c 36 70 53  |..*...o...II.6pS|
-00000030  ce 0c 79 49 14 55 9a 7f  a6 0a 10 65 4f e4 c6 10  |..yI.U.....eO...|
-00000040  c2 31 68 5c 0e 5c ab 8a  a8 1c 52 14 03 03 00 01  |.1h\.\....R.....|
-00000050  01 16 03 03 00 40 25 59  40 9e 5b 9a d5 95 a1 59  |.....@%Y@.[....Y|
-00000060  d4 1d ea 0c 02 d1 66 29  c2 d5 d4 24 7a c7 9e 47  |......f)...$z..G|
-00000070  f7 79 a1 5f 72 fb c8 10  61 81 e8 e3 fb 16 7e 30  |.y._r...a.....~0|
-00000080  e2 cc 95 d2 24 2a 0f 94  96 b6 0a 27 1a 87 c9 36  |....$*.....'...6|
-00000090  c7 b4 e9 21 d1 94                                 |...!..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 f8 15 aa a4 68  |....F...BA.....h|
+00000010  80 59 4e 9f b5 d5 3c e5  da 4b 89 36 bf 26 cb 69  |.YN...<..K.6.&.i|
+00000020  e8 99 d8 a5 3e af 1c ac  b6 bc c9 dd c5 0b 7e d8  |....>.........~.|
+00000030  c6 6a 41 80 8d cd 1a 06  23 cd 5a db ec 67 77 fe  |.jA.....#.Z..gw.|
+00000040  e6 cc 6f bb ea b6 5d e7  03 c9 45 14 03 03 00 01  |..o...]...E.....|
+00000050  01 16 03 03 00 40 7d 9d  03 ca 10 11 dc 09 60 23  |.....@}.......`#|
+00000060  25 db b3 d2 98 2c 37 9e  d1 de 45 01 3e d7 90 ff  |%....,7...E.>...|
+00000070  48 df 65 3f 75 d6 50 21  38 c4 df 0d 24 04 33 54  |H.e?u.P!8...$.3T|
+00000080  4f 3b 95 80 a6 ab 63 07  83 5b a0 e8 68 60 95 03  |O;....c..[..h`..|
+00000090  6d 33 6e dd 88 56                                 |m3n..V|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 fe 1d f1 25 18  |..............%.|
-00000020  dd 7a 1e 10 f0 86 7f 75  74 44 a5 89 92 c8 21 ff  |.z.....utD....!.|
-00000030  b8 1b bf 79 3f 19 8e 12  04 65 58 a7 e5 96 52 3a  |...y?....eX...R:|
-00000040  15 af 57 d8 9e 46 6f 3f  0d 89 67 17 03 03 00 40  |..W..Fo?..g....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 74 52 26 02 91  |...........tR&..|
+00000020  cb 32 d9 03 3f c3 cb 31  71 19 64 8f 12 96 87 22  |.2..?..1q.d...."|
+00000030  ae da 10 2d 7d 37 d0 38  e3 b8 8d 21 ea 44 c4 3c  |...-}7.8...!.D.<|
+00000040  36 ea 0a 38 07 37 ea a2  c3 e8 02 17 03 03 00 40  |6..8.7.........@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  1b fb 13 e3 c0 eb 94 bb  4f e1 9e 47 6a ce 9b 6c  |........O..Gj..l|
-00000070  03 2f bf 0b 2f 08 36 48  b2 00 26 ab fb cc 3c 2f  |./../.6H..&...</|
-00000080  8d 99 82 86 a1 b7 15 04  f0 59 97 d7 50 61 1c a1  |.........Y..Pa..|
+00000060  24 49 ee a7 14 10 1d f9  93 9f 03 63 ab ff 54 9a  |$I.........c..T.|
+00000070  9d 26 3d 0d d1 3d ca 5b  ff 69 c8 17 89 fb 7c d2  |.&=..=.[.i....|.|
+00000080  4b a6 cd d6 91 e3 89 10  1a 6d f4 f5 ae bc 6e 96  |K........m....n.|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 95 ed 23  80 9e f5 f2 37 ac 2d 50  |.......#....7.-P|
-000000b0  3d 30 de 68 be 25 c0 72  cc c9 2d 80 41 82 f7 0e  |=0.h.%.r..-.A...|
-000000c0  2e 86 0e 07 41                                    |....A|
+000000a0  00 00 00 00 00 1f 11 a1  c3 1d 1b d0 63 09 77 2f  |............c.w/|
+000000b0  1a 6a 2c 7b cc f5 01 74  4a a4 81 36 a8 70 c6 96  |.j,{...tJ..6.p..|
+000000c0  fa 12 8e dc bf                                    |.....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
index 547f798..048d10b 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -1,11 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 65  |....\...X..R.WYe|
-00000010  ae b3 ec a4 7a 05 f7 ec  39 22 7d 8c 91 96 6b e0  |....z...9"}...k.|
-00000020  69 81 ff 88 28 17 60 ac  94 19 ff 00 00 04 00 05  |i...(.`.........|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 54 2a 20 9e ee  |....[...W..T* ..|
+00000010  10 ae 28 a1 a8 5a fd 71  a8 f7 23 35 24 60 dd 25  |..(..Z.q..#5$`.%|
+00000020  c6 fe 46 f6 b3 9d 09 0f  5f 0f af 00 00 04 00 05  |..F....._.......|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -54,9 +53,9 @@
 000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
-00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |....@...........|
-00000310  00 04 0e 00 00 00                                 |......|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 17 0d 00  |n8P)l...........|
+00000300  00 13 02 01 40 00 0c 04  01 04 03 05 01 05 03 02  |....@...........|
+00000310  01 02 03 00 00 16 03 03  00 04 0e 00 00 00        |..............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -91,32 +90,33 @@
 000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
 000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
 00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
-00000210  03 03 00 86 10 00 00 82  00 80 47 5a 2f b8 78 46  |..........GZ/.xF|
-00000220  9f 3c fc ab 8b 35 c9 77  da c3 96 78 31 7c 2b 4f  |.<...5.w...x1|+O|
-00000230  56 be 0f 33 bd 17 bc 1c  86 5a ae b3 0f 8b 18 2f  |V..3.....Z...../|
-00000240  48 0d e0 0a 20 d3 53 96  88 d2 8a 7d b6 58 13 44  |H... .S....}.X.D|
-00000250  a5 e8 19 6d 02 df a6 1b  79 c5 54 c2 ef 4d 41 4f  |...m....y.T..MAO|
-00000260  04 1c eb 37 55 b7 2b f4  7c 6d 37 9c f1 89 a0 2c  |...7U.+.|m7....,|
-00000270  0f ba 10 09 e4 a1 ee 0a  7e 9a fd 2c 32 63 1c 55  |........~..,2c.U|
-00000280  85 38 de d0 7b 5f 46 03  1f cc 4d 69 51 97 d8 d7  |.8..{_F...MiQ...|
-00000290  88 6f ba 43 04 b0 42 09  61 5e 16 03 03 00 92 0f  |.o.C..B.a^......|
-000002a0  00 00 8e 04 03 00 8a 30  81 87 02 41 14 3d 4c 71  |.......0...A.=Lq|
-000002b0  c2 32 4a 20 ee b7 69 17  55 e8 99 55 11 76 51 7a  |.2J ..i.U..U.vQz|
-000002c0  74 55 e7 e8 c3 3b b3 70  db 1c 8e f6 8a d4 99 40  |tU...;.p.......@|
-000002d0  6e da 04 fd 7a 47 41 d6  ae c0 63 ad fd 91 a8 58  |n...zGA...c....X|
-000002e0  24 b9 ac 2f 7a 4c bf 5b  24 12 cb 3a f3 02 42 00  |$../zL.[$..:..B.|
-000002f0  90 f9 48 97 0e d4 33 99  09 9f 1d a8 97 16 60 82  |..H...3.......`.|
-00000300  85 cc 5a 5d 79 f7 2f 03  2a c0 b8 12 61 ac 9f 88  |..Z]y./.*...a...|
-00000310  1d 0d 9e 0a ee 28 a8 5a  e2 42 b7 94 e2 e6 0e 13  |.....(.Z.B......|
-00000320  c8 64 dc 4e d3 6b 10 d6  83 41 9c dc d4 53 c3 08  |.d.N.k...A...S..|
-00000330  19 14 03 03 00 01 01 16  03 03 00 24 ef bd e3 23  |...........$...#|
-00000340  10 23 ae 6e b5 12 eb 9c  21 78 db 36 fd bf 7f ee  |.#.n....!x.6....|
-00000350  6f c8 00 2d b6 35 cc 2f  38 73 ae a4 34 cf 0d df  |o..-.5./8s..4...|
+00000210  03 03 00 86 10 00 00 82  00 80 51 0a a7 21 d3 f5  |..........Q..!..|
+00000220  f2 16 ba b1 a0 15 58 ef  d6 a1 cd 03 fe b6 95 84  |......X.........|
+00000230  35 c4 c1 0b d2 8a 01 af  3d 01 15 29 1d 2d 1e c9  |5.......=..).-..|
+00000240  12 0e df 49 87 8a 3a 67  c3 6a a6 04 10 3d 45 e4  |...I..:g.j...=E.|
+00000250  cb d3 aa 37 29 5a 45 6f  f4 20 8c 85 9d 1b 0e 95  |...7)ZEo. ......|
+00000260  f4 0e 03 e5 0f 85 fc e1  20 3e 0f 44 f9 8e fe 28  |........ >.D...(|
+00000270  65 2b ae 12 18 72 26 dd  22 96 31 81 27 dd f7 69  |e+...r&.".1.'..i|
+00000280  b4 90 93 a4 0c f5 b6 f8  73 f3 85 f5 c5 03 1d 74  |........s......t|
+00000290  1a 83 e0 5c 77 bc 41 00  85 bc 16 03 03 00 93 0f  |...\w.A.........|
+000002a0  00 00 8f 04 03 00 8b 30  81 88 02 42 01 33 86 47  |.......0...B.3.G|
+000002b0  4d 91 1a 71 e5 64 25 f2  0b 88 14 34 8d ca e5 d0  |M..q.d%....4....|
+000002c0  09 5b b7 c0 c2 e5 2c 0d  05 36 ee cc 11 1b 6a 8b  |.[....,..6....j.|
+000002d0  ff 15 0c 7f c2 c4 8d 4a  13 33 2f fa ba c9 ae 58  |.......J.3/....X|
+000002e0  97 5a 96 17 e3 df 69 f1  d4 a6 23 7a ef a0 02 42  |.Z....i...#z...B|
+000002f0  01 2a 94 f3 db 84 42 64  85 5b 31 27 c2 72 c2 24  |.*....Bd.[1'.r.$|
+00000300  74 b0 78 e6 ba 09 3d 9f  83 2d 28 29 12 c4 ac 8b  |t.x...=..-()....|
+00000310  e0 32 d2 30 2e 06 53 15  85 3c 29 a9 a5 13 98 93  |.2.0..S..<).....|
+00000320  f4 76 02 96 6a 60 3f 0f  ad 85 b7 66 49 03 c1 2a  |.v..j`?....fI..*|
+00000330  bc 86 14 03 03 00 01 01  16 03 03 00 24 fc e5 8a  |............$...|
+00000340  f9 82 bd 89 d7 db e3 53  09 85 01 cc bc 25 93 96  |.......S.....%..|
+00000350  d3 74 c7 e9 15 f3 e1 f9  01 6e 77 08 92 39 69 b5  |.t.......nw..9i.|
+00000360  43                                                |C|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 a7 50 0f 50 b4  |..........$.P.P.|
-00000010  1c c3 4d f3 7a 64 df 65  ac 35 22 13 46 cc ec 36  |..M.zd.e.5".F..6|
-00000020  e6 d2 f3 67 94 6a 18 85  9f 4a 3c 44 a3 58 b0 17  |...g.j...J<D.X..|
-00000030  03 03 00 21 51 0a 41 8c  fd 50 e3 54 8b 6a 1f 83  |...!Q.A..P.T.j..|
-00000040  a5 37 98 e1 5b 1e ec 03  1d c7 0e 28 6d 79 3f 34  |.7..[......(my?4|
-00000050  de 1c 38 6d 7e 15 03 03  00 16 06 fc b1 7d ad 70  |..8m~........}.p|
-00000060  1a de d4 b7 b5 e7 a2 6d  1b 9a b0 31 0c cc 7b 70  |.......m...1..{p|
+00000000  14 03 03 00 01 01 16 03  03 00 24 55 7c a6 2d 0a  |..........$U|.-.|
+00000010  bb c0 bb cb 23 91 93 e6  83 d3 c2 17 fa 2f d8 fa  |....#......../..|
+00000020  3c 1a e2 50 af f8 e4 97  4b e2 0c 3d 60 cc b0 17  |<..P....K..=`...|
+00000030  03 03 00 21 8d b8 db 0d  4c 1d 99 93 b8 65 dc db  |...!....L....e..|
+00000040  1b ff 77 29 a5 41 34 23  e4 24 43 a1 3f 5e 5f b2  |..w).A4#.$C.?^_.|
+00000050  35 49 6e 1c 94 15 03 03  00 16 37 ed 78 ef 5d c6  |5In.......7.x.].|
+00000060  32 1d 72 1e 2f 02 84 f0  c7 1f 89 83 00 e6 3b a5  |2.r./.........;.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
index 04a5b11..2b5b711 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -1,11 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 6b  |....\...X..R.WYk|
-00000010  11 07 04 39 77 20 c2 b4  3f cb 0a c9 53 fe 5b 3e  |...9w ..?...S.[>|
-00000020  5f 58 2c 7e 30 69 e1 8e  6c 9d c8 00 00 04 00 05  |_X,~0i..l.......|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 de ba cc 44 30  |....[...W.....D0|
+00000010  69 67 7f 91 d6 08 2c d0  1f 5c 60 d5 a5 76 c7 15  |ig....,..\`..v..|
+00000020  fd fd 83 a0 20 b3 63 c1  ed 06 d3 00 00 04 00 05  |.... .c.........|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -54,9 +53,9 @@
 000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
-00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |....@...........|
-00000310  00 04 0e 00 00 00                                 |......|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 17 0d 00  |n8P)l...........|
+00000300  00 13 02 01 40 00 0c 04  01 04 03 05 01 05 03 02  |....@...........|
+00000310  01 02 03 00 00 16 03 03  00 04 0e 00 00 00        |..............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
 00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
@@ -90,32 +89,32 @@
 000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
 000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
 000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
-00000200  16 03 03 00 86 10 00 00  82 00 80 44 89 7d aa 26  |...........D.}.&|
-00000210  30 ce 6b db 25 70 b0 1e  16 fa 5b 3a dd 4a 4b bd  |0.k.%p....[:.JK.|
-00000220  ec ee 50 9d 21 ba 52 b5  51 4f a8 65 d8 2e 41 e2  |..P.!.R.QO.e..A.|
-00000230  e1 dc f3 1a df 58 4f 87  7a d3 e1 e1 1c 13 b2 0b  |.....XO.z.......|
-00000240  b7 43 b7 92 f2 df 19 bb  79 71 e0 71 44 ab 19 2f  |.C......yq.qD../|
-00000250  37 11 ac 62 50 b6 f1 53  fe aa b4 bc 29 8e 0b 4c  |7..bP..S....)..L|
-00000260  0b 12 8d d5 84 a9 fa a9  ea 16 aa c3 0d da 32 c8  |..............2.|
-00000270  e0 4c 9f 99 f8 69 cd a8  c3 b1 76 42 67 f3 ff 15  |.L...i....vBg...|
-00000280  52 95 43 66 da 49 43 25  9d e5 eb 16 03 03 00 88  |R.Cf.IC%........|
-00000290  0f 00 00 84 04 01 00 80  01 d5 0e 1c 75 97 89 52  |............u..R|
-000002a0  1a f0 cc ef 93 6e 71 b2  b1 38 8c 50 11 f7 a3 02  |.....nq..8.P....|
-000002b0  71 c4 d5 6f 8d 01 83 06  2e ea 5a 10 8a 0d d0 fc  |q..o......Z.....|
-000002c0  b6 a2 63 af 4f 99 b5 eb  ab fd 01 c2 fb 26 fc fd  |..c.O........&..|
-000002d0  ad 2c b3 63 b3 87 a6 f5  14 ea 7d e7 fe a8 e7 7e  |.,.c......}....~|
-000002e0  20 ab b9 f6 c3 58 bd c0  f3 96 eb 83 dc 42 6c 0d  | ....X.......Bl.|
-000002f0  5e e8 09 55 c7 b8 24 05  dd e1 7c af 9f 2c 22 6c  |^..U..$...|..,"l|
-00000300  fa b8 94 13 3b f1 09 e1  38 59 fc a1 8c cb aa ca  |....;...8Y......|
-00000310  f8 e0 2a 9c 36 f9 c3 2b  14 03 03 00 01 01 16 03  |..*.6..+........|
-00000320  03 00 24 d0 12 7c cc d2  3e 37 1f f4 7d b4 c0 fc  |..$..|..>7..}...|
-00000330  19 f6 c8 ea 62 12 e0 0d  af 62 d4 69 f7 96 5a c0  |....b....b.i..Z.|
-00000340  97 d3 bb b0 a3 f7 3f                              |......?|
+00000200  16 03 03 00 86 10 00 00  82 00 80 6c 19 7b fb 96  |...........l.{..|
+00000210  52 57 c1 8b 78 72 4b 67  c9 66 ce 61 71 6c 83 90  |RW..xrKg.f.aql..|
+00000220  56 90 fc bc 40 41 12 30  bf 3f 20 58 75 3d 31 45  |V...@A.0.? Xu=1E|
+00000230  67 61 57 fc 0f 48 1d e1  a4 ec 75 4d bc e3 09 62  |gaW..H....uM...b|
+00000240  98 8e 40 cb 53 cb 97 31  32 b7 20 f3 dd 5d 29 62  |..@.S..12. ..])b|
+00000250  90 18 94 98 84 d8 42 34  fc a4 35 80 55 46 32 a1  |......B4..5.UF2.|
+00000260  6f 0e d2 33 c3 53 6a 46  87 74 fd 68 15 35 b8 c4  |o..3.SjF.t.h.5..|
+00000270  2b da b4 55 9c 6e 87 94  01 6a 72 12 8a 01 8a 37  |+..U.n...jr....7|
+00000280  ac 5b d7 55 27 40 58 fc  0d 30 12 16 03 03 00 88  |.[.U'@X..0......|
+00000290  0f 00 00 84 04 01 00 80  06 71 c6 af f8 53 b9 eb  |.........q...S..|
+000002a0  9a 99 44 fa 65 dc af cc  69 b4 cf 10 fc b0 f2 33  |..D.e...i......3|
+000002b0  da 8a 3f cb f1 8d 51 ae  90 7d f3 02 57 0e ea b9  |..?...Q..}..W...|
+000002c0  37 2d 2e dc ad 89 44 04  4f 21 04 44 54 9f 9e 92  |7-....D.O!.DT...|
+000002d0  7e b7 4c 53 b8 3c 89 c0  c1 1e f7 df cc c6 2f 76  |~.LS.<......../v|
+000002e0  be 91 bc a0 4d c7 e1 df  9d 19 e3 0d ab 17 e4 d4  |....M...........|
+000002f0  c3 4c 75 e2 71 5c a3 df  9a 17 82 38 2a 4b f8 ae  |.Lu.q\.....8*K..|
+00000300  ad 13 a7 f3 13 f8 72 78  49 fe 80 d9 bd 77 a3 48  |......rxI....w.H|
+00000310  43 a7 76 00 15 1a 14 5d  14 03 03 00 01 01 16 03  |C.v....]........|
+00000320  03 00 24 1d 80 33 0a 75  ae d5 13 d5 46 f9 89 3d  |..$..3.u....F..=|
+00000330  15 95 f2 c5 2d c5 e0 7f  cc 6e d7 36 9f 72 d6 74  |....-....n.6.r.t|
+00000340  7b c1 4f ed 89 ff c1                              |{.O....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 cd 20 85 1e 74  |..........$. ..t|
-00000010  18 b2 71 48 d5 10 61 c6  b0 18 26 83 c2 7f f1 b1  |..qH..a...&.....|
-00000020  2f b5 35 d0 47 a8 99 9a  9a a5 62 64 fb f9 29 17  |/.5.G.....bd..).|
-00000030  03 03 00 21 22 7b ed 61  e3 9b 6d 98 b9 23 98 e3  |...!"{.a..m..#..|
-00000040  55 11 b8 0f 7e 2b e1 c1  d4 f1 83 79 c3 f8 03 f0  |U...~+.....y....|
-00000050  02 5c 61 24 d7 15 03 03  00 16 14 2b a3 5a 56 f0  |.\a$.......+.ZV.|
-00000060  92 da d0 e6 32 91 d8 30  7a b4 d0 a2 93 f5 01 ea  |....2..0z.......|
+00000000  14 03 03 00 01 01 16 03  03 00 24 6c f7 56 21 17  |..........$l.V!.|
+00000010  3d d6 ad 06 34 a6 0d a0  22 b6 26 38 a2 b2 39 52  |=...4...".&8..9R|
+00000020  8a cb 0e 5b b2 f6 32 b2  da 71 8a 72 13 40 f2 17  |...[..2..q.r.@..|
+00000030  03 03 00 21 69 bc 35 92  9c 17 4d aa ce 85 35 35  |...!i.5...M...55|
+00000040  98 8e c3 ff fd 36 9b 47  dd a7 85 8a 20 05 05 b8  |.....6.G.... ...|
+00000050  87 31 66 41 a0 15 03 03  00 16 e9 28 e0 39 fe da  |.1fA.......(.9..|
+00000060  b1 0a c3 22 cf 9e 33 60  b9 52 18 ad 03 c8 ee 6b  |..."..3`.R.....k|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
index 562fe1a..698409c 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -1,11 +1,10 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 1b  |....\...X..R.WY.|
-00000010  08 fe f7 8a bf 07 84 2b  60 a6 13 2d 15 13 f8 b6  |.......+`..-....|
-00000020  d4 b6 3b f2 7a 98 ff 32  a0 68 7c 00 00 04 00 05  |..;.z..2.h|.....|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
-00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000000  16 03 01 00 5b 01 00 00  57 03 03 72 1e c6 5e 14  |....[...W..r..^.|
+00000010  4d 88 9c 2c 6e fb bb bb  37 26 f7 0f 06 d5 e8 aa  |M..,n...7&......|
+00000020  53 e0 df d0 de 81 f8 33  b1 86 ff 00 00 04 00 05  |S......3........|
+00000030  00 ff 02 01 00 00 29 00  0d 00 20 00 1e 06 01 06  |......)... .....|
+00000040  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000050  01 03 02 03 03 02 01 02  02 02 03 00 0f 00 01 01  |................|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -54,28 +53,28 @@
 000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
-00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |....@...........|
-00000310  00 04 0e 00 00 00                                 |......|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 17 0d 00  |n8P)l...........|
+00000300  00 13 02 01 40 00 0c 04  01 04 03 05 01 05 03 02  |....@...........|
+00000310  01 02 03 00 00 16 03 03  00 04 0e 00 00 00        |..............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 07 0b 00 00  03 00 00 00 16 03 03 00  |................|
-00000010  86 10 00 00 82 00 80 6b  51 48 d3 18 7d 30 e0 0c  |.......kQH..}0..|
-00000020  20 8d f3 e4 39 47 30 0e  a5 85 79 f9 8b 11 50 9e  | ...9G0...y...P.|
-00000030  81 71 5c 26 c6 bb cb aa  d5 00 d1 89 79 b1 77 2d  |.q\&........y.w-|
-00000040  eb 9b 86 7c 52 c6 f7 b7  10 b0 b6 94 22 51 b8 12  |...|R......."Q..|
-00000050  3c 09 35 8e 1b cc f4 3b  b7 b8 78 ab 89 59 41 49  |<.5....;..x..YAI|
-00000060  21 31 eb f0 f8 94 63 3d  e6 96 8f b6 63 95 05 dd  |!1....c=....c...|
-00000070  46 b3 00 8a d6 83 75 99  1b 5a 48 0a 23 b5 10 c1  |F.....u..ZH.#...|
-00000080  95 b5 bc 15 72 b5 f5 a0  62 e2 1d c0 ff d2 87 a5  |....r...b.......|
-00000090  97 5c 33 49 a7 26 35 14  03 03 00 01 01 16 03 03  |.\3I.&5.........|
-000000a0  00 24 61 38 1f 9d fb d9  65 2e 02 07 fb be f9 85  |.$a8....e.......|
-000000b0  8d 15 34 c0 d1 0e 4e 10  3c 25 60 2f ac 04 21 66  |..4...N.<%`/..!f|
-000000c0  04 9d 9a 60 31 72                                 |...`1r|
+00000010  86 10 00 00 82 00 80 5b  13 f1 87 cb 3b f1 72 32  |.......[....;.r2|
+00000020  a0 24 fd ea 6a b1 de 7d  54 4a ff a5 b0 01 8f de  |.$..j..}TJ......|
+00000030  95 d1 a9 7f d4 1d 97 0f  52 cb 9b 60 5d cb 37 d0  |........R..`].7.|
+00000040  37 eb 8f 2b c6 08 86 b7  d2 87 8e 12 78 af a8 a3  |7..+........x...|
+00000050  a5 35 cc b7 33 25 60 9a  cb 4e b9 b9 51 e0 4c 69  |.5..3%`..N..Q.Li|
+00000060  7b 2f 68 39 9e 40 c0 0c  77 4f 04 f5 47 7f 45 55  |{/h9.@..wO..G.EU|
+00000070  e9 90 f1 9e df 11 4a af  9f cc 7e 96 31 d7 b4 d2  |......J...~.1...|
+00000080  bb 0d 03 56 9b 97 4e 40  53 af 2d c0 2a f9 29 8e  |...V..N@S.-.*.).|
+00000090  82 d0 f7 9a 89 59 5f 14  03 03 00 01 01 16 03 03  |.....Y_.........|
+000000a0  00 24 d1 27 e7 27 e2 a4  81 4e 02 be 66 7e 78 44  |.$.'.'...N..f~xD|
+000000b0  ee 40 84 f7 fa 17 ad 6e  99 5c 48 df bb c0 94 f5  |.@.....n.\H.....|
+000000c0  a2 c6 30 6d 2d 08                                 |..0m-.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 fe 0e 3e 84 af  |..........$..>..|
-00000010  e5 6b 10 ed 41 9c 2b e0  ba e0 2b 53 61 36 1b 40  |.k..A.+...+Sa6.@|
-00000020  35 de 3a c7 c3 5c df 74  67 f7 05 74 84 f5 e1 17  |5.:..\.tg..t....|
-00000030  03 03 00 21 d3 8d 81 85  b7 1f 30 bd 89 33 f9 81  |...!......0..3..|
-00000040  89 f7 af d1 be b0 c1 46  e3 df 32 f6 dc 2f 4d 82  |.......F..2../M.|
-00000050  0a 84 9f 5b 03 15 03 03  00 16 13 af 37 91 82 67  |...[........7..g|
-00000060  b0 7c 5e 0e ec 8e cc 31  a0 ea a5 72 a4 2b 0b 73  |.|^....1...r.+.s|
+00000000  14 03 03 00 01 01 16 03  03 00 24 41 b5 43 2a 5c  |..........$A.C*\|
+00000010  f5 f6 e1 b5 a2 cc 1c c8  86 ae cc a2 0c c4 6b 73  |..............ks|
+00000020  ab 3d 91 09 04 6d e0 18  af 85 dd 90 9a eb 44 17  |.=...m........D.|
+00000030  03 03 00 21 74 b4 fd cb  c4 7b 81 67 76 18 0f b3  |...!t....{.gv...|
+00000040  b7 3f 30 2f c9 86 23 f1  79 38 ef 0c da 52 b7 ab  |.?0/..#.y8...R..|
+00000050  f7 9a ca 27 73 15 03 03  00 16 37 2b 19 cc bd f9  |...'s.....7+....|
+00000060  cd 14 30 21 4f c0 45 e9  e7 ac 7c c4 93 51 f6 aa  |..0!O.E...|..Q..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
index 0e480be..3b7238a 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -1,7 +1,7 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 a1 01 00 00  9d 03 03 eb 02 58 55 90  |.............XU.|
-00000010  a0 ba 80 52 28 a5 36 35  ee 6d eb e1 b0 d3 5d 89  |...R(.65.m....].|
-00000020  e8 2d a3 5e b1 83 e8 2f  00 f2 1e 00 00 04 c0 0a  |.-.^.../........|
+00000000  16 03 01 00 a1 01 00 00  9d 03 03 0f b7 07 5f c7  |.............._.|
+00000010  18 b8 39 6d 92 b3 90 ed  bf 5c 48 7c 6a 56 ee e9  |..9m.....\H|jV..|
+00000020  7a 5b 5f 71 a4 f0 7f 47  57 73 78 00 00 04 c0 0a  |z[_q...GWsx.....|
 00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
 00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
 00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
@@ -47,43 +47,43 @@
 00000210  0e bd 3f a3 8c 25 c1 33  13 83 0d 94 06 bb d4 37  |..?..%.3.......7|
 00000220  7a f6 ec 7a c9 86 2e dd  d7 11 69 7f 85 7c 56 de  |z..z......i..|V.|
 00000230  fb 31 78 2b e4 c7 78 0d  ae cb be 9e 4e 36 24 31  |.1x+..x.....N6$1|
-00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d7 0c 00  |{j.9....*.......|
-00000250  00 d3 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d8 0c 00  |{j.9....*.......|
+00000250  00 d4 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
 00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000290  41 03 56 6b dc 5a 89 04  03 00 8a 30 81 87 02 41  |A.Vk.Z.....0...A|
-000002a0  68 cb cd c0 12 5e 1e b3  cc d9 47 e7 b5 11 5e be  |h....^....G...^.|
-000002b0  74 5b 90 93 3f 4c 07 20  a1 94 50 bb 23 82 fc 5b  |t[..?L. ..P.#..[|
-000002c0  78 87 a3 a1 fe 7c 6f 84  93 8f b8 f7 2e 56 65 85  |x....|o......Ve.|
-000002d0  1d 9e 8e 52 b0 89 b0 a7  66 58 98 55 30 64 94 91  |...R....fX.U0d..|
-000002e0  8e 02 42 01 3d 74 eb a4  64 9e 7c 8b 05 57 5c f7  |..B.=t..d.|..W\.|
-000002f0  fe a7 58 f4 21 7b 75 ea  51 1e 1c be 80 4e 00 d1  |..X.!{u.Q....N..|
-00000300  06 80 58 90 c2 f3 47 da  22 8b a2 6b f0 2e 34 d0  |..X...G."..k..4.|
-00000310  1a 84 54 87 62 96 b9 2c  91 9f 3f 93 24 df 6c a3  |..T.b..,..?.$.l.|
-00000320  77 1f d2 e4 30 16 03 03  00 04 0e 00 00 00        |w...0.........|
+00000290  41 03 56 6b dc 5a 89 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
+000002a0  00 d3 cf 21 cd 3c 2e 11  f5 f8 1d c8 c1 57 4b f8  |...!.<.......WK.|
+000002b0  1a c0 2b 1d 47 0f 2d a5  ac a1 c8 83 5d 76 87 05  |..+.G.-.....]v..|
+000002c0  2b 0d 36 d5 57 9f b9 8a  a0 a2 94 67 6a cd 29 db  |+.6.W......gj.).|
+000002d0  04 b0 6b 06 d9 f7 17 9f  1c 60 92 e7 4e 50 48 7f  |..k......`..NPH.|
+000002e0  dc d0 02 42 01 56 fd 38  bd 05 a5 16 6d 91 d1 ce  |...B.V.8....m...|
+000002f0  bb 8c 45 b2 76 2f 92 9c  8b 94 57 7d de 53 8b 7b  |..E.v/....W}.S.{|
+00000300  80 26 6c 4a 43 4b a6 c9  46 49 08 ab c7 57 f3 d9  |.&lJCK..FI...W..|
+00000310  fa 1d 55 fe 91 de 8a 0d  8b d1 44 96 87 85 cb 02  |..U.......D.....|
+00000320  76 9c 00 ad 5f b8 16 03  03 00 04 0e 00 00 00     |v..._..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 04 12 72 83 8c  |....F...BA...r..|
-00000010  55 75 c4 34 48 5d d4 e3  9a 34 54 46 83 2f 69 36  |Uu.4H]...4TF./i6|
-00000020  e2 98 65 4d d2 b3 d4 6e  35 93 42 80 02 bd 26 a4  |..eM...n5.B...&.|
-00000030  ca 53 8d 50 c8 78 ec e3  0d 68 31 12 11 fe 76 52  |.S.P.x...h1...vR|
-00000040  0d 2f 63 76 43 74 5b 55  bd 9a 01 14 03 03 00 01  |./cvCt[U........|
-00000050  01 16 03 03 00 40 5f b8  b6 b9 cd 93 37 67 53 6f  |.....@_.....7gSo|
-00000060  cd 2d c6 c2 92 28 d6 ab  b7 31 ab 75 99 c8 83 7d  |.-...(...1.u...}|
-00000070  99 69 03 2d 52 6f ae 06  ec 34 05 fc 3b dd d0 0b  |.i.-Ro...4..;...|
-00000080  22 4a 84 cd 86 6c 11 10  3d 0d 9c 0f c8 c9 24 a6  |"J...l..=.....$.|
-00000090  f3 e6 e7 87 31 13                                 |....1.|
+00000000  16 03 03 00 46 10 00 00  42 41 04 0b dc ea 22 05  |....F...BA....".|
+00000010  44 c2 09 47 65 31 3b 0b  e1 05 1a 87 8c 2d 3b 56  |D..Ge1;......-;V|
+00000020  49 34 27 3e d6 3b 93 e2  12 7f 5d 7b dc 85 c8 96  |I4'>.;....]{....|
+00000030  4c 8c f9 18 6f 15 cf db  6e 2c 14 6a c9 dd 1c 70  |L...o...n,.j...p|
+00000040  7e 05 c4 17 71 76 df 10  ee 8c b1 14 03 03 00 01  |~...qv..........|
+00000050  01 16 03 03 00 40 ff 12  88 36 3c 00 17 d1 b9 41  |.....@...6<....A|
+00000060  7a 12 25 94 4c 90 65 62  d8 09 ab f9 b4 ee c3 de  |z.%.L.eb........|
+00000070  46 2f cb ee 18 76 4f 76  8e dd 89 fc 7a 21 3b 5f  |F/...vOv....z!;_|
+00000080  ff ac 1c 03 aa be 96 82  82 ea 2e 22 2a 80 b3 86  |..........."*...|
+00000090  38 e4 4d 90 91 46                                 |8.M..F|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 a9 71 da 7a 3d  |............q.z=|
-00000020  c1 17 da fa 05 ac ed a6  79 79 31 67 83 de 86 92  |........yy1g....|
-00000030  de 7e 6f 5c dc d7 e8 29  df 51 15 a1 6f 38 84 a5  |.~o\...).Q..o8..|
-00000040  a6 e4 f2 56 8a cc bf ad  f4 b8 0c 17 03 03 00 40  |...V...........@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 e5 c1 f0 6a db  |..............j.|
+00000020  05 98 ed 33 94 73 7f 13  7f 78 17 7f d1 9e c5 a7  |...3.s...x......|
+00000030  62 7f 85 14 2c 7d b2 8e  ef 75 a9 df 92 cc 22 20  |b...,}...u...." |
+00000040  66 08 85 22 d3 ea 5c 4c  4c c8 d7 17 03 03 00 40  |f.."..\LL......@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  b1 a6 a1 eb f4 26 ef e9  25 7d c8 b5 a5 4b dc c8  |.....&..%}...K..|
-00000070  32 58 d6 c3 94 e7 f7 20  10 9e a1 db 10 db e4 42  |2X..... .......B|
-00000080  3c c5 26 e7 70 f2 d7 f0  38 10 a7 63 61 22 1b 57  |<.&.p...8..ca".W|
+00000060  f2 20 07 d2 13 ca ed 01  c9 7b 91 14 01 2c 08 f5  |. .......{...,..|
+00000070  8a 69 94 bc 19 9a d9 65  6b 15 04 b4 45 17 ec 6f  |.i.....ek...E..o|
+00000080  85 de 31 dc a2 de 8b 4d  53 57 66 4a 29 21 5a 20  |..1....MSWfJ)!Z |
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 29 ea 96  ea 08 88 6c 5d 67 91 f7  |.....).....l]g..|
-000000b0  31 8e b8 3a 9a d5 87 2a  81 2f 80 fb 7f b5 80 03  |1..:...*./......|
-000000c0  9c 8b 7e 39 7b                                    |..~9{|
+000000a0  00 00 00 00 00 55 15 f7  89 8d 75 57 7e 92 db ec  |.....U....uW~...|
+000000b0  32 ec 07 5c 83 32 36 59  61 f1 9d a6 7a eb 76 c1  |2..\.26Ya...z.v.|
+000000c0  c7 96 3f 4d 0a                                    |..?M.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
index e3e62f2..b20ad95 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -1,11 +1,11 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 60 01 00 00  5c 03 03 52 cc 57 59 7e  |....`...\..R.WY~|
-00000010  43 5c 3b fd 50 ab 61 3f  64 a4 f9 bd ba 8c 28 e1  |C\;.P.a?d.....(.|
-00000020  f9 a1 45 7e 48 9e 62 af  25 de 0e 00 00 04 00 05  |..E~H.b.%.......|
-00000030  00 ff 01 00 00 2f 00 23  00 00 00 0d 00 22 00 20  |...../.#.....". |
-00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
-00000060  00 0f 00 01 01                                    |.....|
+00000000  16 03 01 00 5f 01 00 00  5b 03 03 01 02 22 4f 51  |...._...[...."OQ|
+00000010  53 d9 c0 f2 4b 61 53 2d  04 cd ab 95 ed 6a 74 8c  |S...KaS-.....jt.|
+00000020  96 00 70 e3 bf d0 5a 03  7a 1e 75 00 00 04 00 05  |..p...Z.z.u.....|
+00000030  00 ff 02 01 00 00 2d 00  23 00 00 00 0d 00 20 00  |......-.#..... .|
+00000040  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000050  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000060  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -57,31 +57,32 @@
 000002f0  71 99 9b 26 6e 38 50 29  6c 90 a7 bd d9 16 03 03  |q..&n8P)l.......|
 00000300  00 04 0e 00 00 00                                 |......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 6e 2e 79 82 3a  |...........n.y.:|
-00000010  c4 68 72 f5 a2 42 3d 71  f9 ec 22 8c 0b fa f0 82  |.hr..B=q..".....|
-00000020  82 c0 cb fc 52 0a 51 03  04 8c eb 4a 4e 4f b6 49  |....R.Q....JNO.I|
-00000030  ef 94 65 21 3c f7 9d 46  85 6e 35 d5 17 6b ff a3  |..e!<..F.n5..k..|
-00000040  5e 4d c1 36 1a 2f 68 f5  06 d4 2d 73 4f 1c 3b 7b  |^M.6./h...-sO.;{|
-00000050  c1 fa 4e 7e 7c f9 6c 13  a6 f4 3a 43 e9 aa be 22  |..N~|.l...:C..."|
-00000060  85 6f 2f 7c 5b b0 08 e2  86 b2 ae cb a9 12 d8 32  |.o/|[..........2|
-00000070  80 1d e4 2e 5d c3 66 d1  19 e5 89 33 2a 88 24 40  |....].f....3*.$@|
-00000080  2a 6d 6b b5 f1 92 4b 66  06 b8 49 14 03 03 00 01  |*mk...Kf..I.....|
-00000090  01 16 03 03 00 24 16 49  e2 a0 67 31 cf 0d 72 cb  |.....$.I..g1..r.|
-000000a0  ac 16 2c 80 37 71 69 f7  5f c4 d3 00 19 b7 4b fb  |..,.7qi._.....K.|
-000000b0  e5 e9 74 8e 30 b3 1c c5  ae e6                    |..t.0.....|
+00000000  16 03 03 00 86 10 00 00  82 00 80 80 38 a6 b0 01  |............8...|
+00000010  2a 9e cf 11 34 45 e8 6d  f5 1c 44 ef 74 74 61 32  |*...4E.m..D.tta2|
+00000020  71 5f f8 c1 a9 65 2d af  7e 7e 38 84 d3 f2 b9 3d  |q_...e-.~~8....=|
+00000030  76 12 b8 e0 41 7e 25 2a  53 b0 1a c7 8d bd d6 3d  |v...A~%*S......=|
+00000040  a5 8a dd 94 76 80 fc 3e  fd 41 ac 71 c3 ad 0e 1f  |....v..>.A.q....|
+00000050  30 a7 7a 64 e2 f3 f7 c1  1f bc 53 99 35 4e 24 34  |0.zd......S.5N$4|
+00000060  e9 25 20 d0 da 00 30 d4  16 40 5e 78 8e 72 ea 03  |.% ...0..@^x.r..|
+00000070  9e eb ca 89 4e 2f 60 d0  0c 9d 98 44 e0 7c 19 a4  |....N/`....D.|..|
+00000080  ec 0f 6b 67 35 06 08 9c  d9 2d bb 14 03 03 00 01  |..kg5....-......|
+00000090  01 16 03 03 00 24 ca d6  25 be 3b a7 b0 e1 42 3b  |.....$..%.;...B;|
+000000a0  ce ef a5 7e b6 4a d5 74  e1 ca bf 34 6c 67 3b 02  |...~.J.t...4lg;.|
+000000b0  0a f5 e8 e7 d1 a8 a6 2d  cb 02                    |.......-..|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 4b d1 ef ba 06 38 1e  e1 88 82 3a cd 03 ac 3b  |.K....8....:...;|
-00000030  39 0a e0 19 fd af 6c 57  30 df 31 6e f7 92 38 4b  |9.....lW0.1n..8K|
-00000040  5d 77 90 39 ff 32 51 f5  ed 12 d7 b0 7c 4d 6c c5  |]w.9.2Q.....|Ml.|
-00000050  76 e4 72 48 3e 59 23 fe  0d 15 df f4 ba ea b9 67  |v.rH>Y#........g|
-00000060  16 23 8f 7d 15 b6 11 f1  ab d7 d4 cd a3 21 82 92  |.#.}.........!..|
-00000070  2a 12 cf 95 f3 60 b2 14  03 03 00 01 01 16 03 03  |*....`..........|
-00000080  00 24 89 ad 87 04 4f 08  dc 2a 71 37 fb f1 95 d1  |.$....O..*q7....|
-00000090  2e 3c c2 6e 0f 38 5d e4  0e c3 f7 27 d0 46 a3 c1  |.<.n.8]....'.F..|
-000000a0  a8 3b 06 ed 96 ec 17 03  03 00 21 30 d4 9f 0b 49  |.;........!0...I|
-000000b0  9f a2 a8 a1 2c 0a 79 93  56 2d 8a ee 85 ed 62 42  |....,.y.V-....bB|
-000000c0  8c 18 fe 7a 09 3a 24 c4  5e ed 7d 2a 15 03 03 00  |...z.:$.^.}*....|
-000000d0  16 a0 24 0a 8b 90 4c fc  99 ba 67 bb 04 1e 59 69  |..$...L...g...Yi|
-000000e0  c2 98 49 b5 00 0b e0                              |..I....|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f 2c b5 83 61 e8 c1 5d  af d6 da c9 8f df 1e c4  |o,..a..]........|
+00000040  16 47 a0 dd cf 3c 9d 95  11 fe 01 fb 52 5b d0 aa  |.G...<......R[..|
+00000050  56 fb 04 d5 7f 89 31 7d  75 e3 df f4 28 6a fb 1f  |V.....1}u...(j..|
+00000060  76 ee 77 55 0b 33 94 82  e2 ee 73 2f 7f a7 f6 7c  |v.wU.3....s/...||
+00000070  68 25 eb fd 56 5b 89 29  b4 32 b6 92 57 3f c3 f9  |h%..V[.).2..W?..|
+00000080  01 fb 01 25 7f 0f 10 14  03 03 00 01 01 16 03 03  |...%............|
+00000090  00 24 9a 9b 1b 57 2c 86  71 0c 6d 4f 6c 40 a2 98  |.$...W,.q.mOl@..|
+000000a0  7d e3 f5 75 0e 4a b7 82  1c d8 f7 8c 22 a5 5b 34  |}..u.J......".[4|
+000000b0  19 79 12 e2 a4 e6 17 03  03 00 21 53 7a cc 02 0f  |.y........!Sz...|
+000000c0  6d b5 9d 8c ff 4a 2d 29  31 59 38 96 bb 6b a8 93  |m....J-)1Y8..k..|
+000000d0  09 af 38 c7 4d 6e 31 ef  18 d4 59 35 15 03 03 00  |..8.Mn1...Y5....|
+000000e0  16 1e 04 62 d6 6b 6c fc  0b 70 f8 32 d0 11 59 64  |...b.kl..p.2..Yd|
+000000f0  11 71 b0 ab ac 2d 6d                              |.q...-m|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
index 30f0026..e1ac9a6 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -1,11 +1,11 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 60 01 00 00  5c 03 03 54 23 54 02 17  |....`...\..T#T..|
-00000010  f3 53 13 3d 48 88 c3 19  b9 d1 3d 33 7f f5 99 56  |.S.=H.....=3...V|
-00000020  04 71 1b d9 d5 64 8a 0d  4a 54 00 00 00 04 00 05  |.q...d..JT......|
-00000030  00 ff 01 00 00 2f 00 23  00 00 00 0d 00 22 00 20  |...../.#.....". |
-00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
-00000060  00 0f 00 01 01                                    |.....|
+00000000  16 03 01 00 5f 01 00 00  5b 03 03 be c5 99 df f1  |...._...[.......|
+00000010  cc c8 fd d9 4c c5 09 18  5f 59 9a 78 47 ef 00 d5  |....L..._Y.xG...|
+00000020  81 45 3e ac a0 a5 ee d6  d0 8c d8 00 00 04 00 05  |.E>.............|
+00000030  00 ff 02 01 00 00 2d 00  23 00 00 00 0d 00 20 00  |......-.#..... .|
+00000040  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000050  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000060  0f 00 01 01                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -57,31 +57,32 @@
 000002f0  71 99 9b 26 6e 38 50 29  6c 90 a7 bd d9 16 03 03  |q..&n8P)l.......|
 00000300  00 04 0e 00 00 00                                 |......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 27 e9 a4 f7 e7  |...........'....|
-00000010  df 25 de 84 8c 1f d6 e6  c3 11 28 55 9a c1 91 37  |.%........(U...7|
-00000020  84 f5 ba f8 80 0d ca 50  cb 1e 72 f7 97 6f c2 b2  |.......P..r..o..|
-00000030  04 4d 13 7c e0 6e a0 1f  91 e1 38 1b a2 c0 55 16  |.M.|.n....8...U.|
-00000040  7f 29 fc ed 1c 1a cf 72  14 c3 00 c1 dd 36 36 af  |.).....r.....66.|
-00000050  a6 e4 a8 be ba ec 13 d0  1e d0 1d fd e1 5b 27 fd  |.............['.|
-00000060  9a da 2e 12 c8 b0 b9 c2  b9 76 ec 7f 3c 98 b6 63  |.........v..<..c|
-00000070  bc da f0 07 7a 3d e7 61  f4 2f 12 80 3b f9 3b cc  |....z=.a./..;.;.|
-00000080  05 c8 2f 7e 28 b2 73 bf  97 61 29 14 03 03 00 01  |../~(.s..a).....|
-00000090  01 16 03 03 00 24 17 59  a9 45 53 46 33 96 50 dd  |.....$.Y.ESF3.P.|
-000000a0  3e 23 aa 91 38 f8 56 4a  2f 1a f2 b1 44 9b ce 17  |>#..8.VJ/...D...|
-000000b0  6b 8a 89 76 bc 67 b8 8b  ba 90                    |k..v.g....|
+00000000  16 03 03 00 86 10 00 00  82 00 80 59 1f 86 2f cd  |...........Y../.|
+00000010  b9 8f 0d e8 f9 3a 5b a8  73 2f 33 8b c6 ef 5e e2  |.....:[.s/3...^.|
+00000020  78 93 fa 40 b7 b4 cb e7  3e 35 15 33 24 1d 63 5d  |x..@....>5.3$.c]|
+00000030  dc 8d 45 94 3f 19 ed e0  3a f3 4e 44 62 1d ff ea  |..E.?...:.NDb...|
+00000040  d6 e4 01 b0 26 c5 36 34  78 d1 e6 62 27 62 f0 29  |....&.64x..b'b.)|
+00000050  fd 7d 13 af 59 0a 41 fa  78 42 7d 0d d8 07 79 23  |.}..Y.A.xB}...y#|
+00000060  5e 4e cd 03 b1 3c bb 6d  fb 19 54 49 f1 c7 d7 54  |^N...<.m..TI...T|
+00000070  3e af 11 40 8b 7e 3d 2c  8b e3 02 ad fd 29 88 48  |>..@.~=,.....).H|
+00000080  b1 ed 52 74 50 a7 ef 99  9f af bd 14 03 03 00 01  |..RtP...........|
+00000090  01 16 03 03 00 24 f3 c1  8c ee e7 4d 07 80 c4 c3  |.....$.....M....|
+000000a0  09 87 85 cd 64 46 73 c7  17 4e 9e 90 4c 63 30 35  |....dFs..N..Lc05|
+000000b0  52 f5 10 f6 60 75 fc 93  41 57                    |R...`u..AW|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 4b d1 ef ba 2d db 0c  ba 9a d4 20 76 57 c8 ec  |.K...-..... vW..|
-00000030  dc 2d 77 fb fb 3b 93 5f  53 e0 14 4f 90 fb d6 55  |.-w..;._S..O...U|
-00000040  57 8c 8d 0d 25 ea 5d 0d  f2 91 e5 12 22 12 ec 7b  |W...%.]....."..{|
-00000050  5f b6 6e fd 07 59 23 24  fc b1 97 ca ea 56 a5 c2  |_.n..Y#$.....V..|
-00000060  a0 e4 9e 99 64 f2 64 d0  75 7a 46 63 e3 dc 21 ed  |....d.d.uzFc..!.|
-00000070  78 56 e9 e1 ab 66 80 14  03 03 00 01 01 16 03 03  |xV...f..........|
-00000080  00 24 fc 14 68 07 17 1f  df b7 84 cb fd c1 e0 e4  |.$..h...........|
-00000090  f2 1a ea 34 b5 00 7f 70  be c8 1c 0a d6 55 e3 57  |...4...p.....U.W|
-000000a0  50 4e 6d 7d 8a 5d 17 03  03 00 21 24 27 50 40 c1  |PNm}.]....!$'P@.|
-000000b0  c5 bd c7 9f 95 d9 ba 2e  7b 0e db ea a7 31 81 05  |........{....1..|
-000000c0  75 43 b1 63 cf b8 55 92  ef 76 98 a9 15 03 03 00  |uC.c..U..v......|
-000000d0  16 d7 ea 3c 79 e7 a6 2f  61 39 ec 4e 95 86 48 5e  |...<y../a9.N..H^|
-000000e0  75 a0 9e 41 42 89 67                              |u..AB.g|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f 2c b5 83 61 98 30 ec  c6 53 ac a0 2a a9 72 53  |o,..a.0..S..*.rS|
+00000040  64 7c c5 d5 db 0a 80 d0  1e ea 59 c8 b8 60 ff b9  |d|........Y..`..|
+00000050  3d 06 68 16 cd 60 3b 15  e9 59 c1 a2 18 76 c2 1f  |=.h..`;..Y...v..|
+00000060  fd 77 00 e6 38 33 94 98  69 cb 23 4a 61 d7 fe 1a  |.w..83..i.#Ja...|
+00000070  e7 3a 57 b1 78 c7 c0 d1  03 bb 83 69 72 b9 25 c3  |.:W.x......ir.%.|
+00000080  2f f7 56 2e 95 6f 88 14  03 03 00 01 01 16 03 03  |/.V..o..........|
+00000090  00 24 a6 8c 15 5c ae a0  8c 03 cc d2 2c 45 aa 7a  |.$...\......,E.z|
+000000a0  1d 1a ed 58 f4 92 a2 0d  b0 a4 81 90 e3 a6 0b 09  |...X............|
+000000b0  8f f2 1b 61 c7 f7 17 03  03 00 21 cf 8f 7a 50 bc  |...a......!..zP.|
+000000c0  a9 b6 d2 88 24 21 0b ef  5c e5 1c 34 4a d9 b6 b5  |....$!..\..4J...|
+000000d0  88 c6 14 8c 79 96 c5 0c  31 22 f8 7d 15 03 03 00  |....y...1".}....|
+000000e0  16 e7 69 82 9d e6 54 2d  f9 6d 04 a9 5b 3e bc f9  |..i...T-.m..[>..|
+000000f0  4e 1a 07 04 7a 56 50                              |N...zVP|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
index 0ddfe02..f499d52 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -1,15 +1,15 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9c 01 00 00  98 03 03 53 04 f1 30 73  |...........S..0s|
-00000010  a1 ea 8c d2 90 1c c6 d6  0d 3c af 58 21 65 90 25  |.........<.X!e.%|
-00000020  5e fa f4 27 22 65 c9 68  90 b9 04 00 00 04 c0 2f  |^..'"e.h......./|
-00000030  00 ff 01 00 00 6b 00 0b  00 04 03 00 01 02 00 0a  |.....k..........|
-00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
-00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 22 00 20 06 01 06 02  |.........". ....|
-00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-000000a0  01                                                |.|
+00000000  16 03 01 00 a1 01 00 00  9d 03 03 9a bc 85 2d 9c  |..............-.|
+00000010  c3 b2 9a c4 2e 4d 2a 49  04 5f 0e 39 9a bd 17 d9  |.....M*I._.9....|
+00000020  1f 5e 07 82 2e 86 03 79  e5 b0 35 00 00 04 c0 2f  |.^.....y..5..../|
+00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
+00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
+00000080  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
+00000090  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
+000000a0  03 00 0f 00 01 01                                 |......|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -63,31 +63,31 @@
 00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000340  41 03 56 6b dc 5a 89 04  01 00 80 a2 54 61 84 29  |A.Vk.Z......Ta.)|
-00000350  3e 97 4b 97 9a 9f 5c c0  49 6d 86 d2 79 8e 95 a1  |>.K...\.Im..y...|
-00000360  0a 5a 36 73 34 bb 05 73  35 47 e1 2b 5d f3 ef 36  |.Z6s4..s5G.+]..6|
-00000370  a8 32 e2 7e ef aa 3f 1f  b3 64 60 d4 06 2e 98 e3  |.2.~..?..d`.....|
-00000380  11 e2 60 3c d6 20 17 63  b2 6f a0 cd 21 01 2b 4e  |..`<. .c.o..!.+N|
-00000390  b2 a8 55 04 39 37 5c 6c  71 66 4d a3 eb 1b 83 67  |..U.97\lqfM....g|
-000003a0  6b 15 a0 56 9a f1 a2 79  92 29 ce 58 3c 10 4d 65  |k..V...y.).X<.Me|
-000003b0  1f 22 e3 ea d8 74 aa 01  7e ca f3 89 23 41 4d bd  |."...t..~...#AM.|
-000003c0  df 77 4e 59 54 97 74 ad  07 ea c0 16 03 03 00 04  |.wNYT.t.........|
+00000340  41 03 56 6b dc 5a 89 05  01 00 80 ba cb 00 ec a3  |A.Vk.Z..........|
+00000350  0f 9b 9b 0a f8 5c 6f 46  b4 93 a9 de 47 35 43 62  |.....\oF....G5Cb|
+00000360  06 d5 19 36 25 80 7c 81  3a df 01 6e f1 8f 50 4f  |...6%.|.:..n..PO|
+00000370  23 ee 1e 13 47 c6 9b 1c  3d 5f e3 8b 60 c3 f1 c4  |#...G...=_..`...|
+00000380  4b 36 4c 3c 71 bb 5c 0d  17 38 3a da 8c 3b c7 48  |K6L<q.\..8:..;.H|
+00000390  a4 c2 fa c5 3c ff 5d cc  76 41 dc 21 b9 6e ba 12  |....<.].vA.!.n..|
+000003a0  d2 21 21 f1 7e 9b f3 10  dd 57 de 50 a8 3f ab da  |.!!.~....W.P.?..|
+000003b0  53 14 97 25 d1 36 f0 9d  42 e9 9f 87 12 8c e5 19  |S..%.6..B.......|
+000003c0  f9 f4 96 3a 70 37 c9 4a  7f ce af 16 03 03 00 04  |...:p7.J........|
 000003d0  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 45 65 ce f7 b9  |....F...BA.Ee...|
-00000010  52 e3 fb 13 db 91 f2 65  43 84 57 f5 1a 19 a0 e6  |R......eC.W.....|
-00000020  89 2d bb 2c 83 6b 62 f6  6f 1f 26 ae 59 67 bd dc  |.-.,.kb.o.&.Yg..|
-00000030  c4 9e 0b dc 7d 6e f8 6b  95 8c 61 47 3d cd d1 df  |....}n.k..aG=...|
-00000040  82 45 30 81 c3 a3 49 5d  85 59 70 14 03 03 00 01  |.E0...I].Yp.....|
-00000050  01 16 03 03 00 28 3f aa  85 33 f9 c6 95 a0 56 ff  |.....(?..3....V.|
-00000060  1c f1 5a ba 6e 41 50 0c  ab 92 e1 e2 8e 89 1c f1  |..Z.nAP.........|
-00000070  fa 54 1b f1 f5 00 01 12  6d c4 96 78 b6 87        |.T......m..x..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 e3 f4 0a 79 25  |....F...BA....y%|
+00000010  6a a9 07 ae 8f 18 74 f3  0b e9 b1 0f da 35 58 4b  |j.....t......5XK|
+00000020  91 ca d7 58 46 39 51 a2  ef 9a c0 ec e6 b2 e5 27  |...XF9Q........'|
+00000030  97 7e 45 fd b8 1f 72 8d  ee 9b 58 82 45 2f e5 f4  |.~E...r...X.E/..|
+00000040  dd d5 cb ad f8 ac 4d 53  39 92 b9 14 03 03 00 01  |......MS9.......|
+00000050  01 16 03 03 00 28 b8 f7  4e 1a 2f d7 5b c9 6c ab  |.....(..N./.[.l.|
+00000060  bc 90 ce d0 dd 58 68 ff  43 00 55 23 25 e1 4b 33  |.....Xh.C.U#%.K3|
+00000070  d4 60 96 88 df f2 23 dd  b0 a9 f1 5b 91 73        |.`....#....[.s|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 28 00 00 00 00 00  |..........(.....|
-00000010  00 00 00 94 5c be 46 05  d6 d0 b0 3a 56 dc 2c 10  |....\.F....:V.,.|
-00000020  0f 6f 5d 33 33 7f a5 4e  74 84 bf 63 87 c4 f4 49  |.o]33..Nt..c...I|
-00000030  bc 6b ab 17 03 03 00 25  00 00 00 00 00 00 00 01  |.k.....%........|
-00000040  7e 4f f9 ae ae fe 6b a0  4a f8 0f 0b b4 b6 65 b6  |~O....k.J.....e.|
-00000050  be 24 5f 94 6d d1 db 54  11 07 b9 ce 01 15 03 03  |.$_.m..T........|
-00000060  00 1a 00 00 00 00 00 00  00 02 a8 1c d6 62 ac fd  |.............b..|
-00000070  77 ba 23 92 5d 34 f1 17  c7 e1 1c 99              |w.#.]4......|
+00000010  00 00 00 2c 58 45 b5 85  96 2b 55 45 3c ff 4e 46  |...,XE...+UE<.NF|
+00000020  75 96 8e c2 44 24 24 3c  bc 24 e7 fb a4 b1 5b b3  |u...D$$<.$....[.|
+00000030  b6 9a e6 17 03 03 00 25  00 00 00 00 00 00 00 01  |.......%........|
+00000040  89 60 e2 59 3a ab 37 21  89 95 ef c6 1d fb 55 4d  |.`.Y:.7!......UM|
+00000050  9b ba b5 55 2b 11 81 5c  d3 56 26 84 be 15 03 03  |...U+..\.V&.....|
+00000060  00 1a 00 00 00 00 00 00  00 02 66 4c a5 50 b7 7b  |..........fL.P.{|
+00000070  20 60 08 0f 80 33 84 b2  f4 e4 81 d4              | `...3......|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
index 1c979c3..a8aaf5f 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
@@ -1,14 +1,15 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9a 01 00 00  96 03 03 37 7c 30 6d df  |...........7|0m.|
-00000010  4d 94 90 04 59 df ec 01  11 77 29 b6 4f 95 50 ef  |M...Y....w).O.P.|
-00000020  ca d0 0f f4 a6 35 98 3b  ee 16 72 00 00 04 c0 30  |.....5.;..r....0|
-00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
-00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
-00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 20 00 1e 06 01 06 02  |......... ......|
-00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+00000000  16 03 01 00 a1 01 00 00  9d 03 03 77 d9 ce 2c 4d  |...........w..,M|
+00000010  da 71 bb b0 04 5f e1 29  ea 23 9f 21 2d cb 0b 75  |.q..._.).#.!-..u|
+00000020  be 29 65 df 8b a1 50 3f  14 a8 c0 00 00 04 c0 30  |.)e...P?.......0|
+00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
+00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
+00000080  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
+00000090  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
+000000a0  03 00 0f 00 01 01                                 |......|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -62,31 +63,31 @@
 00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000340  41 03 56 6b dc 5a 89 04  01 00 80 4f 66 0e d5 7f  |A.Vk.Z.....Of...|
-00000350  a8 99 4d dc 5b a7 b0 32  67 b2 8a 2e ca 90 58 f0  |..M.[..2g.....X.|
-00000360  8d f1 fd 74 c1 3c 84 28  9d 25 7e 0a 61 f8 90 2d  |...t.<.(.%~.a..-|
-00000370  99 f3 90 c9 26 ab a7 d2  38 87 e1 2b 12 6e 93 17  |....&...8..+.n..|
-00000380  3c 2f 11 8c d8 67 73 11  68 b9 d0 a7 ad 44 83 72  |</...gs.h....D.r|
-00000390  fc e4 6b ce 7f 02 7e 33  89 4b f3 dc 30 42 c0 4b  |..k...~3.K..0B.K|
-000003a0  2b 29 eb e6 1c 43 bb a7  27 b9 3e f4 76 ec 69 4d  |+)...C..'.>.v.iM|
-000003b0  df 49 d4 f6 b4 ac f6 0b  1d d1 68 61 30 b1 52 07  |.I........ha0.R.|
-000003c0  a5 6d 31 5e 13 24 8c 32  cd 76 57 16 03 03 00 04  |.m1^.$.2.vW.....|
+00000340  41 03 56 6b dc 5a 89 05  01 00 80 3f a6 7f 45 a0  |A.Vk.Z.....?..E.|
+00000350  a7 43 d0 8a 4b 50 39 77  c3 61 eb 88 73 02 de 5c  |.C..KP9w.a..s..\|
+00000360  4d 57 45 80 c1 ee 31 be  bc ca 70 48 a1 a5 6c 40  |MWE...1...pH..l@|
+00000370  de 54 4f dd e2 2d d8 7a  4c 68 f0 fe 28 28 ec 45  |.TO..-.zLh..((.E|
+00000380  45 79 c6 f6 68 9d 5f b8  eb 76 0b 53 72 76 6f a7  |Ey..h._..v.Srvo.|
+00000390  00 9b 18 ba 85 ad f3 10  3d cf 08 9c 63 b2 84 4f  |........=...c..O|
+000003a0  57 b6 b6 d8 3e ec c3 76  22 9e cf 31 d5 4c 68 f1  |W...>..v"..1.Lh.|
+000003b0  f3 a5 61 8a df b1 78 0f  14 9d 57 ef a8 d6 3b f5  |..a...x...W...;.|
+000003c0  a4 77 dd aa 5f e3 8b 2b  cf d2 64 16 03 03 00 04  |.w.._..+..d.....|
 000003d0  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 08 73 d7 79 87  |....F...BA..s.y.|
-00000010  39 45 dd 69 33 71 a0 48  a0 8b 6e 2f 99 dc a1 4f  |9E.i3q.H..n/...O|
-00000020  21 ca 70 b3 98 fe cc 5a  94 04 1b 8d 4d a4 46 24  |!.p....Z....M.F$|
-00000030  c6 61 bd e1 49 92 83 8d  ea 22 fb b1 43 90 24 7e  |.a..I...."..C.$~|
-00000040  d0 e5 4b cb c3 8a 41 f7  fd d1 9f 14 03 03 00 01  |..K...A.........|
-00000050  01 16 03 03 00 28 e3 99  f0 d3 65 4e 29 dd d6 eb  |.....(....eN)...|
-00000060  c0 b3 f9 e2 8b bb 68 61  b2 7f 63 db de fb ae d2  |......ha..c.....|
-00000070  94 b7 45 9b 34 cb a4 26  3f 04 92 34 02 89        |..E.4..&?..4..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 eb 6a bc 30 f6  |....F...BA..j.0.|
+00000010  ef 35 bb 4d 35 31 34 93  27 59 d9 6a fc e4 6c ac  |.5.M514.'Y.j..l.|
+00000020  fe 23 c9 b4 88 66 98 15  a3 84 dc 53 95 ea bb 43  |.#...f.....S...C|
+00000030  16 dc 03 5e 4a 83 d2 47  32 a0 2d ad 56 40 bd 24  |...^J..G2.-.V@.$|
+00000040  ad 47 af fa f3 d7 50 d3  b5 02 67 14 03 03 00 01  |.G....P...g.....|
+00000050  01 16 03 03 00 28 8c 86  3b 84 aa 50 d3 e6 bf c9  |.....(..;..P....|
+00000060  c6 03 4b c5 07 ac 12 96  88 95 64 92 0d 0c d9 8f  |..K.......d.....|
+00000070  11 2f e2 9e 32 e8 2b 4e  a7 1a 88 0a a5 f6        |./..2.+N......|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 28 00 00 00 00 00  |..........(.....|
-00000010  00 00 00 5e 63 30 5d 4d  2b 87 3f 7b 9c 06 2e 44  |...^c0]M+.?{...D|
-00000020  92 c5 d0 e8 07 fa 9f db  a7 2c dc ec 16 78 bd 37  |.........,...x.7|
-00000030  8a f7 24 17 03 03 00 25  00 00 00 00 00 00 00 01  |..$....%........|
-00000040  0b af 29 75 f0 67 6b 78  8c 3a 65 44 53 25 9e d5  |..)u.gkx.:eDS%..|
-00000050  8e 7e 24 5f c9 95 a1 3e  63 d2 52 09 32 15 03 03  |.~$_...>c.R.2...|
-00000060  00 1a 00 00 00 00 00 00  00 02 0b f2 f7 93 57 b3  |..............W.|
-00000070  5b 19 fd e7 a1 0f e9 41  ca f5 74 17              |[......A..t.|
+00000010  00 00 00 ac 6a 42 ae b7  31 ba 00 dd 82 2f 54 ad  |....jB..1..../T.|
+00000020  85 f6 77 2a 3c 68 24 e6  f5 4b 0e 80 4f 4c 60 04  |..w*<h$..K..OL`.|
+00000030  ac c3 a7 17 03 03 00 25  00 00 00 00 00 00 00 01  |.......%........|
+00000040  00 9a 15 f2 55 01 5f 18  c2 da 14 e8 50 a7 4f 4f  |....U._.....P.OO|
+00000050  4a d4 e2 21 86 4d 25 d9  11 4a 6d d2 1c 15 03 03  |J..!.M%..Jm.....|
+00000060  00 1a 00 00 00 00 00 00  00 02 a6 d4 e9 f9 cd 9a  |................|
+00000070  07 4f 7c 50 ef 6a dd 10  35 8c 43 e9              |.O|P.j..5.C.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-Resume b/src/crypto/tls/testdata/Server-TLSv12-Resume
index c495d4a..979ce97 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-Resume
+++ b/src/crypto/tls/testdata/Server-TLSv12-Resume
@@ -1,36 +1,37 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 e8 01 00 00  e4 03 03 52 cc 57 59 c3  |...........R.WY.|
-00000010  8b df 97 05 d8 5f 16 22  b4 b1 e7 cb 7d 2f 9b 58  |....._."....}/.X|
-00000020  a3 f4 d7 2c a4 c1 9d 49  ed 4b ba 20 90 da 90 3e  |...,...I.K. ...>|
-00000030  36 19 7a db 56 43 26 f7  dc 42 57 33 22 ed 9d a4  |6.z.VC&..BW3"...|
-00000040  9d 53 da f8 9d 4e 60 66  71 a0 2e 2e 00 04 00 05  |.S...N`fq.......|
-00000050  00 ff 01 00 00 97 00 23  00 68 00 00 00 00 00 00  |.......#.h......|
-00000060  00 00 00 00 00 00 00 00  00 00 65 ea 4b d1 ef ba  |..........e.K...|
-00000070  06 38 1e e1 88 82 3a cd  03 ac 3b 39 0a e0 19 fd  |.8....:...;9....|
-00000080  af 6c 57 30 df 31 6e f7  92 38 4b 5d 77 90 39 ff  |.lW0.1n..8K]w.9.|
-00000090  32 51 f5 ed 12 d7 b0 7c  4d 6c c5 76 e4 72 48 3e  |2Q.....|Ml.v.rH>|
-000000a0  59 23 fe 0d 15 df f4 ba  ea b9 67 16 23 8f 7d 15  |Y#........g.#.}.|
-000000b0  b6 11 f1 ab d7 d4 cd a3  21 82 92 2a 12 cf 95 f3  |........!..*....|
-000000c0  60 b2 00 0d 00 22 00 20  06 01 06 02 06 03 05 01  |`....". ........|
-000000d0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000e0  02 01 02 02 02 03 01 01  00 0f 00 01 01           |.............|
+00000000  16 03 01 00 f7 01 00 00  f3 03 03 6a 1a d3 0a d3  |...........j....|
+00000010  e0 34 f9 c4 1b cc 42 bc  0b eb 97 fd 51 b7 77 fd  |.4....B.....Q.w.|
+00000020  50 0a 13 8c b6 ac 8e a1  ba 1f 74 20 fb 19 d1 6a  |P.........t ...j|
+00000030  cf 1c 8b fb 77 97 7b 11  a5 fe 66 dc b8 b6 21 ad  |....w.{...f...!.|
+00000040  8b b4 5f 38 ca 51 ca a3  af 40 84 8b 00 04 00 05  |.._8.Q...@......|
+00000050  00 ff 02 01 00 00 a5 00  23 00 78 50 46 ad c1 db  |........#.xPF...|
+00000060  a8 38 86 7b 2b bb fd d0  c3 42 3e 00 00 00 00 00  |.8.{+....B>.....|
+00000070  00 00 00 00 00 00 00 00  00 00 00 94 6f 2c b5 83  |............o,..|
+00000080  61 e8 c1 5d af d6 da c9  8f df 1e c4 16 47 a0 dd  |a..].........G..|
+00000090  cf 3c 9d 95 11 fe 01 fb  52 5b d0 aa 56 fb 04 d5  |.<......R[..V...|
+000000a0  7f 89 31 7d 75 e3 df f4  28 6a fb 1f 76 ee 77 55  |..1}u...(j..v.wU|
+000000b0  0b 33 94 82 e2 ee 73 2f  7f a7 f6 7c 68 25 eb fd  |.3....s/...|h%..|
+000000c0  56 5b 89 29 b4 32 b6 92  57 3f c3 f9 01 fb 01 25  |V[.).2..W?.....%|
+000000d0  7f 0f 10 00 0d 00 20 00  1e 06 01 06 02 06 03 05  |...... .........|
+000000e0  01 05 02 05 03 04 01 04  02 04 03 03 01 03 02 03  |................|
+000000f0  03 02 01 02 02 02 03 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 51 02 00 00  4d 03 03 00 00 00 00 00  |....Q...M.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000020  00 00 00 00 00 00 00 00  00 00 00 20 90 da 90 3e  |........... ...>|
-00000030  36 19 7a db 56 43 26 f7  dc 42 57 33 22 ed 9d a4  |6.z.VC&..BW3"...|
-00000040  9d 53 da f8 9d 4e 60 66  71 a0 2e 2e 00 05 00 00  |.S...N`fq.......|
+00000020  00 00 00 00 00 00 00 00  00 00 00 20 fb 19 d1 6a  |........... ...j|
+00000030  cf 1c 8b fb 77 97 7b 11  a5 fe 66 dc b8 b6 21 ad  |....w.{...f...!.|
+00000040  8b b4 5f 38 ca 51 ca a3  af 40 84 8b 00 05 00 00  |.._8.Q...@......|
 00000050  05 ff 01 00 01 00 14 03  03 00 01 01 16 03 03 00  |................|
-00000060  24 11 12 ff 28 10 14 4c  e5 0e ad a7 fa f3 92 fb  |$...(..L........|
-00000070  13 7d ae f2 b2 4a 6b a1  9e 67 cf a8 f7 8c 6f a0  |.}...Jk..g....o.|
-00000080  6c 30 0e 18 55                                    |l0..U|
+00000060  24 0e 65 19 5e 79 90 4b  40 13 f1 5b 2f ed 0b f5  |$.e.^y.K@..[/...|
+00000070  cc 39 23 24 91 b3 b2 49  f6 9b d5 60 f3 ed bd 2a  |.9#$...I...`...*|
+00000080  31 00 14 5a 8e                                    |1..Z.|
 >>> Flow 3 (client to server)
-00000000  14 03 03 00 01 01 16 03  03 00 24 0d 46 41 8b 24  |..........$.FA.$|
-00000010  36 01 a9 fd 8b ec fc e6  b1 83 96 df 0d 3e 53 54  |6............>ST|
-00000020  58 b8 43 f2 a6 25 5e 1a  ae 19 9e d2 28 44 92     |X.C..%^.....(D.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 72 4d 5d 05 d6  |..........$rM]..|
+00000010  79 93 41 21 a7 86 75 49  50 fe b2 6c a9 38 d7 5e  |y.A!..uIP..l.8.^|
+00000020  b7 f7 33 18 b0 53 ab ab  b7 5b ee 09 e7 83 51     |..3..S...[....Q|
 >>> Flow 4 (server to client)
-00000000  17 03 03 00 21 c4 fb f6  53 bb 3e 04 cc 0b a0 03  |....!...S.>.....|
-00000010  fa 49 96 da b5 8d b2 f2  e5 d8 f3 5c 27 57 4f 9c  |.I.........\'WO.|
-00000020  30 00 34 fc 52 92 15 03  03 00 16 a3 02 7a 50 d2  |0.4.R........zP.|
-00000030  c6 b3 fc 69 8f e4 94 ae  ab 22 ad 05 1d 15 69 b9  |...i....."....i.|
-00000040  a5                                                |.|
+00000000  17 03 03 00 21 1a 35 ab  27 ac db 7f e4 11 f2 b4  |....!.5.'.......|
+00000010  38 f5 3f 5d be 7a 58 74  92 05 a5 9c 8e a8 f2 ca  |8.?].zXt........|
+00000020  cd f0 2e 18 62 57 15 03  03 00 16 33 18 76 93 bb  |....bW.....3.v..|
+00000030  48 86 cc 13 79 ad e2 51  c6 ac 3e 89 2a 4f 05 e1  |H...y..Q..>.*O..|
+00000040  ee                                                |.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
index db833f6..9cbbd3f 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
+++ b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -1,19 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 e8 01 00 00  e4 03 03 54 23 54 02 a5  |...........T#T..|
-00000010  10 11 0f 6d e5 2d 2f e8  bb 52 b1 38 3f 65 01 43  |...m.-/..R.8?e.C|
-00000020  36 cc 48 f6 09 22 a1 85  20 28 3c 20 35 8b fe 7a  |6.H..".. (< 5..z|
-00000030  41 3b 59 3a 5d b9 b3 21  f0 62 e9 0d 7b af f5 5d  |A;Y:]..!.b..{..]|
-00000040  fa 65 1a 40 c8 ca cd 74  8c ef d2 fb 00 04 00 05  |.e.@...t........|
-00000050  00 ff 01 00 00 97 00 23  00 68 00 00 00 00 00 00  |.......#.h......|
-00000060  00 00 00 00 00 00 00 00  00 00 65 ea 4b d1 ef ba  |..........e.K...|
-00000070  2d db 0c ba 9a d4 20 76  57 c8 ec dc 2d 77 fb fb  |-..... vW...-w..|
-00000080  3b 93 5f 53 e0 14 4f 90  fb d6 55 57 8c 8d 0d 25  |;._S..O...UW...%|
-00000090  ea 5d 0d f2 91 e5 12 22  12 ec 7b 5f b6 6e fd 07  |.]....."..{_.n..|
-000000a0  59 23 24 fc b1 97 ca ea  56 a5 c2 a0 e4 9e 99 64  |Y#$.....V......d|
-000000b0  f2 64 d0 75 7a 46 63 e3  dc 21 ed 78 56 e9 e1 ab  |.d.uzFc..!.xV...|
-000000c0  66 80 00 0d 00 22 00 20  06 01 06 02 06 03 05 01  |f....". ........|
-000000d0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000e0  02 01 02 02 02 03 01 01  00 0f 00 01 01           |.............|
+00000000  16 03 01 00 f7 01 00 00  f3 03 03 c0 99 dc 56 0b  |..............V.|
+00000010  50 7d 49 f8 f3 f7 60 a1  c7 38 e0 90 1f de 78 c3  |P}I...`..8....x.|
+00000020  43 04 0d b4 4c c0 6e 01  40 ec 3a 20 93 7c bd 44  |C...L.n.@.: .|.D|
+00000030  57 52 7d dd 4d db b6 6d  cc d5 44 34 a6 64 87 cb  |WR}.M..m..D4.d..|
+00000040  cb dc 38 d4 33 3a 1a 6f  fc f0 6f 73 00 04 00 05  |..8.3:.o..os....|
+00000050  00 ff 02 01 00 00 a5 00  23 00 78 50 46 ad c1 db  |........#.xPF...|
+00000060  a8 38 86 7b 2b bb fd d0  c3 42 3e 00 00 00 00 00  |.8.{+....B>.....|
+00000070  00 00 00 00 00 00 00 00  00 00 00 94 6f 2c b5 83  |............o,..|
+00000080  61 98 30 ec c6 53 ac a0  2a a9 72 53 64 7c c5 d5  |a.0..S..*.rSd|..|
+00000090  db 0a 80 d0 1e ea 59 c8  b8 60 ff b9 3d 06 68 16  |......Y..`..=.h.|
+000000a0  cd 60 3b 15 e9 59 c1 a2  18 76 c2 1f fd 77 00 e6  |.`;..Y...v...w..|
+000000b0  38 33 94 98 69 cb 23 4a  61 d7 fe 1a e7 3a 57 b1  |83..i.#Ja....:W.|
+000000c0  78 c7 c0 d1 03 bb 83 69  72 b9 25 c3 2f f7 56 2e  |x......ir.%./.V.|
+000000d0  95 6f 88 00 0d 00 20 00  1e 06 01 06 02 06 03 05  |.o.... .........|
+000000e0  01 05 02 05 03 04 01 04  02 04 03 03 01 03 02 03  |................|
+000000f0  03 02 01 02 02 02 03 00  0f 00 01 01              |............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -65,23 +66,23 @@
 000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
 00000300  00 00                                             |..|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 ae 02 dd 1f 1a  |................|
-00000010  86 83 f5 2f 82 46 4b 29  58 aa a1 b3 56 8b 4e 40  |.../.FK)X...V.N@|
-00000020  ef 23 65 67 ad 48 e5 e1  fd ae dd bf 68 fd bd a6  |.#eg.H......h...|
-00000030  13 a0 7e 05 ab f7 20 e1  6a 4e d1 37 93 08 1d c9  |..~... .jN.7....|
-00000040  37 e0 b5 34 28 bf 20 45  45 da 0f 7e 51 a7 c6 ae  |7..4(. EE..~Q...|
-00000050  61 6c 07 1b 73 ef da 6e  25 c4 ed be e3 3f da ae  |al..s..n%....?..|
-00000060  cd 3c 17 9c 2e ee fb 47  9d b3 a1 b2 c3 5d e0 83  |.<.....G.....]..|
-00000070  74 20 37 2d 72 d6 d0 4d  58 0e 26 1c 50 22 95 08  |t 7-r..MX.&.P"..|
-00000080  7d e0 5f 86 99 9e 2c 2e  a7 a0 7f 14 03 03 00 01  |}._...,.........|
-00000090  01 16 03 03 00 24 a2 ab  41 25 a5 cf 04 18 1d 98  |.....$..A%......|
-000000a0  88 6c 59 21 86 33 54 f4  35 b4 21 6e a5 29 d5 6e  |.lY!.3T.5.!n.).n|
-000000b0  3d 08 72 b0 af 46 b5 8f  6b 86                    |=.r..F..k.|
+00000000  16 03 03 00 86 10 00 00  82 00 80 5d 49 92 9d 5b  |...........]I..[|
+00000010  41 7a 83 f0 6d 32 de b8  49 00 2d e0 2f f9 f1 12  |Az..m2..I.-./...|
+00000020  0f 49 45 2b 58 fd 1d 72  49 e7 74 74 bc 97 73 f7  |.IE+X..rI.tt..s.|
+00000030  01 a9 10 53 ea 4a b5 5d  09 92 01 62 b7 50 cd 46  |...S.J.]...b.P.F|
+00000040  79 ec 35 08 0d 41 5f 09  41 fa 77 30 48 14 6b fe  |y.5..A_.A.w0H.k.|
+00000050  ca 12 d7 97 61 7a da 52  89 07 52 b0 81 c0 54 35  |....az.R..R...T5|
+00000060  7d 36 6c be 85 45 6b 67  e3 06 55 f7 af 40 d5 7d  |}6l..Ekg..U..@.}|
+00000070  34 bb ee 0c 49 6b fb 0a  c0 ec 04 85 28 4f 15 d7  |4...Ik......(O..|
+00000080  f3 e5 92 86 30 27 e9 15  b7 1d ae 14 03 03 00 01  |....0'..........|
+00000090  01 16 03 03 00 24 64 7a  6c c1 71 df b3 a2 a7 a8  |.....$dzl.q.....|
+000000a0  ea fd 04 d6 7c fc eb a1  18 21 42 f4 ba 09 75 1c  |....|....!B...u.|
+000000b0  f7 00 01 37 cc bb e1 11  c9 ef                    |...7......|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 59 20 4d c2 17  |..........$Y M..|
-00000010  8b 3c 9b 33 d9 f9 ef fb  80 18 1f 67 a7 58 12 89  |.<.3.......g.X..|
-00000020  4e 73 0f 2d 7b e6 c4 a6  79 73 01 da 22 e8 54 17  |Ns.-{...ys..".T.|
-00000030  03 03 00 21 36 ca 64 0f  4a 12 a5 50 3d 97 bb 39  |...!6.d.J..P=..9|
-00000040  02 fc ed d1 82 6a 9a 2e  21 79 f6 e1 b3 cc 32 db  |.....j..!y....2.|
-00000050  0f 5d b3 fb a5 15 03 03  00 16 51 f4 be 57 7a df  |.]........Q..Wz.|
-00000060  f1 f2 bd b5 51 5e 45 80  be 0b 9a 0c d1 19 3c 79  |....Q^E.......<y|
+00000000  14 03 03 00 01 01 16 03  03 00 24 c9 e4 67 51 5a  |..........$..gQZ|
+00000010  0a b3 8d 30 c6 e8 f3 df  52 a7 85 b3 e0 5a 64 0a  |...0....R....Zd.|
+00000020  19 96 96 0f 6d a7 1a 74  0d 47 29 a0 d1 db 8f 17  |....m..t.G).....|
+00000030  03 03 00 21 10 7b 5f 4a  b0 d8 25 2d d4 66 76 65  |...!.{_J..%-.fve|
+00000040  3c 03 c8 bd 15 19 d2 fc  19 f0 e6 ac c5 9d 8b 17  |<...............|
+00000050  26 d9 1e 71 4d 15 03 03  00 16 36 16 72 83 f8 79  |&..qM.....6.r..y|
+00000060  4c ca 20 39 4a 0c a4 55  06 79 b6 8a ab cb 9a f2  |L. 9J..U.y......|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
new file mode 100644
index 0000000..88884ac
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 6f 01 00 00  6b 03 03 6a 01 e6 6b 95  |....o...k..j..k.|
+00000010  30 a8 26 2a ba 53 dd 79  6e 54 fa 69 ee e0 23 d8  |0.&*.S.ynT.i..#.|
+00000020  1c 9e 7a 9a ea 7d 13 30  c1 00 d6 00 00 04 00 2f  |..z..}.0......./|
+00000030  00 ff 02 01 00 00 3d 00  00 00 10 00 0e 00 00 0b  |......=.........|
+00000040  73 6e 69 74 65 73 74 2e  63 6f 6d 00 0d 00 20 00  |snitest.com... .|
+00000050  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000060  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000070  0f 00 01 01                                       |....|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 00 0b 00 01 fc 00  |................|
+00000040  01 f9 00 01 f6 30 82 01  f2 30 82 01 5d a0 03 02  |.....0...0..]...|
+00000050  01 02 02 01 00 30 0b 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000060  01 05 30 28 31 10 30 0e  06 03 55 04 0a 13 07 41  |..0(1.0...U....A|
+00000070  63 6d 65 20 43 6f 31 14  30 12 06 03 55 04 03 13  |cme Co1.0...U...|
+00000080  0b 73 6e 69 74 65 73 74  2e 63 6f 6d 30 1e 17 0d  |.snitest.com0...|
+00000090  31 32 30 34 31 31 31 37  34 30 33 35 5a 17 0d 31  |120411174035Z..1|
+000000a0  33 30 34 31 31 31 37 34  35 33 35 5a 30 28 31 10  |30411174535Z0(1.|
+000000b0  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+000000c0  31 14 30 12 06 03 55 04  03 13 0b 73 6e 69 74 65  |1.0...U....snite|
+000000d0  73 74 2e 63 6f 6d 30 81  9d 30 0b 06 09 2a 86 48  |st.com0..0...*.H|
+000000e0  86 f7 0d 01 01 01 03 81  8d 00 30 81 89 02 81 81  |..........0.....|
+000000f0  00 bb 79 d6 f5 17 b5 e5  bf 46 10 d0 dc 69 be e6  |..y......F...i..|
+00000100  2b 07 43 5a d0 03 2d 8a  7a 43 85 b7 14 52 e7 a5  |+.CZ..-.zC...R..|
+00000110  65 4c 2c 78 b8 23 8c b5  b4 82 e5 de 1f 95 3b 7e  |eL,x.#........;~|
+00000120  62 a5 2c a5 33 d6 fe 12  5c 7a 56 fc f5 06 bf fa  |b.,.3...\zV.....|
+00000130  58 7b 26 3f b5 cd 04 d3  d0 c9 21 96 4a c7 f4 54  |X{&?......!.J..T|
+00000140  9f 5a bf ef 42 71 00 fe  18 99 07 7f 7e 88 7d 7d  |.Z..Bq......~.}}|
+00000150  f1 04 39 c4 a2 2e db 51  c9 7c e3 c0 4c 3b 32 66  |..9....Q.|..L;2f|
+00000160  01 cf af b1 1d b8 71 9a  1d db db 89 6b ae da 2d  |......q.....k..-|
+00000170  79 02 03 01 00 01 a3 32  30 30 30 0e 06 03 55 1d  |y......2000...U.|
+00000180  0f 01 01 ff 04 04 03 02  00 a0 30 0d 06 03 55 1d  |..........0...U.|
+00000190  0e 04 06 04 04 01 02 03  04 30 0f 06 03 55 1d 23  |.........0...U.#|
+000001a0  04 08 30 06 80 04 01 02  03 04 30 0b 06 09 2a 86  |..0.......0...*.|
+000001b0  48 86 f7 0d 01 01 05 03  81 81 00 89 c6 45 5f 1c  |H............E_.|
+000001c0  1f 5e f8 eb 1a b1 74 ee  24 39 05 9f 5c 42 59 bb  |.^....t.$9..\BY.|
+000001d0  1a 8d 86 cd b1 d0 56 f5  6a 71 7d a4 0e 95 ab 90  |......V.jq}.....|
+000001e0  f5 9e 8d ea f6 27 c1 57  99 50 94 db 08 02 26 6e  |.....'.W.P....&n|
+000001f0  b3 4f c6 84 2d ea 8a 4b  68 d9 c1 38 91 03 ab 84  |.O..-..Kh..8....|
+00000200  fb 9e 1f 85 d9 b5 d2 3f  f2 31 2c 86 70 fb b5 40  |.......?.1,.p..@|
+00000210  14 82 45 a4 eb af e2 64  d9 0c 8a 4c f4 f8 5b 0f  |..E....d...L..[.|
+00000220  ac 12 ac 2f c4 a3 15 4b  ad 52 46 28 68 af 96 c6  |.../...K.RF(h...|
+00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
+00000240  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 03 e1 70 db fd  |.............p..|
+00000010  a5 69 b6 da ef 2a 3b 81  4a 2a bc 21 fb ae a2 31  |.i...*;.J*.!...1|
+00000020  ac d9 34 f0 62 ff da 86  9c b1 c6 e1 cd 63 dc 42  |..4.b........c.B|
+00000030  9a 72 b2 cf 6c 6a e0 f5  30 b7 7e 9e 4e a1 fe 64  |.r..lj..0.~.N..d|
+00000040  f8 a3 f6 f2 d1 44 3a 82  5a 39 c1 ac 29 22 f7 90  |.....D:.Z9..)"..|
+00000050  71 ee 2e 62 c1 1a 22 6f  00 7d 73 4c e4 a3 d2 9a  |q..b.."o.}sL....|
+00000060  a4 34 4d fb 68 8e 99 91  e3 6d 14 f2 ac 4d 36 60  |.4M.h....m...M6`|
+00000070  9b 79 26 4b ff cf 80 3b  8d 8a 04 20 86 73 bb ff  |.y&K...;... .s..|
+00000080  c3 99 22 04 89 0c 2c 65  a0 d6 4d 14 03 03 00 01  |.."...,e..M.....|
+00000090  01 16 03 03 00 40 a9 0b  6e 2d 74 2a ae 5e c3 36  |.....@..n-t*.^.6|
+000000a0  50 80 8a d0 81 b6 b4 76  56 39 c0 b6 f8 d9 d6 fb  |P......vV9......|
+000000b0  bb 24 2d 82 ec 9f f7 d3  4d 9d e1 78 df ea 6a 0a  |.$-.....M..x..j.|
+000000c0  59 e8 b2 36 31 8e 70 eb  3e e5 e9 1b 9d f3 d7 09  |Y..61.p.>.......|
+000000d0  9b 80 55 b5 e4 e4                                 |..U...|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 a4 81 32 49 09  |.............2I.|
+00000020  07 8c 05 d1 1c 18 fe ca  d7 b8 7f 66 b0 42 2b 6d  |...........f.B+m|
+00000030  5a cc 72 01 3e 75 3c 23  a2 b7 56 64 b2 b3 0f 1d  |Z.r.>u<#..Vd....|
+00000040  ce a7 02 f7 88 bf 78 93  37 85 12 17 03 03 00 40  |......x.7......@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  49 b3 f9 ba be 6f df 65  cd 37 79 07 57 40 a4 30  |I....o.e.7y.W@.0|
+00000070  f1 f6 d7 2e 87 d2 bd 5c  f9 cf 13 c5 91 eb 0c 41  |.......\.......A|
+00000080  c3 13 fb b2 de 0c 59 a9  1e e4 d5 b2 ea 4f 88 df  |......Y......O..|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 b2 e1 cb  94 94 30 e1 da 42 ea df  |..........0..B..|
+000000b0  fc 8d 54 8d b2 d9 3b 33  4e 53 98 e9 14 e3 c1 d9  |..T...;3NS......|
+000000c0  de b8 e5 51 ca                                    |...Q.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
new file mode 100644
index 0000000..ebd284b
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 6f 01 00 00  6b 03 03 3d 70 50 1f cc  |....o...k..=pP..|
+00000010  5b 7a b5 67 c2 fc e8 65  a9 3d 7c 2a 93 ef 0d 41  |[z.g...e.=|*...A|
+00000020  a1 7d 78 a8 af 7d 70 af  ce 1b 0e 00 00 04 00 2f  |.}x..}p......../|
+00000030  00 ff 02 01 00 00 3d 00  00 00 10 00 0e 00 00 0b  |......=.........|
+00000040  73 6e 69 74 65 73 74 2e  63 6f 6d 00 0d 00 20 00  |snitest.com... .|
+00000050  1e 06 01 06 02 06 03 05  01 05 02 05 03 04 01 04  |................|
+00000060  02 04 03 03 01 03 02 03  03 02 01 02 02 02 03 00  |................|
+00000070  0f 00 01 01                                       |....|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 00 0b 00 01 fc 00  |................|
+00000040  01 f9 00 01 f6 30 82 01  f2 30 82 01 5d a0 03 02  |.....0...0..]...|
+00000050  01 02 02 01 00 30 0b 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000060  01 05 30 28 31 10 30 0e  06 03 55 04 0a 13 07 41  |..0(1.0...U....A|
+00000070  63 6d 65 20 43 6f 31 14  30 12 06 03 55 04 03 13  |cme Co1.0...U...|
+00000080  0b 73 6e 69 74 65 73 74  2e 63 6f 6d 30 1e 17 0d  |.snitest.com0...|
+00000090  31 32 30 34 31 31 31 37  34 30 33 35 5a 17 0d 31  |120411174035Z..1|
+000000a0  33 30 34 31 31 31 37 34  35 33 35 5a 30 28 31 10  |30411174535Z0(1.|
+000000b0  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+000000c0  31 14 30 12 06 03 55 04  03 13 0b 73 6e 69 74 65  |1.0...U....snite|
+000000d0  73 74 2e 63 6f 6d 30 81  9d 30 0b 06 09 2a 86 48  |st.com0..0...*.H|
+000000e0  86 f7 0d 01 01 01 03 81  8d 00 30 81 89 02 81 81  |..........0.....|
+000000f0  00 bb 79 d6 f5 17 b5 e5  bf 46 10 d0 dc 69 be e6  |..y......F...i..|
+00000100  2b 07 43 5a d0 03 2d 8a  7a 43 85 b7 14 52 e7 a5  |+.CZ..-.zC...R..|
+00000110  65 4c 2c 78 b8 23 8c b5  b4 82 e5 de 1f 95 3b 7e  |eL,x.#........;~|
+00000120  62 a5 2c a5 33 d6 fe 12  5c 7a 56 fc f5 06 bf fa  |b.,.3...\zV.....|
+00000130  58 7b 26 3f b5 cd 04 d3  d0 c9 21 96 4a c7 f4 54  |X{&?......!.J..T|
+00000140  9f 5a bf ef 42 71 00 fe  18 99 07 7f 7e 88 7d 7d  |.Z..Bq......~.}}|
+00000150  f1 04 39 c4 a2 2e db 51  c9 7c e3 c0 4c 3b 32 66  |..9....Q.|..L;2f|
+00000160  01 cf af b1 1d b8 71 9a  1d db db 89 6b ae da 2d  |......q.....k..-|
+00000170  79 02 03 01 00 01 a3 32  30 30 30 0e 06 03 55 1d  |y......2000...U.|
+00000180  0f 01 01 ff 04 04 03 02  00 a0 30 0d 06 03 55 1d  |..........0...U.|
+00000190  0e 04 06 04 04 01 02 03  04 30 0f 06 03 55 1d 23  |.........0...U.#|
+000001a0  04 08 30 06 80 04 01 02  03 04 30 0b 06 09 2a 86  |..0.......0...*.|
+000001b0  48 86 f7 0d 01 01 05 03  81 81 00 89 c6 45 5f 1c  |H............E_.|
+000001c0  1f 5e f8 eb 1a b1 74 ee  24 39 05 9f 5c 42 59 bb  |.^....t.$9..\BY.|
+000001d0  1a 8d 86 cd b1 d0 56 f5  6a 71 7d a4 0e 95 ab 90  |......V.jq}.....|
+000001e0  f5 9e 8d ea f6 27 c1 57  99 50 94 db 08 02 26 6e  |.....'.W.P....&n|
+000001f0  b3 4f c6 84 2d ea 8a 4b  68 d9 c1 38 91 03 ab 84  |.O..-..Kh..8....|
+00000200  fb 9e 1f 85 d9 b5 d2 3f  f2 31 2c 86 70 fb b5 40  |.......?.1,.p..@|
+00000210  14 82 45 a4 eb af e2 64  d9 0c 8a 4c f4 f8 5b 0f  |..E....d...L..[.|
+00000220  ac 12 ac 2f c4 a3 15 4b  ad 52 46 28 68 af 96 c6  |.../...K.RF(h...|
+00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
+00000240  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 1c 6d 66 c4 c1  |............mf..|
+00000010  92 07 67 6c f7 54 32 70  31 53 89 8d 60 29 d8 df  |..gl.T2p1S..`)..|
+00000020  8b b9 62 a0 3c 79 e3 67  45 e9 6d 6e f5 9b cd 18  |..b.<y.gE.mn....|
+00000030  13 4a 3b 14 11 2b 05 4c  e3 8a 7e 03 b5 ca 3d 14  |.J;..+.L..~...=.|
+00000040  da 84 6f cd 31 8b 4f 43  62 cf ff 39 a9 c6 95 5d  |..o.1.OCb..9...]|
+00000050  8a 54 b6 6f eb cf ed e7  05 33 b0 74 03 7e 49 6f  |.T.o.....3.t.~Io|
+00000060  88 6c c4 7d 3f 63 bd 49  11 57 e8 95 9f 4e ff 6f  |.l.}?c.I.W...N.o|
+00000070  92 20 fd fe 2b 07 22 ff  03 0a 36 0d 29 c7 21 a9  |. ..+."...6.).!.|
+00000080  50 28 73 f9 25 ce eb 16  90 0d d3 14 03 03 00 01  |P(s.%...........|
+00000090  01 16 03 03 00 40 f2 b1  15 c1 86 c7 63 b3 52 93  |.....@......c.R.|
+000000a0  c2 27 cc 1a 30 9a 59 1b  0c 92 11 ba bc 2b af ca  |.'..0.Y......+..|
+000000b0  b2 44 66 0f 86 19 2c 38  08 ca ee 40 67 60 21 39  |.Df...,8...@g`!9|
+000000c0  03 77 f5 5b c9 2e 62 6d  1a 0c 1e 86 cf 30 a9 89  |.w.[..bm.....0..|
+000000d0  ba f9 d7 ff ed 2c                                 |.....,|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |..........@.....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 88 5b 91 f7 4e  |............[..N|
+00000020  07 30 30 98 88 5c de 79  e0 63 1a 91 17 3a 2f bf  |.00..\.y.c...:/.|
+00000030  8b 6b 61 f9 56 d7 43 bf  87 42 34 f3 09 b1 5e 67  |.ka.V.C..B4...^g|
+00000040  a2 33 0d 15 b8 7d c5 a8  35 50 4f 17 03 03 00 40  |.3...}..5PO....@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  50 27 94 e0 5a da 24 8f  b2 d3 f3 f6 a4 1e f6 ac  |P'..Z.$.........|
+00000070  b9 2a 48 85 41 f7 84 4c  1e f4 ca aa 90 1f f8 1b  |.*H.A..L........|
+00000080  2f 53 01 2b 5e 48 82 ab  f0 70 ad 4b 8f 5d bd 27  |/S.+^H...p.K.].'|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 5c 38 ba  1e 5a 18 9a a0 31 aa 98  |.....\8..Z...1..|
+000000b0  68 3e ba 01 42 ee b7 78  1a ed 56 f8 b6 49 a7 4c  |h>..B..x..V..I.L|
+000000c0  e1 8d dd 1c 9c                                    |.....|
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
index 0923027..7be50ce 100644
--- a/src/crypto/tls/ticket.go
+++ b/src/crypto/tls/ticket.go
@@ -22,6 +22,9 @@
 	cipherSuite  uint16
 	masterSecret []byte
 	certificates [][]byte
+	// usedOldKey is true if the ticket from which this session came from
+	// was encrypted with an older key and thus should be refreshed.
+	usedOldKey bool
 }
 
 func (s *sessionState) equal(i interface{}) bool {
@@ -132,20 +135,23 @@
 
 func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
 	serialized := state.marshal()
-	encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size)
-	iv := encrypted[:aes.BlockSize]
+	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
+	keyName := encrypted[:ticketKeyNameLen]
+	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 
 	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
 		return nil, err
 	}
-	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+	key := c.config.ticketKeys()[0]
+	copy(keyName, key.keyName[:])
+	block, err := aes.NewCipher(key.aesKey[:])
 	if err != nil {
 		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
 	}
-	cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized)
+	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized)
 
-	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+	mac := hmac.New(sha256.New, key.hmacKey[:])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
 	mac.Sum(macBytes[:0])
 
@@ -154,14 +160,29 @@
 
 func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
 	if c.config.SessionTicketsDisabled ||
-		len(encrypted) < aes.BlockSize+sha256.Size {
+		len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
 		return nil, false
 	}
 
-	iv := encrypted[:aes.BlockSize]
+	keyName := encrypted[:ticketKeyNameLen]
+	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 
-	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+	keys := c.config.ticketKeys()
+	keyIndex := -1
+	for i, candidateKey := range keys {
+		if bytes.Equal(keyName, candidateKey.keyName[:]) {
+			keyIndex = i
+			break
+		}
+	}
+
+	if keyIndex == -1 {
+		return nil, false
+	}
+	key := &keys[keyIndex]
+
+	mac := hmac.New(sha256.New, key.hmacKey[:])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
 	expected := mac.Sum(nil)
 
@@ -169,15 +190,15 @@
 		return nil, false
 	}
 
-	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+	block, err := aes.NewCipher(key.aesKey[:])
 	if err != nil {
 		return nil, false
 	}
-	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
 	plaintext := ciphertext
 	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
 
-	state := new(sessionState)
+	state := &sessionState{usedOldKey: keyIndex > 0}
 	ok := state.unmarshal(plaintext)
 	return state, ok
 }
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index 39a5781..9fb08dd 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.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.
 
-// +build cgo,!arm
+// +build cgo,!arm,!arm64
 
 package x509
 
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 96b6599..78de56c 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.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.
 
-//go:generate go run root_darwin_arm_gen.go -output root_darwin_arm.go
+//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
 
 package x509
 
diff --git a/src/crypto/x509/root_darwin_arm_gen.go b/src/crypto/x509/root_darwin_arm_gen.go
index 194e016..40e85b7 100644
--- a/src/crypto/x509/root_darwin_arm_gen.go
+++ b/src/crypto/x509/root_darwin_arm_gen.go
@@ -4,7 +4,7 @@
 
 // +build ignore
 
-// Generates root_darwin_arm.go.
+// Generates root_darwin_armx.go.
 //
 // As of iOS 8, there is no API for querying the system trusted X.509 root
 // certificates. We could use SecTrustEvaluate to verify that a trust chain
@@ -31,7 +31,7 @@
 	"strings"
 )
 
-var output = flag.String("output", "root_darwin_arm.go", "file name to write")
+var output = flag.String("output", "root_darwin_armx.go", "file name to write")
 
 func main() {
 	certs, err := selectCerts()
@@ -178,6 +178,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build darwin
+// +build arm arm64
+
 package x509
 
 func initSystemRoots() {
diff --git a/src/crypto/x509/root_darwin_arm.go b/src/crypto/x509/root_darwin_armx.go
similarity index 99%
rename from src/crypto/x509/root_darwin_arm.go
rename to src/crypto/x509/root_darwin_armx.go
index 43cd9ec..62b7d24 100644
--- a/src/crypto/x509/root_darwin_arm.go
+++ b/src/crypto/x509/root_darwin_armx.go
@@ -1,9 +1,12 @@
-// Created by root_darwin_arm_gen --output root_darwin_arm.go; DO NOT EDIT
+// Created by root_darwin_arm_gen --output root_darwin_armx.go; DO NOT EDIT
 
 // 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
+// +build arm arm64
+
 package x509
 
 func initSystemRoots() {
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index e4718d0..cc6d23c 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -10,8 +10,9 @@
 )
 
 func TestSystemRoots(t *testing.T) {
-	if runtime.GOARCH == "arm" {
-		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+	switch runtime.GOARCH {
+	case "arm", "arm64":
+		t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
 	}
 
 	sysRoots := systemRootsPool()         // actual system roots
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 7226d0a..21b870c 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -215,6 +215,10 @@
 		return c.systemVerify(&opts)
 	}
 
+	if len(c.UnhandledCriticalExtensions) > 0 {
+		return nil, UnhandledCriticalExtension{}
+	}
+
 	if opts.Roots == nil {
 		opts.Roots = systemRootsPool()
 		if opts.Roots == nil {
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index e75120e..be6c013 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -37,8 +37,10 @@
 // typically found in PEM blocks with "BEGIN PUBLIC KEY".
 func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
 	var pki publicKeyInfo
-	if _, err = asn1.Unmarshal(derBytes, &pki); err != nil {
-		return
+	if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after ASN.1 of public-key")
 	}
 	algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
 	if algo == UnknownPublicKeyAlgorithm {
@@ -488,6 +490,16 @@
 	// field is not populated when parsing certificates, see Extensions.
 	ExtraExtensions []pkix.Extension
 
+	// UnhandledCriticalExtensions contains a list of extension IDs that
+	// were not (fully) processed when parsing. Verify will fail if this
+	// slice is non-empty, unless verification is delegated to an OS
+	// library which understands all the critical extensions.
+	//
+	// Users can access these extensions using Extensions and can remove
+	// elements from this slice if they believe that they have been
+	// handled.
+	UnhandledCriticalExtensions []asn1.ObjectIdentifier
+
 	ExtKeyUsage        []ExtKeyUsage           // Sequence of extended key usages.
 	UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
 
@@ -619,6 +631,12 @@
 // CheckSignature verifies that signature is a valid signature over signed from
 // c's public key.
 func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
+	return checkSignature(algo, signed, signature, c.PublicKey)
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// a crypto.PublicKey.
+func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
 	var hashType crypto.Hash
 
 	switch algo {
@@ -642,13 +660,15 @@
 	h.Write(signed)
 	digest := h.Sum(nil)
 
-	switch pub := c.PublicKey.(type) {
+	switch pub := publicKey.(type) {
 	case *rsa.PublicKey:
 		return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
 	case *dsa.PublicKey:
 		dsaSig := new(dsaSignature)
-		if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+		if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
 			return err
+		} else if len(rest) != 0 {
+			return errors.New("x509: trailing data after DSA signature")
 		}
 		if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
 			return errors.New("x509: DSA signature contained zero or negative values")
@@ -659,8 +679,10 @@
 		return
 	case *ecdsa.PublicKey:
 		ecdsaSig := new(ecdsaSignature)
-		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
+		if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
 			return err
+		} else if len(rest) != 0 {
+			return errors.New("x509: trailing data after ECDSA signature")
 		}
 		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
 			return errors.New("x509: ECDSA signature contained zero or negative values")
@@ -729,10 +751,13 @@
 	switch algo {
 	case RSA:
 		p := new(rsaPublicKey)
-		_, err := asn1.Unmarshal(asn1Data, p)
+		rest, err := asn1.Unmarshal(asn1Data, p)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after RSA public key")
+		}
 
 		if p.N.Sign() <= 0 {
 			return nil, errors.New("x509: RSA modulus is not a positive number")
@@ -748,16 +773,22 @@
 		return pub, nil
 	case DSA:
 		var p *big.Int
-		_, err := asn1.Unmarshal(asn1Data, &p)
+		rest, err := asn1.Unmarshal(asn1Data, &p)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after DSA public key")
+		}
 		paramsData := keyData.Algorithm.Parameters.FullBytes
 		params := new(dsaAlgorithmParameters)
-		_, err = asn1.Unmarshal(paramsData, params)
+		rest, err = asn1.Unmarshal(paramsData, params)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after DSA parameters")
+		}
 		if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
 			return nil, errors.New("x509: zero or negative DSA parameter")
 		}
@@ -773,10 +804,13 @@
 	case ECDSA:
 		paramsData := keyData.Algorithm.Parameters.FullBytes
 		namedCurveOID := new(asn1.ObjectIdentifier)
-		_, err := asn1.Unmarshal(paramsData, namedCurveOID)
+		rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after ECDSA parameters")
+		}
 		namedCurve := namedCurveFromOID(*namedCurveOID)
 		if namedCurve == nil {
 			return nil, errors.New("x509: unsupported elliptic curve")
@@ -814,7 +848,11 @@
 	//      iPAddress                       [7]     OCTET STRING,
 	//      registeredID                    [8]     OBJECT IDENTIFIER }
 	var seq asn1.RawValue
-	if _, err = asn1.Unmarshal(value, &seq); err != nil {
+	var rest []byte
+	if rest, err = asn1.Unmarshal(value, &seq); err != nil {
+		return
+	} else if len(rest) != 0 {
+		err = errors.New("x509: trailing data after X.509 extension")
 		return
 	}
 	if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
@@ -822,7 +860,7 @@
 		return
 	}
 
-	rest := seq.Bytes
+	rest = seq.Bytes
 	for len(rest) > 0 {
 		var v asn1.RawValue
 		rest, err = asn1.Unmarshal(rest, &v)
@@ -876,11 +914,15 @@
 	out.SerialNumber = in.TBSCertificate.SerialNumber
 
 	var issuer, subject pkix.RDNSequence
-	if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
+	if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
 		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 subject")
 	}
-	if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
+	if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
 		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 subject")
 	}
 
 	out.Issuer.FillFromRDNSequence(&issuer)
@@ -891,15 +933,17 @@
 
 	for _, e := range in.TBSCertificate.Extensions {
 		out.Extensions = append(out.Extensions, e)
-		failIfCritical := false
+		unhandled := false
 
 		if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
 			switch e.Id[3] {
 			case 15:
 				// RFC 5280, 4.2.1.3
 				var usageBits asn1.BitString
-				if _, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 KeyUsage")
 				}
 
 				var usage int
@@ -913,8 +957,10 @@
 			case 19:
 				// RFC 5280, 4.2.1.9
 				var constraints basicConstraints
-				if _, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 BasicConstraints")
 				}
 
 				out.BasicConstraintsValid = true
@@ -930,7 +976,7 @@
 
 				if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 {
 					// If we didn't parse anything then we do the critical check, below.
-					failIfCritical = true
+					unhandled = true
 				}
 
 			case 30:
@@ -950,8 +996,10 @@
 				// BaseDistance ::= INTEGER (0..MAX)
 
 				var constraints nameConstraints
-				if _, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 NameConstraints")
 				}
 
 				if len(constraints.Excluded) > 0 && e.Critical {
@@ -983,15 +1031,20 @@
 				//     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
 
 				var cdp []distributionPoint
-				if _, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 CRL distribution point")
 				}
 
 				for _, dp := range cdp {
 					var n asn1.RawValue
-					if _, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
+					if _, err := asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
 						return nil, err
 					}
+					// Trailing data after the fullName is
+					// allowed because other elements of
+					// the SEQUENCE can appear.
 
 					if n.Tag == 6 {
 						out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
@@ -1001,8 +1054,10 @@
 			case 35:
 				// RFC 5280, 4.2.1.1
 				var a authKeyId
-				if _, err = asn1.Unmarshal(e.Value, &a); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 authority key-id")
 				}
 				out.AuthorityKeyId = a.Id
 
@@ -1016,8 +1071,10 @@
 				// KeyPurposeId ::= OBJECT IDENTIFIER
 
 				var keyUsage []asn1.ObjectIdentifier
-				if _, err = asn1.Unmarshal(e.Value, &keyUsage); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
 				}
 
 				for _, u := range keyUsage {
@@ -1031,16 +1088,20 @@
 			case 14:
 				// RFC 5280, 4.2.1.2
 				var keyid []byte
-				if _, err = asn1.Unmarshal(e.Value, &keyid); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 authority key-id")
 				}
 				out.SubjectKeyId = keyid
 
 			case 32:
 				// RFC 5280 4.2.1.4: Certificate Policies
 				var policies []policyInformation
-				if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 certificate policies")
 				}
 				out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
 				for i, policy := range policies {
@@ -1048,14 +1109,16 @@
 				}
 
 			default:
-				// Unknown extensions cause an error if marked as critical.
-				failIfCritical = true
+				// Unknown extensions are recorded if critical.
+				unhandled = true
 			}
 		} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
 			// RFC 5280 4.2.2.1: Authority Information Access
 			var aia []authorityInfoAccess
-			if _, err = asn1.Unmarshal(e.Value, &aia); err != nil {
+			if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
 				return nil, err
+			} else if len(rest) != 0 {
+				return nil, errors.New("x509: trailing data after X.509 authority information")
 			}
 
 			for _, v := range aia {
@@ -1070,12 +1133,12 @@
 				}
 			}
 		} else {
-			// Unknown extensions cause an error if marked as critical.
-			failIfCritical = true
+			// Unknown extensions are recorded if critical.
+			unhandled = true
 		}
 
-		if e.Critical && failIfCritical {
-			return out, UnhandledCriticalExtension{}
+		if e.Critical && unhandled {
+			out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
 		}
 	}
 
@@ -1562,11 +1625,12 @@
 // ParseDERCRL parses a DER encoded CRL from the given bytes.
 func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
 	certList = new(pkix.CertificateList)
-	_, err = asn1.Unmarshal(derBytes, certList)
-	if err != nil {
-		certList = nil
+	if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after CRL")
 	}
-	return
+	return certList, nil
 }
 
 // CreateCRL returns a DER encoded CRL, signed by this Certificate, that
@@ -1669,11 +1733,11 @@
 // signature requests (see RFC 2986):
 
 type tbsCertificateRequest struct {
-	Raw        asn1.RawContent
-	Version    int
-	Subject    asn1.RawValue
-	PublicKey  publicKeyInfo
-	Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"`
+	Raw           asn1.RawContent
+	Version       int
+	Subject       asn1.RawValue
+	PublicKey     publicKeyInfo
+	RawAttributes []asn1.RawValue `asn1:"tag:0"`
 }
 
 type certificateRequest struct {
@@ -1687,6 +1751,36 @@
 // extensions in a CSR.
 var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 
+// newRawAttributes converts AttributeTypeAndValueSETs from a template
+// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
+func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
+	var rawAttributes []asn1.RawValue
+	b, err := asn1.Marshal(attributes)
+	rest, err := asn1.Unmarshal(b, &rawAttributes)
+	if err != nil {
+		return nil, err
+	}
+	if len(rest) != 0 {
+		return nil, errors.New("x509: failed to unmarshall raw CSR Attributes")
+	}
+	return rawAttributes, nil
+}
+
+// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
+func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
+	var attributes []pkix.AttributeTypeAndValueSET
+	for _, rawAttr := range rawAttributes {
+		var attr pkix.AttributeTypeAndValueSET
+		rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
+		// Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
+		// (i.e.: challengePassword or unstructuredName).
+		if err == nil && len(rest) == 0 {
+			attributes = append(attributes, attr)
+		}
+	}
+	return attributes
+}
+
 // CreateCertificateRequest creates a new certificate based on a template. The
 // following members of template are used: Subject, Attributes,
 // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
@@ -1799,6 +1893,11 @@
 		}
 	}
 
+	rawAttributes, err := newRawAttributes(attributes)
+	if err != nil {
+		return
+	}
+
 	tbsCSR := tbsCertificateRequest{
 		Version: 0, // PKCS #10, RFC 2986
 		Subject: asn1.RawValue{FullBytes: asn1Subject},
@@ -1809,7 +1908,7 @@
 				BitLength: len(publicKeyBytes) * 8,
 			},
 		},
-		Attributes: attributes,
+		RawAttributes: rawAttributes,
 	}
 
 	tbsCSRContents, err := asn1.Marshal(tbsCSR)
@@ -1866,7 +1965,7 @@
 		PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
 
 		Version:    in.TBSCSR.Version,
-		Attributes: in.TBSCSR.Attributes,
+		Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
 	}
 
 	var err error
@@ -1876,15 +1975,17 @@
 	}
 
 	var subject pkix.RDNSequence
-	if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+	if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
 		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 Subject")
 	}
 
 	out.Subject.FillFromRDNSequence(&subject)
 
 	var extensions []pkix.AttributeTypeAndValue
 
-	for _, atvSet := range in.TBSCSR.Attributes {
+	for _, atvSet := range out.Attributes {
 		if !atvSet.Type.Equal(oidExtensionRequest) {
 			continue
 		}
@@ -1920,3 +2021,8 @@
 
 	return out, nil
 }
+
+// CheckSignature verifies that the signature on c is a valid signature
+func (c *CertificateRequest) CheckSignature() (err error) {
+	return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
+}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index b74cbab..86a8b16 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -509,7 +509,13 @@
 				CommonName: "foo",
 			},
 			NotBefore: time.Unix(1000, 0),
-			NotAfter:  time.Unix(100000, 0),
+			NotAfter:  time.Now().AddDate(1, 0, 0),
+
+			BasicConstraintsValid: true,
+			IsCA: true,
+
+			KeyUsage:    KeyUsageCertSign,
+			ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
 
 			ExtraExtensions: []pkix.Extension{
 				{
@@ -525,13 +531,29 @@
 			t.Fatalf("failed to create certificate: %s", err)
 		}
 
-		_, err = ParseCertificate(derBytes)
+		cert, err := ParseCertificate(derBytes)
+		if err != nil {
+			t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err)
+		}
+
+		roots := NewCertPool()
+		roots.AddCert(cert)
+
+		// Setting Roots ensures that Verify won't delegate to the OS
+		// library and thus the correct error should always be
+		// returned.
+		_, err = cert.Verify(VerifyOptions{Roots: roots})
 		if err == nil {
-			t.Fatalf("Certificate with critical extension was parsed without error.")
+			t.Fatal("Certificate with unknown critical extension was verified without error")
 		}
 		if _, ok := err.(UnhandledCriticalExtension); !ok {
 			t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
 		}
+
+		cert.UnhandledCriticalExtensions = nil
+		if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil {
+			t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err)
+		}
 	}
 }
 
@@ -830,8 +852,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
@@ -903,6 +926,12 @@
 			continue
 		}
 
+		err = out.CheckSignature()
+		if err != nil {
+			t.Errorf("%s: failed to check certificate request signature: %s", test.name, err)
+			continue
+		}
+
 		if out.Subject.CommonName != template.Subject.CommonName {
 			t.Errorf("%s: output subject common name and template subject common name don't match", test.name)
 		} else if len(out.Subject.Organization) != len(template.Subject.Organization) {
@@ -1014,33 +1043,35 @@
 }
 
 func TestParseCertificateRequest(t *testing.T) {
-	csrBytes := fromBase64(csrBase64)
-	csr, err := ParseCertificateRequest(csrBytes)
-	if err != nil {
-		t.Fatalf("failed to parse CSR: %s", err)
-	}
-
-	if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher@golang.org" {
-		t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
-	}
-
-	if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
-		t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
-	}
-
-	if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
-		t.Errorf("incorrect Subject name: %v", csr.Subject)
-	}
-
-	found := false
-	for _, e := range csr.Extensions {
-		if e.Id.Equal(oidExtensionBasicConstraints) {
-			found = true
-			break
+	for _, csrBase64 := range csrBase64Array {
+		csrBytes := fromBase64(csrBase64)
+		csr, err := ParseCertificateRequest(csrBytes)
+		if err != nil {
+			t.Fatalf("failed to parse CSR: %s", err)
 		}
-	}
-	if !found {
-		t.Errorf("basic constraints extension not found in CSR")
+
+		if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher@golang.org" {
+			t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
+		}
+
+		if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
+			t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
+		}
+
+		if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
+			t.Errorf("incorrect Subject name: %v", csr.Subject)
+		}
+
+		found := false
+		for _, e := range csr.Extensions {
+			if e.Id.Equal(oidExtensionBasicConstraints) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			t.Errorf("basic constraints extension not found in CSR")
+		}
 	}
 }
 
@@ -1129,12 +1160,20 @@
 	}
 }
 
-// This CSR was generated with OpenSSL:
-//  openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
+// These CSR was generated with OpenSSL:
+//  openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf
 //
-// The openssl.cnf needs to include this section:
+// With openssl.cnf containing the following sections:
 //   [ v3_req ]
 //   basicConstraints = CA:FALSE
 //   keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 //   subjectAltName = email:gopher@golang.org,DNS:test.example.com
-const csrBase64 = "MIIC4zCCAcsCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOY+MVedRg2JEnyeLcSzcsMv2VcsTfkB5+Etd6hihAh6MrGezNyASMMKuQN6YhCX1icQDiQtGsDLTtheNnSXK06tAhHjAP/hGlszRJp+5+rP2M58fDBAkUBEhskbCUWwpY14jFtVuGNJ8vF8h8IeczdolvQhX9lVai9G0EUXJMliMKdjA899H0mRs9PzHyidyrXFNiZlQXfD8Kg7gETn2Ny965iyI6ujAIYSCvam6TnxRHYH2MBKyVGvsYGbPYUQJCsgdgyajEg6ekihvQY3SzO1HSAlZAd7d1QYO4VeWJ2mY6Wu3Jpmh+AmG19S9CcHqGjd0bhuAX9cpPOKgnEmqn0CAwEAAaBZMFcGCSqGSIb3DQEJDjFKMEgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYERZ29waGVyQGdvbGFuZy5vcmeCEHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAC9+QpKfdabxwCWwf4IEe1cKjdXLS1ScSuw27a3kZzQiPV78WJMa6dB8dqhdH5BRwGZ/qsgLrO6ZHlNeIv2Ib41Ccq71ecHW/nXc94A1BzJ/bVdI9LZcmTUvR1/m1jCpN7UqQ0ml1u9VihK7Pe762hEYxuWDQzYEU0l15S/bXmqeq3eF1A59XT/2jwe5+NV0Wwf4UQlkTXsAQMsJ+KzrQafd8Qv2A49o048uRvmjeJDrXLawGVianZ7D5A6Fpd1rZh6XcjqBpmgLw41DRQWENOdzhy+HyphKRv1MlY8OLkNqpGMhu8DdgJVGoT16DGiickoEa7Z3UCPVNgdTkT9jq7U="
+//   [ req_attributes ]
+//   challengePassword = ignored challenge
+//   unstructuredName  = ignored unstructured name
+var csrBase64Array = [...]string{
+	// Just [ v3_req ]
+	"MIIDHDCCAgQCAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaBZMFcGCSqGSIb3DQEJDjFKMEgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYERZ29waGVyQGdvbGFuZy5vcmeCEHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBAB6VPMRrchvNW61Tokyq3ZvO6/NoGIbuwUn54q6l5VZW0Ep5Nq8juhegSSnaJ0jrovmUgKDN9vEo2KxuAtwG6udS6Ami3zP+hRd4k9Q8djJPb78nrjzWiindLK5Fps9U5mMoi1ER8ViveyAOTfnZt/jsKUaRsscY2FzE9t9/o5moE6LTcHUS4Ap1eheR+J72WOnQYn3cifYaemsA9MJuLko+kQ6xseqttbh9zjqd9fiCSh/LNkzos9c+mg2yMADitaZinAh+HZi50ooEbjaT3erNq9O6RqwJlgD00g6MQdoz9bTAryCUhCQfkIaepmQ7BxS0pqWNW3MMwfDwx/Snz6g=",
+	// Both [ v3_req ] and [ req_attributes ]
+	"MIIDaTCCAlECAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaCBpTAgBgkqhkiG9w0BCQcxEwwRaWdub3JlZCBjaGFsbGVuZ2UwKAYJKoZIhvcNAQkCMRsMGWlnbm9yZWQgdW5zdHJ1Y3R1cmVkIG5hbWUwVwYJKoZIhvcNAQkOMUowSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAuBgNVHREEJzAlgRFnb3BoZXJAZ29sYW5nLm9yZ4IQdGVzdC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAgxe2N5O48EMsYE7o0rZBB0wi3Ov5/yYfnmmVI22Y3sP6VXbLDW0+UWIeSccOhzUCcZ/G4qcrfhhx6gTZTeA01nP7TdTJURvWAH5iFqj9sQ0qnLq6nEcVHij3sG6M5+BxAIVClQBk6lTCzgphc835Fjj6qSLuJ20XHdL5UfUbiJxx299CHgyBRL+hBUIPfz8p+ZgamyAuDLfnj54zzcRVyLlrmMLNPZNll1Q70RxoU6uWvLH8wB8vQe3Q/guSGubLyLRTUQVPh+dw1L4t8MKFWfX/48jwRM4gIRHFHPeAAE9D9YAoqdIvj/iFm/eQ++7DP8MDwOZWsXeB6jjwHuLmkQ==",
+}
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index a993fd4..8cbbb29 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -89,7 +89,10 @@
 	stmtsMade   int
 	stmtsClosed int
 	numPrepare  int
-	bad         bool
+
+	// bad connection tests; see isBad()
+	bad       bool
+	stickyBad bool
 }
 
 func (c *fakeConn) incrStat(v *int) {
@@ -243,13 +246,15 @@
 }
 
 func (c *fakeConn) isBad() bool {
-	// if not simulating bad conn, do nothing
-	if !c.bad {
+	if c.stickyBad {
+		return true
+	} else if c.bad {
+		// alternate between bad conn and not bad conn
+		c.db.badConn = !c.db.badConn
+		return c.db.badConn
+	} else {
 		return false
 	}
-	// alternate between bad conn and not bad conn
-	c.db.badConn = !c.db.badConn
-	return c.db.badConn
 }
 
 func (c *fakeConn) Begin() (driver.Tx, error) {
@@ -466,7 +471,7 @@
 		panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
 	}
 
-	if hookPrepareBadConn != nil && hookPrepareBadConn() {
+	if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) {
 		return nil, driver.ErrBadConn
 	}
 
@@ -529,7 +534,7 @@
 		return nil, errClosed
 	}
 
-	if hookExecBadConn != nil && hookExecBadConn() {
+	if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) {
 		return nil, driver.ErrBadConn
 	}
 
@@ -613,7 +618,7 @@
 		return nil, errClosed
 	}
 
-	if hookQueryBadConn != nil && hookQueryBadConn() {
+	if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) {
 		return nil, driver.ErrBadConn
 	}
 
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index b0e8894..96c93ed 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -235,6 +235,18 @@
 	maxOpen  int                    // <= 0 means unlimited
 }
 
+// connReuseStrategy determines how (*DB).conn returns database connections.
+type connReuseStrategy uint8
+
+const (
+	// alwaysNewConn forces a new connection to the database.
+	alwaysNewConn connReuseStrategy = iota
+	// cachedOrNewConn returns a cached connection, if available, else waits
+	// for one to become available (if MaxOpenConns has been reached) or
+	// creates a new database connection.
+	cachedOrNewConn
+)
+
 // driverConn wraps a driver.Conn with a mutex, to
 // be held during all calls into the Conn. (including any calls onto
 // interfaces returned via that Conn, such as calls on Tx, Stmt,
@@ -465,7 +477,7 @@
 	// TODO(bradfitz): give drivers an optional hook to implement
 	// this in a more efficient or more reliable way, if they
 	// have one.
-	dc, err := db.conn()
+	dc, err := db.conn(cachedOrNewConn)
 	if err != nil {
 		return err
 	}
@@ -651,17 +663,28 @@
 
 var errDBClosed = errors.New("sql: database is closed")
 
-// conn returns a newly-opened or cached *driverConn
-func (db *DB) conn() (*driverConn, error) {
+// conn returns a newly-opened or cached *driverConn.
+func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
 	db.mu.Lock()
 	if db.closed {
 		db.mu.Unlock()
 		return nil, errDBClosed
 	}
 
-	// If db.maxOpen > 0 and the number of open connections is over the limit
-	// and there are no free connection, make a request and wait.
-	if db.maxOpen > 0 && db.numOpen >= db.maxOpen && len(db.freeConn) == 0 {
+	// Prefer a free connection, if possible.
+	numFree := len(db.freeConn)
+	if strategy == cachedOrNewConn && numFree > 0 {
+		conn := db.freeConn[0]
+		copy(db.freeConn, db.freeConn[1:])
+		db.freeConn = db.freeConn[:numFree-1]
+		conn.inUse = true
+		db.mu.Unlock()
+		return conn, nil
+	}
+
+	// Out of free connections or we were asked not to use one.  If we're not
+	// allowed to open any more connections, make a request and wait.
+	if db.maxOpen > 0 && db.numOpen >= db.maxOpen {
 		// Make the connRequest channel. It's buffered so that the
 		// connectionOpener doesn't block while waiting for the req to be read.
 		req := make(chan connRequest, 1)
@@ -671,15 +694,6 @@
 		return ret.conn, ret.err
 	}
 
-	if c := len(db.freeConn); c > 0 {
-		conn := db.freeConn[0]
-		copy(db.freeConn, db.freeConn[1:])
-		db.freeConn = db.freeConn[:c-1]
-		conn.inUse = true
-		db.mu.Unlock()
-		return conn, nil
-	}
-
 	db.numOpen++ // optimistically
 	db.mu.Unlock()
 	ci, err := db.driver.Open(db.dsn)
@@ -782,6 +796,9 @@
 // If a connRequest was fulfilled or the *driverConn was placed in the
 // freeConn list, then true is returned, otherwise false is returned.
 func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
+	if db.maxOpen > 0 && db.numOpen > db.maxOpen {
+		return false
+	}
 	if c := len(db.connRequests); c > 0 {
 		req := db.connRequests[0]
 		// This copy is O(n) but in practice faster than a linked list.
@@ -805,8 +822,9 @@
 }
 
 // maxBadConnRetries is the number of maximum retries if the driver returns
-// driver.ErrBadConn to signal a broken connection.
-const maxBadConnRetries = 10
+// driver.ErrBadConn to signal a broken connection before forcing a new
+// connection to be opened.
+const maxBadConnRetries = 2
 
 // Prepare creates a prepared statement for later queries or executions.
 // Multiple queries or executions may be run concurrently from the
@@ -815,22 +833,25 @@
 	var stmt *Stmt
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		stmt, err = db.prepare(query)
+		stmt, err = db.prepare(query, cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.prepare(query, alwaysNewConn)
+	}
 	return stmt, err
 }
 
-func (db *DB) prepare(query string) (*Stmt, error) {
+func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
 	// TODO: check if db.driver supports an optional
 	// driver.Preparer interface and call that instead, if so,
 	// otherwise we make a prepared statement that's bound
 	// to a connection, and to execute this prepared statement
 	// we either need to use this connection (if it's free), else
 	// get a new connection + re-prepare + execute on that one.
-	dc, err := db.conn()
+	dc, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -858,16 +879,19 @@
 	var res Result
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		res, err = db.exec(query, args)
+		res, err = db.exec(query, args, cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.exec(query, args, alwaysNewConn)
+	}
 	return res, err
 }
 
-func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
-	dc, err := db.conn()
+func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
+	dc, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -907,16 +931,19 @@
 	var rows *Rows
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		rows, err = db.query(query, args)
+		rows, err = db.query(query, args, cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.query(query, args, alwaysNewConn)
+	}
 	return rows, err
 }
 
-func (db *DB) query(query string, args []interface{}) (*Rows, error) {
-	ci, err := db.conn()
+func (db *DB) query(query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
+	ci, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -995,16 +1022,19 @@
 	var tx *Tx
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		tx, err = db.begin()
+		tx, err = db.begin(cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.begin(alwaysNewConn)
+	}
 	return tx, err
 }
 
-func (db *DB) begin() (tx *Tx, err error) {
-	dc, err := db.conn()
+func (db *DB) begin(strategy connReuseStrategy) (tx *Tx, err error) {
+	dc, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -1393,7 +1423,7 @@
 	s.mu.Unlock()
 
 	// TODO(bradfitz): or always wait for one? make configurable later?
-	dc, err := s.db.conn()
+	dc, err := s.db.conn(cachedOrNewConn)
 	if err != nil {
 		return nil, nil, nil, err
 	}
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index e225ffe..94f80a6 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -1070,6 +1070,57 @@
 	}
 }
 
+// Issue 9453: tests that SetMaxOpenConns can be lowered at runtime
+// and affects the subsequent release of connections.
+func TestMaxOpenConnsOnBusy(t *testing.T) {
+	defer setHookpostCloseConn(nil)
+	setHookpostCloseConn(func(_ *fakeConn, err error) {
+		if err != nil {
+			t.Errorf("Error closing fakeConn: %v", err)
+		}
+	})
+
+	db := newTestDB(t, "magicquery")
+	defer closeDB(t, db)
+
+	db.SetMaxOpenConns(3)
+
+	conn0, err := db.conn(cachedOrNewConn)
+	if err != nil {
+		t.Fatalf("db open conn fail: %v", err)
+	}
+
+	conn1, err := db.conn(cachedOrNewConn)
+	if err != nil {
+		t.Fatalf("db open conn fail: %v", err)
+	}
+
+	conn2, err := db.conn(cachedOrNewConn)
+	if err != nil {
+		t.Fatalf("db open conn fail: %v", err)
+	}
+
+	if g, w := db.numOpen, 3; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+
+	db.SetMaxOpenConns(2)
+	if g, w := db.numOpen, 3; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+
+	conn0.releaseConn(nil)
+	conn1.releaseConn(nil)
+	if g, w := db.numOpen, 2; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+
+	conn2.releaseConn(nil)
+	if g, w := db.numOpen, 2; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+}
+
 func TestSingleOpenConn(t *testing.T) {
 	db := newTestDB(t, "people")
 	defer closeDB(t, db)
@@ -1334,6 +1385,79 @@
 	}
 }
 
+// Test cases where there's more than maxBadConnRetries bad connections in the
+// pool (issue 8834)
+func TestManyErrBadConn(t *testing.T) {
+	manyErrBadConnSetup := func() *DB {
+		db := newTestDB(t, "people")
+
+		nconn := maxBadConnRetries + 1
+		db.SetMaxIdleConns(nconn)
+		db.SetMaxOpenConns(nconn)
+		// open enough connections
+		func() {
+			for i := 0; i < nconn; i++ {
+				rows, err := db.Query("SELECT|people|age,name|")
+				if err != nil {
+					t.Fatal(err)
+				}
+				defer rows.Close()
+			}
+		}()
+
+		if db.numOpen != nconn {
+			t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
+		} else if len(db.freeConn) != nconn {
+			t.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db.freeConn), nconn)
+		}
+		for _, conn := range db.freeConn {
+			conn.ci.(*fakeConn).stickyBad = true
+		}
+		return db
+	}
+
+	// Query
+	db := manyErrBadConnSetup()
+	defer closeDB(t, db)
+	rows, err := db.Query("SELECT|people|age,name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = rows.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Exec
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	_, err = db.Exec("INSERT|people|name=Julia,age=19")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Begin
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = tx.Rollback(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Prepare
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	stmt, err := db.Prepare("SELECT|people|age,name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = stmt.Close(); err != nil {
+		t.Fatal(err)
+	}
+}
+
 // golang.org/issue/5781
 func TestErrBadConnReconnect(t *testing.T) {
 	db := newTestDB(t, "foo")
diff --git a/src/debug/dwarf/class_string.go b/src/debug/dwarf/class_string.go
new file mode 100644
index 0000000..0b1206b
--- /dev/null
+++ b/src/debug/dwarf/class_string.go
@@ -0,0 +1,17 @@
+// generated by stringer -type=Class; DO NOT EDIT
+
+package dwarf
+
+import "fmt"
+
+const _Class_name = "ClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt"
+
+var _Class_index = [...]uint8{0, 12, 22, 35, 47, 56, 68, 83, 94, 111, 125, 142, 153, 170, 184}
+
+func (i Class) String() string {
+	i -= 1
+	if i < 0 || i+1 >= Class(len(_Class_index)) {
+		return fmt.Sprintf("Class(%d)", i+1)
+	}
+	return _Class_name[_Class_index[i]:_Class_index[i+1]]
+}
diff --git a/src/debug/dwarf/entry.go b/src/debug/dwarf/entry.go
index 2742ae0..a94be32 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -23,8 +23,9 @@
 }
 
 type afield struct {
-	attr Attr
-	fmt  format
+	attr  Attr
+	fmt   format
+	class Class
 }
 
 // a map from entry format ids to their descriptions
@@ -32,7 +33,7 @@
 
 // ParseAbbrev returns the abbreviation table that starts at byte off
 // in the .debug_abbrev section.
-func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
+func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
 	if m, ok := d.abbrevCache[off]; ok {
 		return m, nil
 	}
@@ -80,6 +81,7 @@
 		for i := range a.field {
 			a.field[i].attr = Attr(b.uint())
 			a.field[i].fmt = format(b.uint())
+			a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b)
 		}
 		b.uint()
 		b.uint()
@@ -93,6 +95,118 @@
 	return m, nil
 }
 
+// attrIsExprloc indicates attributes that allow exprloc values that
+// are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure
+// 20.
+var attrIsExprloc = map[Attr]bool{
+	AttrLocation:      true,
+	AttrByteSize:      true,
+	AttrBitOffset:     true,
+	AttrBitSize:       true,
+	AttrStringLength:  true,
+	AttrLowerBound:    true,
+	AttrReturnAddr:    true,
+	AttrStrideSize:    true,
+	AttrUpperBound:    true,
+	AttrCount:         true,
+	AttrDataMemberLoc: true,
+	AttrFrameBase:     true,
+	AttrSegment:       true,
+	AttrStaticLink:    true,
+	AttrUseLocation:   true,
+	AttrVtableElemLoc: true,
+	AttrAllocated:     true,
+	AttrAssociated:    true,
+	AttrDataLocation:  true,
+	AttrStride:        true,
+}
+
+// attrPtrClass indicates the *ptr class of attributes that have
+// encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3.
+var attrPtrClass = map[Attr]Class{
+	AttrLocation:      ClassLocListPtr,
+	AttrStmtList:      ClassLinePtr,
+	AttrStringLength:  ClassLocListPtr,
+	AttrReturnAddr:    ClassLocListPtr,
+	AttrStartScope:    ClassRangeListPtr,
+	AttrDataMemberLoc: ClassLocListPtr,
+	AttrFrameBase:     ClassLocListPtr,
+	AttrMacroInfo:     ClassMacPtr,
+	AttrSegment:       ClassLocListPtr,
+	AttrStaticLink:    ClassLocListPtr,
+	AttrUseLocation:   ClassLocListPtr,
+	AttrVtableElemLoc: ClassLocListPtr,
+	AttrRanges:        ClassRangeListPtr,
+}
+
+// formToClass returns the DWARF 4 Class for the given form. If the
+// DWARF version is less then 4, it will disambiguate some forms
+// depending on the attribute.
+func formToClass(form format, attr Attr, vers int, b *buf) Class {
+	switch form {
+	default:
+		b.error("cannot determine class of unknown attribute form")
+		return 0
+
+	case formAddr:
+		return ClassAddress
+
+	case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock:
+		// In DWARF 2 and 3, ClassExprLoc was encoded as a
+		// block. DWARF 4 distinguishes ClassBlock and
+		// ClassExprLoc, but there are no attributes that can
+		// be both, so we also promote ClassBlock values in
+		// DWARF 4 that should be ClassExprLoc in case
+		// producers get this wrong.
+		if attrIsExprloc[attr] {
+			return ClassExprLoc
+		}
+		return ClassBlock
+
+	case formData1, formData2, formData4, formData8, formSdata, formUdata:
+		// In DWARF 2 and 3, ClassPtr was encoded as a
+		// constant. Unlike ClassExprLoc/ClassBlock, some
+		// DWARF 4 attributes need to distinguish Class*Ptr
+		// from ClassConstant, so we only do this promotion
+		// for versions 2 and 3.
+		if class, ok := attrPtrClass[attr]; vers < 4 && ok {
+			return class
+		}
+		return ClassConstant
+
+	case formFlag, formFlagPresent:
+		return ClassFlag
+
+	case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata:
+		return ClassReference
+
+	case formRefSig8:
+		return ClassReferenceSig
+
+	case formString, formStrp:
+		return ClassString
+
+	case formSecOffset:
+		// DWARF 4 defines four *ptr classes, but doesn't
+		// distinguish them in the encoding. Disambiguate
+		// these classes using the attribute.
+		if class, ok := attrPtrClass[attr]; ok {
+			return class
+		}
+		b.error("cannot determine class of unknown attribute with formSecOffset")
+		return 0
+
+	case formExprloc:
+		return ClassExprLoc
+
+	case formGnuRefAlt:
+		return ClassReferenceAlt
+
+	case formGnuStrpAlt:
+		return ClassStringAlt
+	}
+}
+
 // An entry is a sequence of attribute/value pairs.
 type Entry struct {
 	Offset   Offset // offset of Entry in DWARF info
@@ -102,9 +216,115 @@
 }
 
 // A Field is a single attribute/value pair in an Entry.
+//
+// A value can be one of several "attribute classes" defined by DWARF.
+// The Go types corresponding to each class are:
+//
+//    DWARF class       Go type        Class
+//    -----------       -------        -----
+//    address           uint64         ClassAddress
+//    block             []byte         ClassBlock
+//    constant          int64          ClassConstant
+//    flag              bool           ClassFlag
+//    reference
+//      to info         dwarf.Offset   ClassReference
+//      to type unit    uint64         ClassReferenceSig
+//    string            string         ClassString
+//    exprloc           []byte         ClassExprLoc
+//    lineptr           int64          ClassLinePtr
+//    loclistptr        int64          ClassLocListPtr
+//    macptr            int64          ClassMacPtr
+//    rangelistptr      int64          ClassRangeListPtr
 type Field struct {
-	Attr Attr
-	Val  interface{}
+	Attr  Attr
+	Val   interface{}
+	Class Class
+}
+
+// A Class is the DWARF 4 class of an attibute value.
+//
+// In general, a given attribute's value may take on one of several
+// possible classes defined by DWARF, each of which leads to a
+// slightly different interpretation of the attribute.
+//
+// DWARF version 4 distinguishes attribute value classes more finely
+// than previous versions of DWARF. The reader will disambiguate
+// coarser classes from earlier versions of DWARF into the appropriate
+// DWARF 4 class. For example, DWARF 2 uses "constant" for constants
+// as well as all types of section offsets, but the reader will
+// canonicalize attributes in DWARF 2 files that refer to section
+// offsets to one of the Class*Ptr classes, even though these classes
+// were only defined in DWARF 3.
+type Class int
+
+const (
+	// ClassAddress represents values of type uint64 that are
+	// addresses on the target machine.
+	ClassAddress Class = 1 + iota
+
+	// ClassBlock represents values of type []byte whose
+	// interpretation depends on the attribute.
+	ClassBlock
+
+	// ClassConstant represents values of type int64 that are
+	// constants. The interpretation of this constant depends on
+	// the attribute.
+	ClassConstant
+
+	// ClassExprLoc represents values of type []byte that contain
+	// an encoded DWARF expression or location description.
+	ClassExprLoc
+
+	// ClassFlag represents values of type bool.
+	ClassFlag
+
+	// ClassLinePtr represents values that are an int64 offset
+	// into the "line" section.
+	ClassLinePtr
+
+	// ClassLocListPtr repersents values that are an int64 offset
+	// into the "loclist" section.
+	ClassLocListPtr
+
+	// ClassMacPtr represents values that are an int64 offset into
+	// the "mac" section.
+	ClassMacPtr
+
+	// ClassMacPtr represents values that are an int64 offset into
+	// the "rangelist" section.
+	ClassRangeListPtr
+
+	// ClassReference represents values that are an Offset offset
+	// of an Entry in the info section (for use with Reader.Seek).
+	// The DWARF specification combines ClassReference and
+	// ClassReferenceSig into class "reference".
+	ClassReference
+
+	// ClassReferenceSig represents values that are a uint64 type
+	// signature referencing a type Entry.
+	ClassReferenceSig
+
+	// ClassString represents values that are strings. If the
+	// compilation unit specifies the AttrUseUTF8 flag (strongly
+	// recommended), the string value will be encoded in UTF-8.
+	// Otherwise, the encoding is unspecified.
+	ClassString
+
+	// ClassReferenceAlt represents values of type int64 that are
+	// an offset into the DWARF "info" section of an alternate
+	// object file.
+	ClassReferenceAlt
+
+	// ClassStringAlt represents values of type int64 that are an
+	// offset into the DWARF string section of an alternate object
+	// file.
+	ClassStringAlt
+)
+
+//go:generate stringer -type=Class
+
+func (i Class) GoString() string {
+	return "dwarf." + i.String()
 }
 
 // Val returns the value associated with attribute Attr in Entry,
@@ -115,9 +335,18 @@
 //	v, ok := e.Val(AttrSibling).(int64)
 //
 func (e *Entry) Val(a Attr) interface{} {
-	for _, f := range e.Field {
+	if f := e.AttrField(a); f != nil {
+		return f.Val
+	}
+	return nil
+}
+
+// AttrField returns the Field associated with attribute Attr in
+// Entry, or nil if there is no such attribute.
+func (e *Entry) AttrField(a Attr) *Field {
+	for i, f := range e.Field {
 		if f.Attr == a {
-			return f.Val
+			return &e.Field[i]
 		}
 	}
 	return nil
@@ -148,6 +377,7 @@
 	}
 	for i := range e.Field {
 		e.Field[i].Attr = a.field[i].attr
+		e.Field[i].Class = a.field[i].class
 		fmt := a.field[i].fmt
 		if fmt == formIndirect {
 			fmt = format(b.uint())
@@ -292,6 +522,12 @@
 	return r
 }
 
+// AddressSize returns the size in bytes of addresses in the current compilation
+// unit.
+func (r *Reader) AddressSize() int {
+	return r.d.unit[r.unit].asize
+}
+
 // Seek positions the Reader at offset off in the encoded entry stream.
 // Offset 0 can be used to denote the first entry.
 func (r *Reader) Seek(off Offset) {
@@ -311,6 +547,7 @@
 	i := d.offsetToUnit(off)
 	if i == -1 {
 		r.err = errors.New("offset out of range")
+		return
 	}
 	u := &d.unit[i]
 	r.unit = i
diff --git a/src/debug/dwarf/type.go b/src/debug/dwarf/type.go
index 6986b19..a5daa1d 100644
--- a/src/debug/dwarf/type.go
+++ b/src/debug/dwarf/type.go
@@ -268,6 +268,9 @@
 	Next() (*Entry, error)
 	clone() typeReader
 	offset() Offset
+	// AddressSize returns the size in bytes of addresses in the current
+	// compilation unit.
+	AddressSize() int
 }
 
 // Type reads the type at off in the DWARF ``info'' section.
@@ -286,6 +289,7 @@
 	if err != nil {
 		return nil, err
 	}
+	addressSize := r.AddressSize()
 	if e == nil || e.Offset != off {
 		return nil, DecodeError{name, off, "no type at offset"}
 	}
@@ -668,6 +672,12 @@
 		b, ok := e.Val(AttrByteSize).(int64)
 		if !ok {
 			b = -1
+			switch t := typ.(type) {
+			case *TypedefType:
+				b = t.Type.Size()
+			case *PtrType:
+				b = int64(addressSize)
+			}
 		}
 		typ.Common().ByteSize = b
 	}
diff --git a/src/debug/dwarf/typeunit.go b/src/debug/dwarf/typeunit.go
index 80971bb..9cfb4a8 100644
--- a/src/debug/dwarf/typeunit.go
+++ b/src/debug/dwarf/typeunit.go
@@ -33,9 +33,9 @@
 			return b.err
 		}
 		hdroff := b.off
-		vers := b.uint16()
+		vers := int(b.uint16())
 		if vers != 4 {
-			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+			b.error("unsupported DWARF version " + strconv.Itoa(vers))
 			return b.err
 		}
 		var ao uint32
@@ -49,7 +49,7 @@
 			}
 			ao = uint32(ao64)
 		}
-		atable, err := d.parseAbbrev(ao)
+		atable, err := d.parseAbbrev(ao, vers)
 		if err != nil {
 			return err
 		}
@@ -129,6 +129,11 @@
 	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
 }
 
+// AddressSize returns the size in bytes of addresses in the current type unit.
+func (tur *typeUnitReader) AddressSize() int {
+	return tur.tu.unit.asize
+}
+
 // Next reads the next Entry from the type unit.
 func (tur *typeUnitReader) Next() (*Entry, error) {
 	if tur.err != nil {
diff --git a/src/debug/dwarf/unit.go b/src/debug/dwarf/unit.go
index 901ba0d..ceb6cdb 100644
--- a/src/debug/dwarf/unit.go
+++ b/src/debug/dwarf/unit.go
@@ -67,7 +67,7 @@
 			break
 		}
 		u.vers = int(vers)
-		atable, err := d.parseAbbrev(b.uint32())
+		atable, err := d.parseAbbrev(b.uint32(), u.vers)
 		if err != nil {
 			if b.err == nil {
 				b.err = err
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index 0d10ec5..48fe9d2 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -245,56 +245,56 @@
 	{
 		"testdata/go-relocation-test-gcc441-x86-64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc441-x86.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc424-x86-64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc482-aarch64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc492-arm.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c"}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x28)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc5-ppc.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc482-ppc64le.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-clang-x86.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}}}},
 		},
 	},
 	{
 		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
 		[]relocationTestEntry{
-			{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}},
-			{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}},
+			{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}}}},
+			{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}}}},
 		},
 	},
 }
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 1415fac..6855a65 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -84,7 +84,11 @@
 }
 
 func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
-	symdat, err := f.Section(".gosymtab").Data()
+	s := f.Section(".gosymtab")
+	if s == nil {
+		t.Skip("no .gosymtab section")
+	}
+	symdat, err := s.Data()
 	if err != nil {
 		f.Close()
 		t.Fatalf("reading %s gosymtab: %v", file, err)
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index aa99ca5..7172c1c 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -579,6 +579,8 @@
 				result, err = parseObjectIdentifier(innerBytes)
 			case tagUTCTime:
 				result, err = parseUTCTime(innerBytes)
+			case tagGeneralizedTime:
+				result, err = parseGeneralizedTime(innerBytes)
 			case tagOctetString:
 				result = innerBytes
 			default:
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index 4e864d0..1a2ae25 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -358,6 +358,8 @@
 var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
 	{"", fieldParameters{}},
 	{"ia5", fieldParameters{stringType: tagIA5String}},
+	{"generalized", fieldParameters{timeType: tagGeneralizedTime}},
+	{"utc", fieldParameters{timeType: tagUTCTime}},
 	{"printable", fieldParameters{stringType: tagPrintableString}},
 	{"optional", fieldParameters{optional: true}},
 	{"explicit", fieldParameters{explicit: true, tag: new(int)}},
@@ -366,7 +368,7 @@
 	{"default:42", fieldParameters{defaultValue: newInt64(42)}},
 	{"tag:17", fieldParameters{tag: newInt(17)}},
 	{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
-	{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false, false}},
+	{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, 0, false, false}},
 	{"set", fieldParameters{set: true}},
 }
 
diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go
index 33a117e..ab85e04 100644
--- a/src/encoding/asn1/common.go
+++ b/src/encoding/asn1/common.go
@@ -74,6 +74,7 @@
 	defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
 	tag          *int   // the EXPLICIT or IMPLICIT tag (maybe nil).
 	stringType   int    // the string tag to use when marshaling.
+	timeType     int    // the time tag to use when marshaling.
 	set          bool   // true iff this should be encoded as a SET
 	omitEmpty    bool   // true iff this should be omitted if empty when marshaling.
 
@@ -94,6 +95,10 @@
 			if ret.tag == nil {
 				ret.tag = new(int)
 			}
+		case part == "generalized":
+			ret.timeType = tagGeneralizedTime
+		case part == "utc":
+			ret.timeType = tagUTCTime
 		case part == "ia5":
 			ret.stringType = tagIA5String
 		case part == "printable":
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index bf92c04..67a019d 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -410,9 +410,11 @@
 
 func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
 	switch value.Type() {
+	case flagType:
+		return nil
 	case timeType:
 		t := value.Interface().(time.Time)
-		if outsideUTCRange(t) {
+		if params.timeType == tagGeneralizedTime || outsideUTCRange(t) {
 			return marshalGeneralizedTime(out, t)
 		} else {
 			return marshalUTCTime(out, t)
@@ -552,6 +554,10 @@
 	}
 	class := classUniversal
 
+	if params.timeType != 0 && tag != tagUTCTime {
+		return StructuralError{"explicit time type given to non-time member"}
+	}
+
 	if params.stringType != 0 && tag != tagPrintableString {
 		return StructuralError{"explicit string type given to non-string member"}
 	}
@@ -575,7 +581,7 @@
 			tag = params.stringType
 		}
 	case tagUTCTime:
-		if outsideUTCRange(v.Interface().(time.Time)) {
+		if params.timeType == tagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
 			tag = tagGeneralizedTime
 		}
 	}
diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go
index 5b0115f..cdca8aa 100644
--- a/src/encoding/asn1/marshal_test.go
+++ b/src/encoding/asn1/marshal_test.go
@@ -42,6 +42,14 @@
 	A int `asn1:"explicit,tag:5"`
 }
 
+type flagTest struct {
+	A Flag `asn1:"tag:0,optional"`
+}
+
+type generalizedTimeTest struct {
+	A time.Time `asn1:"generalized"`
+}
+
 type ia5StringTest struct {
 	A string `asn1:"ia5"`
 }
@@ -92,10 +100,13 @@
 	{[]byte{1, 2, 3}, "0403010203"},
 	{implicitTagTest{64}, "3003850140"},
 	{explicitTagTest{64}, "3005a503020140"},
+	{flagTest{true}, "30028000"},
+	{flagTest{false}, "3000"},
 	{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
 	{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
 	{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
 	{farFuture(), "180f32313030303430353132303130315a"},
+	{generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"},
 	{BitString{[]byte{0x80}, 1}, "03020780"},
 	{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
 	{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index db4a409..3302fb4 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -6,10 +6,8 @@
 package base64
 
 import (
-	"bytes"
 	"io"
 	"strconv"
-	"strings"
 )
 
 /*
@@ -22,7 +20,7 @@
 // (RFC 1421).  RFC 4648 also defines an alternate encoding, which is
 // the standard encoding with - and _ substituted for + and /.
 type Encoding struct {
-	encode    string
+	encode    [64]byte
 	decodeMap [256]byte
 	padChar   rune
 }
@@ -40,9 +38,14 @@
 // The resulting Encoding uses the default padding character ('='),
 // which may be changed or disabled via WithPadding.
 func NewEncoding(encoder string) *Encoding {
+	if len(encoder) != 64 {
+		panic("encoding alphabet is not 64-bytes long")
+	}
+
 	e := new(Encoding)
-	e.encode = encoder
 	e.padChar = StdPadding
+	copy(e.encode[:], encoder)
+
 	for i := 0; i < len(e.decodeMap); i++ {
 		e.decodeMap[i] = 0xFF
 	}
@@ -77,13 +80,6 @@
 // This is the same as URLEncoding but omits padding characters.
 var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
 
-var removeNewlinesMapper = func(r rune) rune {
-	if r == '\r' || r == '\n' {
-		return -1
-	}
-	return r
-}
-
 /*
  * Encoder
  */
@@ -99,46 +95,45 @@
 		return
 	}
 
-	for len(src) > 0 {
-		var b0, b1, b2, b3 byte
+	di, si := 0, 0
+	n := (len(src) / 3) * 3
+	for si < n {
+		// Convert 3x 8bit source bytes into 4 bytes
+		val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
 
-		// Unpack 4x 6-bit source blocks into a 4 byte
-		// destination quantum
-		switch len(src) {
-		default:
-			b3 = src[2] & 0x3F
-			b2 = src[2] >> 6
-			fallthrough
-		case 2:
-			b2 |= (src[1] << 2) & 0x3F
-			b1 = src[1] >> 4
-			fallthrough
-		case 1:
-			b1 |= (src[0] << 4) & 0x3F
-			b0 = src[0] >> 2
+		dst[di+0] = enc.encode[val>>18&0x3F]
+		dst[di+1] = enc.encode[val>>12&0x3F]
+		dst[di+2] = enc.encode[val>>6&0x3F]
+		dst[di+3] = enc.encode[val&0x3F]
+
+		si += 3
+		di += 4
+	}
+
+	remain := len(src) - si
+	if remain == 0 {
+		return
+	}
+	// Add the remaining small block
+	val := uint(src[si+0]) << 16
+	if remain == 2 {
+		val |= uint(src[si+1]) << 8
+	}
+
+	dst[di+0] = enc.encode[val>>18&0x3F]
+	dst[di+1] = enc.encode[val>>12&0x3F]
+
+	switch remain {
+	case 2:
+		dst[di+2] = enc.encode[val>>6&0x3F]
+		if enc.padChar != NoPadding {
+			dst[di+3] = byte(enc.padChar)
 		}
-
-		// Encode 6-bit blocks using the base64 alphabet
-		dst[0] = enc.encode[b0]
-		dst[1] = enc.encode[b1]
-		if len(src) >= 3 {
-			dst[2] = enc.encode[b2]
-			dst[3] = enc.encode[b3]
-		} else { // Final incomplete quantum
-			if len(src) >= 2 {
-				dst[2] = enc.encode[b2]
-			}
-			if enc.padChar != NoPadding {
-				if len(src) < 2 {
-					dst[2] = byte(enc.padChar)
-				}
-				dst[3] = byte(enc.padChar)
-			}
-			break
+	case 1:
+		if enc.padChar != NoPadding {
+			dst[di+2] = byte(enc.padChar)
+			dst[di+3] = byte(enc.padChar)
 		}
-
-		src = src[3:]
-		dst = dst[4:]
 	}
 }
 
@@ -248,67 +243,83 @@
 
 // decode is like Decode but returns an additional 'end' value, which
 // indicates if end-of-message padding or a partial quantum was encountered
-// and thus any additional data is an error. This method assumes that src has been
-// stripped of all supported whitespace ('\r' and '\n').
+// and thus any additional data is an error.
 func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
-	olen := len(src)
-	for len(src) > 0 && !end {
+	si := 0
+
+	// skip over newlines
+	for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+		si++
+	}
+
+	for si < len(src) && !end {
 		// Decode quantum using the base64 alphabet
 		var dbuf [4]byte
 		dinc, dlen := 3, 4
 
 		for j := range dbuf {
-			if len(src) == 0 {
+			if len(src) == si {
 				if enc.padChar != NoPadding || j < 2 {
-					return n, false, CorruptInputError(olen - len(src) - j)
+					return n, false, CorruptInputError(si - j)
 				}
 				dinc, dlen, end = j-1, j, true
 				break
 			}
-			in := src[0]
-			src = src[1:]
+			in := src[si]
+
+			si++
+			// skip over newlines
+			for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+				si++
+			}
+
 			if rune(in) == enc.padChar {
 				// We've reached the end and there's padding
 				switch j {
 				case 0, 1:
 					// incorrect padding
-					return n, false, CorruptInputError(olen - len(src) - 1)
+					return n, false, CorruptInputError(si - 1)
 				case 2:
 					// "==" is expected, the first "=" is already consumed.
-					if len(src) == 0 {
+					if si == len(src) {
 						// not enough padding
-						return n, false, CorruptInputError(olen)
+						return n, false, CorruptInputError(len(src))
 					}
-					if rune(src[0]) != enc.padChar {
+					if rune(src[si]) != enc.padChar {
 						// incorrect padding
-						return n, false, CorruptInputError(olen - len(src) - 1)
+						return n, false, CorruptInputError(si - 1)
 					}
-					src = src[1:]
+
+					si++
+					// skip over newlines
+					for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+						si++
+					}
 				}
-				if len(src) > 0 {
+				if si < len(src) {
 					// trailing garbage
-					err = CorruptInputError(olen - len(src))
+					err = CorruptInputError(si)
 				}
 				dinc, dlen, end = 3, j, true
 				break
 			}
 			dbuf[j] = enc.decodeMap[in]
 			if dbuf[j] == 0xFF {
-				return n, false, CorruptInputError(olen - len(src) - 1)
+				return n, false, CorruptInputError(si - 1)
 			}
 		}
 
-		// Pack 4x 6-bit source blocks into 3 byte destination
-		// quantum
+		// Convert 4x 6bit source bytes into 3 bytes
+		val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
 		switch dlen {
 		case 4:
-			dst[2] = dbuf[2]<<6 | dbuf[3]
+			dst[2] = byte(val >> 0)
 			fallthrough
 		case 3:
-			dst[1] = dbuf[1]<<4 | dbuf[2]>>2
+			dst[1] = byte(val >> 8)
 			fallthrough
 		case 2:
-			dst[0] = dbuf[0]<<2 | dbuf[1]>>4
+			dst[0] = byte(val >> 16)
 		}
 		dst = dst[dinc:]
 		n += dlen - 1
@@ -323,14 +334,12 @@
 // number of bytes successfully written and CorruptInputError.
 // New line characters (\r and \n) are ignored.
 func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
-	src = bytes.Map(removeNewlinesMapper, src)
 	n, _, err = enc.decode(dst, src)
 	return
 }
 
 // DecodeString returns the bytes represented by the base64 string s.
 func (enc *Encoding) DecodeString(s string) ([]byte, error) {
-	s = strings.Map(removeNewlinesMapper, s)
 	dbuf := make([]byte, enc.DecodedLen(len(s)))
 	n, _, err := enc.decode(dbuf, []byte(s))
 	return dbuf[:n], err
@@ -359,6 +368,8 @@
 		return n, nil
 	}
 
+	// This code assumes that d.r strips supported whitespace ('\r' and '\n').
+
 	// Read a chunk.
 	nn := len(p) / 3 * 4
 	if nn < 4 {
diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go
index d943295..d0a0904 100644
--- a/src/encoding/csv/reader.go
+++ b/src/encoding/csv/reader.go
@@ -228,6 +228,12 @@
 	}
 	r.r.UnreadRune()
 
+	// If FieldsPerRecord is greater then 0 we can assume the final
+	// length of fields to be equal to FieldsPerRecord.
+	if r.FieldsPerRecord > 0 {
+		fields = make([]string, 0, r.FieldsPerRecord)
+	}
+
 	// At this point we have at least one field.
 	for {
 		haveField, delim, err := r.parseField()
diff --git a/src/encoding/csv/reader_test.go b/src/encoding/csv/reader_test.go
index 123df06..b3c4f3b 100644
--- a/src/encoding/csv/reader_test.go
+++ b/src/encoding/csv/reader_test.go
@@ -282,3 +282,25 @@
 		}
 	}
 }
+
+func BenchmarkRead(b *testing.B) {
+	data := `x,y,z,w
+x,y,z,
+x,y,,
+x,,,
+,,,
+"x","y","z","w"
+"x","y","z",""
+"x","y","",""
+"x","","",""
+"","","",""
+`
+
+	for i := 0; i < b.N; i++ {
+		_, err := NewReader(strings.NewReader(data)).ReadAll()
+
+		if err != nil {
+			b.Fatalf("could not read data: %s", err)
+		}
+	}
+}
diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go
index 56a7298..c2583bf 100644
--- a/src/encoding/gob/codec_test.go
+++ b/src/encoding/gob/codec_test.go
@@ -1473,3 +1473,22 @@
 		}
 	}
 }
+
+// Don't crash, just give error with invalid type id.
+// Issue 9649.
+func TestErrorInvalidTypeId(t *testing.T) {
+	data := []byte{0x01, 0x00, 0x01, 0x00}
+	d := NewDecoder(bytes.NewReader(data))
+	// When running d.Decode(&foo) the first time the decoder stops
+	// after []byte{0x01, 0x00} and reports an errBadType. Running
+	// d.Decode(&foo) again on exactly the same input sequence should
+	// give another errBadType, but instead caused a panic because
+	// decoderMap wasn't cleaned up properly after the first error.
+	for i := 0; i < 2; i++ {
+		var foo struct{}
+		err := d.Decode(&foo)
+		if err != errBadType {
+			t.Fatal("decode: expected %s, got %s", errBadType, err)
+		}
+	}
+}
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index a5bef93..b34110f 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -182,6 +182,17 @@
 	return int64(x >> 1)
 }
 
+// getLength decodes the next uint and makes sure it is a possible
+// size for a data item that follows, which means it must fit in a
+// non-negative int and fit in the buffer.
+func (state *decoderState) getLength() (int, bool) {
+	n := int(state.decodeUint())
+	if n < 0 || state.b.Len() < n || tooBig <= n {
+		return 0, false
+	}
+	return n, true
+}
+
 // decOp is the signature of a decoding operator for a given type.
 type decOp func(i *decInstr, state *decoderState, v reflect.Value)
 
@@ -363,16 +374,9 @@
 // describing the data.
 // uint8 slices are encoded as an unsigned count followed by the raw bytes.
 func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
-	u := state.decodeUint()
-	n := int(u)
-	if n < 0 || uint64(n) != u {
-		errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
-	}
-	if n > state.b.Len() {
-		errorf("%s data too long for buffer: %d", value.Type(), n)
-	}
-	if n > tooBig {
-		errorf("byte slice too big: %d", n)
+	n, ok := state.getLength()
+	if !ok {
+		errorf("bad %s slice length: %d", value.Type(), n)
 	}
 	if value.Cap() < n {
 		value.Set(reflect.MakeSlice(value.Type(), n, n))
@@ -388,13 +392,9 @@
 // describing the data.
 // Strings are encoded as an unsigned count followed by the raw bytes.
 func decString(i *decInstr, state *decoderState, value reflect.Value) {
-	u := state.decodeUint()
-	n := int(u)
-	if n < 0 || uint64(n) != u || n > state.b.Len() {
-		errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
-	}
-	if n > state.b.Len() {
-		errorf("%s data too long for buffer: %d", value.Type(), n)
+	n, ok := state.getLength()
+	if !ok {
+		errorf("bad %s slice length: %d", value.Type(), n)
 	}
 	// Read the data.
 	data := make([]byte, n)
@@ -406,7 +406,11 @@
 
 // ignoreUint8Array skips over the data for a byte slice value with no destination.
 func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("slice length too large")
+	}
+	b := make([]byte, n)
 	state.b.Read(b)
 }
 
@@ -571,6 +575,9 @@
 func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
 	instr := &decInstr{elemOp, 0, nil, errors.New("no error")}
 	for i := 0; i < length; i++ {
+		if state.b.Len() == 0 {
+			errorf("decoding array or slice: length exceeds input size (%d elements)", length)
+		}
 		elemOp(instr, state, noValue)
 	}
 }
@@ -678,7 +685,11 @@
 // ignoreInterface discards the data for an interface value with no destination.
 func (dec *Decoder) ignoreInterface(state *decoderState) {
 	// Read the name of the concrete type.
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("bad interface encoding: name too large for buffer")
+	}
+	b := make([]byte, n)
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -688,14 +699,22 @@
 		error_(dec.err)
 	}
 	// At this point, the decoder buffer contains a delimited value. Just toss it.
-	state.b.Drop(int(state.decodeUint()))
+	n, ok = state.getLength()
+	if !ok {
+		errorf("bad interface encoding: data length too large for buffer")
+	}
+	state.b.Drop(n)
 }
 
 // decodeGobDecoder decodes something implementing the GobDecoder interface.
 // The data is encoded as a byte slice.
 func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) {
 	// Read the bytes for the value.
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("GobDecoder: length too large for buffer")
+	}
+	b := make([]byte, n)
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -717,7 +736,11 @@
 // ignoreGobDecoder discards the data for a GobDecoder value with no destination.
 func (dec *Decoder) ignoreGobDecoder(state *decoderState) {
 	// Read the bytes for the value.
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("GobDecoder: length too large for buffer")
+	}
+	b := make([]byte, n)
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -1043,6 +1066,7 @@
 // compileDec compiles the decoder engine for a value.  If the value is not a struct,
 // it calls out to compileSingle.
 func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
+	defer catchError(&err)
 	rt := ut.base
 	srt := rt
 	if srt.Kind() != reflect.Struct || ut.externalDec != 0 {
@@ -1116,7 +1140,7 @@
 
 var emptyStructType = reflect.TypeOf(emptyStruct{})
 
-// getDecEnginePtr returns the engine for the specified type when the value is to be discarded.
+// getIgnoreEnginePtr returns the engine for the specified type when the value is to be discarded.
 func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err error) {
 	var ok bool
 	if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
@@ -1155,8 +1179,9 @@
 	value = decAlloc(value)
 	engine := *enginePtr
 	if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {
+		wt := dec.wireType[wireId]
 		if engine.numInstr == 0 && st.NumField() > 0 &&
-			dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 {
+			wt != nil && len(wt.StructT.Field) > 0 {
 			name := base.Name()
 			errorf("type mismatch: no fields matched compiling decoder for %s", name)
 		}
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index 4af7195..c0bd379 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -6,8 +6,8 @@
 
 import (
 	"bytes"
+	"encoding/hex"
 	"fmt"
-	"io"
 	"reflect"
 	"strings"
 	"testing"
@@ -187,24 +187,6 @@
 	badTypeCheck(new(ET4), true, "different type of field", t)
 }
 
-func corruptDataCheck(s string, err error, t *testing.T) {
-	b := bytes.NewBufferString(s)
-	dec := NewDecoder(b)
-	err1 := dec.Decode(new(ET2))
-	if err1 != err {
-		t.Errorf("from %q expected error %s; got %s", s, err, err1)
-	}
-}
-
-// Check that we survive bad data.
-func TestBadData(t *testing.T) {
-	corruptDataCheck("", io.EOF, t)
-	corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
-	corruptDataCheck("\x03now is the time for all good men", errBadType, t)
-	// issue 6323.
-	corruptDataCheck("\x04\x24foo", errRange, t)
-}
-
 // Types not supported at top level by the Encoder.
 var unsupportedValues = []interface{}{
 	make(chan int),
@@ -954,3 +936,43 @@
 		t.Fatalf("decode: expected slice too big error, got %s", err.Error())
 	}
 }
+
+type badDataTest struct {
+	input string      // The input encoded as a hex string.
+	error string      // A substring of the error that should result.
+	data  interface{} // What to decode into.
+}
+
+var badDataTests = []badDataTest{
+	{"", "EOF", nil},
+	{"7F6869", "unexpected EOF", nil},
+	{"036e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e", "unknown type id", new(ET2)},
+	{"0424666f6f", "field numbers out of bounds", new(ET2)}, // Issue 6323.
+	{"05100028557b02027f8302", "interface encoding", nil},   // Issue 10270.
+	// Issue 10273.
+	{"130a00fb5dad0bf8ff020263e70002fa28020202a89859", "slice length too large", nil},
+	{"0f1000fb285d003316020735ff023a65c5", "interface encoding", nil},
+	{"03fffb0616fffc00f902ff02ff03bf005d02885802a311a8120228022c028ee7", "GobDecoder", nil},
+	// Issue 10491.
+	{"10fe010f020102fe01100001fe010e000016fe010d030102fe010e00010101015801fe01100000000bfe011000f85555555555555555", "length exceeds input size", nil},
+}
+
+// TestBadData tests that various problems caused by malformed input
+// are caught as errors and do not cause panics.
+func TestBadData(t *testing.T) {
+	for i, test := range badDataTests {
+		data, err := hex.DecodeString(test.input)
+		if err != nil {
+			t.Fatalf("#%d: hex error: %s", i, err)
+		}
+		d := NewDecoder(bytes.NewReader(data))
+		err = d.Decode(test.data)
+		if err == nil {
+			t.Errorf("decode: no error")
+			continue
+		}
+		if !strings.Contains(err.Error(), test.error) {
+			t.Errorf("#%d: decode: expected %q error, got %s", i, test.error, err.Error())
+		}
+	}
+}
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index a0e2058..d0899c0 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -209,7 +209,7 @@
 			return err
 		}
 	case CharData:
-		EscapeText(p, t)
+		escapeText(p, t, false)
 	case Comment:
 		if bytes.Contains(t, endComment) {
 			return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index 8362421..5e9718c 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -1297,7 +1297,7 @@
 	toks: []Token{
 		CharData(" \t\n"),
 	},
-	want: ` &#x9;&#xA;`,
+	want: " &#x9;\n",
 }, {
 	desc: "comment",
 	toks: []Token{
diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go
index 0c64cd7..00792c4 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -1863,6 +1863,13 @@
 // EscapeText writes to w the properly escaped XML equivalent
 // of the plain text data s.
 func EscapeText(w io.Writer, s []byte) error {
+	return escapeText(w, s, true)
+}
+
+// escapeText writes to w the properly escaped XML equivalent
+// of the plain text data s. If escapeNewline is true, newline
+// characters will be escaped.
+func escapeText(w io.Writer, s []byte, escapeNewline bool) error {
 	var esc []byte
 	last := 0
 	for i := 0; i < len(s); {
@@ -1882,6 +1889,9 @@
 		case '\t':
 			esc = esc_tab
 		case '\n':
+			if !escapeNewline {
+				continue
+			}
 			esc = esc_nl
 		case '\r':
 			esc = esc_cr
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index 2cb515a..24c2d6b 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -26,6 +26,7 @@
 	"encoding/json"
 	"fmt"
 	"log"
+	"math"
 	"net/http"
 	"os"
 	"runtime"
@@ -59,28 +60,30 @@
 
 // Float is a 64-bit float variable that satisfies the Var interface.
 type Float struct {
-	mu sync.RWMutex
-	f  float64
+	f uint64
 }
 
 func (v *Float) String() string {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
-	return strconv.FormatFloat(v.f, 'g', -1, 64)
+	return strconv.FormatFloat(
+		math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
 }
 
 // Add adds delta to v.
 func (v *Float) Add(delta float64) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.f += delta
+	for {
+		cur := atomic.LoadUint64(&v.f)
+		curVal := math.Float64frombits(cur)
+		nxtVal := curVal + delta
+		nxt := math.Float64bits(nxtVal)
+		if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
+			return
+		}
+	}
 }
 
 // Set sets v to value.
 func (v *Float) Set(value float64) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.f = value
+	atomic.StoreUint64(&v.f, math.Float64bits(value))
 }
 
 // Map is a string-to-Var map variable that satisfies the Var interface.
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 11e6497..8bc633e 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -7,11 +7,13 @@
 import (
 	"bytes"
 	"encoding/json"
+	"math"
 	"net"
 	"net/http/httptest"
 	"runtime"
 	"strconv"
 	"sync"
+	"sync/atomic"
 	"testing"
 )
 
@@ -70,6 +72,10 @@
 	})
 }
 
+func (v *Float) val() float64 {
+	return math.Float64frombits(atomic.LoadUint64(&v.f))
+}
+
 func TestFloat(t *testing.T) {
 	RemoveAll()
 	reqs := NewFloat("requests-float")
@@ -82,8 +88,8 @@
 
 	reqs.Add(1.5)
 	reqs.Add(1.25)
-	if reqs.f != 2.75 {
-		t.Errorf("reqs.f = %v, want 2.75", reqs.f)
+	if v := reqs.val(); v != 2.75 {
+		t.Errorf("reqs.val() = %v, want 2.75", v)
 	}
 
 	if s := reqs.String(); s != "2.75" {
@@ -91,8 +97,8 @@
 	}
 
 	reqs.Add(-2)
-	if reqs.f != 0.75 {
-		t.Errorf("reqs.f = %v, want 0.75", reqs.f)
+	if v := reqs.val(); v != 0.75 {
+		t.Errorf("reqs.val() = %v, want 0.75", v)
 	}
 }
 
@@ -157,8 +163,8 @@
 	if x := colors.m["blue"].(*Int).i; x != 4 {
 		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
 	}
-	if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 {
-		t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x)
+	if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
+		t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
 	}
 
 	// colors.String() should be '{"red":3, "blue":4}',
diff --git a/src/fmt/doc.go b/src/fmt/doc.go
index 9ba11f4..cbca6ab 100644
--- a/src/fmt/doc.go
+++ b/src/fmt/doc.go
@@ -138,20 +138,23 @@
 	formatting considerations apply for operands that implement
 	certain interfaces. In order of application:
 
-	1. If an operand implements the Formatter interface, it will
+	1. If the operand is a reflect.Value, the concrete value it
+	holds is printed as if it was the operand.
+
+	2. If an operand implements the Formatter interface, it will
 	be invoked. Formatter provides fine control of formatting.
 
-	2. If the %v verb is used with the # flag (%#v) and the operand
+	3. If the %v verb is used with the # flag (%#v) and the operand
 	implements the GoStringer interface, that will be invoked.
 
 	If the format (which is implicitly %v for Println etc.) is valid
 	for a string (%s %q %v %x %X), the following two rules apply:
 
-	3. If an operand implements the error interface, the Error method
+	4. If an operand implements the error interface, the Error method
 	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).
 
-	4. If an operand implements method String() string, that method
+	5. If an operand implements method String() string, that method
 	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).
 
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index c14bd2f..ba99cb0 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -9,6 +9,7 @@
 	. "fmt"
 	"io"
 	"math"
+	"reflect"
 	"runtime"
 	"strings"
 	"testing"
@@ -394,6 +395,8 @@
 	{"%v", &slice, "&[1 2 3 4 5]"},
 	{"%v", &islice, "&[1 hello 2.5 <nil>]"},
 	{"%v", &bslice, "&[1 2 3 4 5]"},
+	{"%v", []byte{1}, "[1]"},
+	{"%v", []byte{}, "[]"},
 
 	// complexes with %v
 	{"%v", 1 + 2i, "(1+2i)"},
@@ -447,6 +450,12 @@
 	{"%d", []int{1, 2, 15}, `[1 2 15]`},
 	{"%d", []byte{1, 2, 15}, `[1 2 15]`},
 	{"%q", []string{"a", "b"}, `["a" "b"]`},
+	{"% 02x", []byte{1}, "01"},
+	{"% 02x", []byte{1, 2, 3}, "01 02 03"},
+	// Special care for empty slices.
+	{"%x", []byte{}, ""},
+	{"%02x", []byte{}, ""},
+	{"% 02x", []byte{}, ""},
 
 	// renamings
 	{"%v", renamedBool(true), "true"},
@@ -528,6 +537,8 @@
 	{"%s", nil, "%!s(<nil>)"},
 	{"%T", nil, "<nil>"},
 	{"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+	{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
+	{"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
 
 	// The "<nil>" show up because maps are printed by
 	// first obtaining a list of keys and then looking up
@@ -546,6 +557,11 @@
 	{"%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.
+	{"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
+	{"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
+	{"%#.80U", '日', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 '日'"},
+
 	// Comparison of padding rules with C printf.
 	/*
 		C program:
@@ -671,6 +687,20 @@
 	{"%x", byteFormatterSlice, "61626364"},
 	// This next case seems wrong, but the docs say the Formatter wins here.
 	{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
+
+	// reflect.Value handled specially in Go 1.5, making it possible to
+	// see inside non-exported fields (which cannot be accessed with Interface()).
+	// Issue 8965.
+	{"%v", reflect.ValueOf(A{}).Field(0).String(), "<int Value>"}, // Equivalent to the old way.
+	{"%v", reflect.ValueOf(A{}).Field(0), "0"},                    // Sees inside the field.
+
+	// verbs apply to the extracted value too.
+	{"%s", reflect.ValueOf("hello"), "hello"},
+	{"%q", reflect.ValueOf("hello"), `"hello"`},
+	{"%#04x", reflect.ValueOf(256), "0x0100"},
+
+	// invalid reflect.Value doesn't crash.
+	{"%v", reflect.Value{}, "<invalid reflect.Value>"},
 }
 
 // zeroFill generates zero-filled strings of the specified width. The length
@@ -797,6 +827,7 @@
 	{"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"},
 	{"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"},
 	{"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence.
+	{"%.[]", SE{}, "%!](BADINDEX)"},                // Issue 10675
 }
 
 func TestReorder(t *testing.T) {
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 4d97d14..099f8a5 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -163,12 +163,20 @@
 	}
 
 	var buf []byte = f.intbuf[0:]
-	if f.widPresent {
-		width := f.wid
+	if f.widPresent || f.precPresent {
+		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".
 			width += 2
 		}
+		if f.unicode {
+			// Also adds "U+".
+			width += 2
+			if f.uniQuote {
+				// Also adds " 'x'".
+				width += 1 + 1 + utf8.UTFMax + 1
+			}
+		}
 		if width > nByte {
 			// We're going to need a bigger boat.
 			buf = make([]byte, width)
@@ -335,7 +343,7 @@
 		}
 		buf = append(buf, digits[c>>4], digits[c&0xF])
 	}
-	f.pad(buf)
+	f.buf.Write(buf)
 }
 
 // fmt_sx formats a string as a hexadecimal encoding of its bytes.
diff --git a/src/fmt/print.go b/src/fmt/print.go
index 59a30d2..d07835d 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -291,6 +291,11 @@
 		return 0, false, end
 	}
 	for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+		const maxInt32 = 1<<31 - 1 // 31 bits is plenty for a width.
+		max := maxInt32/10 - 1
+		if num > max {
+			return 0, false, end // Overflow; crazy long number most likely.
+		}
 		num = num*10 + int(s[newi]-'0')
 		isnum = true
 	}
@@ -789,6 +794,8 @@
 	case []byte:
 		p.fmtBytes(f, verb, nil, depth)
 		wasString = verb == 's'
+	case reflect.Value:
+		return p.printReflectValue(f, verb, depth)
 	default:
 		// If the type is not simple, it might have methods.
 		if handled := p.handleMethods(verb, depth); handled {
@@ -845,6 +852,8 @@
 	p.value = value
 BigSwitch:
 	switch f := value; f.Kind() {
+	case reflect.Invalid:
+		p.buf.WriteString("<invalid reflect.Value>")
 	case reflect.Bool:
 		p.fmtBool(f.Bool(), verb)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -1027,6 +1036,11 @@
 // up to the closing paren, if present, and whether the number parsed
 // ok. The bytes to consume will be 1 if no closing paren is present.
 func parseArgNumber(format string) (index int, wid int, ok bool) {
+	// There must be at least 3 bytes: [n].
+	if len(format) < 3 {
+		return 0, 1, false
+	}
+
 	// Find closing bracket.
 	for i := 1; i < len(format); i++ {
 		if format[i] == ']' {
@@ -1053,7 +1067,7 @@
 		return index, i + wid, true
 	}
 	p.goodArgNum = false
-	return argNum, i + wid, true
+	return argNum, i + wid, ok
 }
 
 func (p *pp) doPrintf(format string, a []interface{}) {
@@ -1123,7 +1137,7 @@
 				p.goodArgNum = false
 			}
 			argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
-			if format[i] == '*' {
+			if i < end && format[i] == '*' {
 				i++
 				p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
 				if !p.fmt.precPresent {
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index 93cd553..9572530 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -81,6 +81,7 @@
 // Scanf scans text read from standard input, storing successive
 // space-separated values into successive arguments as determined by
 // the format.  It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
 func Scanf(format string, a ...interface{}) (n int, err error) {
 	return Fscanf(os.Stdin, format, a...)
 }
diff --git a/src/go/ast/walk.go b/src/go/ast/walk.go
index 73ac386..8ca2195 100644
--- a/src/go/ast/walk.go
+++ b/src/go/ast/walk.go
@@ -361,8 +361,7 @@
 		}
 
 	default:
-		fmt.Printf("ast.Walk: unexpected node type %T", n)
-		panic("ast.Walk")
+		panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
 	}
 
 	v.Visit(nil)
@@ -379,7 +378,8 @@
 
 // Inspect traverses an AST in depth-first order: It starts by calling
 // f(node); node must not be nil. If f returns true, Inspect invokes f
-// for all the non-nil children of node, recursively.
+// recursively for each of the non-nil children of node, followed by a
+// call of f(nil).
 //
 func Inspect(node Node, f func(Node) bool) {
 	Walk(inspector(f), node)
diff --git a/src/go/build/build.go b/src/go/build/build.go
index b590105..124da40 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -259,12 +259,15 @@
 var cgoEnabled = map[string]bool{
 	"darwin/386":      true,
 	"darwin/amd64":    true,
+	"darwin/arm":      true,
+	"darwin/arm64":    true,
 	"dragonfly/amd64": true,
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
+	"linux/arm64":     true,
 	"linux/ppc64le":   true,
 	"android/386":     true,
 	"android/amd64":   true,
@@ -274,6 +277,7 @@
 	"netbsd/arm":      true,
 	"openbsd/386":     true,
 	"openbsd/amd64":   true,
+	"solaris/amd64":   true,
 	"windows/386":     true,
 	"windows/amd64":   true,
 }
@@ -353,6 +357,7 @@
 	Root          string   // root of Go tree where this package lives
 	SrcRoot       string   // package source root directory ("" if unknown)
 	PkgRoot       string   // package install root directory ("" if unknown)
+	PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
 	BinDir        string   // command install directory ("" if unknown)
 	Goroot        bool     // package found in Go root
 	PkgObj        string   // installed .a file
@@ -461,18 +466,21 @@
 		return p, fmt.Errorf("import %q: invalid import path", path)
 	}
 
+	var pkgtargetroot string
 	var pkga string
 	var pkgerr error
+	suffix := ""
+	if ctxt.InstallSuffix != "" {
+		suffix = "_" + ctxt.InstallSuffix
+	}
 	switch ctxt.Compiler {
 	case "gccgo":
+		pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
 		dir, elem := pathpkg.Split(p.ImportPath)
-		pkga = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + dir + "lib" + elem + ".a"
+		pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
 	case "gc":
-		suffix := ""
-		if ctxt.InstallSuffix != "" {
-			suffix = "_" + ctxt.InstallSuffix
-		}
-		pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a"
+		pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
+		pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
 	default:
 		// Save error for end of function.
 		pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
@@ -589,6 +597,7 @@
 		p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
 		p.BinDir = ctxt.joinPath(p.Root, "bin")
 		if pkga != "" {
+			p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot)
 			p.PkgObj = ctxt.joinPath(p.Root, pkga)
 		}
 	}
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index cc51174..92c3fe3 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -109,8 +109,11 @@
 }
 
 func TestLocalDirectory(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+		}
 	}
 
 	cwd, err := os.Getwd()
@@ -227,8 +230,11 @@
 }
 
 func TestImportCmd(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+		}
 	}
 
 	p, err := Import("cmd/internal/objfile", "", 0)
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 5719ffc..84c1e2a 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -8,8 +8,11 @@
 package build
 
 import (
+	"os"
+	"path/filepath"
 	"runtime"
 	"sort"
+	"strings"
 	"testing"
 )
 
@@ -122,7 +125,7 @@
 
 	// Operating system access.
 	"syscall":       {"L0", "unicode/utf16"},
-	"time":          {"L0", "syscall"},
+	"time":          {"L0", "syscall", "internal/syscall/windows/registry"},
 	"os":            {"L1", "os", "syscall", "time", "internal/syscall/windows"},
 	"path/filepath": {"L2", "os", "syscall"},
 	"io/ioutil":     {"L2", "os", "path/filepath", "time"},
@@ -213,7 +216,7 @@
 	"image/png":           {"L4", "compress/zlib"},
 	"index/suffixarray":   {"L4", "regexp"},
 	"math/big":            {"L4"},
-	"mime":                {"L4", "OS", "syscall"},
+	"mime":                {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
 	"net/url":             {"L4"},
 	"text/scanner":        {"L4", "OS"},
 	"text/template/parse": {"L4"},
@@ -240,7 +243,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"},
+	"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"},
 
 	// NET enables use of basic network-related packages.
 	"NET": {
@@ -279,7 +282,7 @@
 	// Random byte, number generation.
 	// This would be part of core crypto except that it imports
 	// math/big, which imports fmt.
-	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall"},
+	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix"},
 
 	// Mathematical crypto: dependencies on fmt (L4) and math/big.
 	// We could avoid some of the fmt, but math/big imports fmt anyway.
@@ -330,6 +333,30 @@
 	"net/http/pprof":    {"L4", "OS", "html/template", "net/http", "runtime/pprof"},
 	"net/rpc":           {"L4", "NET", "encoding/gob", "html/template", "net/http"},
 	"net/rpc/jsonrpc":   {"L4", "NET", "encoding/json", "net/rpc"},
+
+	// Packages below are grandfathered because of issue 10475.
+	// When updating these entries, move them to an appropriate
+	// location above and assign them a justified set of
+	// 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/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"},
+	"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"},
 }
 
 // isMacro reports whether p is a package dependency macro
@@ -375,30 +402,61 @@
 	osPkg{"plan9", "log/syslog"}:   true,
 }
 
+// listStdPkgs returns the same list of packages as "go list std".
+func listStdPkgs(goroot string) ([]string, error) {
+	// Based on cmd/go's matchPackages function.
+	var pkgs []string
+
+	src := filepath.Join(goroot, "src") + string(filepath.Separator)
+	walkFn := func(path string, fi os.FileInfo, err error) error {
+		if err != nil || !fi.IsDir() || path == src {
+			return nil
+		}
+
+		base := filepath.Base(path)
+		if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
+			return filepath.SkipDir
+		}
+
+		name := filepath.ToSlash(path[len(src):])
+		if name == "builtin" || name == "cmd" || strings.Contains(name, ".") {
+			return filepath.SkipDir
+		}
+
+		pkgs = append(pkgs, name)
+		return nil
+	}
+	if err := filepath.Walk(src, walkFn); err != nil {
+		return nil, err
+	}
+	return pkgs, nil
+}
+
 func TestDependencies(t *testing.T) {
-	if runtime.GOOS == "nacl" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm") {
+	iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
+	if runtime.GOOS == "nacl" || iOS {
 		// Tests run in a limited file system and we do not
 		// provide access to every source file.
-		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
 	}
-	var all []string
 
-	for k := range pkgDeps {
-		all = append(all, k)
+	ctxt := Default
+	all, err := listStdPkgs(ctxt.GOROOT)
+	if err != nil {
+		t.Fatal(err)
 	}
 	sort.Strings(all)
 
-	ctxt := Default
 	test := func(mustImport bool) {
 		for _, pkg := range all {
-			if isMacro(pkg) {
-				continue
-			}
 			if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
 				continue
 			}
 			p, err := ctxt.Import(pkg, "", 0)
 			if err != nil {
+				if _, ok := err.(*NoGoError); ok {
+					continue
+				}
 				if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
 					continue
 				}
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index e84a066..2c2cac9 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -5,4 +5,4 @@
 package build
 
 const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
-const goarchList = "386 amd64 amd64p32 arm arm64 ppc64 ppc64le "
+const goarchList = "386 amd64 amd64p32 arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 "
diff --git a/src/go/constants/go13.go b/src/go/constants/go13.go
new file mode 100644
index 0000000..f445b82
--- /dev/null
+++ b/src/go/constants/go13.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build !go1.4
+
+package constants
+
+import (
+	"math"
+	"math/big"
+)
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+	// Before 1.4, there's no Rat.Float32.
+	// Emulate it, albeit at the cost of
+	// imprecision in corner cases.
+	x64, exact := x.Float64()
+	x32 := float32(x64)
+	if math.IsInf(float64(x32), 0) {
+		exact = false
+	}
+	return x32, exact
+}
diff --git a/src/go/constants/go14.go b/src/go/constants/go14.go
new file mode 100644
index 0000000..c698fa6
--- /dev/null
+++ b/src/go/constants/go14.go
@@ -0,0 +1,13 @@
+// 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.
+
+// +build go1.4
+
+package constants
+
+import "math/big"
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+	return x.Float32()
+}
diff --git a/src/go/constants/value.go b/src/go/constants/value.go
new file mode 100644
index 0000000..ad4533c
--- /dev/null
+++ b/src/go/constants/value.go
@@ -0,0 +1,925 @@
+// Copyright 2013 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 constants implements Values representing untyped
+// Go constants and the corresponding operations. Values
+// and operations may have arbitrary or unlimited precision.
+//
+// A special Unknown value may be used when a value
+// is unknown due to an error. Operations on unknown
+// values produce unknown values unless specified
+// otherwise.
+//
+package constants // import "go/constants"
+
+import (
+	"fmt"
+	"go/token"
+	"math/big"
+	"strconv"
+)
+
+// Kind specifies the kind of value represented by a Value.
+type Kind int
+
+// Implementation note: Kinds must be enumerated in
+// order of increasing "complexity" (used by match).
+
+const (
+	// unknown values
+	Unknown Kind = iota
+
+	// non-numeric values
+	Bool
+	String
+
+	// numeric values
+	Int
+	Float
+	Complex
+)
+
+// A Value represents a mathematically exact value of a given Kind.
+type Value interface {
+	// Kind returns the value kind; it is always the smallest
+	// kind in which the value can be represented exactly.
+	Kind() Kind
+
+	// String returns a human-readable form of the value.
+	String() string
+
+	// Prevent external implementations.
+	implementsValue()
+}
+
+// ----------------------------------------------------------------------------
+// Implementations
+
+type (
+	unknownVal struct{}
+	boolVal    bool
+	stringVal  string
+	int64Val   int64
+	intVal     struct{ val *big.Int }
+	floatVal   struct{ val *big.Rat }
+	complexVal struct{ re, im *big.Rat }
+)
+
+func (unknownVal) Kind() Kind { return Unknown }
+func (boolVal) Kind() Kind    { return Bool }
+func (stringVal) Kind() Kind  { return String }
+func (int64Val) Kind() Kind   { return Int }
+func (intVal) Kind() Kind     { return Int }
+func (floatVal) Kind() Kind   { return Float }
+func (complexVal) Kind() Kind { return Complex }
+
+func (unknownVal) String() string   { return "unknown" }
+func (x boolVal) String() string    { return fmt.Sprintf("%v", bool(x)) }
+func (x stringVal) String() string  { return strconv.Quote(string(x)) }
+func (x int64Val) String() string   { return strconv.FormatInt(int64(x), 10) }
+func (x intVal) String() string     { return x.val.String() }
+func (x floatVal) String() string   { return x.val.String() }
+func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) }
+
+func (unknownVal) implementsValue() {}
+func (boolVal) implementsValue()    {}
+func (stringVal) implementsValue()  {}
+func (int64Val) implementsValue()   {}
+func (intVal) implementsValue()     {}
+func (floatVal) implementsValue()   {}
+func (complexVal) implementsValue() {}
+
+// int64 bounds
+var (
+	minInt64 = big.NewInt(-1 << 63)
+	maxInt64 = big.NewInt(1<<63 - 1)
+)
+
+func normInt(x *big.Int) Value {
+	if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
+		return int64Val(x.Int64())
+	}
+	return intVal{x}
+}
+
+func normFloat(x *big.Rat) Value {
+	if x.IsInt() {
+		return normInt(x.Num())
+	}
+	return floatVal{x}
+}
+
+func normComplex(re, im *big.Rat) Value {
+	if im.Sign() == 0 {
+		return normFloat(re)
+	}
+	return complexVal{re, im}
+}
+
+// ----------------------------------------------------------------------------
+// Factories
+
+// MakeUnknown returns the Unknown value.
+func MakeUnknown() Value { return unknownVal{} }
+
+// MakeBool returns the Bool value for x.
+func MakeBool(b bool) Value { return boolVal(b) }
+
+// MakeString returns the String value for x.
+func MakeString(s string) Value { return stringVal(s) }
+
+// MakeInt64 returns the Int value for x.
+func MakeInt64(x int64) Value { return int64Val(x) }
+
+// MakeUint64 returns the Int value for x.
+func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) }
+
+// MakeFloat64 returns the numeric value for x.
+// If x is not finite, the result is unknown.
+func MakeFloat64(x float64) Value {
+	if f := new(big.Rat).SetFloat64(x); f != nil {
+		return normFloat(f)
+	}
+	return unknownVal{}
+}
+
+// MakeFromLiteral returns the corresponding integer, floating-point,
+// imaginary, character, or string value for a Go literal string.
+// If prec > 0, prec specifies an upper limit for the precision of
+// a numeric value. If the literal string is invalid, the result is
+// nil.
+// BUG(gri) Only prec == 0 is supported at the moment.
+func MakeFromLiteral(lit string, tok token.Token, prec uint) Value {
+	if prec != 0 {
+		panic("limited precision not supported")
+	}
+	switch tok {
+	case token.INT:
+		if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
+			return int64Val(x)
+		}
+		if x, ok := new(big.Int).SetString(lit, 0); ok {
+			return intVal{x}
+		}
+
+	case token.FLOAT:
+		if x, ok := new(big.Rat).SetString(lit); ok {
+			return normFloat(x)
+		}
+
+	case token.IMAG:
+		if n := len(lit); n > 0 && lit[n-1] == 'i' {
+			if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
+				return normComplex(big.NewRat(0, 1), im)
+			}
+		}
+
+	case token.CHAR:
+		if n := len(lit); n >= 2 {
+			if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
+				return int64Val(code)
+			}
+		}
+
+	case token.STRING:
+		if s, err := strconv.Unquote(lit); err == nil {
+			return stringVal(s)
+		}
+	}
+
+	return nil
+}
+
+// ----------------------------------------------------------------------------
+// Accessors
+//
+// For unknown arguments the result is the zero value for the respective
+// accessor type, except for Sign, where the result is 1.
+
+// BoolVal returns the Go boolean value of x, which must be a Bool or an Unknown.
+// If x is Unknown, the result is false.
+func BoolVal(x Value) bool {
+	switch x := x.(type) {
+	case boolVal:
+		return bool(x)
+	case unknownVal:
+		return false
+	}
+	panic(fmt.Sprintf("%v not a Bool", x))
+}
+
+// StringVal returns the Go string value of x, which must be a String or an Unknown.
+// If x is Unknown, the result is "".
+func StringVal(x Value) string {
+	switch x := x.(type) {
+	case stringVal:
+		return string(x)
+	case unknownVal:
+		return ""
+	}
+	panic(fmt.Sprintf("%v not a String", x))
+}
+
+// Int64Val returns the Go int64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Int64Val(x Value) (int64, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		return int64(x), true
+	case intVal:
+		return x.val.Int64(), x.val.BitLen() <= 63
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Uint64Val returns the Go uint64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Uint64Val(x Value) (uint64, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		return uint64(x), x >= 0
+	case intVal:
+		return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Float32Val is like Float64Val but for float32 instead of float64.
+func Float32Val(x Value) (float32, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		f := float32(x)
+		return f, int64Val(f) == x
+	case intVal:
+		return ratToFloat32(new(big.Rat).SetFrac(x.val, int1))
+	case floatVal:
+		return ratToFloat32(x.val)
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// Float64Val returns the nearest Go float64 value of x and whether the result is exact;
+// x must be numeric but not Complex, or Unknown. For values too small (too close to 0)
+// to represent as float64, Float64Val silently underflows to 0. The result sign always
+// matches the sign of x, even for 0.
+// If x is Unknown, the result is (0, false).
+func Float64Val(x Value) (float64, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		f := float64(int64(x))
+		return f, int64Val(f) == x
+	case intVal:
+		return new(big.Rat).SetFrac(x.val, int1).Float64()
+	case floatVal:
+		return x.val.Float64()
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// BitLen returns the number of bits required to represent
+// the absolute value x in binary representation; x must be an Int or an Unknown.
+// If x is Unknown, the result is 0.
+func BitLen(x Value) int {
+	switch x := x.(type) {
+	case int64Val:
+		return new(big.Int).SetInt64(int64(x)).BitLen()
+	case intVal:
+		return x.val.BitLen()
+	case unknownVal:
+		return 0
+	}
+	panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0;
+// x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0,
+// otherwise it is != 0. If x is Unknown, the result is 1.
+func Sign(x Value) int {
+	switch x := x.(type) {
+	case int64Val:
+		switch {
+		case x < 0:
+			return -1
+		case x > 0:
+			return 1
+		}
+		return 0
+	case intVal:
+		return x.val.Sign()
+	case floatVal:
+		return x.val.Sign()
+	case complexVal:
+		return x.re.Sign() | x.im.Sign()
+	case unknownVal:
+		return 1 // avoid spurious division by zero errors
+	}
+	panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for serializing/deserializing integers
+
+const (
+	// Compute the size of a Word in bytes.
+	_m       = ^big.Word(0)
+	_log     = _m>>8&1 + _m>>16&1 + _m>>32&1
+	wordSize = 1 << _log
+)
+
+// Bytes returns the bytes for the absolute value of x in little-
+// endian binary representation; x must be an Int.
+func Bytes(x Value) []byte {
+	var val *big.Int
+	switch x := x.(type) {
+	case int64Val:
+		val = new(big.Int).SetInt64(int64(x))
+	case intVal:
+		val = x.val
+	default:
+		panic(fmt.Sprintf("%v not an Int", x))
+	}
+
+	words := val.Bits()
+	bytes := make([]byte, len(words)*wordSize)
+
+	i := 0
+	for _, w := range words {
+		for j := 0; j < wordSize; j++ {
+			bytes[i] = byte(w)
+			w >>= 8
+			i++
+		}
+	}
+	// remove leading 0's
+	for i > 0 && bytes[i-1] == 0 {
+		i--
+	}
+
+	return bytes[:i]
+}
+
+// MakeFromBytes returns the Int value given the bytes of its little-endian
+// binary representation. An empty byte slice argument represents 0.
+func MakeFromBytes(bytes []byte) Value {
+	words := make([]big.Word, (len(bytes)+(wordSize-1))/wordSize)
+
+	i := 0
+	var w big.Word
+	var s uint
+	for _, b := range bytes {
+		w |= big.Word(b) << s
+		if s += 8; s == wordSize*8 {
+			words[i] = w
+			i++
+			w = 0
+			s = 0
+		}
+	}
+	// store last word
+	if i < len(words) {
+		words[i] = w
+		i++
+	}
+	// remove leading 0's
+	for i > 0 && words[i-1] == 0 {
+		i--
+	}
+
+	return normInt(new(big.Int).SetBits(words[:i]))
+}
+
+// ----------------------------------------------------------------------------
+// Support for disassembling fractions
+
+// Num returns the numerator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int
+// with the same sign as x.
+func Num(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal, int64Val, intVal:
+		return x
+	case floatVal:
+		return normInt(x.val.Num())
+	}
+	panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// Denom returns the denominator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int >= 1.
+func Denom(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+	case int64Val, intVal:
+		return int64Val(1)
+	case floatVal:
+		return normInt(x.val.Denom())
+	}
+	panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for assembling/disassembling complex numbers
+
+// MakeImag returns the numeric value x*i (possibly 0);
+// x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown.
+func MakeImag(x Value) Value {
+	var im *big.Rat
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+	case int64Val:
+		im = big.NewRat(int64(x), 1)
+	case intVal:
+		im = new(big.Rat).SetFrac(x.val, int1)
+	case floatVal:
+		im = x.val
+	default:
+		panic(fmt.Sprintf("%v not Int or Float", x))
+	}
+	return normComplex(rat0, im)
+}
+
+// Real returns the real part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Real(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal, int64Val, intVal, floatVal:
+		return x
+	case complexVal:
+		return normFloat(x.re)
+	}
+	panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// Imag returns the imaginary part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Imag(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+	case int64Val, intVal, floatVal:
+		return int64Val(0)
+	case complexVal:
+		return normFloat(x.im)
+	}
+	panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Operations
+
+// is32bit reports whether x can be represented using 32 bits.
+func is32bit(x int64) bool {
+	const s = 32
+	return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// is63bit reports whether x can be represented using 63 bits.
+func is63bit(x int64) bool {
+	const s = 63
+	return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// UnaryOp returns the result of the unary expression op y.
+// The operation must be defined for the operand.
+// If prec > 0 it specifies the ^ (xor) result size in bits.
+// If y is Unknown, the result is Unknown.
+//
+func UnaryOp(op token.Token, y Value, prec uint) Value {
+	switch op {
+	case token.ADD:
+		switch y.(type) {
+		case unknownVal, int64Val, intVal, floatVal, complexVal:
+			return y
+		}
+
+	case token.SUB:
+		switch y := y.(type) {
+		case unknownVal:
+			return y
+		case int64Val:
+			if z := -y; z != y {
+				return z // no overflow
+			}
+			return normInt(new(big.Int).Neg(big.NewInt(int64(y))))
+		case intVal:
+			return normInt(new(big.Int).Neg(y.val))
+		case floatVal:
+			return normFloat(new(big.Rat).Neg(y.val))
+		case complexVal:
+			return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im))
+		}
+
+	case token.XOR:
+		var z big.Int
+		switch y := y.(type) {
+		case unknownVal:
+			return y
+		case int64Val:
+			z.Not(big.NewInt(int64(y)))
+		case intVal:
+			z.Not(y.val)
+		default:
+			goto Error
+		}
+		// For unsigned types, the result will be negative and
+		// thus "too large": We must limit the result precision
+		// to the type's precision.
+		if prec > 0 {
+			z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), prec)) // z &^= (-1)<<prec
+		}
+		return normInt(&z)
+
+	case token.NOT:
+		switch y := y.(type) {
+		case unknownVal:
+			return y
+		case boolVal:
+			return !y
+		}
+	}
+
+Error:
+	panic(fmt.Sprintf("invalid unary operation %s%v", op, y))
+}
+
+var (
+	int1 = big.NewInt(1)
+	rat0 = big.NewRat(0, 1)
+)
+
+func ord(x Value) int {
+	switch x.(type) {
+	default:
+		return 0
+	case boolVal, stringVal:
+		return 1
+	case int64Val:
+		return 2
+	case intVal:
+		return 3
+	case floatVal:
+		return 4
+	case complexVal:
+		return 5
+	}
+}
+
+// match returns the matching representation (same type) with the
+// smallest complexity for two values x and y. If one of them is
+// numeric, both of them must be numeric. If one of them is Unknown,
+// both results are Unknown.
+//
+func match(x, y Value) (_, _ Value) {
+	if ord(x) > ord(y) {
+		y, x = match(y, x)
+		return x, y
+	}
+	// ord(x) <= ord(y)
+
+	switch x := x.(type) {
+	case unknownVal:
+		return x, x
+
+	case boolVal, stringVal, complexVal:
+		return x, y
+
+	case int64Val:
+		switch y := y.(type) {
+		case int64Val:
+			return x, y
+		case intVal:
+			return intVal{big.NewInt(int64(x))}, y
+		case floatVal:
+			return floatVal{big.NewRat(int64(x), 1)}, y
+		case complexVal:
+			return complexVal{big.NewRat(int64(x), 1), rat0}, y
+		}
+
+	case intVal:
+		switch y := y.(type) {
+		case intVal:
+			return x, y
+		case floatVal:
+			return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y
+		case complexVal:
+			return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y
+		}
+
+	case floatVal:
+		switch y := y.(type) {
+		case floatVal:
+			return x, y
+		case complexVal:
+			return complexVal{x.val, rat0}, y
+		}
+	}
+
+	panic("unreachable")
+}
+
+// BinaryOp returns the result of the binary expression x op y.
+// The operation must be defined for the operands. If one of the
+// operands is Unknown, the result is Unknown.
+// To force integer division of Int operands, use op == token.QUO_ASSIGN
+// instead of token.QUO; the result is guaranteed to be Int in this case.
+// Division by zero leads to a run-time panic.
+//
+func BinaryOp(x Value, op token.Token, y Value) Value {
+	x, y = match(x, y)
+
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+
+	case boolVal:
+		y := y.(boolVal)
+		switch op {
+		case token.LAND:
+			return x && y
+		case token.LOR:
+			return x || y
+		}
+
+	case int64Val:
+		a := int64(x)
+		b := int64(y.(int64Val))
+		var c int64
+		switch op {
+		case token.ADD:
+			if !is63bit(a) || !is63bit(b) {
+				return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b)))
+			}
+			c = a + b
+		case token.SUB:
+			if !is63bit(a) || !is63bit(b) {
+				return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b)))
+			}
+			c = a - b
+		case token.MUL:
+			if !is32bit(a) || !is32bit(b) {
+				return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b)))
+			}
+			c = a * b
+		case token.QUO:
+			return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b)))
+		case token.QUO_ASSIGN: // force integer division
+			c = a / b
+		case token.REM:
+			c = a % b
+		case token.AND:
+			c = a & b
+		case token.OR:
+			c = a | b
+		case token.XOR:
+			c = a ^ b
+		case token.AND_NOT:
+			c = a &^ b
+		default:
+			goto Error
+		}
+		return int64Val(c)
+
+	case intVal:
+		a := x.val
+		b := y.(intVal).val
+		var c big.Int
+		switch op {
+		case token.ADD:
+			c.Add(a, b)
+		case token.SUB:
+			c.Sub(a, b)
+		case token.MUL:
+			c.Mul(a, b)
+		case token.QUO:
+			return normFloat(new(big.Rat).SetFrac(a, b))
+		case token.QUO_ASSIGN: // force integer division
+			c.Quo(a, b)
+		case token.REM:
+			c.Rem(a, b)
+		case token.AND:
+			c.And(a, b)
+		case token.OR:
+			c.Or(a, b)
+		case token.XOR:
+			c.Xor(a, b)
+		case token.AND_NOT:
+			c.AndNot(a, b)
+		default:
+			goto Error
+		}
+		return normInt(&c)
+
+	case floatVal:
+		a := x.val
+		b := y.(floatVal).val
+		var c big.Rat
+		switch op {
+		case token.ADD:
+			c.Add(a, b)
+		case token.SUB:
+			c.Sub(a, b)
+		case token.MUL:
+			c.Mul(a, b)
+		case token.QUO:
+			c.Quo(a, b)
+		default:
+			goto Error
+		}
+		return normFloat(&c)
+
+	case complexVal:
+		y := y.(complexVal)
+		a, b := x.re, x.im
+		c, d := y.re, y.im
+		var re, im big.Rat
+		switch op {
+		case token.ADD:
+			// (a+c) + i(b+d)
+			re.Add(a, c)
+			im.Add(b, d)
+		case token.SUB:
+			// (a-c) + i(b-d)
+			re.Sub(a, c)
+			im.Sub(b, d)
+		case token.MUL:
+			// (ac-bd) + i(bc+ad)
+			var ac, bd, bc, ad big.Rat
+			ac.Mul(a, c)
+			bd.Mul(b, d)
+			bc.Mul(b, c)
+			ad.Mul(a, d)
+			re.Sub(&ac, &bd)
+			im.Add(&bc, &ad)
+		case token.QUO:
+			// (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
+			var ac, bd, bc, ad, s, cc, dd big.Rat
+			ac.Mul(a, c)
+			bd.Mul(b, d)
+			bc.Mul(b, c)
+			ad.Mul(a, d)
+			cc.Mul(c, c)
+			dd.Mul(d, d)
+			s.Add(&cc, &dd)
+			re.Add(&ac, &bd)
+			re.Quo(&re, &s)
+			im.Sub(&bc, &ad)
+			im.Quo(&im, &s)
+		default:
+			goto Error
+		}
+		return normComplex(&re, &im)
+
+	case stringVal:
+		if op == token.ADD {
+			return x + y.(stringVal)
+		}
+	}
+
+Error:
+	panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
+}
+
+// Shift returns the result of the shift expression x op s
+// with op == token.SHL or token.SHR (<< or >>). x must be
+// an Int or an Unknown. If x is Unknown, the result is x.
+//
+func Shift(x Value, op token.Token, s uint) Value {
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+
+	case int64Val:
+		if s == 0 {
+			return x
+		}
+		switch op {
+		case token.SHL:
+			z := big.NewInt(int64(x))
+			return normInt(z.Lsh(z, s))
+		case token.SHR:
+			return x >> s
+		}
+
+	case intVal:
+		if s == 0 {
+			return x
+		}
+		var z big.Int
+		switch op {
+		case token.SHL:
+			return normInt(z.Lsh(x.val, s))
+		case token.SHR:
+			return normInt(z.Rsh(x.val, s))
+		}
+	}
+
+	panic(fmt.Sprintf("invalid shift %v %s %d", x, op, s))
+}
+
+func cmpZero(x int, op token.Token) bool {
+	switch op {
+	case token.EQL:
+		return x == 0
+	case token.NEQ:
+		return x != 0
+	case token.LSS:
+		return x < 0
+	case token.LEQ:
+		return x <= 0
+	case token.GTR:
+		return x > 0
+	case token.GEQ:
+		return x >= 0
+	}
+	panic("unreachable")
+}
+
+// Compare returns the result of the comparison x op y.
+// The comparison must be defined for the operands.
+// If one of the operands is Unknown, the result is
+// false.
+//
+func Compare(x Value, op token.Token, y Value) bool {
+	x, y = match(x, y)
+
+	switch x := x.(type) {
+	case unknownVal:
+		return false
+
+	case boolVal:
+		y := y.(boolVal)
+		switch op {
+		case token.EQL:
+			return x == y
+		case token.NEQ:
+			return x != y
+		}
+
+	case int64Val:
+		y := y.(int64Val)
+		switch op {
+		case token.EQL:
+			return x == y
+		case token.NEQ:
+			return x != y
+		case token.LSS:
+			return x < y
+		case token.LEQ:
+			return x <= y
+		case token.GTR:
+			return x > y
+		case token.GEQ:
+			return x >= y
+		}
+
+	case intVal:
+		return cmpZero(x.val.Cmp(y.(intVal).val), op)
+
+	case floatVal:
+		return cmpZero(x.val.Cmp(y.(floatVal).val), op)
+
+	case complexVal:
+		y := y.(complexVal)
+		re := x.re.Cmp(y.re)
+		im := x.im.Cmp(y.im)
+		switch op {
+		case token.EQL:
+			return re == 0 && im == 0
+		case token.NEQ:
+			return re != 0 || im != 0
+		}
+
+	case stringVal:
+		y := y.(stringVal)
+		switch op {
+		case token.EQL:
+			return x == y
+		case token.NEQ:
+			return x != y
+		case token.LSS:
+			return x < y
+		case token.LEQ:
+			return x <= y
+		case token.GTR:
+			return x > y
+		case token.GEQ:
+			return x >= y
+		}
+	}
+
+	panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y))
+}
diff --git a/src/go/constants/value_test.go b/src/go/constants/value_test.go
new file mode 100644
index 0000000..6a74e2d
--- /dev/null
+++ b/src/go/constants/value_test.go
@@ -0,0 +1,375 @@
+// Copyright 2013 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 constants
+
+import (
+	"go/token"
+	"strings"
+	"testing"
+)
+
+// TODO(gri) expand this test framework
+
+var opTests = []string{
+	// unary operations
+	`+ 0 = 0`,
+	`+ ? = ?`,
+	`- 1 = -1`,
+	`- ? = ?`,
+	`^ 0 = -1`,
+	`^ ? = ?`,
+
+	`! true = false`,
+	`! false = true`,
+	`! ? = ?`,
+
+	// etc.
+
+	// binary operations
+	`"" + "" = ""`,
+	`"foo" + "" = "foo"`,
+	`"" + "bar" = "bar"`,
+	`"foo" + "bar" = "foobar"`,
+
+	`0 + 0 = 0`,
+	`0 + 0.1 = 0.1`,
+	`0 + 0.1i = 0.1i`,
+	`0.1 + 0.9 = 1`,
+	`1e100 + 1e100 = 2e100`,
+	`? + 0 = ?`,
+	`0 + ? = ?`,
+
+	`0 - 0 = 0`,
+	`0 - 0.1 = -0.1`,
+	`0 - 0.1i = -0.1i`,
+	`1e100 - 1e100 = 0`,
+	`? - 0 = ?`,
+	`0 - ? = ?`,
+
+	`0 * 0 = 0`,
+	`1 * 0.1 = 0.1`,
+	`1 * 0.1i = 0.1i`,
+	`1i * 1i = -1`,
+	`? * 0 = ?`,
+	`0 * ? = ?`,
+
+	`0 / 0 = "division_by_zero"`,
+	`10 / 2 = 5`,
+	`5 / 3 = 5/3`,
+	`5i / 3i = 5/3`,
+	`? / 0 = ?`,
+	`0 / ? = ?`,
+
+	`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
+	`10 % 3 = 1`,
+	`? % 0 = ?`,
+	`0 % ? = ?`,
+
+	`0 & 0 = 0`,
+	`12345 & 0 = 0`,
+	`0xff & 0xf = 0xf`,
+	`? & 0 = ?`,
+	`0 & ? = ?`,
+
+	`0 | 0 = 0`,
+	`12345 | 0 = 12345`,
+	`0xb | 0xa0 = 0xab`,
+	`? | 0 = ?`,
+	`0 | ? = ?`,
+
+	`0 ^ 0 = 0`,
+	`1 ^ -1 = -2`,
+	`? ^ 0 = ?`,
+	`0 ^ ? = ?`,
+
+	`0 &^ 0 = 0`,
+	`0xf &^ 1 = 0xe`,
+	`1 &^ 0xf = 0`,
+	// etc.
+
+	// shifts
+	`0 << 0 = 0`,
+	`1 << 10 = 1024`,
+	`0 >> 0 = 0`,
+	`1024 >> 10 == 1`,
+	`? << 0 == ?`,
+	`? >> 10 == ?`,
+	// etc.
+
+	// comparisons
+	`false == false = true`,
+	`false == true = false`,
+	`true == false = false`,
+	`true == true = true`,
+
+	`false != false = false`,
+	`false != true = true`,
+	`true != false = true`,
+	`true != true = false`,
+
+	`"foo" == "bar" = false`,
+	`"foo" != "bar" = true`,
+	`"foo" < "bar" = false`,
+	`"foo" <= "bar" = false`,
+	`"foo" > "bar" = true`,
+	`"foo" >= "bar" = true`,
+
+	`0 == 0 = true`,
+	`0 != 0 = false`,
+	`0 < 10 = true`,
+	`10 <= 10 = true`,
+	`0 > 10 = false`,
+	`10 >= 10 = true`,
+
+	`1/123456789 == 1/123456789 == true`,
+	`1/123456789 != 1/123456789 == false`,
+	`1/123456789 < 1/123456788 == true`,
+	`1/123456788 <= 1/123456789 == false`,
+	`0.11 > 0.11 = false`,
+	`0.11 >= 0.11 = true`,
+
+	`? == 0 = false`,
+	`? != 0 = false`,
+	`? < 10 = false`,
+	`? <= 10 = false`,
+	`? > 10 = false`,
+	`? >= 10 = false`,
+
+	`0 == ? = false`,
+	`0 != ? = false`,
+	`0 < ? = false`,
+	`10 <= ? = false`,
+	`0 > ? = false`,
+	`10 >= ? = false`,
+
+	// etc.
+}
+
+func TestOps(t *testing.T) {
+	for _, test := range opTests {
+		a := strings.Split(test, " ")
+		i := 0 // operator index
+
+		var x, x0 Value
+		switch len(a) {
+		case 4:
+			// unary operation
+		case 5:
+			// binary operation
+			x, x0 = val(a[0]), val(a[0])
+			i = 1
+		default:
+			t.Errorf("invalid test case: %s", test)
+			continue
+		}
+
+		op, ok := optab[a[i]]
+		if !ok {
+			panic("missing optab entry for " + a[i])
+		}
+
+		y, y0 := val(a[i+1]), val(a[i+1])
+
+		got := doOp(x, op, y)
+		want := val(a[i+3])
+		if !eql(got, want) {
+			t.Errorf("%s: got %s; want %s", test, got, want)
+		}
+		if x0 != nil && !eql(x, x0) {
+			t.Errorf("%s: x changed to %s", test, x)
+		}
+		if !eql(y, y0) {
+			t.Errorf("%s: y changed to %s", test, y)
+		}
+	}
+}
+
+func eql(x, y Value) bool {
+	_, ux := x.(unknownVal)
+	_, uy := y.(unknownVal)
+	if ux || uy {
+		return ux == uy
+	}
+	return Compare(x, token.EQL, y)
+}
+
+// ----------------------------------------------------------------------------
+// Support functions
+
+func val(lit string) Value {
+	if len(lit) == 0 {
+		return MakeUnknown()
+	}
+
+	switch lit {
+	case "?":
+		return MakeUnknown()
+	case "true":
+		return MakeBool(true)
+	case "false":
+		return MakeBool(false)
+	}
+
+	tok := token.INT
+	switch first, last := lit[0], lit[len(lit)-1]; {
+	case first == '"' || first == '`':
+		tok = token.STRING
+		lit = strings.Replace(lit, "_", " ", -1)
+	case first == '\'':
+		tok = token.CHAR
+	case last == 'i':
+		tok = token.IMAG
+	default:
+		if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
+			tok = token.FLOAT
+		}
+	}
+
+	return MakeFromLiteral(lit, tok, 0)
+}
+
+var optab = map[string]token.Token{
+	"!": token.NOT,
+
+	"+": token.ADD,
+	"-": token.SUB,
+	"*": token.MUL,
+	"/": token.QUO,
+	"%": token.REM,
+
+	"<<": token.SHL,
+	">>": token.SHR,
+
+	"&":  token.AND,
+	"|":  token.OR,
+	"^":  token.XOR,
+	"&^": token.AND_NOT,
+
+	"==": token.EQL,
+	"!=": token.NEQ,
+	"<":  token.LSS,
+	"<=": token.LEQ,
+	">":  token.GTR,
+	">=": token.GEQ,
+}
+
+func panicHandler(v *Value) {
+	switch p := recover().(type) {
+	case nil:
+		// nothing to do
+	case string:
+		*v = MakeString(p)
+	case error:
+		*v = MakeString(p.Error())
+	default:
+		panic(p)
+	}
+}
+
+func doOp(x Value, op token.Token, y Value) (z Value) {
+	defer panicHandler(&z)
+
+	if x == nil {
+		return UnaryOp(op, y, 0)
+	}
+
+	switch op {
+	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+		return MakeBool(Compare(x, op, y))
+	case token.SHL, token.SHR:
+		s, _ := Int64Val(y)
+		return Shift(x, op, uint(s))
+	default:
+		return BinaryOp(x, op, y)
+	}
+}
+
+// ----------------------------------------------------------------------------
+// Other tests
+
+var fracTests = []string{
+	"0 0 1",
+	"1 1 1",
+	"-1 -1 1",
+	"1.2 6 5",
+	"-0.991 -991 1000",
+	"1e100 1e100 1",
+}
+
+func TestFractions(t *testing.T) {
+	for _, test := range fracTests {
+		a := strings.Split(test, " ")
+		if len(a) != 3 {
+			t.Errorf("invalid test case: %s", test)
+			continue
+		}
+
+		x := val(a[0])
+		n := val(a[1])
+		d := val(a[2])
+
+		if got := Num(x); !eql(got, n) {
+			t.Errorf("%s: got num = %s; want %s", test, got, n)
+		}
+
+		if got := Denom(x); !eql(got, d) {
+			t.Errorf("%s: got denom = %s; want %s", test, got, d)
+		}
+	}
+}
+
+var bytesTests = []string{
+	"0",
+	"1",
+	"123456789",
+	"123456789012345678901234567890123456789012345678901234567890",
+}
+
+func TestBytes(t *testing.T) {
+	for _, test := range bytesTests {
+		x := val(test)
+		bytes := Bytes(x)
+
+		// special case 0
+		if Sign(x) == 0 && len(bytes) != 0 {
+			t.Errorf("%s: got %v; want empty byte slice", test, bytes)
+		}
+
+		if n := len(bytes); n > 0 && bytes[n-1] == 0 {
+			t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
+		}
+
+		if got := MakeFromBytes(bytes); !eql(got, x) {
+			t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
+		}
+	}
+}
+
+func TestUnknown(t *testing.T) {
+	u := MakeUnknown()
+	var values = []Value{
+		u,
+		MakeBool(false), // token.ADD ok below, operation is never considered
+		MakeString(""),
+		MakeInt64(1),
+		MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0),
+		MakeFloat64(1.2),
+		MakeImag(MakeFloat64(1.2)),
+	}
+	for _, val := range values {
+		x, y := val, u
+		for i := range [2]int{} {
+			if i == 1 {
+				x, y = y, x
+			}
+			if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
+				t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
+			}
+			if got := Compare(x, token.EQL, y); got {
+				t.Errorf("%s == %s: got true; want false", x, y)
+			}
+		}
+	}
+}
diff --git a/src/go/importer/importer.go b/src/go/importer/importer.go
new file mode 100644
index 0000000..1ac44c7
--- /dev/null
+++ b/src/go/importer/importer.go
@@ -0,0 +1,46 @@
+// 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 importer provides access to export data importers.
+package importer
+
+import (
+	"go/internal/gcimporter"
+	"go/types"
+	"io"
+	"runtime"
+)
+
+// A Lookup function returns a reader to access package data for
+// a given import path, or an error if no matching package is found.
+type Lookup func(path string) (io.ReadCloser, error)
+
+// For returns an Importer for the given compiler and lookup interface,
+// or nil. Supported compilers are "gc", and "gccgo". If lookup is nil,
+// the default package lookup mechanism for the given compiler is used.
+func For(compiler string, lookup Lookup) types.Importer {
+	switch compiler {
+	case "gc":
+		if lookup == nil {
+			return make(gcimports)
+		}
+		panic("gc importer for custom import path lookup not yet implemented")
+	case "gccgo":
+		// TODO(gri) We have the code. Plug it in.
+		panic("gccgo importer unimplemented")
+	}
+	// compiler not supported
+	return nil
+}
+
+// Default returns an Importer for the compiler that built the running binary.
+func Default() types.Importer {
+	return For(runtime.Compiler, nil)
+}
+
+type gcimports map[string]*types.Package
+
+func (m gcimports) Import(path string) (*types.Package, error) {
+	return gcimporter.Import(m, path)
+}
diff --git a/src/go/internal/gcimporter/exportdata.go b/src/go/internal/gcimporter/exportdata.go
new file mode 100644
index 0000000..657742b
--- /dev/null
+++ b/src/go/internal/gcimporter/exportdata.go
@@ -0,0 +1,108 @@
+// Copyright 2011 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.
+
+// This file implements FindExportData.
+
+package gcimporter
+
+import (
+	"bufio"
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
+	// See $GOROOT/include/ar.h.
+	hdr := make([]byte, 16+12+6+6+8+10+2)
+	_, err = io.ReadFull(r, hdr)
+	if err != nil {
+		return
+	}
+	// leave for debugging
+	if false {
+		fmt.Printf("header: %s", hdr)
+	}
+	s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
+	size, err = strconv.Atoi(s)
+	if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
+		err = errors.New("invalid archive header")
+		return
+	}
+	name = strings.TrimSpace(string(hdr[:16]))
+	return
+}
+
+// FindExportData positions the reader r at the beginning of the
+// export data section of an underlying GC-created object/archive
+// file by reading from it. The reader must be positioned at the
+// start of the file before calling this function.
+//
+func FindExportData(r *bufio.Reader) (err error) {
+	// Read first line to make sure this is an object file.
+	line, err := r.ReadSlice('\n')
+	if err != nil {
+		return
+	}
+	if string(line) == "!<arch>\n" {
+		// Archive file. Scan to __.PKGDEF.
+		var name string
+		var size int
+		if name, size, err = readGopackHeader(r); err != nil {
+			return
+		}
+
+		// Optional leading __.GOSYMDEF or __.SYMDEF.
+		// Read and discard.
+		if name == "__.SYMDEF" || name == "__.GOSYMDEF" {
+			const block = 4096
+			tmp := make([]byte, block)
+			for size > 0 {
+				n := size
+				if n > block {
+					n = block
+				}
+				if _, err = io.ReadFull(r, tmp[:n]); err != nil {
+					return
+				}
+				size -= n
+			}
+
+			if name, size, err = readGopackHeader(r); err != nil {
+				return
+			}
+		}
+
+		// First real entry should be __.PKGDEF.
+		if name != "__.PKGDEF" {
+			err = errors.New("go archive is missing __.PKGDEF")
+			return
+		}
+
+		// Read first line of __.PKGDEF data, so that line
+		// is once again the first line of the input.
+		if line, err = r.ReadSlice('\n'); err != nil {
+			return
+		}
+	}
+
+	// Now at __.PKGDEF in archive or still at beginning of file.
+	// Either way, line should begin with "go object ".
+	if !strings.HasPrefix(string(line), "go object ") {
+		err = errors.New("not a go object file")
+		return
+	}
+
+	// Skip over object header to export data.
+	// Begins after first line with $$.
+	for line[0] != '$' {
+		if line, err = r.ReadSlice('\n'); err != nil {
+			return
+		}
+	}
+
+	return
+}
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
new file mode 100644
index 0000000..ee83a72
--- /dev/null
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -0,0 +1,957 @@
+// Copyright 2011 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 gcimporter implements Import for gc-generated object files.
+package gcimporter // import "go/internal/gcimporter"
+
+import (
+	"bufio"
+	"errors"
+	"fmt"
+	"go/build"
+	"go/token"
+	"io"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"text/scanner"
+
+	exact "go/constants"
+	"go/types"
+)
+
+// debugging/development support
+const debug = false
+
+var pkgExts = [...]string{".a", ".5", ".6", ".7", ".8", ".9"}
+
+// FindPkg returns the filename and unique package id for an import
+// path based on package information provided by build.Import (using
+// the build.Default build.Context).
+// If no file was found, an empty filename is returned.
+//
+func FindPkg(path, srcDir string) (filename, id string) {
+	if len(path) == 0 {
+		return
+	}
+
+	id = path
+	var noext string
+	switch {
+	default:
+		// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
+		// Don't require the source files to be present.
+		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
+		if bp.PkgObj == "" {
+			return
+		}
+		noext = strings.TrimSuffix(bp.PkgObj, ".a")
+
+	case build.IsLocalImport(path):
+		// "./x" -> "/this/directory/x.ext", "/this/directory/x"
+		noext = filepath.Join(srcDir, path)
+		id = noext
+
+	case filepath.IsAbs(path):
+		// for completeness only - go/build.Import
+		// does not support absolute imports
+		// "/x" -> "/x.ext", "/x"
+		noext = path
+	}
+
+	// try extensions
+	for _, ext := range pkgExts {
+		filename = noext + ext
+		if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+			return
+		}
+	}
+
+	filename = "" // not found
+	return
+}
+
+// ImportData imports a package by reading the gc-generated export data,
+// adds the corresponding package object to the imports map indexed by id,
+// and returns the object.
+//
+// The imports map must contains all packages already imported. The data
+// reader position must be the beginning of the export data section. The
+// filename is only used in error messages.
+//
+// If imports[id] contains the completely imported package, that package
+// can be used directly, and there is no need to call this function (but
+// there is also no harm but for extra time used).
+//
+func ImportData(imports map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
+	// support for parser error handling
+	defer func() {
+		switch r := recover().(type) {
+		case nil:
+			// nothing to do
+		case importError:
+			err = r
+		default:
+			panic(r) // internal error
+		}
+	}()
+
+	var p parser
+	p.init(filename, id, data, imports)
+	pkg = p.parseExport()
+
+	return
+}
+
+// Import imports a gc-generated package given its import path, adds the
+// corresponding package object to the imports map, and returns the object.
+// Local import paths are interpreted relative to the current working directory.
+// The imports map must contains all packages already imported.
+//
+func Import(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
+	// package "unsafe" is handled by the type checker
+	if path == "unsafe" {
+		panic(`gcimporter.Import called for package "unsafe"`)
+	}
+
+	srcDir := "."
+	if build.IsLocalImport(path) {
+		srcDir, err = os.Getwd()
+		if err != nil {
+			return
+		}
+	}
+
+	filename, id := FindPkg(path, srcDir)
+	if filename == "" {
+		err = fmt.Errorf("can't find import: %s", id)
+		return
+	}
+
+	// no need to re-import if the package was imported completely before
+	if pkg = imports[id]; pkg != nil && pkg.Complete() {
+		return
+	}
+
+	// open file
+	f, err := os.Open(filename)
+	if err != nil {
+		return
+	}
+	defer func() {
+		f.Close()
+		if err != nil {
+			// add file name to error
+			err = fmt.Errorf("reading export data: %s: %v", filename, err)
+		}
+	}()
+
+	buf := bufio.NewReader(f)
+	if err = FindExportData(buf); err != nil {
+		return
+	}
+
+	pkg, err = ImportData(imports, filename, id, buf)
+
+	return
+}
+
+// ----------------------------------------------------------------------------
+// Parser
+
+// TODO(gri) Imported objects don't have position information.
+//           Ideally use the debug table line info; alternatively
+//           create some fake position (or the position of the
+//           import). That way error messages referring to imported
+//           objects can print meaningful information.
+
+// parser parses the exports inside a gc compiler-produced
+// object/archive file and populates its scope with the results.
+type parser struct {
+	scanner scanner.Scanner
+	tok     rune                      // current token
+	lit     string                    // literal string; only valid for Ident, Int, String tokens
+	id      string                    // package id of imported package
+	imports map[string]*types.Package // package id -> package object
+}
+
+func (p *parser) init(filename, id string, src io.Reader, imports map[string]*types.Package) {
+	p.scanner.Init(src)
+	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+	p.scanner.Whitespace = 1<<'\t' | 1<<' '
+	p.scanner.Filename = filename // for good error messages
+	p.next()
+	p.id = id
+	p.imports = imports
+	if debug {
+		// check consistency of imports map
+		for _, pkg := range imports {
+			if pkg.Name() == "" {
+				fmt.Printf("no package name for %s\n", pkg.Path())
+			}
+		}
+	}
+}
+
+func (p *parser) next() {
+	p.tok = p.scanner.Scan()
+	switch p.tok {
+	case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
+		p.lit = p.scanner.TokenText()
+	default:
+		p.lit = ""
+	}
+	if debug {
+		fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
+	}
+}
+
+func declTypeName(pkg *types.Package, name string) *types.TypeName {
+	scope := pkg.Scope()
+	if obj := scope.Lookup(name); obj != nil {
+		return obj.(*types.TypeName)
+	}
+	obj := types.NewTypeName(token.NoPos, pkg, name, nil)
+	// a named type may be referred to before the underlying type
+	// is known - set it up
+	types.NewNamed(obj, nil, nil)
+	scope.Insert(obj)
+	return obj
+}
+
+// ----------------------------------------------------------------------------
+// Error handling
+
+// Internal errors are boxed as importErrors.
+type importError struct {
+	pos scanner.Position
+	err error
+}
+
+func (e importError) Error() string {
+	return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *parser) error(err interface{}) {
+	if s, ok := err.(string); ok {
+		err = errors.New(s)
+	}
+	// panic with a runtime.Error if err is not an error
+	panic(importError{p.scanner.Pos(), err.(error)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+	p.error(fmt.Sprintf(format, args...))
+}
+
+func (p *parser) expect(tok rune) string {
+	lit := p.lit
+	if p.tok != tok {
+		p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+	}
+	p.next()
+	return lit
+}
+
+func (p *parser) expectSpecial(tok string) {
+	sep := 'x' // not white space
+	i := 0
+	for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
+		sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+		p.next()
+		i++
+	}
+	if i < len(tok) {
+		p.errorf("expected %q, got %q", tok, tok[0:i])
+	}
+}
+
+func (p *parser) expectKeyword(keyword string) {
+	lit := p.expect(scanner.Ident)
+	if lit != keyword {
+		p.errorf("expected keyword %s, got %q", keyword, lit)
+	}
+}
+
+// ----------------------------------------------------------------------------
+// Qualified and unqualified names
+
+// PackageId = string_lit .
+//
+func (p *parser) parsePackageId() string {
+	id, err := strconv.Unquote(p.expect(scanner.String))
+	if err != nil {
+		p.error(err)
+	}
+	// id == "" stands for the imported package id
+	// (only known at time of package installation)
+	if id == "" {
+		id = p.id
+	}
+	return id
+}
+
+// PackageName = ident .
+//
+func (p *parser) parsePackageName() string {
+	return p.expect(scanner.Ident)
+}
+
+// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
+func (p *parser) parseDotIdent() string {
+	ident := ""
+	if p.tok != scanner.Int {
+		sep := 'x' // not white space
+		for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
+			ident += p.lit
+			sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+			p.next()
+		}
+	}
+	if ident == "" {
+		p.expect(scanner.Ident) // use expect() for error handling
+	}
+	return ident
+}
+
+// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
+//
+func (p *parser) parseQualifiedName() (id, name string) {
+	p.expect('@')
+	id = p.parsePackageId()
+	p.expect('.')
+	// Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
+	if p.tok == '?' {
+		p.next()
+	} else {
+		name = p.parseDotIdent()
+	}
+	return
+}
+
+// getPkg returns the package for a given id. If the package is
+// not found but we have a package name, create the package and
+// add it to the p.imports map.
+//
+func (p *parser) getPkg(id, name string) *types.Package {
+	// package unsafe is not in the imports map - handle explicitly
+	if id == "unsafe" {
+		return types.Unsafe
+	}
+	pkg := p.imports[id]
+	if pkg == nil && name != "" {
+		pkg = types.NewPackage(id, name)
+		p.imports[id] = pkg
+	}
+	return pkg
+}
+
+// parseExportedName is like parseQualifiedName, but
+// the package id is resolved to an imported *types.Package.
+//
+func (p *parser) parseExportedName() (pkg *types.Package, name string) {
+	id, name := p.parseQualifiedName()
+	pkg = p.getPkg(id, "")
+	if pkg == nil {
+		p.errorf("%s package not found", id)
+	}
+	return
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+// BasicType = identifier .
+//
+func (p *parser) parseBasicType() types.Type {
+	id := p.expect(scanner.Ident)
+	obj := types.Universe.Lookup(id)
+	if obj, ok := obj.(*types.TypeName); ok {
+		return obj.Type()
+	}
+	p.errorf("not a basic type: %s", id)
+	return nil
+}
+
+// ArrayType = "[" int_lit "]" Type .
+//
+func (p *parser) parseArrayType() types.Type {
+	// "[" already consumed and lookahead known not to be "]"
+	lit := p.expect(scanner.Int)
+	p.expect(']')
+	elem := p.parseType()
+	n, err := strconv.ParseInt(lit, 10, 64)
+	if err != nil {
+		p.error(err)
+	}
+	return types.NewArray(elem, n)
+}
+
+// MapType = "map" "[" Type "]" Type .
+//
+func (p *parser) parseMapType() types.Type {
+	p.expectKeyword("map")
+	p.expect('[')
+	key := p.parseType()
+	p.expect(']')
+	elem := p.parseType()
+	return types.NewMap(key, elem)
+}
+
+// Name = identifier | "?" | QualifiedName .
+//
+// If materializePkg is set, the returned package is guaranteed to be set.
+// For fully qualified names, the returned package may be a fake package
+// (without name, scope, and not in the p.imports map), created for the
+// sole purpose of providing a package path. Fake packages are created
+// when the package id is not found in the p.imports map; in that case
+// we cannot create a real package because we don't have a package name.
+// For non-qualified names, the returned package is the imported package.
+//
+func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) {
+	switch p.tok {
+	case scanner.Ident:
+		pkg = p.imports[p.id]
+		name = p.lit
+		p.next()
+	case '?':
+		// anonymous
+		pkg = p.imports[p.id]
+		p.next()
+	case '@':
+		// exported name prefixed with package path
+		var id string
+		id, name = p.parseQualifiedName()
+		if materializePkg {
+			// we don't have a package name - if the package
+			// doesn't exist yet, create a fake package instead
+			pkg = p.getPkg(id, "")
+			if pkg == nil {
+				pkg = types.NewPackage(id, "")
+			}
+		}
+	default:
+		p.error("name expected")
+	}
+	return
+}
+
+func deref(typ types.Type) types.Type {
+	if p, _ := typ.(*types.Pointer); p != nil {
+		return p.Elem()
+	}
+	return typ
+}
+
+// Field = Name Type [ string_lit ] .
+//
+func (p *parser) parseField() (*types.Var, string) {
+	pkg, name := p.parseName(true)
+	typ := p.parseType()
+	anonymous := false
+	if name == "" {
+		// anonymous field - typ must be T or *T and T must be a type name
+		switch typ := deref(typ).(type) {
+		case *types.Basic: // basic types are named types
+			pkg = nil
+			name = typ.Name()
+		case *types.Named:
+			name = typ.Obj().Name()
+		default:
+			p.errorf("anonymous field expected")
+		}
+		anonymous = true
+	}
+	tag := ""
+	if p.tok == scanner.String {
+		s := p.expect(scanner.String)
+		var err error
+		tag, err = strconv.Unquote(s)
+		if err != nil {
+			p.errorf("invalid struct tag %s: %s", s, err)
+		}
+	}
+	return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
+}
+
+// StructType = "struct" "{" [ FieldList ] "}" .
+// FieldList  = Field { ";" Field } .
+//
+func (p *parser) parseStructType() types.Type {
+	var fields []*types.Var
+	var tags []string
+
+	p.expectKeyword("struct")
+	p.expect('{')
+	for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+		if i > 0 {
+			p.expect(';')
+		}
+		fld, tag := p.parseField()
+		if tag != "" && tags == nil {
+			tags = make([]string, i)
+		}
+		if tags != nil {
+			tags = append(tags, tag)
+		}
+		fields = append(fields, fld)
+	}
+	p.expect('}')
+
+	return types.NewStruct(fields, tags)
+}
+
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
+//
+func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
+	_, name := p.parseName(false)
+	// remove gc-specific parameter numbering
+	if i := strings.Index(name, "·"); i >= 0 {
+		name = name[:i]
+	}
+	if p.tok == '.' {
+		p.expectSpecial("...")
+		isVariadic = true
+	}
+	typ := p.parseType()
+	if isVariadic {
+		typ = types.NewSlice(typ)
+	}
+	// ignore argument tag (e.g. "noescape")
+	if p.tok == scanner.String {
+		p.next()
+	}
+	// TODO(gri) should we provide a package?
+	par = types.NewVar(token.NoPos, nil, name, typ)
+	return
+}
+
+// Parameters    = "(" [ ParameterList ] ")" .
+// ParameterList = { Parameter "," } Parameter .
+//
+func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
+	p.expect('(')
+	for p.tok != ')' && p.tok != scanner.EOF {
+		if len(list) > 0 {
+			p.expect(',')
+		}
+		par, variadic := p.parseParameter()
+		list = append(list, par)
+		if variadic {
+			if isVariadic {
+				p.error("... not on final argument")
+			}
+			isVariadic = true
+		}
+	}
+	p.expect(')')
+
+	return
+}
+
+// Signature = Parameters [ Result ] .
+// Result    = Type | Parameters .
+//
+func (p *parser) parseSignature(recv *types.Var) *types.Signature {
+	params, isVariadic := p.parseParameters()
+
+	// optional result type
+	var results []*types.Var
+	if p.tok == '(' {
+		var variadic bool
+		results, variadic = p.parseParameters()
+		if variadic {
+			p.error("... not permitted on result type")
+		}
+	}
+
+	return types.NewSignature(nil, recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
+}
+
+// InterfaceType = "interface" "{" [ MethodList ] "}" .
+// MethodList    = Method { ";" Method } .
+// Method        = Name Signature .
+//
+// The methods of embedded interfaces are always "inlined"
+// by the compiler and thus embedded interfaces are never
+// visible in the export data.
+//
+func (p *parser) parseInterfaceType() types.Type {
+	var methods []*types.Func
+
+	p.expectKeyword("interface")
+	p.expect('{')
+	for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+		if i > 0 {
+			p.expect(';')
+		}
+		pkg, name := p.parseName(true)
+		sig := p.parseSignature(nil)
+		methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
+	}
+	p.expect('}')
+
+	// Complete requires the type's embedded interfaces to be fully defined,
+	// but we do not define any
+	return types.NewInterface(methods, nil).Complete()
+}
+
+// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
+//
+func (p *parser) parseChanType() types.Type {
+	dir := types.SendRecv
+	if p.tok == scanner.Ident {
+		p.expectKeyword("chan")
+		if p.tok == '<' {
+			p.expectSpecial("<-")
+			dir = types.SendOnly
+		}
+	} else {
+		p.expectSpecial("<-")
+		p.expectKeyword("chan")
+		dir = types.RecvOnly
+	}
+	elem := p.parseType()
+	return types.NewChan(dir, elem)
+}
+
+// Type =
+//	BasicType | TypeName | ArrayType | SliceType | StructType |
+//      PointerType | FuncType | InterfaceType | MapType | ChanType |
+//      "(" Type ")" .
+//
+// BasicType   = ident .
+// TypeName    = ExportedName .
+// SliceType   = "[" "]" Type .
+// PointerType = "*" Type .
+// FuncType    = "func" Signature .
+//
+func (p *parser) parseType() types.Type {
+	switch p.tok {
+	case scanner.Ident:
+		switch p.lit {
+		default:
+			return p.parseBasicType()
+		case "struct":
+			return p.parseStructType()
+		case "func":
+			// FuncType
+			p.next()
+			return p.parseSignature(nil)
+		case "interface":
+			return p.parseInterfaceType()
+		case "map":
+			return p.parseMapType()
+		case "chan":
+			return p.parseChanType()
+		}
+	case '@':
+		// TypeName
+		pkg, name := p.parseExportedName()
+		return declTypeName(pkg, name).Type()
+	case '[':
+		p.next() // look ahead
+		if p.tok == ']' {
+			// SliceType
+			p.next()
+			return types.NewSlice(p.parseType())
+		}
+		return p.parseArrayType()
+	case '*':
+		// PointerType
+		p.next()
+		return types.NewPointer(p.parseType())
+	case '<':
+		return p.parseChanType()
+	case '(':
+		// "(" Type ")"
+		p.next()
+		typ := p.parseType()
+		p.expect(')')
+		return typ
+	}
+	p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+	return nil
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// ImportDecl = "import" PackageName PackageId .
+//
+func (p *parser) parseImportDecl() {
+	p.expectKeyword("import")
+	name := p.parsePackageName()
+	p.getPkg(p.parsePackageId(), name)
+}
+
+// int_lit = [ "+" | "-" ] { "0" ... "9" } .
+//
+func (p *parser) parseInt() string {
+	s := ""
+	switch p.tok {
+	case '-':
+		s = "-"
+		p.next()
+	case '+':
+		p.next()
+	}
+	return s + p.expect(scanner.Int)
+}
+
+// number = int_lit [ "p" int_lit ] .
+//
+func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) {
+	// mantissa
+	mant := exact.MakeFromLiteral(p.parseInt(), token.INT, 0)
+	if mant == nil {
+		panic("invalid mantissa")
+	}
+
+	if p.lit == "p" {
+		// exponent (base 2)
+		p.next()
+		exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
+		if err != nil {
+			p.error(err)
+		}
+		if exp < 0 {
+			denom := exact.MakeInt64(1)
+			denom = exact.Shift(denom, token.SHL, uint(-exp))
+			typ = types.Typ[types.UntypedFloat]
+			val = exact.BinaryOp(mant, token.QUO, denom)
+			return
+		}
+		if exp > 0 {
+			mant = exact.Shift(mant, token.SHL, uint(exp))
+		}
+		typ = types.Typ[types.UntypedFloat]
+		val = mant
+		return
+	}
+
+	typ = types.Typ[types.UntypedInt]
+	val = mant
+	return
+}
+
+// ConstDecl   = "const" ExportedName [ Type ] "=" Literal .
+// Literal     = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
+// bool_lit    = "true" | "false" .
+// complex_lit = "(" float_lit "+" float_lit "i" ")" .
+// rune_lit    = "(" int_lit "+" int_lit ")" .
+// string_lit  = `"` { unicode_char } `"` .
+//
+func (p *parser) parseConstDecl() {
+	p.expectKeyword("const")
+	pkg, name := p.parseExportedName()
+
+	var typ0 types.Type
+	if p.tok != '=' {
+		typ0 = p.parseType()
+	}
+
+	p.expect('=')
+	var typ types.Type
+	var val exact.Value
+	switch p.tok {
+	case scanner.Ident:
+		// bool_lit
+		if p.lit != "true" && p.lit != "false" {
+			p.error("expected true or false")
+		}
+		typ = types.Typ[types.UntypedBool]
+		val = exact.MakeBool(p.lit == "true")
+		p.next()
+
+	case '-', scanner.Int:
+		// int_lit
+		typ, val = p.parseNumber()
+
+	case '(':
+		// complex_lit or rune_lit
+		p.next()
+		if p.tok == scanner.Char {
+			p.next()
+			p.expect('+')
+			typ = types.Typ[types.UntypedRune]
+			_, val = p.parseNumber()
+			p.expect(')')
+			break
+		}
+		_, re := p.parseNumber()
+		p.expect('+')
+		_, im := p.parseNumber()
+		p.expectKeyword("i")
+		p.expect(')')
+		typ = types.Typ[types.UntypedComplex]
+		val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+
+	case scanner.Char:
+		// rune_lit
+		typ = types.Typ[types.UntypedRune]
+		val = exact.MakeFromLiteral(p.lit, token.CHAR, 0)
+		p.next()
+
+	case scanner.String:
+		// string_lit
+		typ = types.Typ[types.UntypedString]
+		val = exact.MakeFromLiteral(p.lit, token.STRING, 0)
+		p.next()
+
+	default:
+		p.errorf("expected literal got %s", scanner.TokenString(p.tok))
+	}
+
+	if typ0 == nil {
+		typ0 = typ
+	}
+
+	pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
+}
+
+// TypeDecl = "type" ExportedName Type .
+//
+func (p *parser) parseTypeDecl() {
+	p.expectKeyword("type")
+	pkg, name := p.parseExportedName()
+	obj := declTypeName(pkg, name)
+
+	// The type object may have been imported before and thus already
+	// have a type associated with it. We still need to parse the type
+	// structure, but throw it away if the object already has a type.
+	// This ensures that all imports refer to the same type object for
+	// a given type declaration.
+	typ := p.parseType()
+
+	if name := obj.Type().(*types.Named); name.Underlying() == nil {
+		name.SetUnderlying(typ)
+	}
+}
+
+// VarDecl = "var" ExportedName Type .
+//
+func (p *parser) parseVarDecl() {
+	p.expectKeyword("var")
+	pkg, name := p.parseExportedName()
+	typ := p.parseType()
+	pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
+}
+
+// Func = Signature [ Body ] .
+// Body = "{" ... "}" .
+//
+func (p *parser) parseFunc(recv *types.Var) *types.Signature {
+	sig := p.parseSignature(recv)
+	if p.tok == '{' {
+		p.next()
+		for i := 1; i > 0; p.next() {
+			switch p.tok {
+			case '{':
+				i++
+			case '}':
+				i--
+			}
+		}
+	}
+	return sig
+}
+
+// MethodDecl = "func" Receiver Name Func .
+// Receiver   = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
+//
+func (p *parser) parseMethodDecl() {
+	// "func" already consumed
+	p.expect('(')
+	recv, _ := p.parseParameter() // receiver
+	p.expect(')')
+
+	// determine receiver base type object
+	base := deref(recv.Type()).(*types.Named)
+
+	// parse method name, signature, and possibly inlined body
+	_, name := p.parseName(true)
+	sig := p.parseFunc(recv)
+
+	// methods always belong to the same package as the base type object
+	pkg := base.Obj().Pkg()
+
+	// add method to type unless type was imported before
+	// and method exists already
+	// TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
+	base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+}
+
+// FuncDecl = "func" ExportedName Func .
+//
+func (p *parser) parseFuncDecl() {
+	// "func" already consumed
+	pkg, name := p.parseExportedName()
+	typ := p.parseFunc(nil)
+	pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
+}
+
+// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
+//
+func (p *parser) parseDecl() {
+	if p.tok == scanner.Ident {
+		switch p.lit {
+		case "import":
+			p.parseImportDecl()
+		case "const":
+			p.parseConstDecl()
+		case "type":
+			p.parseTypeDecl()
+		case "var":
+			p.parseVarDecl()
+		case "func":
+			p.next() // look ahead
+			if p.tok == '(' {
+				p.parseMethodDecl()
+			} else {
+				p.parseFuncDecl()
+			}
+		}
+	}
+	p.expect('\n')
+}
+
+// ----------------------------------------------------------------------------
+// Export
+
+// Export        = "PackageClause { Decl } "$$" .
+// PackageClause = "package" PackageName [ "safe" ] "\n" .
+//
+func (p *parser) parseExport() *types.Package {
+	p.expectKeyword("package")
+	name := p.parsePackageName()
+	if p.tok == scanner.Ident && p.lit == "safe" {
+		// package was compiled with -u option - ignore
+		p.next()
+	}
+	p.expect('\n')
+
+	pkg := p.getPkg(p.id, name)
+
+	for p.tok != '$' && p.tok != scanner.EOF {
+		p.parseDecl()
+	}
+
+	if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
+		// don't call next()/expect() since reading past the
+		// export data may cause scanner errors (e.g. NUL chars)
+		p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
+	}
+
+	if n := p.scanner.ErrorCount; n != 0 {
+		p.errorf("expected no scanner errors, got %d", n)
+	}
+
+	// package was imported completely and without errors
+	pkg.MarkComplete()
+
+	return pkg
+}
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
new file mode 100644
index 0000000..5d4de39
--- /dev/null
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -0,0 +1,231 @@
+// Copyright 2011 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 gcimporter
+
+import (
+	"go/build"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+
+	"go/types"
+)
+
+// skipSpecialPlatforms causes the test to be skipped for platforms where
+// builders (build.golang.org) don't have access to compiled packages for
+// import.
+func skipSpecialPlatforms(t *testing.T) {
+	switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
+	case "nacl-amd64p32",
+		"nacl-386",
+		"nacl-arm",
+		"darwin-arm",
+		"darwin-arm64":
+		t.Skipf("no compiled packages available for import on %s", platform)
+	}
+}
+
+var gcPath string // Go compiler path
+
+func init() {
+	if char, err := build.ArchChar(runtime.GOARCH); err == nil {
+		gcPath = filepath.Join(build.ToolDir, char+"g")
+		return
+	}
+	gcPath = "unknown-GOARCH-compiler"
+}
+
+func compile(t *testing.T, dirname, filename string) string {
+	cmd := exec.Command(gcPath, filename)
+	cmd.Dir = dirname
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		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)
+}
+
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*types.Package)
+
+func testPath(t *testing.T, path string) bool {
+	t0 := time.Now()
+	_, err := Import(imports, path)
+	if err != nil {
+		t.Errorf("testPath(%s): %s", path, err)
+		return false
+	}
+	t.Logf("testPath(%s): %v", path, time.Since(t0))
+	return true
+}
+
+const maxTime = 30 * time.Second
+
+func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
+	dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
+	list, err := ioutil.ReadDir(dirname)
+	if err != nil {
+		t.Fatalf("testDir(%s): %s", dirname, err)
+	}
+	for _, f := range list {
+		if time.Now().After(endTime) {
+			t.Log("testing time used up")
+			return
+		}
+		switch {
+		case !f.IsDir():
+			// try extensions
+			for _, ext := range pkgExts {
+				if strings.HasSuffix(f.Name(), ext) {
+					name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
+					if testPath(t, filepath.Join(dir, name)) {
+						nimports++
+					}
+				}
+			}
+		case f.IsDir():
+			nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
+		}
+	}
+	return
+}
+
+func TestImport(t *testing.T) {
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	// On cross-compile builds, the path will not exist.
+	// Need to use GOHOSTOS, which is not available.
+	if _, err := os.Stat(gcPath); err != nil {
+		t.Skipf("skipping test: %v", err)
+	}
+
+	if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
+		defer os.Remove(outFn)
+	}
+
+	nimports := 0
+	if testPath(t, "./testdata/exports") {
+		nimports++
+	}
+	nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
+	t.Logf("tested %d imports", nimports)
+}
+
+var importedObjectTests = []struct {
+	name string
+	want string
+}{
+	{"math.Pi", "const Pi untyped float"},
+	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
+	{"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
+	{"math.Sin", "func Sin(x float64) float64"},
+	// TODO(gri) add more tests
+}
+
+func TestImportedTypes(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	for _, test := range importedObjectTests {
+		s := strings.Split(test.name, ".")
+		if len(s) != 2 {
+			t.Fatal("inconsistent test data")
+		}
+		importPath := s[0]
+		objName := s[1]
+
+		pkg, err := Import(imports, importPath)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+
+		obj := pkg.Scope().Lookup(objName)
+		if obj == nil {
+			t.Errorf("%s: object not found", test.name)
+			continue
+		}
+
+		got := types.ObjectString(pkg, obj)
+		if got != test.want {
+			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+		}
+	}
+}
+
+func TestIssue5815(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	pkg, err := Import(make(map[string]*types.Package), "strings")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	scope := pkg.Scope()
+	for _, name := range scope.Names() {
+		obj := scope.Lookup(name)
+		if obj.Pkg() == nil {
+			t.Errorf("no pkg for %s", obj)
+		}
+		if tname, _ := obj.(*types.TypeName); tname != nil {
+			named := tname.Type().(*types.Named)
+			for i := 0; i < named.NumMethods(); i++ {
+				m := named.Method(i)
+				if m.Pkg() == nil {
+					t.Errorf("no pkg for %s", m)
+				}
+			}
+		}
+	}
+}
+
+// Smoke test to ensure that imported methods get the correct package.
+func TestCorrectMethodPackage(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	imports := make(map[string]*types.Package)
+	_, err := Import(imports, "net/http")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
+	mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
+	sel := mset.Lookup(nil, "Lock")
+	lock := sel.Obj().(*types.Func)
+	if got, want := lock.Pkg().Path(), "sync"; got != want {
+		t.Errorf("got package path %q; want %q", got, want)
+	}
+}
diff --git a/src/go/internal/gcimporter/testdata/exports.go b/src/go/internal/gcimporter/testdata/exports.go
new file mode 100644
index 0000000..8ee28b0
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/exports.go
@@ -0,0 +1,89 @@
+// Copyright 2011 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.
+
+// This file is used to generate an object file which
+// serves as test file for gcimporter_test.go.
+
+package exports
+
+import (
+	"go/ast"
+)
+
+// Issue 3682: Correctly read dotted identifiers from export data.
+const init1 = 0
+
+func init() {}
+
+const (
+	C0 int = 0
+	C1     = 3.14159265
+	C2     = 2.718281828i
+	C3     = -123.456e-789
+	C4     = +123.456E+789
+	C5     = 1234i
+	C6     = "foo\n"
+	C7     = `bar\n`
+)
+
+type (
+	T1  int
+	T2  [10]int
+	T3  []int
+	T4  *int
+	T5  chan int
+	T6a chan<- int
+	T6b chan (<-chan int)
+	T6c chan<- (chan int)
+	T7  <-chan *ast.File
+	T8  struct{}
+	T9  struct {
+		a    int
+		b, c float32
+		d    []string `go:"tag"`
+	}
+	T10 struct {
+		T8
+		T9
+		_ *T10
+	}
+	T11 map[int]string
+	T12 interface{}
+	T13 interface {
+		m1()
+		m2(int) float32
+	}
+	T14 interface {
+		T12
+		T13
+		m3(x ...struct{}) []T9
+	}
+	T15 func()
+	T16 func(int)
+	T17 func(x int)
+	T18 func() float32
+	T19 func() (x float32)
+	T20 func(...interface{})
+	T21 struct{ next *T21 }
+	T22 struct{ link *T23 }
+	T23 struct{ link *T22 }
+	T24 *T24
+	T25 *T26
+	T26 *T27
+	T27 *T25
+	T28 func(T28) T28
+)
+
+var (
+	V0 int
+	V1 = -991.0
+)
+
+func F1()         {}
+func F2(x int)    {}
+func F3() int     { return 0 }
+func F4() float32 { return 0 }
+func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
+
+func (p *T1) M1()
diff --git a/src/go/scanner/errors.go b/src/go/scanner/errors.go
index 7c9ab25..bf7bfa3 100644
--- a/src/go/scanner/errors.go
+++ b/src/go/scanner/errors.go
@@ -54,25 +54,16 @@
 	// Note that it is not sufficient to simply compare file offsets because
 	// the offsets do not reflect modified line information (through //line
 	// comments).
-	if e.Filename < f.Filename {
-		return true
+	if e.Filename != f.Filename {
+		return e.Filename < f.Filename
 	}
-	if e.Filename == f.Filename {
-		if e.Line < f.Line {
-			return true
-		}
-		if e.Line == f.Line {
-			if e.Column < f.Column {
-				return true
-			}
-			if e.Column == f.Column {
-				if p[i].Msg < p[j].Msg {
-					return true
-				}
-			}
-		}
+	if e.Line != f.Line {
+		return e.Line < f.Line
 	}
-	return false
+	if e.Column != f.Column {
+		return e.Column < f.Column
+	}
+	return p[i].Msg < p[j].Msg
 }
 
 // Sort sorts an ErrorList. *Error entries are sorted by position,
diff --git a/src/go/types.bash b/src/go/types.bash
new file mode 100644
index 0000000..1a384d4
--- /dev/null
+++ b/src/go/types.bash
@@ -0,0 +1,97 @@
+#!/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
new file mode 100644
index 0000000..a2a55e3
--- /dev/null
+++ b/src/go/types/api.go
@@ -0,0 +1,336 @@
+// Copyright 2012 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 types declares the data types and implements
+// the algorithms for type-checking of Go packages. Use
+// Config.Check to invoke the type checker for a package.
+// Alternatively, create a new type checked with NewChecker
+// and invoke it incrementally by calling Checker.Files.
+//
+// Type-checking consists of several interdependent phases:
+//
+// Name resolution maps each identifier (ast.Ident) in the program to the
+// language object (Object) it denotes.
+// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
+//
+// Constant folding computes the exact constant value (exact.Value) for
+// every expression (ast.Expr) that is a compile-time constant.
+// Use Info.Types[expr].Value for the results of constant folding.
+//
+// Type inference computes the type (Type) of every expression (ast.Expr)
+// and checks for compliance with the language specification.
+// Use Info.Types[expr].Type for the results of type inference.
+//
+package types // import "go/types"
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+// An Error describes a type-checking error; it implements the error interface.
+// A "soft" error is an error that still permits a valid interpretation of a
+// package (such as "unused variable"); "hard" errors may lead to unpredictable
+// behavior if ignored.
+type Error struct {
+	Fset *token.FileSet // file set for interpretation of Pos
+	Pos  token.Pos      // error position
+	Msg  string         // error message
+	Soft bool           // if set, error is "soft"
+}
+
+// Error returns an error string formatted as follows:
+// filename:line:column: message
+func (err Error) Error() string {
+	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
+}
+
+// An importer resolves import paths to Packages.
+// See go/importer for existing implementations.
+type Importer interface {
+	// Import returns the imported package for the given import
+	// path, or an error if the package couldn't be imported.
+	// Import is responsible for returning the same package for
+	// matching import paths.
+	Import(path string) (*Package, error)
+}
+
+// A Config specifies the configuration for type checking.
+// The zero value for Config is a ready-to-use default configuration.
+type Config struct {
+	// If IgnoreFuncBodies is set, function bodies are not
+	// type-checked.
+	IgnoreFuncBodies bool
+
+	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
+	// declares an empty "C" package and errors are omitted for qualified
+	// identifiers referring to package C (which won't find an object).
+	// This feature is intended for the standard library cmd/api tool.
+	//
+	// Caution: Effects may be unpredictable due to follow-up errors.
+	//          Do not use casually!
+	FakeImportC bool
+
+	// If Error != nil, it is called with each error found
+	// during type checking; err has dynamic type Error.
+	// Secondary errors (for instance, to enumerate all types
+	// involved in an invalid recursive type declaration) have
+	// error strings that start with a '\t' character.
+	// If Error == nil, type-checking stops with the first
+	// error found.
+	Error func(err error)
+
+	// Importer is called for each import declaration except when
+	// importing package "unsafe". An error is reported if an
+	// importer is needed but none was installed.
+	Importer Importer
+
+	// If Sizes != nil, it provides the sizing functions for package unsafe.
+	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
+	Sizes Sizes
+
+	// If DisableUnusedImportCheck is set, packages are not checked
+	// for unused imports.
+	DisableUnusedImportCheck bool
+}
+
+// Info holds result type information for a type-checked package.
+// Only the information for which a map is provided is collected.
+// If the package has type errors, the collected information may
+// be incomplete.
+type Info struct {
+	// Types maps expressions to their types, and for constant
+	// expressions, their values. Invalid expressions are omitted.
+	//
+	// For (possibly parenthesized) identifiers denoting built-in
+	// functions, the recorded signatures are call-site specific:
+	// if the call result is not a constant, the recorded type is
+	// an argument-specific signature. Otherwise, the recorded type
+	// is invalid.
+	//
+	// Identifiers on the lhs of declarations (i.e., the identifiers
+	// which are being declared) are collected in the Defs map.
+	// Identifiers denoting packages are collected in the Uses maps.
+	Types map[ast.Expr]TypeAndValue
+
+	// Defs maps identifiers to the objects they define (including
+	// package names, dots "." of dot-imports, and blank "_" identifiers).
+	// For identifiers that do not denote objects (e.g., the package name
+	// in package clauses, or symbolic variables t in t := x.(type) of
+	// type switch headers), the corresponding objects are nil.
+	//
+	// For an anonymous field, Defs returns the field *Var it defines.
+	//
+	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
+	Defs map[*ast.Ident]Object
+
+	// Uses maps identifiers to the objects they denote.
+	//
+	// For an anonymous field, Uses returns the *TypeName it denotes.
+	//
+	// Invariant: Uses[id].Pos() != id.Pos()
+	Uses map[*ast.Ident]Object
+
+	// Implicits maps nodes to their implicitly declared objects, if any.
+	// The following node and object types may appear:
+	//
+	//	node               declared object
+	//
+	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
+	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
+	//      *ast.Field         anonymous struct field or parameter *Var
+	//
+	Implicits map[ast.Node]Object
+
+	// Selections maps selector expressions (excluding qualified identifiers)
+	// to their corresponding selections.
+	Selections map[*ast.SelectorExpr]*Selection
+
+	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
+	// associated with a specific node but with all files belonging to a package.
+	// Thus, the package scope can be found in the type-checked Package object.
+	// Scopes nest, with the Universe scope being the outermost scope, enclosing
+	// the package scope, which contains (one or more) files scopes, which enclose
+	// function scopes which in turn enclose statement and function literal scopes.
+	// Note that even though package-level functions are declared in the package
+	// scope, the function scopes are embedded in the file scope of the file
+	// containing the function declaration.
+	//
+	// The following node types may appear in Scopes:
+	//
+	//	*ast.File
+	//	*ast.FuncType
+	//	*ast.BlockStmt
+	//	*ast.IfStmt
+	//	*ast.SwitchStmt
+	//	*ast.TypeSwitchStmt
+	//	*ast.CaseClause
+	//	*ast.CommClause
+	//	*ast.ForStmt
+	//	*ast.RangeStmt
+	//
+	Scopes map[ast.Node]*Scope
+
+	// InitOrder is the list of package-level initializers in the order in which
+	// they must be executed. Initializers referring to variables related by an
+	// initialization dependency appear in topological order, the others appear
+	// in source order. Variables without an initialization expression do not
+	// appear in this list.
+	InitOrder []*Initializer
+}
+
+// TypeOf returns the type of expression e, or nil if not found.
+// Precondition: the Types, Uses and Defs maps are populated.
+//
+func (info *Info) TypeOf(e ast.Expr) Type {
+	if t, ok := info.Types[e]; ok {
+		return t.Type
+	}
+	if id, _ := e.(*ast.Ident); id != nil {
+		if obj := info.ObjectOf(id); obj != nil {
+			return obj.Type()
+		}
+	}
+	return nil
+}
+
+// ObjectOf returns the object denoted by the specified id,
+// or nil if not found.
+//
+// If id is an anonymous struct field, ObjectOf returns the field (*Var)
+// it uses, not the type (*TypeName) it defines.
+//
+// Precondition: the Uses and Defs maps are populated.
+//
+func (info *Info) ObjectOf(id *ast.Ident) Object {
+	if obj, _ := info.Defs[id]; obj != nil {
+		return obj
+	}
+	return info.Uses[id]
+}
+
+// TypeAndValue reports the type and value (for constants)
+// of the corresponding expression.
+type TypeAndValue struct {
+	mode  operandMode
+	Type  Type
+	Value exact.Value
+}
+
+// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
+// "void" values as regular values but with the empty tuple type.
+
+// IsVoid reports whether the corresponding expression
+// is a function call without results.
+func (tv TypeAndValue) IsVoid() bool {
+	return tv.mode == novalue
+}
+
+// IsType reports whether the corresponding expression specifies a type.
+func (tv TypeAndValue) IsType() bool {
+	return tv.mode == typexpr
+}
+
+// IsBuiltin reports whether the corresponding expression denotes
+// a (possibly parenthesized) built-in function.
+func (tv TypeAndValue) IsBuiltin() bool {
+	return tv.mode == builtin
+}
+
+// IsValue reports whether the corresponding expression is a value.
+// Builtins are not considered values. Constant values have a non-
+// nil Value.
+func (tv TypeAndValue) IsValue() bool {
+	switch tv.mode {
+	case constant, variable, mapindex, value, commaok:
+		return true
+	}
+	return false
+}
+
+// IsNil reports whether the corresponding expression denotes the
+// predeclared value nil.
+func (tv TypeAndValue) IsNil() bool {
+	return tv.mode == value && tv.Type == Typ[UntypedNil]
+}
+
+// Addressable reports whether the corresponding expression
+// is addressable (http://golang.org/ref/spec#Address_operators).
+func (tv TypeAndValue) Addressable() bool {
+	return tv.mode == variable
+}
+
+// Assignable reports whether the corresponding expression
+// is assignable to (provided a value of the right type).
+func (tv TypeAndValue) Assignable() bool {
+	return tv.mode == variable || tv.mode == mapindex
+}
+
+// HasOk reports whether the corresponding expression may be
+// used on the lhs of a comma-ok assignment.
+func (tv TypeAndValue) HasOk() bool {
+	return tv.mode == commaok || tv.mode == mapindex
+}
+
+// An Initializer describes a package-level variable, or a list of variables in case
+// of a multi-valued initialization expression, and the corresponding initialization
+// expression.
+type Initializer struct {
+	Lhs []*Var // var Lhs = Rhs
+	Rhs ast.Expr
+}
+
+func (init *Initializer) String() string {
+	var buf bytes.Buffer
+	for i, lhs := range init.Lhs {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(lhs.Name())
+	}
+	buf.WriteString(" = ")
+	WriteExpr(&buf, init.Rhs)
+	return buf.String()
+}
+
+// Check type-checks a package and returns the resulting package object,
+// the first error if any, and if info != nil, additional type information.
+// The package is marked as complete if no errors occurred, otherwise it is
+// incomplete. See Config.Error for controlling behavior in the presence of
+// errors.
+//
+// The package is specified by a list of *ast.Files and corresponding
+// file set, and the package path the package is identified with.
+// The clean path must not be empty or dot (".").
+func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
+	pkg := NewPackage(path, "")
+	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
+}
+
+// AssertableTo reports whether a value of type V can be asserted to have type T.
+func AssertableTo(V *Interface, T Type) bool {
+	m, _ := assertableTo(V, T)
+	return m == nil
+}
+
+// AssignableTo reports whether a value of type V is assignable to a variable of type T.
+func AssignableTo(V, T Type) bool {
+	x := operand{mode: value, typ: V}
+	return x.assignableTo(nil, T) // config not needed for non-constant x
+}
+
+// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
+func ConvertibleTo(V, T Type) bool {
+	x := operand{mode: value, typ: V}
+	return x.convertibleTo(nil, T) // config not needed for non-constant x
+}
+
+// Implements reports whether type V implements interface T.
+func Implements(V Type, T *Interface) bool {
+	f, _ := MissingMethod(V, T, true)
+	return f == nil
+}
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
new file mode 100644
index 0000000..3ab909c
--- /dev/null
+++ b/src/go/types/api_test.go
@@ -0,0 +1,958 @@
+// Copyright 2013 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 types_test
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"runtime"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+// skipSpecialPlatforms causes the test to be skipped for platforms where
+// builders (build.golang.org) don't have access to compiled packages for
+// import.
+func skipSpecialPlatforms(t *testing.T) {
+	switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
+	case "nacl-amd64p32",
+		"nacl-386",
+		"nacl-arm",
+		"darwin-arm",
+		"darwin-arm64":
+		t.Skipf("no compiled packages available for import on %s", platform)
+	}
+}
+
+func pkgFor(path, source string, info *Info) (*Package, error) {
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, path, source, 0)
+	if err != nil {
+		return nil, err
+	}
+
+	conf := Config{Importer: importer.Default()}
+	return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
+}
+
+func mustTypecheck(t *testing.T, path, source string, info *Info) string {
+	pkg, err := pkgFor(path, source, info)
+	if err != nil {
+		name := path
+		if pkg != nil {
+			name = "package " + pkg.Name()
+		}
+		t.Fatalf("%s: didn't type-check (%s)", name, err)
+	}
+	return pkg.Name()
+}
+
+func TestValuesInfo(t *testing.T) {
+	var tests = []struct {
+		src  string
+		expr string // constant expression
+		typ  string // constant type
+		val  string // constant value
+	}{
+		{`package a0; const _ = false`, `false`, `untyped bool`, `false`},
+		{`package a1; const _ = 0`, `0`, `untyped int`, `0`},
+		{`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
+		{`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
+		{`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`},
+		{`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
+
+		{`package b0; var _ = false`, `false`, `bool`, `false`},
+		{`package b1; var _ = 0`, `0`, `int`, `0`},
+		{`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
+		{`package b3; var _ = 0.`, `0.`, `float64`, `0`},
+		{`package b4; var _ = 0i`, `0i`, `complex128`, `0`},
+		{`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
+
+		{`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
+		{`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
+		{`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
+
+		{`package c1a; var _ = int(0)`, `0`, `int`, `0`},
+		{`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
+		{`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
+
+		{`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
+		{`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
+		{`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
+
+		{`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
+		{`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
+		{`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
+
+		{`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`},
+		{`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`},
+		{`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`},
+
+		{`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
+		{`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
+		{`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
+
+		{`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
+		{`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
+		{`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
+		{`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
+
+		{`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
+		{`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
+		{`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
+		{`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
+		{`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`},
+		{`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`},
+		{`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`},
+		{`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`},
+
+		{`package f0 ; var _ float32 =  1e-200`, `1e-200`, `float32`, `0`},
+		{`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
+		{`package f2a; var _ float64 =  1e-2000`, `1e-2000`, `float64`, `0`},
+		{`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
+		{`package f2b; var _         =  1e-2000`, `1e-2000`, `float64`, `0`},
+		{`package f3b; var _         = -1e-2000`, `-1e-2000`, `float64`, `0`},
+		{`package f4 ; var _ complex64  =  1e-200 `, `1e-200`, `complex64`, `0`},
+		{`package f5 ; var _ complex64  = -1e-200 `, `-1e-200`, `complex64`, `0`},
+		{`package f6a; var _ complex128 =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
+		{`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+		{`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
+		{`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+	}
+
+	for _, test := range tests {
+		info := Info{
+			Types: make(map[ast.Expr]TypeAndValue),
+		}
+		name := mustTypecheck(t, "ValuesInfo", test.src, &info)
+
+		// look for constant expression
+		var expr ast.Expr
+		for e := range info.Types {
+			if ExprString(e) == test.expr {
+				expr = e
+				break
+			}
+		}
+		if expr == nil {
+			t.Errorf("package %s: no expression found for %s", name, test.expr)
+			continue
+		}
+		tv := info.Types[expr]
+
+		// check that type is correct
+		if got := tv.Type.String(); got != test.typ {
+			t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
+			continue
+		}
+
+		// check that value is correct
+		if got := tv.Value.String(); got != test.val {
+			t.Errorf("package %s: got value %s; want %s", name, got, test.val)
+		}
+	}
+}
+
+func TestTypesInfo(t *testing.T) {
+	var tests = []struct {
+		src  string
+		expr string // expression
+		typ  string // value type
+	}{
+		// single-valued expressions of untyped constants
+		{`package b0; var x interface{} = false`, `false`, `bool`},
+		{`package b1; var x interface{} = 0`, `0`, `int`},
+		{`package b2; var x interface{} = 0.`, `0.`, `float64`},
+		{`package b3; var x interface{} = 0i`, `0i`, `complex128`},
+		{`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
+
+		// comma-ok expressions
+		{`package p0; var x interface{}; var _, _ = x.(int)`,
+			`x.(int)`,
+			`(int, bool)`,
+		},
+		{`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
+			`x.(int)`,
+			`(int, bool)`,
+		},
+		// TODO(gri): uncomment if we accept issue 8189.
+		// {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+		// 	`m["foo"]`,
+		// 	`(complex128, p2.mybool)`,
+		// },
+		// TODO(gri): remove if we accept issue 8189.
+		{`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+			`m["foo"]`,
+			`(complex128, bool)`,
+		},
+		{`package p3; var c chan string; var _, _ = <-c`,
+			`<-c`,
+			`(string, bool)`,
+		},
+
+		// issue 6796
+		{`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
+			`x.(int)`,
+			`(int, bool)`,
+		},
+		{`package issue6796_b; var c chan string; var _, _ = (<-c)`,
+			`(<-c)`,
+			`(string, bool)`,
+		},
+		{`package issue6796_c; var c chan string; var _, _ = (<-c)`,
+			`<-c`,
+			`(string, bool)`,
+		},
+		{`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
+			`(<-c)`,
+			`(string, bool)`,
+		},
+		{`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
+			`(<-c)`,
+			`(string, bool)`,
+		},
+
+		// issue 7060
+		{`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
+			`m[0]`,
+			`(string, bool)`,
+		},
+		{`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
+			`m[0]`,
+			`(string, bool)`,
+		},
+		{`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
+			`m[0]`,
+			`(string, bool)`,
+		},
+		{`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
+			`<-ch`,
+			`(string, bool)`,
+		},
+		{`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
+			`<-ch`,
+			`(string, bool)`,
+		},
+		{`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
+			`<-ch`,
+			`(string, bool)`,
+		},
+	}
+
+	for _, test := range tests {
+		info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+		name := mustTypecheck(t, "TypesInfo", test.src, &info)
+
+		// look for expression type
+		var typ Type
+		for e, tv := range info.Types {
+			if ExprString(e) == test.expr {
+				typ = tv.Type
+				break
+			}
+		}
+		if typ == nil {
+			t.Errorf("package %s: no type found for %s", name, test.expr)
+			continue
+		}
+
+		// check that type is correct
+		if got := typ.String(); got != test.typ {
+			t.Errorf("package %s: got %s; want %s", name, got, test.typ)
+		}
+	}
+}
+
+func predString(tv TypeAndValue) string {
+	var buf bytes.Buffer
+	pred := func(b bool, s string) {
+		if b {
+			if buf.Len() > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(s)
+		}
+	}
+
+	pred(tv.IsVoid(), "void")
+	pred(tv.IsType(), "type")
+	pred(tv.IsBuiltin(), "builtin")
+	pred(tv.IsValue() && tv.Value != nil, "const")
+	pred(tv.IsValue() && tv.Value == nil, "value")
+	pred(tv.IsNil(), "nil")
+	pred(tv.Addressable(), "addressable")
+	pred(tv.Assignable(), "assignable")
+	pred(tv.HasOk(), "hasOk")
+
+	if buf.Len() == 0 {
+		return "invalid"
+	}
+	return buf.String()
+}
+
+func TestPredicatesInfo(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	var tests = []struct {
+		src  string
+		expr string
+		pred string
+	}{
+		// void
+		{`package n0; func f() { f() }`, `f()`, `void`},
+
+		// types
+		{`package t0; type _ int`, `int`, `type`},
+		{`package t1; type _ []int`, `[]int`, `type`},
+		{`package t2; type _ func()`, `func()`, `type`},
+
+		// built-ins
+		{`package b0; var _ = len("")`, `len`, `builtin`},
+		{`package b1; var _ = (len)("")`, `(len)`, `builtin`},
+
+		// constants
+		{`package c0; var _ = 42`, `42`, `const`},
+		{`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
+		{`package c2; const (i = 1i; _ = i)`, `i`, `const`},
+
+		// values
+		{`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
+		{`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
+		{`package v2; var _ = func(){}`, `(func() literal)`, `value`},
+		{`package v4; func f() { _ = f }`, `f`, `value`},
+		{`package v3; var _ *int = nil`, `nil`, `value, nil`},
+		{`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
+
+		// addressable (and thus assignable) operands
+		{`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
+		{`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
+		{`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
+		{`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
+		{`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
+		{`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
+		{`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
+		{`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
+		// composite literals are not addressable
+
+		// assignable but not addressable values
+		{`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+		{`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+
+		// hasOk expressions
+		{`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
+		{`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
+
+		// missing entries
+		// - package names are collected in the Uses map
+		// - identifiers being declared are collected in the Defs map
+		{`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
+		{`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
+		{`package m2; const c = 0`, `c`, `<missing>`},
+		{`package m3; type T int`, `T`, `<missing>`},
+		{`package m4; var v int`, `v`, `<missing>`},
+		{`package m5; func f() {}`, `f`, `<missing>`},
+		{`package m6; func _(x int) {}`, `x`, `<missing>`},
+		{`package m6; func _()(x int) { return }`, `x`, `<missing>`},
+		{`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
+	}
+
+	for _, test := range tests {
+		info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+		name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
+
+		// look for expression predicates
+		got := "<missing>"
+		for e, tv := range info.Types {
+			//println(name, ExprString(e))
+			if ExprString(e) == test.expr {
+				got = predString(tv)
+				break
+			}
+		}
+
+		if got != test.pred {
+			t.Errorf("package %s: got %s; want %s", name, got, test.pred)
+		}
+	}
+}
+
+func TestScopesInfo(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	var tests = []struct {
+		src    string
+		scopes []string // list of scope descriptors of the form kind:varlist
+	}{
+		{`package p0`, []string{
+			"file:",
+		}},
+		{`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
+			"file:fmt m",
+		}},
+		{`package p2; func _() {}`, []string{
+			"file:", "func:",
+		}},
+		{`package p3; func _(x, y int) {}`, []string{
+			"file:", "func:x y",
+		}},
+		{`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
+			"file:", "func:x y z", // redeclaration of x
+		}},
+		{`package p5; func _(x, y int) (u, _ int) { return }`, []string{
+			"file:", "func:u x y",
+		}},
+		{`package p6; func _() { { var x int; _ = x } }`, []string{
+			"file:", "func:", "block:x",
+		}},
+		{`package p7; func _() { if true {} }`, []string{
+			"file:", "func:", "if:", "block:",
+		}},
+		{`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
+			"file:", "func:", "if:x", "block:y",
+		}},
+		{`package p9; func _() { switch x := 0; x {} }`, []string{
+			"file:", "func:", "switch:x",
+		}},
+		{`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
+			"file:", "func:", "switch:x", "case:y", "case:",
+		}},
+		{`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
+			"file:", "func:t", "type switch:",
+		}},
+		{`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
+			"file:", "func:t", "type switch:t",
+		}},
+		{`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
+			"file:", "func:t", "type switch:", "case:x", // x implicitly declared
+		}},
+		{`package p14; func _() { select{} }`, []string{
+			"file:", "func:",
+		}},
+		{`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
+			"file:", "func:c", "comm:",
+		}},
+		{`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
+			"file:", "func:c", "comm:i x",
+		}},
+		{`package p17; func _() { for{} }`, []string{
+			"file:", "func:", "for:", "block:",
+		}},
+		{`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
+			"file:", "func:n", "for:i", "block:",
+		}},
+		{`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
+			"file:", "func:a", "range:i", "block:",
+		}},
+		{`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
+			"file:", "func:a", "range:i x", "block:",
+		}},
+	}
+
+	for _, test := range tests {
+		info := Info{Scopes: make(map[ast.Node]*Scope)}
+		name := mustTypecheck(t, "ScopesInfo", test.src, &info)
+
+		// number of scopes must match
+		if len(info.Scopes) != len(test.scopes) {
+			t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
+		}
+
+		// scope descriptions must match
+		for node, scope := range info.Scopes {
+			kind := "<unknown node kind>"
+			switch node.(type) {
+			case *ast.File:
+				kind = "file"
+			case *ast.FuncType:
+				kind = "func"
+			case *ast.BlockStmt:
+				kind = "block"
+			case *ast.IfStmt:
+				kind = "if"
+			case *ast.SwitchStmt:
+				kind = "switch"
+			case *ast.TypeSwitchStmt:
+				kind = "type switch"
+			case *ast.CaseClause:
+				kind = "case"
+			case *ast.CommClause:
+				kind = "comm"
+			case *ast.ForStmt:
+				kind = "for"
+			case *ast.RangeStmt:
+				kind = "range"
+			}
+
+			// look for matching scope description
+			desc := kind + ":" + strings.Join(scope.Names(), " ")
+			found := false
+			for _, d := range test.scopes {
+				if desc == d {
+					found = true
+					break
+				}
+			}
+			if !found {
+				t.Errorf("package %s: no matching scope found for %s", name, desc)
+			}
+		}
+	}
+}
+
+func TestInitOrderInfo(t *testing.T) {
+	var tests = []struct {
+		src   string
+		inits []string
+	}{
+		{`package p0; var (x = 1; y = x)`, []string{
+			"x = 1", "y = x",
+		}},
+		{`package p1; var (a = 1; b = 2; c = 3)`, []string{
+			"a = 1", "b = 2", "c = 3",
+		}},
+		{`package p2; var (a, b, c = 1, 2, 3)`, []string{
+			"a = 1", "b = 2", "c = 3",
+		}},
+		{`package p3; var _ = f(); func f() int { return 1 }`, []string{
+			"_ = f()", // blank var
+		}},
+		{`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
+			"a = 0", "z = 0", "y = z", "x = y",
+		}},
+		{`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
+			"a, _ = m[0]", // blank var
+		}},
+		{`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
+			"z = 0", "a, b = f()",
+		}},
+		{`package p7; var (a = func() int { return b }(); b = 1)`, []string{
+			"b = 1", "a = (func() int literal)()",
+		}},
+		{`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
+			"c = 1", "a, b = (func() (_, _ int) literal)()",
+		}},
+		{`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
+			"y = 1", "x = T.m",
+		}},
+		{`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
+			"a = 0", "b = 0", "c = 0", "d = c + b",
+		}},
+		{`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
+			"c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
+		}},
+		// emit an initializer for n:1 initializations only once (not for each node
+		// on the lhs which may appear in different order in the dependency graph)
+		{`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
+			"b = 0", "x, y = m[0]", "a = x",
+		}},
+		// test case from spec section on package initialization
+		{`package p12
+
+		var (
+			a = c + b
+			b = f()
+			c = f()
+			d = 3
+		)
+
+		func f() int {
+			d++
+			return d
+		}`, []string{
+			"d = 3", "b = f()", "c = f()", "a = c + b",
+		}},
+		// test case for issue 7131
+		{`package main
+
+		var counter int
+		func next() int { counter++; return counter }
+
+		var _ = makeOrder()
+		func makeOrder() []int { return []int{f, b, d, e, c, a} }
+
+		var a       = next()
+		var b, c    = next(), next()
+		var d, e, f = next(), next(), next()
+		`, []string{
+			"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
+		}},
+	}
+
+	for _, test := range tests {
+		info := Info{}
+		name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
+
+		// number of initializers must match
+		if len(info.InitOrder) != len(test.inits) {
+			t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
+			continue
+		}
+
+		// initializers must match
+		for i, want := range test.inits {
+			got := info.InitOrder[i].String()
+			if got != want {
+				t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
+				continue
+			}
+		}
+	}
+}
+
+func TestMultiFileInitOrder(t *testing.T) {
+	fset := token.NewFileSet()
+	mustParse := func(src string) *ast.File {
+		f, err := parser.ParseFile(fset, "main", src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		return f
+	}
+
+	fileA := mustParse(`package main; var a = 1`)
+	fileB := mustParse(`package main; var b = 2`)
+
+	// The initialization order must not depend on the parse
+	// order of the files, only on the presentation order to
+	// the type-checker.
+	for _, test := range []struct {
+		files []*ast.File
+		want  string
+	}{
+		{[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
+		{[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
+	} {
+		var info Info
+		if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
+			t.Fatal(err)
+		}
+		if got := fmt.Sprint(info.InitOrder); got != test.want {
+			t.Fatalf("got %s; want %s", got, test.want)
+		}
+	}
+}
+
+func TestFiles(t *testing.T) {
+	var sources = []string{
+		"package p; type T struct{}; func (T) m1() {}",
+		"package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
+		"package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
+		"package p",
+	}
+
+	var conf Config
+	fset := token.NewFileSet()
+	pkg := NewPackage("p", "p")
+	var info Info
+	check := NewChecker(&conf, fset, pkg, &info)
+
+	for i, src := range sources {
+		filename := fmt.Sprintf("sources%d", i)
+		f, err := parser.ParseFile(fset, filename, src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := check.Files([]*ast.File{f}); err != nil {
+			t.Error(err)
+		}
+	}
+
+	// check InitOrder is [x y]
+	var vars []string
+	for _, init := range info.InitOrder {
+		for _, v := range init.Lhs {
+			vars = append(vars, v.Name())
+		}
+	}
+	if got, want := fmt.Sprint(vars), "[x y]"; got != want {
+		t.Errorf("InitOrder == %s, want %s", got, want)
+	}
+}
+
+type testImporter map[string]*Package
+
+func (m testImporter) Import(path string) (*Package, error) {
+	if pkg := m[path]; pkg != nil {
+		return pkg, nil
+	}
+	return nil, fmt.Errorf("package %q not found", path)
+}
+
+func TestSelection(t *testing.T) {
+	selections := make(map[*ast.SelectorExpr]*Selection)
+
+	fset := token.NewFileSet()
+	imports := make(testImporter)
+	conf := Config{Importer: imports}
+	makePkg := func(path, src string) {
+		f, err := parser.ParseFile(fset, path+".go", src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
+		if err != nil {
+			t.Fatal(err)
+		}
+		imports[path] = pkg
+	}
+
+	const libSrc = `
+package lib
+type T float64
+const C T = 3
+var V T
+func F() {}
+func (T) M() {}
+`
+	const mainSrc = `
+package main
+import "lib"
+
+type A struct {
+	*B
+	C
+}
+
+type B struct {
+	b int
+}
+
+func (B) f(int)
+
+type C struct {
+	c int
+}
+
+func (C) g()
+func (*C) h()
+
+func main() {
+	// qualified identifiers
+	var _ lib.T
+        _ = lib.C
+        _ = lib.F
+        _ = lib.V
+	_ = lib.T.M
+
+	// fields
+	_ = A{}.B
+	_ = new(A).B
+
+	_ = A{}.C
+	_ = new(A).C
+
+	_ = A{}.b
+	_ = new(A).b
+
+	_ = A{}.c
+	_ = new(A).c
+
+	// methods
+        _ = A{}.f
+        _ = new(A).f
+        _ = A{}.g
+        _ = new(A).g
+        _ = new(A).h
+
+        _ = B{}.f
+        _ = new(B).f
+
+        _ = C{}.g
+        _ = new(C).g
+        _ = new(C).h
+
+	// method expressions
+        _ = A.f
+        _ = (*A).f
+        _ = B.f
+        _ = (*B).f
+}`
+
+	wantOut := map[string][2]string{
+		"lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
+
+		"A{}.B":    {"field (main.A) B *main.B", ".[0]"},
+		"new(A).B": {"field (*main.A) B *main.B", "->[0]"},
+		"A{}.C":    {"field (main.A) C main.C", ".[1]"},
+		"new(A).C": {"field (*main.A) C main.C", "->[1]"},
+		"A{}.b":    {"field (main.A) b int", "->[0 0]"},
+		"new(A).b": {"field (*main.A) b int", "->[0 0]"},
+		"A{}.c":    {"field (main.A) c int", ".[1 0]"},
+		"new(A).c": {"field (*main.A) c int", "->[1 0]"},
+
+		"A{}.f":    {"method (main.A) f(int)", "->[0 0]"},
+		"new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
+		"A{}.g":    {"method (main.A) g()", ".[1 0]"},
+		"new(A).g": {"method (*main.A) g()", "->[1 0]"},
+		"new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ?
+		"B{}.f":    {"method (main.B) f(int)", ".[0]"},
+		"new(B).f": {"method (*main.B) f(int)", "->[0]"},
+		"C{}.g":    {"method (main.C) g()", ".[0]"},
+		"new(C).g": {"method (*main.C) g()", "->[0]"},
+		"new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
+
+		"A.f":    {"method expr (main.A) f(main.A, int)", "->[0 0]"},
+		"(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
+		"B.f":    {"method expr (main.B) f(main.B, int)", ".[0]"},
+		"(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+	}
+
+	makePkg("lib", libSrc)
+	makePkg("main", mainSrc)
+
+	for e, sel := range selections {
+		sel.String() // assertion: must not panic
+
+		start := fset.Position(e.Pos()).Offset
+		end := fset.Position(e.End()).Offset
+		syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
+
+		direct := "."
+		if sel.Indirect() {
+			direct = "->"
+		}
+		got := [2]string{
+			sel.String(),
+			fmt.Sprintf("%s%v", direct, sel.Index()),
+		}
+		want := wantOut[syntax]
+		if want != got {
+			t.Errorf("%s: got %q; want %q", syntax, got, want)
+		}
+		delete(wantOut, syntax)
+
+		// We must explicitly assert properties of the
+		// Signature's receiver since it doesn't participate
+		// in Identical() or String().
+		sig, _ := sel.Type().(*Signature)
+		if sel.Kind() == MethodVal {
+			got := sig.Recv().Type()
+			want := sel.Recv()
+			if !Identical(got, want) {
+				t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
+			}
+		} else if sig != nil && sig.Recv() != nil {
+			t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
+		}
+	}
+	// Assert that all wantOut entries were used exactly once.
+	for syntax := range wantOut {
+		t.Errorf("no ast.Selection found with syntax %q", syntax)
+	}
+}
+
+func TestIssue8518(t *testing.T) {
+	fset := token.NewFileSet()
+	imports := make(testImporter)
+	conf := Config{
+		Error:    func(err error) { t.Log(err) }, // don't exit after first error
+		Importer: imports,
+	}
+	makePkg := func(path, src string) {
+		f, err := parser.ParseFile(fset, path, src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
+		imports[path] = pkg
+	}
+
+	const libSrc = `
+package a 
+import "missing"
+const C1 = foo
+const C2 = missing.C
+`
+
+	const mainSrc = `
+package main
+import "a"
+var _ = a.C1
+var _ = a.C2
+`
+
+	makePkg("a", libSrc)
+	makePkg("main", mainSrc) // don't crash when type-checking this package
+}
+
+func TestLookupFieldOrMethod(t *testing.T) {
+	// Test cases assume a lookup of the form a.f or x.f, where a stands for an
+	// addressable value, and x for a non-addressable value (even though a variable
+	// for ease of test case writing).
+	var tests = []struct {
+		src      string
+		found    bool
+		index    []int
+		indirect bool
+	}{
+		// field lookups
+		{"var x T; type T struct{}", false, nil, false},
+		{"var x T; type T struct{ f int }", true, []int{0}, false},
+		{"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
+
+		// method lookups
+		{"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
+		{"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
+		{"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
+		{"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
+
+		// collisions
+		{"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
+		{"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
+
+		// outside methodset
+		// (*T).f method exists, but value of type T is not addressable
+		{"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
+	}
+
+	for _, test := range tests {
+		pkg, err := pkgFor("test", "package p;"+test.src, nil)
+		if err != nil {
+			t.Errorf("%s: incorrect test case: %s", test.src, err)
+			continue
+		}
+
+		obj := pkg.Scope().Lookup("a")
+		if obj == nil {
+			if obj = pkg.Scope().Lookup("x"); obj == nil {
+				t.Errorf("%s: incorrect test case - no object a or x", test.src)
+				continue
+			}
+		}
+
+		f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
+		if (f != nil) != test.found {
+			if f == nil {
+				t.Errorf("%s: got no object; want one", test.src)
+			} else {
+				t.Errorf("%s: got object = %v; want none", test.src, f)
+			}
+		}
+		if !sameSlice(index, test.index) {
+			t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
+		}
+		if indirect != test.indirect {
+			t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
+		}
+	}
+}
+
+func sameSlice(a, b []int) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, x := range a {
+		if x != b[i] {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
new file mode 100644
index 0000000..14ee286
--- /dev/null
+++ b/src/go/types/assignments.go
@@ -0,0 +1,323 @@
+// Copyright 2013 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.
+
+// This file implements initialization and assignment checks.
+
+package types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+// assignment reports whether x can be assigned to a variable of type T,
+// if necessary by attempting to convert untyped values to the appropriate
+// type. If x.mode == invalid upon return, then assignment has already
+// issued an error message and the caller doesn't have to report another.
+// Use T == nil to indicate assignment to an untyped blank identifier.
+//
+// TODO(gri) Should find a better way to handle in-band errors.
+//
+func (check *Checker) assignment(x *operand, T Type) bool {
+	switch x.mode {
+	case invalid:
+		return true // error reported before
+	case constant, variable, mapindex, value, commaok:
+		// ok
+	default:
+		unreachable()
+	}
+
+	// x must be a single value
+	// (tuple types are never named - no need for underlying type)
+	if t, _ := x.typ.(*Tuple); t != nil {
+		assert(t.Len() > 1)
+		check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x)
+		x.mode = invalid
+		return false
+	}
+
+	if isUntyped(x.typ) {
+		target := T
+		// spec: "If an untyped constant is assigned to a variable of interface
+		// type or the blank identifier, the constant is first converted to type
+		// bool, rune, int, float64, complex128 or string respectively, depending
+		// on whether the value is a boolean, rune, integer, floating-point, complex,
+		// or string constant."
+		if T == nil || IsInterface(T) {
+			if T == nil && x.typ == Typ[UntypedNil] {
+				check.errorf(x.pos(), "use of untyped nil")
+				x.mode = invalid
+				return false
+			}
+			target = defaultType(x.typ)
+		}
+		check.convertUntyped(x, target)
+		if x.mode == invalid {
+			return false
+		}
+	}
+
+	// spec: "If a left-hand side is the blank identifier, any typed or
+	// non-constant value except for the predeclared identifier nil may
+	// be assigned to it."
+	return T == nil || x.assignableTo(check.conf, T)
+}
+
+func (check *Checker) initConst(lhs *Const, x *operand) {
+	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+		if lhs.typ == nil {
+			lhs.typ = Typ[Invalid]
+		}
+		return
+	}
+
+	// rhs must be a constant
+	if x.mode != constant {
+		check.errorf(x.pos(), "%s is not constant", x)
+		if lhs.typ == nil {
+			lhs.typ = Typ[Invalid]
+		}
+		return
+	}
+	assert(isConstType(x.typ))
+
+	// If the lhs doesn't have a type yet, use the type of x.
+	if lhs.typ == nil {
+		lhs.typ = x.typ
+	}
+
+	if !check.assignment(x, lhs.typ) {
+		if x.mode != invalid {
+			check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x)
+		}
+		return
+	}
+
+	lhs.val = x.val
+}
+
+// If result is set, lhs is a function result parameter and x is a return result.
+func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
+	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+		if lhs.typ == nil {
+			lhs.typ = Typ[Invalid]
+		}
+		return nil
+	}
+
+	// If the lhs doesn't have a type yet, use the type of x.
+	if lhs.typ == nil {
+		typ := x.typ
+		if isUntyped(typ) {
+			// convert untyped types to default types
+			if typ == Typ[UntypedNil] {
+				check.errorf(x.pos(), "use of untyped nil")
+				lhs.typ = Typ[Invalid]
+				return nil
+			}
+			typ = defaultType(typ)
+		}
+		lhs.typ = typ
+	}
+
+	if !check.assignment(x, lhs.typ) {
+		if x.mode != invalid {
+			if result {
+				// don't refer to lhs.name because it may be an anonymous result parameter
+				check.errorf(x.pos(), "cannot return %s as value of type %s", x, lhs.typ)
+			} else {
+				check.errorf(x.pos(), "cannot initialize %s with %s", lhs, x)
+			}
+		}
+		return nil
+	}
+
+	return x.typ
+}
+
+func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
+	if x.mode == invalid || x.typ == Typ[Invalid] {
+		return nil
+	}
+
+	// Determine if the lhs is a (possibly parenthesized) identifier.
+	ident, _ := unparen(lhs).(*ast.Ident)
+
+	// Don't evaluate lhs if it is the blank identifier.
+	if ident != nil && ident.Name == "_" {
+		check.recordDef(ident, nil)
+		if !check.assignment(x, nil) {
+			assert(x.mode == invalid)
+			x.typ = nil
+		}
+		return x.typ
+	}
+
+	// If the lhs is an identifier denoting a variable v, this assignment
+	// is not a 'use' of v. Remember current value of v.used and restore
+	// after evaluating the lhs via check.expr.
+	var v *Var
+	var v_used bool
+	if ident != nil {
+		if _, obj := check.scope.LookupParent(ident.Name); obj != nil {
+			v, _ = obj.(*Var)
+			if v != nil {
+				v_used = v.used
+			}
+		}
+	}
+
+	var z operand
+	check.expr(&z, lhs)
+	if v != nil {
+		v.used = v_used // restore v.used
+	}
+
+	if z.mode == invalid || z.typ == Typ[Invalid] {
+		return nil
+	}
+
+	// spec: "Each left-hand side operand must be addressable, a map index
+	// expression, or the blank identifier. Operands may be parenthesized."
+	switch z.mode {
+	case invalid:
+		return nil
+	case variable, mapindex:
+		// ok
+	default:
+		check.errorf(z.pos(), "cannot assign to %s", &z)
+		return nil
+	}
+
+	if !check.assignment(x, z.typ) {
+		if x.mode != invalid {
+			check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
+		}
+		return nil
+	}
+
+	return x.typ
+}
+
+// If returnPos is valid, initVars is called to type-check the assignment of
+// return expressions, and returnPos is the position of the return statement.
+func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
+	l := len(lhs)
+	get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
+	if get == nil || l != r {
+		// invalidate lhs and use rhs
+		for _, obj := range lhs {
+			if obj.typ == nil {
+				obj.typ = Typ[Invalid]
+			}
+		}
+		if get == nil {
+			return // error reported by unpack
+		}
+		check.useGetter(get, r)
+		if returnPos.IsValid() {
+			check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
+			return
+		}
+		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+		return
+	}
+
+	var x operand
+	if commaOk {
+		var a [2]Type
+		for i := range a {
+			get(&x, i)
+			a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
+		}
+		check.recordCommaOkTypes(rhs[0], a)
+		return
+	}
+
+	for i, lhs := range lhs {
+		get(&x, i)
+		check.initVar(lhs, &x, returnPos.IsValid())
+	}
+}
+
+func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
+	l := len(lhs)
+	get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2)
+	if get == nil {
+		return // error reported by unpack
+	}
+	if l != r {
+		check.useGetter(get, r)
+		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+		return
+	}
+
+	var x operand
+	if commaOk {
+		var a [2]Type
+		for i := range a {
+			get(&x, i)
+			a[i] = check.assignVar(lhs[i], &x)
+		}
+		check.recordCommaOkTypes(rhs[0], a)
+		return
+	}
+
+	for i, lhs := range lhs {
+		get(&x, i)
+		check.assignVar(lhs, &x)
+	}
+}
+
+func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
+	scope := check.scope
+
+	// collect lhs variables
+	var newVars []*Var
+	var lhsVars = make([]*Var, len(lhs))
+	for i, lhs := range lhs {
+		var obj *Var
+		if ident, _ := lhs.(*ast.Ident); ident != nil {
+			// Use the correct obj if the ident is redeclared. The
+			// variable's scope starts after the declaration; so we
+			// must use Scope.Lookup here and call Scope.Insert
+			// (via check.declare) later.
+			name := ident.Name
+			if alt := scope.Lookup(name); alt != nil {
+				// redeclared object must be a variable
+				if alt, _ := alt.(*Var); alt != nil {
+					obj = alt
+				} else {
+					check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
+				}
+				check.recordUse(ident, alt)
+			} else {
+				// declare new variable, possibly a blank (_) variable
+				obj = NewVar(ident.Pos(), check.pkg, name, nil)
+				if name != "_" {
+					newVars = append(newVars, obj)
+				}
+				check.recordDef(ident, obj)
+			}
+		} else {
+			check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+		}
+		if obj == nil {
+			obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+		}
+		lhsVars[i] = obj
+	}
+
+	check.initVars(lhsVars, rhs, token.NoPos)
+
+	// declare new variables
+	if len(newVars) > 0 {
+		for _, obj := range newVars {
+			check.declare(scope, nil, obj) // recordObject already called
+		}
+	} else {
+		check.softErrorf(pos, "no new variables on left side of :=")
+	}
+}
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
new file mode 100644
index 0000000..203a9c1
--- /dev/null
+++ b/src/go/types/builtins.go
@@ -0,0 +1,627 @@
+// Copyright 2012 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.
+
+// This file implements typechecking of builtin function calls.
+
+package types
+
+import (
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+// builtin type-checks a call to the built-in specified by id and
+// returns true if the call is valid, with *x holding the result;
+// but x.expr is not set. If the call is invalid, the result is
+// false, and *x is undefined.
+//
+func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
+	// append is the only built-in that permits the use of ... for the last argument
+	bin := predeclaredFuncs[id]
+	if call.Ellipsis.IsValid() && id != _Append {
+		check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name)
+		check.use(call.Args...)
+		return
+	}
+
+	// For len(x) and cap(x) we need to know if x contains any function calls or
+	// receive operations. Save/restore current setting and set hasCallOrRecv to
+	// false for the evaluation of x so that we can check it afterwards.
+	// Note: We must do this _before_ calling unpack because unpack evaluates the
+	//       first argument before we even call arg(x, 0)!
+	if id == _Len || id == _Cap {
+		defer func(b bool) {
+			check.hasCallOrRecv = b
+		}(check.hasCallOrRecv)
+		check.hasCallOrRecv = false
+	}
+
+	// determine actual arguments
+	var arg getter
+	nargs := len(call.Args)
+	switch id {
+	default:
+		// make argument getter
+		arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+		if arg == nil {
+			return
+		}
+		// evaluate first argument, if present
+		if nargs > 0 {
+			arg(x, 0)
+			if x.mode == invalid {
+				return
+			}
+		}
+	case _Make, _New, _Offsetof, _Trace:
+		// arguments require special handling
+	}
+
+	// check argument count
+	{
+		msg := ""
+		if nargs < bin.nargs {
+			msg = "not enough"
+		} else if !bin.variadic && nargs > bin.nargs {
+			msg = "too many"
+		}
+		if msg != "" {
+			check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+			return
+		}
+	}
+
+	switch id {
+	case _Append:
+		// append(s S, x ...T) S, where T is the element type of S
+		// spec: "The variadic function append appends zero or more values x to s of type
+		// S, which must be a slice type, and returns the resulting slice, also of type S.
+		// The values x are passed to a parameter of type ...T where T is the element type
+		// of S and the respective parameter passing rules apply."
+		S := x.typ
+		var T Type
+		if s, _ := S.Underlying().(*Slice); s != nil {
+			T = s.elem
+		} else {
+			check.invalidArg(x.pos(), "%s is not a slice", x)
+			return
+		}
+
+		// remember arguments that have been evaluated already
+		alist := []operand{*x}
+
+		// spec: "As a special case, append also accepts a first argument assignable
+		// to type []byte with a second argument of string type followed by ... .
+		// This form appends the bytes of the string.
+		if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(UniverseByte)) {
+			arg(x, 1)
+			if x.mode == invalid {
+				return
+			}
+			if isString(x.typ) {
+				if check.Types != nil {
+					sig := makeSig(S, S, x.typ)
+					sig.variadic = true
+					check.recordBuiltinType(call.Fun, sig)
+				}
+				x.mode = value
+				x.typ = S
+				break
+			}
+			alist = append(alist, *x)
+			// fallthrough
+		}
+
+		// check general case by creating custom signature
+		sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
+		sig.variadic = true
+		check.arguments(x, call, sig, func(x *operand, i int) {
+			// only evaluate arguments that have not been evaluated before
+			if i < len(alist) {
+				*x = alist[i]
+				return
+			}
+			arg(x, i)
+		}, nargs)
+		// ok to continue even if check.arguments reported errors
+
+		x.mode = value
+		x.typ = S
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, sig)
+		}
+
+	case _Cap, _Len:
+		// cap(x)
+		// len(x)
+		mode := invalid
+		var typ Type
+		var val exact.Value
+		switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
+		case *Basic:
+			if isString(t) && id == _Len {
+				if x.mode == constant {
+					mode = constant
+					val = exact.MakeInt64(int64(len(exact.StringVal(x.val))))
+				} else {
+					mode = value
+				}
+			}
+
+		case *Array:
+			mode = value
+			// spec: "The expressions len(s) and cap(s) are constants
+			// if the type of s is an array or pointer to an array and
+			// the expression s does not contain channel receives or
+			// function calls; in this case s is not evaluated."
+			if !check.hasCallOrRecv {
+				mode = constant
+				val = exact.MakeInt64(t.len)
+			}
+
+		case *Slice, *Chan:
+			mode = value
+
+		case *Map:
+			if id == _Len {
+				mode = value
+			}
+		}
+
+		if mode == invalid {
+			check.invalidArg(x.pos(), "%s for %s", x, bin.name)
+			return
+		}
+
+		x.mode = mode
+		x.typ = Typ[Int]
+		x.val = val
+		if check.Types != nil && mode != constant {
+			check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
+		}
+
+	case _Close:
+		// close(c)
+		c, _ := x.typ.Underlying().(*Chan)
+		if c == nil {
+			check.invalidArg(x.pos(), "%s is not a channel", x)
+			return
+		}
+		if c.dir == RecvOnly {
+			check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
+			return
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, c))
+		}
+
+	case _Complex:
+		// complex(x, y realT) complexT
+		if !check.complexArg(x) {
+			return
+		}
+
+		var y operand
+		arg(&y, 1)
+		if y.mode == invalid {
+			return
+		}
+		if !check.complexArg(&y) {
+			return
+		}
+
+		check.convertUntyped(x, y.typ)
+		if x.mode == invalid {
+			return
+		}
+		check.convertUntyped(&y, x.typ)
+		if y.mode == invalid {
+			return
+		}
+
+		if !Identical(x.typ, y.typ) {
+			check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+			return
+		}
+
+		if x.mode == constant && y.mode == constant {
+			x.val = exact.BinaryOp(x.val, token.ADD, exact.MakeImag(y.val))
+		} else {
+			x.mode = value
+		}
+
+		realT := x.typ
+		complexT := Typ[Invalid]
+		switch realT.Underlying().(*Basic).kind {
+		case Float32:
+			complexT = Typ[Complex64]
+		case Float64:
+			complexT = Typ[Complex128]
+		case UntypedInt, UntypedRune, UntypedFloat:
+			if x.mode == constant {
+				realT = defaultType(realT).(*Basic)
+				complexT = Typ[UntypedComplex]
+			} else {
+				// untyped but not constant; probably because one
+				// operand is a non-constant shift of untyped lhs
+				realT = Typ[Float64]
+				complexT = Typ[Complex128]
+			}
+		default:
+			check.invalidArg(x.pos(), "float32 or float64 arguments expected")
+			return
+		}
+
+		x.typ = complexT
+		if check.Types != nil && x.mode != constant {
+			check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT))
+		}
+
+		if x.mode != constant {
+			// The arguments have now their final types, which at run-
+			// time will be materialized. Update the expression trees.
+			// If the current types are untyped, the materialized type
+			// is the respective default type.
+			// (If the result is constant, the arguments are never
+			// materialized and there is nothing to do.)
+			check.updateExprType(x.expr, realT, true)
+			check.updateExprType(y.expr, realT, true)
+		}
+
+	case _Copy:
+		// copy(x, y []T) int
+		var dst Type
+		if t, _ := x.typ.Underlying().(*Slice); t != nil {
+			dst = t.elem
+		}
+
+		var y operand
+		arg(&y, 1)
+		if y.mode == invalid {
+			return
+		}
+		var src Type
+		switch t := y.typ.Underlying().(type) {
+		case *Basic:
+			if isString(y.typ) {
+				src = UniverseByte
+			}
+		case *Slice:
+			src = t.elem
+		}
+
+		if dst == nil || src == nil {
+			check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
+			return
+		}
+
+		if !Identical(dst, src) {
+			check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+			return
+		}
+
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
+		}
+		x.mode = value
+		x.typ = Typ[Int]
+
+	case _Delete:
+		// delete(m, k)
+		m, _ := x.typ.Underlying().(*Map)
+		if m == nil {
+			check.invalidArg(x.pos(), "%s is not a map", x)
+			return
+		}
+		arg(x, 1) // k
+		if x.mode == invalid {
+			return
+		}
+
+		if !x.assignableTo(check.conf, m.key) {
+			check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
+			return
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key))
+		}
+
+	case _Imag, _Real:
+		// imag(complexT) realT
+		// real(complexT) realT
+		if !isComplex(x.typ) {
+			check.invalidArg(x.pos(), "%s must be a complex number", x)
+			return
+		}
+		if x.mode == constant {
+			if id == _Real {
+				x.val = exact.Real(x.val)
+			} else {
+				x.val = exact.Imag(x.val)
+			}
+		} else {
+			x.mode = value
+		}
+		var k BasicKind
+		switch x.typ.Underlying().(*Basic).kind {
+		case Complex64:
+			k = Float32
+		case Complex128:
+			k = Float64
+		case UntypedComplex:
+			k = UntypedFloat
+		default:
+			unreachable()
+		}
+
+		if check.Types != nil && x.mode != constant {
+			check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ))
+		}
+		x.typ = Typ[k]
+
+	case _Make:
+		// make(T, n)
+		// make(T, n, m)
+		// (no argument evaluated yet)
+		arg0 := call.Args[0]
+		T := check.typ(arg0)
+		if T == Typ[Invalid] {
+			return
+		}
+
+		var min int // minimum number of arguments
+		switch T.Underlying().(type) {
+		case *Slice:
+			min = 2
+		case *Map, *Chan:
+			min = 1
+		default:
+			check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
+			return
+		}
+		if nargs < min || min+1 < nargs {
+			check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
+			return
+		}
+		var sizes []int64 // constant integer arguments, if any
+		for _, arg := range call.Args[1:] {
+			if s, ok := check.index(arg, -1); ok && s >= 0 {
+				sizes = append(sizes, s)
+			}
+		}
+		if len(sizes) == 2 && sizes[0] > sizes[1] {
+			check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
+			// safe to continue
+		}
+		x.mode = value
+		x.typ = T
+		if check.Types != nil {
+			params := [...]Type{T, Typ[Int], Typ[Int]}
+			check.recordBuiltinType(call.Fun, makeSig(x.typ, params[:1+len(sizes)]...))
+		}
+
+	case _New:
+		// new(T)
+		// (no argument evaluated yet)
+		T := check.typ(call.Args[0])
+		if T == Typ[Invalid] {
+			return
+		}
+
+		x.mode = value
+		x.typ = &Pointer{base: T}
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
+		}
+
+	case _Panic:
+		// panic(x)
+		T := new(Interface)
+		if !check.assignment(x, T) {
+			assert(x.mode == invalid)
+			return
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, T))
+		}
+
+	case _Print, _Println:
+		// print(x, y, ...)
+		// println(x, y, ...)
+		var params []Type
+		if nargs > 0 {
+			params = make([]Type, nargs)
+			for i := 0; i < nargs; i++ {
+				if i > 0 {
+					arg(x, i) // first argument already evaluated
+				}
+				if !check.assignment(x, nil) {
+					assert(x.mode == invalid)
+					return
+				}
+				params[i] = x.typ
+			}
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, params...))
+		}
+
+	case _Recover:
+		// recover() interface{}
+		x.mode = value
+		x.typ = new(Interface)
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(x.typ))
+		}
+
+	case _Alignof:
+		// unsafe.Alignof(x T) uintptr
+		if !check.assignment(x, nil) {
+			assert(x.mode == invalid)
+			return
+		}
+
+		x.mode = constant
+		x.val = exact.MakeInt64(check.conf.alignof(x.typ))
+		x.typ = Typ[Uintptr]
+		// result is constant - no need to record signature
+
+	case _Offsetof:
+		// unsafe.Offsetof(x T) uintptr, where x must be a selector
+		// (no argument evaluated yet)
+		arg0 := call.Args[0]
+		selx, _ := unparen(arg0).(*ast.SelectorExpr)
+		if selx == nil {
+			check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
+			check.use(arg0)
+			return
+		}
+
+		check.expr(x, selx.X)
+		if x.mode == invalid {
+			return
+		}
+
+		base := derefStructPtr(x.typ)
+		sel := selx.Sel.Name
+		obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
+		switch obj.(type) {
+		case nil:
+			check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
+			return
+		case *Func:
+			// TODO(gri) Using derefStructPtr may result in methods being found
+			// that don't actually exist. An error either way, but the error
+			// message is confusing. See: http://play.golang.org/p/al75v23kUy ,
+			// but go/types reports: "invalid argument: x.m is a method value".
+			check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
+			return
+		}
+		if indirect {
+			check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
+			return
+		}
+
+		// TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
+		check.recordSelection(selx, FieldVal, base, obj, index, false)
+
+		offs := check.conf.offsetof(base, index)
+		x.mode = constant
+		x.val = exact.MakeInt64(offs)
+		x.typ = Typ[Uintptr]
+		// result is constant - no need to record signature
+
+	case _Sizeof:
+		// unsafe.Sizeof(x T) uintptr
+		if !check.assignment(x, nil) {
+			assert(x.mode == invalid)
+			return
+		}
+
+		x.mode = constant
+		x.val = exact.MakeInt64(check.conf.sizeof(x.typ))
+		x.typ = Typ[Uintptr]
+		// result is constant - no need to record signature
+
+	case _Assert:
+		// assert(pred) causes a typechecker error if pred is false.
+		// The result of assert is the value of pred if there is no error.
+		// Note: assert is only available in self-test mode.
+		if x.mode != constant || !isBoolean(x.typ) {
+			check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+			return
+		}
+		if x.val.Kind() != exact.Bool {
+			check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+			return
+		}
+		if !exact.BoolVal(x.val) {
+			check.errorf(call.Pos(), "%s failed", call)
+			// compile-time assertion failure - safe to continue
+		}
+		// result is constant - no need to record signature
+
+	case _Trace:
+		// trace(x, y, z, ...) dumps the positions, expressions, and
+		// values of its arguments. The result of trace is the value
+		// of the first argument.
+		// Note: trace is only available in self-test mode.
+		// (no argument evaluated yet)
+		if nargs == 0 {
+			check.dump("%s: trace() without arguments", call.Pos())
+			x.mode = novalue
+			break
+		}
+		var t operand
+		x1 := x
+		for _, arg := range call.Args {
+			check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+			check.dump("%s: %s", x1.pos(), x1)
+			x1 = &t // use incoming x only for first argument
+		}
+		// trace is only available in test mode - no need to record signature
+
+	default:
+		unreachable()
+	}
+
+	return true
+}
+
+// makeSig makes a signature for the given argument and result types.
+// Default types are used for untyped arguments, and res may be nil.
+func makeSig(res Type, args ...Type) *Signature {
+	list := make([]*Var, len(args))
+	for i, param := range args {
+		list[i] = NewVar(token.NoPos, nil, "", defaultType(param))
+	}
+	params := NewTuple(list...)
+	var result *Tuple
+	if res != nil {
+		assert(!isUntyped(res))
+		result = NewTuple(NewVar(token.NoPos, nil, "", res))
+	}
+	return &Signature{params: params, results: result}
+}
+
+// implicitArrayDeref returns A if typ is of the form *A and A is an array;
+// otherwise it returns typ.
+//
+func implicitArrayDeref(typ Type) Type {
+	if p, ok := typ.(*Pointer); ok {
+		if a, ok := p.base.Underlying().(*Array); ok {
+			return a
+		}
+	}
+	return typ
+}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+	for {
+		p, ok := e.(*ast.ParenExpr)
+		if !ok {
+			return e
+		}
+		e = p.X
+	}
+}
+
+func (check *Checker) complexArg(x *operand) bool {
+	t, _ := x.typ.Underlying().(*Basic)
+	if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) {
+		return true
+	}
+	check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
+	return false
+}
diff --git a/src/go/types/builtins_test.go b/src/go/types/builtins_test.go
new file mode 100644
index 0000000..9835a48
--- /dev/null
+++ b/src/go/types/builtins_test.go
@@ -0,0 +1,204 @@
+// Copyright 2013 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 types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"testing"
+
+	. "go/types"
+)
+
+var builtinCalls = []struct {
+	name, src, sig string
+}{
+	{"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
+	{"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
+	{"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
+	{"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
+	{"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
+	{"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
+	{"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
+
+	{"cap", `var s [10]int; _ = cap(s)`, `invalid type`},  // constant
+	{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
+	{"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
+	{"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
+
+	{"len", `_ = len("foo")`, `invalid type`}, // constant
+	{"len", `var s string; _ = len(s)`, `func(string) int`},
+	{"len", `var s [10]int; _ = len(s)`, `invalid type`},  // constant
+	{"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
+	{"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
+	{"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
+	{"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
+
+	{"close", `var c chan int; close(c)`, `func(chan int)`},
+	{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
+
+	{"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
+	{"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
+	{"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
+	{"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
+	{"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
+
+	{"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
+	{"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
+	{"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
+	{"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
+	{"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
+
+	{"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
+	{"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
+
+	{"imag", `_ = imag(1i)`, `invalid type`}, // constant
+	{"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
+	{"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
+	{"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
+	{"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
+
+	{"real", `_ = real(1i)`, `invalid type`}, // constant
+	{"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
+	{"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
+	{"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
+	{"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
+
+	{"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
+	{"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
+
+	{"new", `_ = new(int)`, `func(int) *int`},
+	{"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
+
+	{"panic", `panic(0)`, `func(interface{})`},
+	{"panic", `panic("foo")`, `func(interface{})`},
+
+	{"print", `print()`, `func()`},
+	{"print", `print(0)`, `func(int)`},
+	{"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+	{"println", `println()`, `func()`},
+	{"println", `println(0)`, `func(int)`},
+	{"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+	{"recover", `recover()`, `func() interface{}`},
+	{"recover", `_ = recover()`, `func() interface{}`},
+
+	{"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
+	{"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
+
+	{"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
+	{"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
+
+	{"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
+	{"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
+
+	{"assert", `assert(true)`, `invalid type`},                                    // constant
+	{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
+
+	// no tests for trace since it produces output as a side-effect
+}
+
+func TestBuiltinSignatures(t *testing.T) {
+	DefPredeclaredTestFuncs()
+
+	seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
+	for _, call := range builtinCalls {
+		testBuiltinSignature(t, call.name, call.src, call.sig)
+		seen[call.name] = true
+	}
+
+	// make sure we didn't miss one
+	for _, name := range Universe.Names() {
+		if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
+			t.Errorf("missing test for %s", name)
+		}
+	}
+	for _, name := range Unsafe.Scope().Names() {
+		if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
+			t.Errorf("missing test for unsafe.%s", name)
+		}
+	}
+}
+
+func testBuiltinSignature(t *testing.T, name, src0, want string) {
+	src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Errorf("%s: %s", src0, err)
+		return
+	}
+
+	conf := Config{Importer: importer.Default()}
+	uses := make(map[*ast.Ident]Object)
+	types := make(map[ast.Expr]TypeAndValue)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types})
+	if err != nil {
+		t.Errorf("%s: %s", src0, err)
+		return
+	}
+
+	// find called function
+	n := 0
+	var fun ast.Expr
+	for x := range types {
+		if call, _ := x.(*ast.CallExpr); call != nil {
+			fun = call.Fun
+			n++
+		}
+	}
+	if n != 1 {
+		t.Errorf("%s: got %d CallExprs; want 1", src0, n)
+		return
+	}
+
+	// check recorded types for fun and descendents (may be parenthesized)
+	for {
+		// the recorded type for the built-in must match the wanted signature
+		typ := types[fun].Type
+		if typ == nil {
+			t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
+			return
+		}
+		if got := typ.String(); got != want {
+			t.Errorf("%s: got type %s; want %s", src0, got, want)
+			return
+		}
+
+		// called function must be a (possibly parenthesized, qualified)
+		// identifier denoting the expected built-in
+		switch p := fun.(type) {
+		case *ast.Ident:
+			obj := uses[p]
+			if obj == nil {
+				t.Errorf("%s: no object found for %s", src0, p)
+				return
+			}
+			bin, _ := obj.(*Builtin)
+			if bin == nil {
+				t.Errorf("%s: %s does not denote a built-in", src0, p)
+				return
+			}
+			if bin.Name() != name {
+				t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
+				return
+			}
+			return // we're done
+
+		case *ast.ParenExpr:
+			fun = p.X // unpack
+
+		case *ast.SelectorExpr:
+			// built-in from package unsafe - ignore details
+			return // we're done
+
+		default:
+			t.Errorf("%s: invalid function call", src0)
+			return
+		}
+	}
+}
diff --git a/src/go/types/call.go b/src/go/types/call.go
new file mode 100644
index 0000000..7f366a8
--- /dev/null
+++ b/src/go/types/call.go
@@ -0,0 +1,441 @@
+// Copyright 2013 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.
+
+// This file implements typechecking of call and selector expressions.
+
+package types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
+	check.exprOrType(x, e.Fun)
+
+	switch x.mode {
+	case invalid:
+		check.use(e.Args...)
+		x.mode = invalid
+		x.expr = e
+		return statement
+
+	case typexpr:
+		// conversion
+		T := x.typ
+		x.mode = invalid
+		switch n := len(e.Args); n {
+		case 0:
+			check.errorf(e.Rparen, "missing argument in conversion to %s", T)
+		case 1:
+			check.expr(x, e.Args[0])
+			if x.mode != invalid {
+				check.conversion(x, T)
+			}
+		default:
+			check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
+		}
+		x.expr = e
+		return conversion
+
+	case builtin:
+		id := x.id
+		if !check.builtin(x, e, id) {
+			x.mode = invalid
+		}
+		x.expr = e
+		// a non-constant result implies a function call
+		if x.mode != invalid && x.mode != constant {
+			check.hasCallOrRecv = true
+		}
+		return predeclaredFuncs[id].kind
+
+	default:
+		// function/method call
+		sig, _ := x.typ.Underlying().(*Signature)
+		if sig == nil {
+			check.invalidOp(x.pos(), "cannot call non-function %s", x)
+			x.mode = invalid
+			x.expr = e
+			return statement
+		}
+
+		arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
+		if arg == nil {
+			x.mode = invalid
+			x.expr = e
+			return statement
+		}
+
+		check.arguments(x, e, sig, arg, n)
+
+		// determine result
+		switch sig.results.Len() {
+		case 0:
+			x.mode = novalue
+		case 1:
+			x.mode = value
+			x.typ = sig.results.vars[0].typ // unpack tuple
+		default:
+			x.mode = value
+			x.typ = sig.results
+		}
+		x.expr = e
+		check.hasCallOrRecv = true
+
+		return statement
+	}
+}
+
+// use type-checks each argument.
+// Useful to make sure expressions are evaluated
+// (and variables are "used") in the presence of other errors.
+func (check *Checker) use(arg ...ast.Expr) {
+	var x operand
+	for _, e := range arg {
+		check.rawExpr(&x, e, nil)
+	}
+}
+
+// useGetter is like use, but takes a getter instead of a list of expressions.
+// It should be called instead of use if a getter is present to avoid repeated
+// evaluation of the first argument (since the getter was likely obtained via
+// unpack, which may have evaluated the first argument already).
+func (check *Checker) useGetter(get getter, n int) {
+	var x operand
+	for i := 0; i < n; i++ {
+		get(&x, i)
+	}
+}
+
+// A getter sets x as the i'th operand, where 0 <= i < n and n is the total
+// number of operands (context-specific, and maintained elsewhere). A getter
+// type-checks the i'th operand; the details of the actual check are getter-
+// specific.
+type getter func(x *operand, i int)
+
+// unpack takes a getter get and a number of operands n. If n == 1, unpack
+// calls the incoming getter for the first operand. If that operand is
+// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
+// function call, or a comma-ok expression and allowCommaOk is set, the result
+// is a new getter and operand count providing access to the function results,
+// or comma-ok values, respectively. The third result value reports if it
+// is indeed the comma-ok case. In all other cases, the incoming getter and
+// operand count are returned unchanged, and the third result value is false.
+//
+// In other words, if there's exactly one operand that - after type-checking
+// by calling get - stands for multiple operands, the resulting getter provides
+// access to those operands instead.
+//
+// If the returned getter is called at most once for a given operand index i
+// (including i == 0), that operand is guaranteed to cause only one call of
+// the incoming getter with that i.
+//
+func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
+	if n == 1 {
+		// possibly result of an n-valued function call or comma,ok value
+		var x0 operand
+		get(&x0, 0)
+		if x0.mode == invalid {
+			return nil, 0, false
+		}
+
+		if t, ok := x0.typ.(*Tuple); ok {
+			// result of an n-valued function call
+			return func(x *operand, i int) {
+				x.mode = value
+				x.expr = x0.expr
+				x.typ = t.At(i).typ
+			}, t.Len(), false
+		}
+
+		if x0.mode == mapindex || x0.mode == commaok {
+			// comma-ok value
+			if allowCommaOk {
+				a := [2]Type{x0.typ, Typ[UntypedBool]}
+				return func(x *operand, i int) {
+					x.mode = value
+					x.expr = x0.expr
+					x.typ = a[i]
+				}, 2, true
+			}
+			x0.mode = value
+		}
+
+		// single value
+		return func(x *operand, i int) {
+			if i != 0 {
+				unreachable()
+			}
+			*x = x0
+		}, 1, false
+	}
+
+	// zero or multiple values
+	return get, n, false
+}
+
+// arguments checks argument passing for the call with the given signature.
+// The arg function provides the operand for the i'th argument.
+func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
+	if call.Ellipsis.IsValid() {
+		// last argument is of the form x...
+		if len(call.Args) == 1 && n > 1 {
+			// f()... is not permitted if f() is multi-valued
+			check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
+			check.useGetter(arg, n)
+			return
+		}
+		if !sig.variadic {
+			check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+			check.useGetter(arg, n)
+			return
+		}
+	}
+
+	// evaluate arguments
+	for i := 0; i < n; i++ {
+		arg(x, i)
+		if x.mode != invalid {
+			var ellipsis token.Pos
+			if i == n-1 && call.Ellipsis.IsValid() {
+				ellipsis = call.Ellipsis
+			}
+			check.argument(sig, i, x, ellipsis)
+		}
+	}
+
+	// check argument count
+	if sig.variadic {
+		// a variadic function accepts an "empty"
+		// last argument: count one extra
+		n++
+	}
+	if n < sig.params.Len() {
+		check.errorf(call.Rparen, "too few arguments in call to %s", call.Fun)
+		// ok to continue
+	}
+}
+
+// argument checks passing of argument x to the i'th parameter of the given signature.
+// If ellipsis is valid, the argument is followed by ... at that position in the call.
+func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
+	n := sig.params.Len()
+
+	// determine parameter type
+	var typ Type
+	switch {
+	case i < n:
+		typ = sig.params.vars[i].typ
+	case sig.variadic:
+		typ = sig.params.vars[n-1].typ
+		if debug {
+			if _, ok := typ.(*Slice); !ok {
+				check.dump("%s: expected unnamed slice type, got %s", sig.params.vars[n-1].Pos(), typ)
+			}
+		}
+	default:
+		check.errorf(x.pos(), "too many arguments")
+		return
+	}
+
+	if ellipsis.IsValid() {
+		// argument is of the form x...
+		if i != n-1 {
+			check.errorf(ellipsis, "can only use ... with matching parameter")
+			return
+		}
+		switch t := x.typ.Underlying().(type) {
+		case *Slice:
+			// ok
+		case *Tuple:
+			check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x)
+			return
+		default:
+			check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
+			return
+		}
+	} else if sig.variadic && i >= n-1 {
+		// use the variadic parameter slice's element type
+		typ = typ.(*Slice).elem
+	}
+
+	if !check.assignment(x, typ) && x.mode != invalid {
+		check.errorf(x.pos(), "cannot pass argument %s to parameter of type %s", x, typ)
+	}
+}
+
+func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
+	// these must be declared before the "goto Error" statements
+	var (
+		obj      Object
+		index    []int
+		indirect bool
+	)
+
+	sel := e.Sel.Name
+	// If the identifier refers to a package, handle everything here
+	// so we don't need a "package" mode for operands: package names
+	// can only appear in qualified identifiers which are mapped to
+	// selector expressions.
+	if ident, ok := e.X.(*ast.Ident); ok {
+		_, obj := check.scope.LookupParent(ident.Name)
+		if pkg, _ := obj.(*PkgName); pkg != nil {
+			assert(pkg.pkg == check.pkg)
+			check.recordUse(ident, pkg)
+			pkg.used = true
+			exp := pkg.imported.scope.Lookup(sel)
+			if exp == nil {
+				if !pkg.imported.fake {
+					check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
+				}
+				goto Error
+			}
+			if !exp.Exported() {
+				check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
+				// ok to continue
+			}
+			check.recordUse(e.Sel, exp)
+			// Simplified version of the code for *ast.Idents:
+			// - imported objects are always fully initialized
+			switch exp := exp.(type) {
+			case *Const:
+				assert(exp.Val() != nil)
+				x.mode = constant
+				x.typ = exp.typ
+				x.val = exp.val
+			case *TypeName:
+				x.mode = typexpr
+				x.typ = exp.typ
+			case *Var:
+				x.mode = variable
+				x.typ = exp.typ
+			case *Func:
+				x.mode = value
+				x.typ = exp.typ
+			case *Builtin:
+				x.mode = builtin
+				x.typ = exp.typ
+				x.id = exp.id
+			default:
+				unreachable()
+			}
+			x.expr = e
+			return
+		}
+	}
+
+	check.exprOrType(x, e.X)
+	if x.mode == invalid {
+		goto Error
+	}
+
+	obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+	if obj == nil {
+		switch {
+		case index != nil:
+			// TODO(gri) should provide actual type where the conflict happens
+			check.invalidOp(e.Pos(), "ambiguous selector %s", sel)
+		case indirect:
+			check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x.typ)
+		default:
+			check.invalidOp(e.Pos(), "%s has no field or method %s", x, sel)
+		}
+		goto Error
+	}
+
+	if x.mode == typexpr {
+		// method expression
+		m, _ := obj.(*Func)
+		if m == nil {
+			check.invalidOp(e.Pos(), "%s has no method %s", x, sel)
+			goto Error
+		}
+
+		check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
+
+		// the receiver type becomes the type of the first function
+		// argument of the method expression's function type
+		var params []*Var
+		sig := m.typ.(*Signature)
+		if sig.params != nil {
+			params = sig.params.vars
+		}
+		x.mode = value
+		x.typ = &Signature{
+			params:   NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...),
+			results:  sig.results,
+			variadic: sig.variadic,
+		}
+
+		check.addDeclDep(m)
+
+	} else {
+		// regular selector
+		switch obj := obj.(type) {
+		case *Var:
+			check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+			if x.mode == variable || indirect {
+				x.mode = variable
+			} else {
+				x.mode = value
+			}
+			x.typ = obj.typ
+
+		case *Func:
+			// TODO(gri) If we needed to take into account the receiver's
+			// addressability, should we report the type &(x.typ) instead?
+			check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
+
+			if debug {
+				// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
+				typ := x.typ
+				if x.mode == variable {
+					// If typ is not an (unnamed) pointer or an interface,
+					// use *typ instead, because the method set of *typ
+					// includes the methods of typ.
+					// Variables are addressable, so we can always take their
+					// address.
+					if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {
+						typ = &Pointer{base: typ}
+					}
+				}
+				// If we created a synthetic pointer type above, we will throw
+				// away the method set computed here after use.
+				// TODO(gri) Method set computation should probably always compute
+				// both, the value and the pointer receiver method set and represent
+				// them in a single structure.
+				// TODO(gri) Consider also using a method set cache for the lifetime
+				// of checker once we rely on MethodSet lookup instead of individual
+				// lookup.
+				mset := NewMethodSet(typ)
+				if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
+					check.dump("%s: (%s).%v -> %s", e.Pos(), typ, obj.name, m)
+					check.dump("%s\n", mset)
+					panic("method sets and lookup don't agree")
+				}
+			}
+
+			x.mode = value
+
+			// remove receiver
+			sig := *obj.typ.(*Signature)
+			sig.recv = nil
+			x.typ = &sig
+
+			check.addDeclDep(obj)
+
+		default:
+			unreachable()
+		}
+	}
+
+	// everything went well
+	x.expr = e
+	return
+
+Error:
+	x.mode = invalid
+	x.expr = e
+}
diff --git a/src/go/types/check.go b/src/go/types/check.go
new file mode 100644
index 0000000..b4c356a
--- /dev/null
+++ b/src/go/types/check.go
@@ -0,0 +1,357 @@
+// Copyright 2011 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.
+
+// This file implements the Check function, which drives type-checking.
+
+package types
+
+import (
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+// debugging/development support
+const (
+	debug = false // leave on during development
+	trace = false // turn on for detailed type resolution traces
+)
+
+// If Strict is set, the type-checker enforces additional
+// rules not specified by the Go 1 spec, but which will
+// catch guaranteed run-time errors if the respective
+// code is executed. In other words, programs passing in
+// Strict mode are Go 1 compliant, but not all Go 1 programs
+// will pass in Strict mode. The additional rules are:
+//
+// - A type assertion x.(T) where T is an interface type
+//   is invalid if any (statically known) method that exists
+//   for both x and T have different signatures.
+//
+const strict = false
+
+// exprInfo stores information about an untyped expression.
+type exprInfo struct {
+	isLhs bool // expression is lhs operand of a shift with delayed type-check
+	mode  operandMode
+	typ   *Basic
+	val   exact.Value // constant value; or nil (if not a constant)
+}
+
+// funcInfo stores the information required for type-checking a function.
+type funcInfo struct {
+	name string    // for debugging/tracing only
+	decl *declInfo // for cycle detection
+	sig  *Signature
+	body *ast.BlockStmt
+}
+
+// A context represents the context within which an object is type-checked.
+type context struct {
+	decl          *declInfo   // package-level declaration whose init expression/function body is checked
+	scope         *Scope      // top-most scope for lookups
+	iota          exact.Value // value of iota in a constant declaration; nil otherwise
+	sig           *Signature  // function signature if inside a function; nil otherwise
+	hasLabel      bool        // set if a function makes use of labels (only ~1% of functions); unused outside functions
+	hasCallOrRecv bool        // set if an expression contains a function call or channel receive operation
+}
+
+// A Checker maintains the state of the type checker.
+// It must be created with NewChecker.
+type Checker struct {
+	// package information
+	// (initialized by NewChecker, valid for the life-time of checker)
+	conf *Config
+	fset *token.FileSet
+	pkg  *Package
+	*Info
+	objMap map[Object]*declInfo // maps package-level object to declaration info
+
+	// information collected during type-checking of a set of package files
+	// (initialized by Files, valid only for the duration of check.Files;
+	// maps and lists are allocated on demand)
+	files            []*ast.File                       // package files
+	unusedDotImports map[*Scope]map[*Package]token.Pos // positions of unused dot-imported packages for each file scope
+
+	firstErr error                 // first error encountered
+	methods  map[string][]*Func    // maps type names to associated methods
+	untyped  map[ast.Expr]exprInfo // map of expressions without final type
+	funcs    []funcInfo            // list of functions to type-check
+	delayed  []func()              // delayed checks requiring fully setup types
+
+	// context within which the current object is type-checked
+	// (valid only for the duration of type-checking a specific object)
+	context
+
+	// debugging
+	indent int // indentation for tracing
+}
+
+// addUnusedImport adds the position of a dot-imported package
+// pkg to the map of dot imports for the given file scope.
+func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) {
+	mm := check.unusedDotImports
+	if mm == nil {
+		mm = make(map[*Scope]map[*Package]token.Pos)
+		check.unusedDotImports = mm
+	}
+	m := mm[scope]
+	if m == nil {
+		m = make(map[*Package]token.Pos)
+		mm[scope] = m
+	}
+	m[pkg] = pos
+}
+
+// addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
+func (check *Checker) addDeclDep(to Object) {
+	from := check.decl
+	if from == nil {
+		return // not in a package-level init expression
+	}
+	if _, found := check.objMap[to]; !found {
+		return // to is not a package-level object
+	}
+	from.addDep(to)
+}
+
+func (check *Checker) assocMethod(tname string, meth *Func) {
+	m := check.methods
+	if m == nil {
+		m = make(map[string][]*Func)
+		check.methods = m
+	}
+	m[tname] = append(m[tname], meth)
+}
+
+func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val exact.Value) {
+	m := check.untyped
+	if m == nil {
+		m = make(map[ast.Expr]exprInfo)
+		check.untyped = m
+	}
+	m[e] = exprInfo{lhs, mode, typ, val}
+}
+
+func (check *Checker) later(name string, decl *declInfo, sig *Signature, body *ast.BlockStmt) {
+	check.funcs = append(check.funcs, funcInfo{name, decl, sig, body})
+}
+
+func (check *Checker) delay(f func()) {
+	check.delayed = append(check.delayed, f)
+}
+
+// NewChecker returns a new Checker instance for a given package.
+// Package files may be added incrementally via checker.Files.
+func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
+	// make sure we have a configuration
+	if conf == nil {
+		conf = new(Config)
+	}
+
+	// make sure we have an info struct
+	if info == nil {
+		info = new(Info)
+	}
+
+	return &Checker{
+		conf:   conf,
+		fset:   fset,
+		pkg:    pkg,
+		Info:   info,
+		objMap: make(map[Object]*declInfo),
+	}
+}
+
+// initFiles initializes the files-specific portion of checker.
+// The provided files must all belong to the same package.
+func (check *Checker) initFiles(files []*ast.File) {
+	// start with a clean slate (check.Files may be called multiple times)
+	check.files = nil
+	check.unusedDotImports = nil
+
+	check.firstErr = nil
+	check.methods = nil
+	check.untyped = nil
+	check.funcs = nil
+	check.delayed = nil
+
+	// determine package name and collect valid files
+	pkg := check.pkg
+	for _, file := range files {
+		switch name := file.Name.Name; pkg.name {
+		case "":
+			if name != "_" {
+				pkg.name = name
+			} else {
+				check.errorf(file.Name.Pos(), "invalid package name _")
+			}
+			fallthrough
+
+		case name:
+			check.files = append(check.files, file)
+
+		default:
+			check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
+			// ignore this file
+		}
+	}
+}
+
+// A bailout panic is used for early termination.
+type bailout struct{}
+
+func (check *Checker) handleBailout(err *error) {
+	switch p := recover().(type) {
+	case nil, bailout:
+		// normal return or early exit
+		*err = check.firstErr
+	default:
+		// re-panic
+		panic(p)
+	}
+}
+
+// Files checks the provided files as part of the checker's package.
+func (check *Checker) Files(files []*ast.File) (err error) {
+	defer check.handleBailout(&err)
+
+	check.initFiles(files)
+
+	check.collectObjects()
+
+	check.packageObjects(check.resolveOrder())
+
+	check.functionBodies()
+
+	check.initOrder()
+
+	if !check.conf.DisableUnusedImportCheck {
+		check.unusedImports()
+	}
+
+	// perform delayed checks
+	for _, f := range check.delayed {
+		f()
+	}
+
+	check.recordUntyped()
+
+	check.pkg.complete = true
+	return
+}
+
+func (check *Checker) recordUntyped() {
+	if !debug && check.Types == nil {
+		return // nothing to do
+	}
+
+	for x, info := range check.untyped {
+		if debug && isTyped(info.typ) {
+			check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ)
+			unreachable()
+		}
+		check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+	}
+}
+
+func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val exact.Value) {
+	assert(x != nil)
+	assert(typ != nil)
+	if mode == invalid {
+		return // omit
+	}
+	assert(typ != nil)
+	if mode == constant {
+		assert(val != nil)
+		assert(typ == Typ[Invalid] || isConstType(typ))
+	}
+	if m := check.Types; m != nil {
+		m[x] = TypeAndValue{mode, typ, val}
+	}
+}
+
+func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
+	// f must be a (possibly parenthesized) identifier denoting a built-in
+	// (built-ins in package unsafe always produce a constant result and
+	// we don't record their signatures, so we don't see qualified idents
+	// here): record the signature for f and possible children.
+	for {
+		check.recordTypeAndValue(f, builtin, sig, nil)
+		switch p := f.(type) {
+		case *ast.Ident:
+			return // we're done
+		case *ast.ParenExpr:
+			f = p.X
+		default:
+			unreachable()
+		}
+	}
+}
+
+func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
+	assert(x != nil)
+	if a[0] == nil || a[1] == nil {
+		return
+	}
+	assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
+	if m := check.Types; m != nil {
+		for {
+			tv := m[x]
+			assert(tv.Type != nil) // should have been recorded already
+			pos := x.Pos()
+			tv.Type = NewTuple(
+				NewVar(pos, check.pkg, "", a[0]),
+				NewVar(pos, check.pkg, "", a[1]),
+			)
+			m[x] = tv
+			// if x is a parenthesized expression (p.X), update p.X
+			p, _ := x.(*ast.ParenExpr)
+			if p == nil {
+				break
+			}
+			x = p.X
+		}
+	}
+}
+
+func (check *Checker) recordDef(id *ast.Ident, obj Object) {
+	assert(id != nil)
+	if m := check.Defs; m != nil {
+		m[id] = obj
+	}
+}
+
+func (check *Checker) recordUse(id *ast.Ident, obj Object) {
+	assert(id != nil)
+	assert(obj != nil)
+	if m := check.Uses; m != nil {
+		m[id] = obj
+	}
+}
+
+func (check *Checker) recordImplicit(node ast.Node, obj Object) {
+	assert(node != nil)
+	assert(obj != nil)
+	if m := check.Implicits; m != nil {
+		m[node] = obj
+	}
+}
+
+func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+	assert(obj != nil && (recv == nil || len(index) > 0))
+	check.recordUse(x.Sel, obj)
+	// TODO(gri) Should we also call recordTypeAndValue?
+	if m := check.Selections; m != nil {
+		m[x] = &Selection{kind, recv, obj, index, indirect}
+	}
+}
+
+func (check *Checker) recordScope(node ast.Node, scope *Scope) {
+	assert(node != nil)
+	assert(scope != nil)
+	if m := check.Scopes; m != nil {
+		m[node] = scope
+	}
+}
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
new file mode 100644
index 0000000..2584392
--- /dev/null
+++ b/src/go/types/check_test.go
@@ -0,0 +1,297 @@
+// Copyright 2011 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.
+
+// This file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+//	package p
+//	func f() {
+//		_ = x /* ERROR "not declared" */ + 1
+//	}
+
+// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
+//           and test against strict mode.
+
+package types_test
+
+import (
+	"flag"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/scanner"
+	"go/token"
+	"io/ioutil"
+	"regexp"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+var (
+	listErrors = flag.Bool("list", false, "list errors")
+	testFiles  = flag.String("files", "", "space-separated list of test files")
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+// Each tests entry is list of files belonging to the same package.
+var tests = [][]string{
+	{"testdata/errors.src"},
+	{"testdata/importdecl0a.src", "testdata/importdecl0b.src"},
+	{"testdata/importdecl1a.src", "testdata/importdecl1b.src"},
+	{"testdata/cycles.src"},
+	{"testdata/cycles1.src"},
+	{"testdata/cycles2.src"},
+	{"testdata/cycles3.src"},
+	{"testdata/cycles4.src"},
+	{"testdata/init0.src"},
+	{"testdata/init1.src"},
+	{"testdata/init2.src"},
+	{"testdata/decls0.src"},
+	{"testdata/decls1.src"},
+	{"testdata/decls2a.src", "testdata/decls2b.src"},
+	{"testdata/decls3.src"},
+	{"testdata/const0.src"},
+	{"testdata/const1.src"},
+	{"testdata/constdecl.src"},
+	{"testdata/vardecl.src"},
+	{"testdata/expr0.src"},
+	{"testdata/expr1.src"},
+	{"testdata/expr2.src"},
+	{"testdata/expr3.src"},
+	{"testdata/methodsets.src"},
+	{"testdata/shifts.src"},
+	{"testdata/builtins.src"},
+	{"testdata/conversions.src"},
+	{"testdata/stmt0.src"},
+	{"testdata/stmt1.src"},
+	{"testdata/gotos.src"},
+	{"testdata/labels.src"},
+	{"testdata/issues.src"},
+	{"testdata/blank.src"},
+}
+
+var fset = token.NewFileSet()
+
+// Positioned errors are of the form filename:line:column: message .
+var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
+
+// splitError splits an error's error message into a position string
+// and the actual error message. If there's no position information,
+// pos is the empty string, and msg is the entire error message.
+//
+func splitError(err error) (pos, msg string) {
+	msg = err.Error()
+	if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 {
+		pos = m[1]
+		msg = m[2]
+	}
+	return
+}
+
+func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) {
+	var files []*ast.File
+	var errlist []error
+	for _, filename := range filenames {
+		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+		if file == nil {
+			t.Fatalf("%s: %s", filename, err)
+		}
+		files = append(files, file)
+		if err != nil {
+			if list, _ := err.(scanner.ErrorList); len(list) > 0 {
+				for _, err := range list {
+					errlist = append(errlist, err)
+				}
+			} else {
+				errlist = append(errlist, err)
+			}
+		}
+	}
+	return files, errlist
+}
+
+// ERROR comments must start with text `ERROR "rx"` or `ERROR rx` where
+// rx is a regular expression that matches the expected error message.
+// Space around "rx" or rx is ignored. Use the form `ERROR HERE "rx"`
+// for error messages that are located immediately after rather than
+// at a token's position.
+//
+var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`)
+
+// errMap collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
+	// map of position strings to lists of error message patterns
+	errmap := make(map[string][]string)
+
+	for _, file := range files {
+		filename := fset.Position(file.Package).Filename
+		src, err := ioutil.ReadFile(filename)
+		if err != nil {
+			t.Fatalf("%s: could not read %s", testname, filename)
+		}
+
+		var s scanner.Scanner
+		s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments)
+		var prev token.Pos // position of last non-comment, non-semicolon token
+		var here token.Pos // position immediately after the token at position prev
+
+	scanFile:
+		for {
+			pos, tok, lit := s.Scan()
+			switch tok {
+			case token.EOF:
+				break scanFile
+			case token.COMMENT:
+				if lit[1] == '*' {
+					lit = lit[:len(lit)-2] // strip trailing */
+				}
+				if s := errRx.FindStringSubmatch(lit[2:]); len(s) == 3 {
+					pos := prev
+					if s[1] == "HERE" {
+						pos = here
+					}
+					p := fset.Position(pos).String()
+					errmap[p] = append(errmap[p], strings.TrimSpace(s[2]))
+				}
+			case token.SEMICOLON:
+				// ignore automatically inserted semicolon
+				if lit == "\n" {
+					continue scanFile
+				}
+				fallthrough
+			default:
+				prev = pos
+				var l int // token length
+				if tok.IsLiteral() {
+					l = len(lit)
+				} else {
+					l = len(tok.String())
+				}
+				here = prev + token.Pos(l)
+			}
+		}
+	}
+
+	return errmap
+}
+
+func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
+	for _, err := range errlist {
+		pos, gotMsg := splitError(err)
+		list := errmap[pos]
+		index := -1 // list index of matching message, if any
+		// we expect one of the messages in list to match the error at pos
+		for i, wantRx := range list {
+			rx, err := regexp.Compile(wantRx)
+			if err != nil {
+				t.Errorf("%s: %v", pos, err)
+				continue
+			}
+			if rx.MatchString(gotMsg) {
+				index = i
+				break
+			}
+		}
+		if index >= 0 {
+			// eliminate from list
+			if n := len(list) - 1; n > 0 {
+				// not the last entry - swap in last element and shorten list by 1
+				list[index] = list[n]
+				errmap[pos] = list[:n]
+			} else {
+				// last entry - remove list from map
+				delete(errmap, pos)
+			}
+		} else {
+			t.Errorf("%s: no error expected: %q", pos, gotMsg)
+		}
+	}
+}
+
+func checkFiles(t *testing.T, testfiles []string) {
+	// parse files and collect parser errors
+	files, errlist := parseFiles(t, testfiles)
+
+	pkgName := "<no package>"
+	if len(files) > 0 {
+		pkgName = files[0].Name.Name
+	}
+
+	if *listErrors && len(errlist) > 0 {
+		t.Errorf("--- %s:", pkgName)
+		for _, err := range errlist {
+			t.Error(err)
+		}
+	}
+
+	// typecheck and collect typechecker errors
+	var conf Config
+	conf.Importer = importer.Default()
+	conf.Error = func(err error) {
+		if *listErrors {
+			t.Error(err)
+			return
+		}
+		// Ignore secondary error messages starting with "\t";
+		// they are clarifying messages for a primary error.
+		if !strings.Contains(err.Error(), ": \t") {
+			errlist = append(errlist, err)
+		}
+	}
+	conf.Check(pkgName, fset, files, nil)
+
+	if *listErrors {
+		return
+	}
+
+	// match and eliminate errors;
+	// we are expecting the following errors
+	errmap := errMap(t, pkgName, files)
+	eliminate(t, errmap, errlist)
+
+	// there should be no expected errors left
+	if len(errmap) > 0 {
+		t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap))
+		for pos, list := range errmap {
+			for _, rx := range list {
+				t.Errorf("%s: %q", pos, rx)
+			}
+		}
+	}
+}
+
+func TestCheck(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// Declare builtins for testing.
+	DefPredeclaredTestFuncs()
+
+	// If explicit test files are specified, only check those.
+	if files := *testFiles; files != "" {
+		checkFiles(t, strings.Split(files, " "))
+		return
+	}
+
+	// Otherwise, run all the tests.
+	for _, files := range tests {
+		checkFiles(t, files)
+	}
+}
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
new file mode 100644
index 0000000..0cf9953
--- /dev/null
+++ b/src/go/types/conversions.go
@@ -0,0 +1,146 @@
+// Copyright 2012 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.
+
+// This file implements typechecking of conversions.
+
+package types
+
+import exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+
+// Conversion type-checks the conversion T(x).
+// The result is in x.
+func (check *Checker) conversion(x *operand, T Type) {
+	constArg := x.mode == constant
+
+	var ok bool
+	switch {
+	case constArg && isConstType(T):
+		// constant conversion
+		switch t := T.Underlying().(*Basic); {
+		case representableConst(x.val, check.conf, t.kind, &x.val):
+			ok = true
+		case x.isInteger() && isString(t):
+			codepoint := int64(-1)
+			if i, ok := exact.Int64Val(x.val); ok {
+				codepoint = i
+			}
+			// If codepoint < 0 the absolute value is too large (or unknown) for
+			// conversion. This is the same as converting any other out-of-range
+			// value - let string(codepoint) do the work.
+			x.val = exact.MakeString(string(codepoint))
+			ok = true
+		}
+	case x.convertibleTo(check.conf, T):
+		// non-constant conversion
+		x.mode = value
+		ok = true
+	}
+
+	if !ok {
+		check.errorf(x.pos(), "cannot convert %s to %s", x, T)
+		x.mode = invalid
+		return
+	}
+
+	// The conversion argument types are final. For untyped values the
+	// conversion provides the type, per the spec: "A constant may be
+	// given a type explicitly by a constant declaration or conversion,...".
+	final := x.typ
+	if isUntyped(x.typ) {
+		final = T
+		// - For conversions to interfaces, use the argument's default type.
+		// - For conversions of untyped constants to non-constant types, also
+		//   use the default type (e.g., []byte("foo") should report string
+		//   not []byte as type for the constant "foo").
+		// - Keep untyped nil for untyped nil arguments.
+		if IsInterface(T) || constArg && !isConstType(T) {
+			final = defaultType(x.typ)
+		}
+		check.updateExprType(x.expr, final, true)
+	}
+
+	x.typ = T
+}
+
+func (x *operand) convertibleTo(conf *Config, T Type) bool {
+	// "x is assignable to T"
+	if x.assignableTo(conf, T) {
+		return true
+	}
+
+	// "x's type and T have identical underlying types"
+	V := x.typ
+	Vu := V.Underlying()
+	Tu := T.Underlying()
+	if Identical(Vu, Tu) {
+		return true
+	}
+
+	// "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
+	if V, ok := V.(*Pointer); ok {
+		if T, ok := T.(*Pointer); ok {
+			if Identical(V.base.Underlying(), T.base.Underlying()) {
+				return true
+			}
+		}
+	}
+
+	// "x's type and T are both integer or floating point types"
+	if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
+		return true
+	}
+
+	// "x's type and T are both complex types"
+	if isComplex(V) && isComplex(T) {
+		return true
+	}
+
+	// "x is an integer or a slice of bytes or runes and T is a string type"
+	if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
+		return true
+	}
+
+	// "x is a string and T is a slice of bytes or runes"
+	if isString(V) && isBytesOrRunes(Tu) {
+		return true
+	}
+
+	// package unsafe:
+	// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+	if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
+		return true
+	}
+	// "and vice versa"
+	if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
+		return true
+	}
+
+	return false
+}
+
+func isUintptr(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.kind == Uintptr
+}
+
+func isUnsafePointer(typ Type) bool {
+	// TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
+	//            The spec does not say so, but gc claims it is. See also
+	//            issue 6326.
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.kind == UnsafePointer
+}
+
+func isPointer(typ Type) bool {
+	_, ok := typ.Underlying().(*Pointer)
+	return ok
+}
+
+func isBytesOrRunes(typ Type) bool {
+	if s, ok := typ.(*Slice); ok {
+		t, ok := s.elem.Underlying().(*Basic)
+		return ok && (t.kind == Byte || t.kind == Rune)
+	}
+	return false
+}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
new file mode 100644
index 0000000..c2c18ec
--- /dev/null
+++ b/src/go/types/decl.go
@@ -0,0 +1,418 @@
+// 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.
+
+package types
+
+import (
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+func (check *Checker) reportAltDecl(obj Object) {
+	if pos := obj.Pos(); pos.IsValid() {
+		// We use "other" rather than "previous" here because
+		// the first declaration seen may not be textually
+		// earlier in the source.
+		check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+	}
+}
+
+func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object) {
+	// spec: "The blank identifier, represented by the underscore
+	// character _, may be used in a declaration like any other
+	// identifier but the declaration does not introduce a new
+	// binding."
+	if obj.Name() != "_" {
+		if alt := scope.Insert(obj); alt != nil {
+			check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+			check.reportAltDecl(alt)
+			return
+		}
+	}
+	if id != nil {
+		check.recordDef(id, obj)
+	}
+}
+
+// objDecl type-checks the declaration of obj in its respective (file) context.
+// See check.typ for the details on def and path.
+func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
+	if obj.Type() != nil {
+		return // already checked - nothing to do
+	}
+
+	if trace {
+		check.trace(obj.Pos(), "-- declaring %s", obj.Name())
+		check.indent++
+		defer func() {
+			check.indent--
+			check.trace(obj.Pos(), "=> %s", obj)
+		}()
+	}
+
+	d := check.objMap[obj]
+	if d == nil {
+		check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+		unreachable()
+	}
+
+	// save/restore current context and setup object context
+	defer func(ctxt context) {
+		check.context = ctxt
+	}(check.context)
+	check.context = context{
+		scope: d.file,
+	}
+
+	// Const and var declarations must not have initialization
+	// cycles. We track them by remembering the current declaration
+	// in check.decl. Initialization expressions depending on other
+	// consts, vars, or functions, add dependencies to the current
+	// check.decl.
+	switch obj := obj.(type) {
+	case *Const:
+		check.decl = d // new package-level const decl
+		check.constDecl(obj, d.typ, d.init)
+	case *Var:
+		check.decl = d // new package-level var decl
+		check.varDecl(obj, d.lhs, d.typ, d.init)
+	case *TypeName:
+		// invalid recursive types are detected via path
+		check.typeDecl(obj, d.typ, def, path)
+	case *Func:
+		// functions may be recursive - no need to track dependencies
+		check.funcDecl(obj, d)
+	default:
+		unreachable()
+	}
+}
+
+func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
+	assert(obj.typ == nil)
+
+	if obj.visited {
+		obj.typ = Typ[Invalid]
+		return
+	}
+	obj.visited = true
+
+	// use the correct value of iota
+	assert(check.iota == nil)
+	check.iota = obj.val
+	defer func() { check.iota = nil }()
+
+	// provide valid constant value under all circumstances
+	obj.val = exact.MakeUnknown()
+
+	// determine type, if any
+	if typ != nil {
+		t := check.typ(typ)
+		if !isConstType(t) {
+			check.errorf(typ.Pos(), "invalid constant type %s", t)
+			obj.typ = Typ[Invalid]
+			return
+		}
+		obj.typ = t
+	}
+
+	// check initialization
+	var x operand
+	if init != nil {
+		check.expr(&x, init)
+	}
+	check.initConst(obj, &x)
+}
+
+func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
+	assert(obj.typ == nil)
+
+	if obj.visited {
+		obj.typ = Typ[Invalid]
+		return
+	}
+	obj.visited = true
+
+	// var declarations cannot use iota
+	assert(check.iota == nil)
+
+	// determine type, if any
+	if typ != nil {
+		obj.typ = check.typ(typ)
+	}
+
+	// check initialization
+	if init == nil {
+		if typ == nil {
+			// error reported before by arityMatch
+			obj.typ = Typ[Invalid]
+		}
+		return
+	}
+
+	if lhs == nil || len(lhs) == 1 {
+		assert(lhs == nil || lhs[0] == obj)
+		var x operand
+		check.expr(&x, init)
+		check.initVar(obj, &x, false)
+		return
+	}
+
+	if debug {
+		// obj must be one of lhs
+		found := false
+		for _, lhs := range lhs {
+			if obj == lhs {
+				found = true
+				break
+			}
+		}
+		if !found {
+			panic("inconsistent lhs")
+		}
+	}
+	check.initVars(lhs, []ast.Expr{init}, token.NoPos)
+}
+
+// underlying returns the underlying type of typ; possibly by following
+// forward chains of named types. Such chains only exist while named types
+// are incomplete.
+func underlying(typ Type) Type {
+	for {
+		n, _ := typ.(*Named)
+		if n == nil {
+			break
+		}
+		typ = n.underlying
+	}
+	return typ
+}
+
+func (n *Named) setUnderlying(typ Type) {
+	if n != nil {
+		n.underlying = typ
+	}
+}
+
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+	assert(obj.typ == nil)
+
+	// type declarations cannot use iota
+	assert(check.iota == nil)
+
+	named := &Named{obj: obj}
+	def.setUnderlying(named)
+	obj.typ = named // make sure recursive type declarations terminate
+
+	// determine underlying type of named
+	check.typExpr(typ, named, append(path, obj))
+
+	// The underlying type of named may be itself a named type that is
+	// incomplete:
+	//
+	//	type (
+	//		A B
+	//		B *C
+	//		C A
+	//	)
+	//
+	// The type of C is the (named) type of A which is incomplete,
+	// and which has as its underlying type the named type B.
+	// Determine the (final, unnamed) underlying type by resolving
+	// any forward chain (they always end in an unnamed type).
+	named.underlying = underlying(named.underlying)
+
+	// check and add associated methods
+	// TODO(gri) It's easy to create pathological cases where the
+	// current approach is incorrect: In general we need to know
+	// and add all methods _before_ type-checking the type.
+	// See http://play.golang.org/p/WMpE0q2wK8
+	check.addMethodDecls(obj)
+}
+
+func (check *Checker) addMethodDecls(obj *TypeName) {
+	// get associated methods
+	methods := check.methods[obj.name]
+	if len(methods) == 0 {
+		return // no methods
+	}
+	delete(check.methods, obj.name)
+
+	// use an objset to check for name conflicts
+	var mset objset
+
+	// spec: "If the base type is a struct type, the non-blank method
+	// and field names must be distinct."
+	base := obj.typ.(*Named)
+	if t, _ := base.underlying.(*Struct); t != nil {
+		for _, fld := range t.fields {
+			if fld.name != "_" {
+				assert(mset.insert(fld) == nil)
+			}
+		}
+	}
+
+	// Checker.Files may be called multiple times; additional package files
+	// may add methods to already type-checked types. Add pre-existing methods
+	// so that we can detect redeclarations.
+	for _, m := range base.methods {
+		assert(m.name != "_")
+		assert(mset.insert(m) == nil)
+	}
+
+	// type-check methods
+	for _, m := range methods {
+		// spec: "For a base type, the non-blank names of methods bound
+		// to it must be unique."
+		if m.name != "_" {
+			if alt := mset.insert(m); alt != nil {
+				switch alt.(type) {
+				case *Var:
+					check.errorf(m.pos, "field and method with the same name %s", m.name)
+				case *Func:
+					check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+				default:
+					unreachable()
+				}
+				check.reportAltDecl(alt)
+				continue
+			}
+		}
+		check.objDecl(m, nil, nil)
+		// methods with blank _ names cannot be found - don't keep them
+		if m.name != "_" {
+			base.methods = append(base.methods, m)
+		}
+	}
+}
+
+func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
+	assert(obj.typ == nil)
+
+	// func declarations cannot use iota
+	assert(check.iota == nil)
+
+	sig := new(Signature)
+	obj.typ = sig // guard against cycles
+	fdecl := decl.fdecl
+	check.funcType(sig, fdecl.Recv, fdecl.Type)
+	if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
+		check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
+		// ok to continue
+	}
+
+	// function body must be type-checked after global declarations
+	// (functions implemented elsewhere have no body)
+	if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
+		check.later(obj.name, decl, sig, fdecl.Body)
+	}
+}
+
+func (check *Checker) declStmt(decl ast.Decl) {
+	pkg := check.pkg
+
+	switch d := decl.(type) {
+	case *ast.BadDecl:
+		// ignore
+
+	case *ast.GenDecl:
+		var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+		for iota, spec := range d.Specs {
+			switch s := spec.(type) {
+			case *ast.ValueSpec:
+				switch d.Tok {
+				case token.CONST:
+					// determine which init exprs to use
+					switch {
+					case s.Type != nil || len(s.Values) > 0:
+						last = s
+					case last == nil:
+						last = new(ast.ValueSpec) // make sure last exists
+					}
+
+					// declare all constants
+					lhs := make([]*Const, len(s.Names))
+					for i, name := range s.Names {
+						obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
+						lhs[i] = obj
+
+						var init ast.Expr
+						if i < len(last.Values) {
+							init = last.Values[i]
+						}
+
+						check.constDecl(obj, last.Type, init)
+					}
+
+					check.arityMatch(s, last)
+
+					for i, name := range s.Names {
+						check.declare(check.scope, name, lhs[i])
+					}
+
+				case token.VAR:
+					lhs0 := make([]*Var, len(s.Names))
+					for i, name := range s.Names {
+						lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
+					}
+
+					// initialize all variables
+					for i, obj := range lhs0 {
+						var lhs []*Var
+						var init ast.Expr
+						switch len(s.Values) {
+						case len(s.Names):
+							// lhs and rhs match
+							init = s.Values[i]
+						case 1:
+							// rhs is expected to be a multi-valued expression
+							lhs = lhs0
+							init = s.Values[0]
+						default:
+							if i < len(s.Values) {
+								init = s.Values[i]
+							}
+						}
+						check.varDecl(obj, lhs, s.Type, init)
+						if len(s.Values) == 1 {
+							// If we have a single lhs variable we are done either way.
+							// If we have a single rhs expression, it must be a multi-
+							// valued expression, in which case handling the first lhs
+							// variable will cause all lhs variables to have a type
+							// assigned, and we are done as well.
+							if debug {
+								for _, obj := range lhs0 {
+									assert(obj.typ != nil)
+								}
+							}
+							break
+						}
+					}
+
+					check.arityMatch(s, nil)
+
+					// declare all variables
+					// (only at this point are the variable scopes (parents) set)
+					for i, name := range s.Names {
+						check.declare(check.scope, name, lhs0[i])
+					}
+
+				default:
+					check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+				}
+
+			case *ast.TypeSpec:
+				obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+				check.declare(check.scope, s.Name, obj)
+				check.typeDecl(obj, s.Type, nil, nil)
+
+			default:
+				check.invalidAST(s.Pos(), "const, type, or var declaration expected")
+			}
+		}
+
+	default:
+		check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+	}
+}
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
new file mode 100644
index 0000000..0a9dd0e
--- /dev/null
+++ b/src/go/types/errors.go
@@ -0,0 +1,96 @@
+// Copyright 2012 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.
+
+// This file implements various error reporters.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"strings"
+)
+
+func assert(p bool) {
+	if !p {
+		panic("assertion failed")
+	}
+}
+
+func unreachable() {
+	panic("unreachable")
+}
+
+func (check *Checker) sprintf(format string, args ...interface{}) string {
+	for i, arg := range args {
+		switch a := arg.(type) {
+		case nil:
+			arg = "<nil>"
+		case operand:
+			panic("internal error: should always pass *operand")
+		case *operand:
+			arg = operandString(check.pkg, a)
+		case token.Pos:
+			arg = check.fset.Position(a).String()
+		case ast.Expr:
+			arg = ExprString(a)
+		case Object:
+			arg = ObjectString(check.pkg, a)
+		case Type:
+			arg = TypeString(check.pkg, a)
+		}
+		args[i] = arg
+	}
+	return fmt.Sprintf(format, args...)
+}
+
+func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
+	fmt.Printf("%s:\t%s%s\n",
+		check.fset.Position(pos),
+		strings.Repeat(".  ", check.indent),
+		check.sprintf(format, args...),
+	)
+}
+
+// dump is only needed for debugging
+func (check *Checker) dump(format string, args ...interface{}) {
+	fmt.Println(check.sprintf(format, args...))
+}
+
+func (check *Checker) err(pos token.Pos, msg string, soft bool) {
+	err := Error{check.fset, pos, msg, soft}
+	if check.firstErr == nil {
+		check.firstErr = err
+	}
+	f := check.conf.Error
+	if f == nil {
+		panic(bailout{}) // report only first error
+	}
+	f(err)
+}
+
+func (check *Checker) error(pos token.Pos, msg string) {
+	check.err(pos, msg, false)
+}
+
+func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) {
+	check.err(pos, check.sprintf(format, args...), false)
+}
+
+func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) {
+	check.err(pos, check.sprintf(format, args...), true)
+}
+
+func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
+	check.errorf(pos, "invalid AST: "+format, args...)
+}
+
+func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
+	check.errorf(pos, "invalid argument: "+format, args...)
+}
+
+func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
+	check.errorf(pos, "invalid operation: "+format, args...)
+}
diff --git a/src/go/types/eval.go b/src/go/types/eval.go
new file mode 100644
index 0000000..7fa319e
--- /dev/null
+++ b/src/go/types/eval.go
@@ -0,0 +1,95 @@
+// Copyright 2013 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.
+
+// This file implements New, Eval and EvalNode.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+)
+
+// New is a convenience function to create a new type from a given
+// expression or type literal string evaluated in Universe scope.
+// New(str) is shorthand for Eval(str, nil, nil), but only returns
+// the type result, and panics in case of an error.
+// Position info for objects in the result type is undefined.
+//
+func New(str string) Type {
+	tv, err := Eval(str, nil, nil)
+	if err != nil {
+		panic(err)
+	}
+	return tv.Type
+}
+
+// Eval returns the type and, if constant, the value for the
+// expression or type literal string str evaluated in scope.
+// If the expression contains function literals, the function
+// bodies are ignored (though they must be syntactically correct).
+//
+// If pkg == nil, the Universe scope is used and the provided
+// scope is ignored. Otherwise, the scope must belong to the
+// package (either the package scope, or nested within the
+// package scope).
+//
+// An error is returned if the scope is incorrect, the string
+// has syntax errors, or if it cannot be evaluated in the scope.
+// Position info for objects in the result type is undefined.
+//
+// Note: Eval should not be used instead of running Check to compute
+// types and values, but in addition to Check. Eval will re-evaluate
+// its argument each time, and it also does not know about the context
+// in which an expression is used (e.g., an assignment). Thus, top-
+// level untyped constants will return an untyped type rather then the
+// respective context-specific type.
+//
+func Eval(str string, pkg *Package, scope *Scope) (TypeAndValue, error) {
+	node, err := parser.ParseExpr(str)
+	if err != nil {
+		return TypeAndValue{}, err
+	}
+
+	// Create a file set that looks structurally identical to the
+	// one created by parser.ParseExpr for correct error positions.
+	fset := token.NewFileSet()
+	fset.AddFile("", len(str), fset.Base()).SetLinesForContent([]byte(str))
+
+	return EvalNode(fset, node, pkg, scope)
+}
+
+// EvalNode is like Eval but instead of string it accepts
+// an expression node and respective file set.
+//
+// An error is returned if the scope is incorrect
+// if the node cannot be evaluated in the scope.
+//
+func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (tv TypeAndValue, err error) {
+	// verify package/scope relationship
+	if pkg == nil {
+		scope = Universe
+	} else {
+		s := scope
+		for s != nil && s != pkg.scope {
+			s = s.parent
+		}
+		// s == nil || s == pkg.scope
+		if s == nil {
+			return TypeAndValue{}, fmt.Errorf("scope does not belong to package %s", pkg.name)
+		}
+	}
+
+	// initialize checker
+	check := NewChecker(nil, fset, pkg, nil)
+	check.scope = scope
+	defer check.handleBailout(&err)
+
+	// evaluate node
+	var x operand
+	check.rawExpr(&x, node, nil)
+	return TypeAndValue{x.mode, x.typ, x.val}, nil
+}
diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go
new file mode 100644
index 0000000..bc27a8b
--- /dev/null
+++ b/src/go/types/eval_test.go
@@ -0,0 +1,152 @@
+// Copyright 2013 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.
+
+// This file contains tests for Eval.
+
+package types_test
+
+import (
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"strings"
+	"testing"
+
+	_ "go/internal/gcimporter"
+	. "go/types"
+)
+
+func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, typStr, valStr string) {
+	gotTv, err := Eval(str, pkg, scope)
+	if err != nil {
+		t.Errorf("Eval(%q) failed: %s", str, err)
+		return
+	}
+	if gotTv.Type == nil {
+		t.Errorf("Eval(%q) got nil type but no error", str)
+		return
+	}
+
+	// compare types
+	if typ != nil {
+		// we have a type, check identity
+		if !Identical(gotTv.Type, typ) {
+			t.Errorf("Eval(%q) got type %s, want %s", str, gotTv.Type, typ)
+			return
+		}
+	} else {
+		// we have a string, compare type string
+		gotStr := gotTv.Type.String()
+		if gotStr != typStr {
+			t.Errorf("Eval(%q) got type %s, want %s", str, gotStr, typStr)
+			return
+		}
+	}
+
+	// compare values
+	gotStr := ""
+	if gotTv.Value != nil {
+		gotStr = gotTv.Value.String()
+	}
+	if gotStr != valStr {
+		t.Errorf("Eval(%q) got value %s, want %s", str, gotStr, valStr)
+	}
+}
+
+func TestEvalBasic(t *testing.T) {
+	for _, typ := range Typ[Bool : String+1] {
+		testEval(t, nil, nil, typ.Name(), typ, "", "")
+	}
+}
+
+func TestEvalComposite(t *testing.T) {
+	for _, test := range independentTestTypes {
+		testEval(t, nil, nil, test.src, nil, test.str, "")
+	}
+}
+
+func TestEvalArith(t *testing.T) {
+	var tests = []string{
+		`true`,
+		`false == false`,
+		`12345678 + 87654321 == 99999999`,
+		`10 * 20 == 200`,
+		`(1<<1000)*2 >> 100 == 2<<900`,
+		`"foo" + "bar" == "foobar"`,
+		`"abc" <= "bcd"`,
+		`len([10]struct{}{}) == 2*5`,
+	}
+	for _, test := range tests {
+		testEval(t, nil, nil, test, Typ[UntypedBool], "", "true")
+	}
+}
+
+func TestEvalContext(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	src := `
+package p
+import "fmt"
+import m "math"
+const c = 3.0
+type T []int
+func f(a int, s string) float64 {
+	fmt.Println("calling f")
+	_ = m.Pi // use package math
+	const d int = c + 1
+	var x int
+	x = a + len(s)
+	return float64(x)
+}
+`
+	fset := token.NewFileSet()
+	file, err := parser.ParseFile(fset, "p", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	conf := Config{Importer: importer.Default()}
+	pkg, err := conf.Check("p", fset, []*ast.File{file}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	pkgScope := pkg.Scope()
+	if n := pkgScope.NumChildren(); n != 1 {
+		t.Fatalf("got %d file scopes, want 1", n)
+	}
+
+	fileScope := pkgScope.Child(0)
+	if n := fileScope.NumChildren(); n != 1 {
+		t.Fatalf("got %d functions scopes, want 1", n)
+	}
+
+	funcScope := fileScope.Child(0)
+
+	var tests = []string{
+		`true => true, untyped bool`,
+		`fmt.Println => , func(a ...interface{}) (n int, err error)`,
+		`c => 3, untyped float`,
+		`T => , p.T`,
+		`a => , int`,
+		`s => , string`,
+		`d => 4, int`,
+		`x => , int`,
+		`d/c => 1, int`,
+		`c/2 => 3/2, untyped float`,
+		`m.Pi < m.E => false, untyped bool`,
+	}
+	for _, test := range tests {
+		str, typ := split(test, ", ")
+		str, val := split(str, "=>")
+		testEval(t, pkg, funcScope, str, nil, typ, val)
+	}
+}
+
+// split splits string s at the first occurrence of s.
+func split(s, sep string) (string, string) {
+	i := strings.Index(s, sep)
+	return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
new file mode 100644
index 0000000..f91d89e
--- /dev/null
+++ b/src/go/types/expr.go
@@ -0,0 +1,1482 @@
+// Copyright 2012 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.
+
+// This file implements typechecking of expressions.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+	"math"
+)
+
+/*
+Basic algorithm:
+
+Expressions are checked recursively, top down. Expression checker functions
+are generally of the form:
+
+  func f(x *operand, e *ast.Expr, ...)
+
+where e is the expression to be checked, and x is the result of the check.
+The check performed by f may fail in which case x.mode == invalid, and
+related error messages will have been issued by f.
+
+If a hint argument is present, it is the composite literal element type
+of an outer composite literal; it is used to type-check composite literal
+elements that have no explicit type specification in the source
+(e.g.: []T{{...}, {...}}, the hint is the type T in this case).
+
+All expressions are checked via rawExpr, which dispatches according
+to expression kind. Upon returning, rawExpr is recording the types and
+constant values for all expressions that have an untyped type (those types
+may change on the way up in the expression tree). Usually these are constants,
+but the results of comparisons or non-constant shifts of untyped constants
+may also be untyped, but not constant.
+
+Untyped expressions may eventually become fully typed (i.e., not untyped),
+typically when the value is assigned to a variable, or is used otherwise.
+The updateExprType method is used to record this final type and update
+the recorded types: the type-checked expression tree is again traversed down,
+and the new type is propagated as needed. Untyped constant expression values
+that become fully typed must now be representable by the full type (constant
+sub-expression trees are left alone except for their roots). This mechanism
+ensures that a client sees the actual (run-time) type an untyped value would
+have. It also permits type-checking of lhs shift operands "as if the shift
+were not present": when updateExprType visits an untyped lhs shift operand
+and assigns it it's final type, that type must be an integer type, and a
+constant lhs must be representable as an integer.
+
+When an expression gets its final type, either on the way out from rawExpr,
+on the way down in updateExprType, or at the end of the type checker run,
+the type (and constant value, if any) is recorded via Info.Types, if present.
+*/
+
+type opPredicates map[token.Token]func(Type) bool
+
+var unaryOpPredicates = opPredicates{
+	token.ADD: isNumeric,
+	token.SUB: isNumeric,
+	token.XOR: isInteger,
+	token.NOT: isBoolean,
+}
+
+func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
+	if pred := m[op]; pred != nil {
+		if !pred(x.typ) {
+			check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
+			return false
+		}
+	} else {
+		check.invalidAST(x.pos(), "unknown operator %s", op)
+		return false
+	}
+	return true
+}
+
+func (check *Checker) unary(x *operand, op token.Token) {
+	switch op {
+	case token.AND:
+		// spec: "As an exception to the addressability
+		// requirement x may also be a composite literal."
+		if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable {
+			check.invalidOp(x.pos(), "cannot take address of %s", x)
+			x.mode = invalid
+			return
+		}
+		x.mode = value
+		x.typ = &Pointer{base: x.typ}
+		return
+
+	case token.ARROW:
+		typ, ok := x.typ.Underlying().(*Chan)
+		if !ok {
+			check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
+			x.mode = invalid
+			return
+		}
+		if typ.dir == SendOnly {
+			check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
+			x.mode = invalid
+			return
+		}
+		x.mode = commaok
+		x.typ = typ.elem
+		check.hasCallOrRecv = true
+		return
+	}
+
+	if !check.op(unaryOpPredicates, x, op) {
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant {
+		typ := x.typ.Underlying().(*Basic)
+		var prec uint
+		if isUnsigned(typ) {
+			prec = uint(check.conf.sizeof(typ) * 8)
+		}
+		x.val = exact.UnaryOp(op, x.val, prec)
+		// Typed constants must be representable in
+		// their type after each constant operation.
+		if isTyped(typ) {
+			check.representable(x, typ)
+		}
+		return
+	}
+
+	x.mode = value
+	// x.typ remains unchanged
+}
+
+func isShift(op token.Token) bool {
+	return op == token.SHL || op == token.SHR
+}
+
+func isComparison(op token.Token) bool {
+	// Note: tokens are not ordered well to make this much easier
+	switch op {
+	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+		return true
+	}
+	return false
+}
+
+func fitsFloat32(x exact.Value) bool {
+	f32, _ := exact.Float32Val(x)
+	f := float64(f32)
+	return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x exact.Value) exact.Value {
+	f32, _ := exact.Float32Val(x)
+	f := float64(f32)
+	if !math.IsInf(f, 0) {
+		return exact.MakeFloat64(f)
+	}
+	return nil
+}
+
+func fitsFloat64(x exact.Value) bool {
+	f, _ := exact.Float64Val(x)
+	return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x exact.Value) exact.Value {
+	f, _ := exact.Float64Val(x)
+	if !math.IsInf(f, 0) {
+		return exact.MakeFloat64(f)
+	}
+	return nil
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type kind and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+func representableConst(x exact.Value, conf *Config, as BasicKind, rounded *exact.Value) bool {
+	switch x.Kind() {
+	case exact.Unknown:
+		return true
+
+	case exact.Bool:
+		return as == Bool || as == UntypedBool
+
+	case exact.Int:
+		if x, ok := exact.Int64Val(x); ok {
+			switch as {
+			case Int:
+				var s = uint(conf.sizeof(Typ[as])) * 8
+				return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+			case Int8:
+				const s = 8
+				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+			case Int16:
+				const s = 16
+				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+			case Int32:
+				const s = 32
+				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+			case Int64:
+				return true
+			case Uint, Uintptr:
+				if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 {
+					return 0 <= x && x <= int64(1)<<s-1
+				}
+				return 0 <= x
+			case Uint8:
+				const s = 8
+				return 0 <= x && x <= 1<<s-1
+			case Uint16:
+				const s = 16
+				return 0 <= x && x <= 1<<s-1
+			case Uint32:
+				const s = 32
+				return 0 <= x && x <= 1<<s-1
+			case Uint64:
+				return 0 <= x
+			case Float32, Float64, Complex64, Complex128,
+				UntypedInt, UntypedFloat, UntypedComplex:
+				return true
+			}
+		}
+
+		n := exact.BitLen(x)
+		switch as {
+		case Uint, Uintptr:
+			var s = uint(conf.sizeof(Typ[as])) * 8
+			return exact.Sign(x) >= 0 && n <= int(s)
+		case Uint64:
+			return exact.Sign(x) >= 0 && n <= 64
+		case Float32, Complex64:
+			if rounded == nil {
+				return fitsFloat32(x)
+			}
+			r := roundFloat32(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case Float64, Complex128:
+			if rounded == nil {
+				return fitsFloat64(x)
+			}
+			r := roundFloat64(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case UntypedInt, UntypedFloat, UntypedComplex:
+			return true
+		}
+
+	case exact.Float:
+		switch as {
+		case Float32, Complex64:
+			if rounded == nil {
+				return fitsFloat32(x)
+			}
+			r := roundFloat32(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case Float64, Complex128:
+			if rounded == nil {
+				return fitsFloat64(x)
+			}
+			r := roundFloat64(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case UntypedFloat, UntypedComplex:
+			return true
+		}
+
+	case exact.Complex:
+		switch as {
+		case Complex64:
+			if rounded == nil {
+				return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x))
+			}
+			re := roundFloat32(exact.Real(x))
+			im := roundFloat32(exact.Imag(x))
+			if re != nil && im != nil {
+				*rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+				return true
+			}
+		case Complex128:
+			if rounded == nil {
+				return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x))
+			}
+			re := roundFloat64(exact.Real(x))
+			im := roundFloat64(exact.Imag(x))
+			if re != nil && im != nil {
+				*rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+				return true
+			}
+		case UntypedComplex:
+			return true
+		}
+
+	case exact.String:
+		return as == String || as == UntypedString
+
+	default:
+		unreachable()
+	}
+
+	return false
+}
+
+// representable checks that a constant operand is representable in the given basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+	assert(x.mode == constant)
+	if !representableConst(x.val, check.conf, typ.kind, &x.val) {
+		var msg string
+		if isNumeric(x.typ) && isNumeric(typ) {
+			// numeric conversion : error msg
+			//
+			// integer -> integer : overflows
+			// integer -> float   : overflows (actually not possible)
+			// float   -> integer : truncated
+			// float   -> float   : overflows
+			//
+			if !isInteger(x.typ) && isInteger(typ) {
+				msg = "%s truncated to %s"
+			} else {
+				msg = "%s overflows %s"
+			}
+		} else {
+			msg = "cannot convert %s to %s"
+		}
+		check.errorf(x.pos(), msg, x, typ)
+		x.mode = invalid
+	}
+}
+
+// updateExprType updates the type of x to typ and invokes itself
+// recursively for the operands of x, depending on expression kind.
+// If typ is still an untyped and not the final type, updateExprType
+// only updates the recorded untyped type for x and possibly its
+// operands. Otherwise (i.e., typ is not an untyped type anymore,
+// or it is the final type for x), the type and value are recorded.
+// Also, if x is a constant, it must be representable as a value of typ,
+// and if x is the (formerly untyped) lhs operand of a non-constant
+// shift, it must be an integer value.
+//
+func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
+	old, found := check.untyped[x]
+	if !found {
+		return // nothing to do
+	}
+
+	// update operands of x if necessary
+	switch x := x.(type) {
+	case *ast.BadExpr,
+		*ast.FuncLit,
+		*ast.CompositeLit,
+		*ast.IndexExpr,
+		*ast.SliceExpr,
+		*ast.TypeAssertExpr,
+		*ast.StarExpr,
+		*ast.KeyValueExpr,
+		*ast.ArrayType,
+		*ast.StructType,
+		*ast.FuncType,
+		*ast.InterfaceType,
+		*ast.MapType,
+		*ast.ChanType:
+		// These expression are never untyped - nothing to do.
+		// The respective sub-expressions got their final types
+		// upon assignment or use.
+		if debug {
+			check.dump("%s: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
+			unreachable()
+		}
+		return
+
+	case *ast.CallExpr:
+		// Resulting in an untyped constant (e.g., built-in complex).
+		// The respective calls take care of calling updateExprType
+		// for the arguments if necessary.
+
+	case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
+		// An identifier denoting a constant, a constant literal,
+		// or a qualified identifier (imported untyped constant).
+		// No operands to take care of.
+
+	case *ast.ParenExpr:
+		check.updateExprType(x.X, typ, final)
+
+	case *ast.UnaryExpr:
+		// If x is a constant, the operands were constants.
+		// They don't need to be updated since they never
+		// get "materialized" into a typed value; and they
+		// will be processed at the end of the type check.
+		if old.val != nil {
+			break
+		}
+		check.updateExprType(x.X, typ, final)
+
+	case *ast.BinaryExpr:
+		if old.val != nil {
+			break // see comment for unary expressions
+		}
+		if isComparison(x.Op) {
+			// The result type is independent of operand types
+			// and the operand types must have final types.
+		} else if isShift(x.Op) {
+			// The result type depends only on lhs operand.
+			// The rhs type was updated when checking the shift.
+			check.updateExprType(x.X, typ, final)
+		} else {
+			// The operand types match the result type.
+			check.updateExprType(x.X, typ, final)
+			check.updateExprType(x.Y, typ, final)
+		}
+
+	default:
+		unreachable()
+	}
+
+	// If the new type is not final and still untyped, just
+	// update the recorded type.
+	if !final && isUntyped(typ) {
+		old.typ = typ.Underlying().(*Basic)
+		check.untyped[x] = old
+		return
+	}
+
+	// Otherwise we have the final (typed or untyped type).
+	// Remove it from the map of yet untyped expressions.
+	delete(check.untyped, x)
+
+	// If x is the lhs of a shift, its final type must be integer.
+	// We already know from the shift check that it is representable
+	// as an integer if it is a constant.
+	if old.isLhs && !isInteger(typ) {
+		check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+		return
+	}
+
+	// Everything's fine, record final type and value for x.
+	check.recordTypeAndValue(x, old.mode, typ, old.val)
+}
+
+// updateExprVal updates the value of x to val.
+func (check *Checker) updateExprVal(x ast.Expr, val exact.Value) {
+	if info, ok := check.untyped[x]; ok {
+		info.val = val
+		check.untyped[x] = info
+	}
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+	if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+		return
+	}
+
+	// TODO(gri) Sloppy code - clean up. This function is central
+	//           to assignment and expression checking.
+
+	if isUntyped(target) {
+		// both x and target are untyped
+		xkind := x.typ.(*Basic).kind
+		tkind := target.(*Basic).kind
+		if isNumeric(x.typ) && isNumeric(target) {
+			if xkind < tkind {
+				x.typ = target
+				check.updateExprType(x.expr, target, false)
+			}
+		} else if xkind != tkind {
+			goto Error
+		}
+		return
+	}
+
+	// typed target
+	switch t := target.Underlying().(type) {
+	case *Basic:
+		if x.mode == constant {
+			check.representable(x, t)
+			if x.mode == invalid {
+				return
+			}
+			// expression value may have been rounded - update if needed
+			// TODO(gri) A floating-point value may silently underflow to
+			// zero. If it was negative, the sign is lost. See issue 6898.
+			check.updateExprVal(x.expr, x.val)
+		} else {
+			// Non-constant untyped values may appear as the
+			// result of comparisons (untyped bool), intermediate
+			// (delayed-checked) rhs operands of shifts, and as
+			// the value nil.
+			switch x.typ.(*Basic).kind {
+			case UntypedBool:
+				if !isBoolean(target) {
+					goto Error
+				}
+			case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
+				if !isNumeric(target) {
+					goto Error
+				}
+			case UntypedString:
+				// Non-constant untyped string values are not
+				// permitted by the spec and should not occur.
+				unreachable()
+			case UntypedNil:
+				// Unsafe.Pointer is a basic type that includes nil.
+				if !hasNil(target) {
+					goto Error
+				}
+			default:
+				goto Error
+			}
+		}
+	case *Interface:
+		if !x.isNil() && !t.Empty() /* empty interfaces are ok */ {
+			goto Error
+		}
+		// Update operand types to the default type rather then
+		// the target (interface) type: values must have concrete
+		// dynamic types. If the value is nil, keep it untyped
+		// (this is important for tools such as go vet which need
+		// the dynamic type for argument checking of say, print
+		// functions)
+		if x.isNil() {
+			target = Typ[UntypedNil]
+		} else {
+			// cannot assign untyped values to non-empty interfaces
+			if !t.Empty() {
+				goto Error
+			}
+			target = defaultType(x.typ)
+		}
+	case *Pointer, *Signature, *Slice, *Map, *Chan:
+		if !x.isNil() {
+			goto Error
+		}
+		// keep nil untyped - see comment for interfaces, above
+		target = Typ[UntypedNil]
+	default:
+		goto Error
+	}
+
+	x.typ = target
+	check.updateExprType(x.expr, target, true) // UntypedNils are final
+	return
+
+Error:
+	check.errorf(x.pos(), "cannot convert %s to %s", x, target)
+	x.mode = invalid
+}
+
+func (check *Checker) comparison(x, y *operand, op token.Token) {
+	// spec: "In any comparison, the first operand must be assignable
+	// to the type of the second operand, or vice versa."
+	err := ""
+	if x.assignableTo(check.conf, y.typ) || y.assignableTo(check.conf, x.typ) {
+		defined := false
+		switch op {
+		case token.EQL, token.NEQ:
+			// spec: "The equality operators == and != apply to operands that are comparable."
+			defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
+		case token.LSS, token.LEQ, token.GTR, token.GEQ:
+			// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
+			defined = isOrdered(x.typ)
+		default:
+			unreachable()
+		}
+		if !defined {
+			typ := x.typ
+			if x.isNil() {
+				typ = y.typ
+			}
+			err = check.sprintf("operator %s not defined for %s", op, typ)
+		}
+	} else {
+		err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+	}
+
+	if err != "" {
+		check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant && y.mode == constant {
+		x.val = exact.MakeBool(exact.Compare(x.val, op, y.val))
+		// The operands are never materialized; no need to update
+		// their types.
+	} else {
+		x.mode = value
+		// The operands have now their final types, which at run-
+		// time will be materialized. Update the expression trees.
+		// If the current types are untyped, the materialized type
+		// is the respective default type.
+		check.updateExprType(x.expr, defaultType(x.typ), true)
+		check.updateExprType(y.expr, defaultType(y.typ), true)
+	}
+
+	// spec: "Comparison operators compare two operands and yield
+	//        an untyped boolean value."
+	x.typ = Typ[UntypedBool]
+}
+
+func (check *Checker) shift(x, y *operand, op token.Token) {
+	untypedx := isUntyped(x.typ)
+
+	// The lhs must be of integer type or be representable
+	// as an integer; otherwise the shift has no chance.
+	if !isInteger(x.typ) && (!untypedx || !representableConst(x.val, nil, UntypedInt, nil)) {
+		check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+		x.mode = invalid
+		return
+	}
+
+	// spec: "The right operand in a shift expression must have unsigned
+	// integer type or be an untyped constant that can be converted to
+	// unsigned integer type."
+	switch {
+	case isInteger(y.typ) && isUnsigned(y.typ):
+		// nothing to do
+	case isUntyped(y.typ):
+		check.convertUntyped(y, Typ[UntypedInt])
+		if y.mode == invalid {
+			x.mode = invalid
+			return
+		}
+	default:
+		check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant {
+		if y.mode == constant {
+			// rhs must be within reasonable bounds
+			const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
+			s, ok := exact.Uint64Val(y.val)
+			if !ok || s > stupidShift {
+				check.invalidOp(y.pos(), "stupid shift count %s", y)
+				x.mode = invalid
+				return
+			}
+			// The lhs is representable as an integer but may not be an integer
+			// (e.g., 2.0, an untyped float) - this can only happen for untyped
+			// non-integer numeric constants. Correct the type so that the shift
+			// result is of integer type.
+			if !isInteger(x.typ) {
+				x.typ = Typ[UntypedInt]
+			}
+			x.val = exact.Shift(x.val, op, uint(s))
+			return
+		}
+
+		// non-constant shift with constant lhs
+		if untypedx {
+			// spec: "If the left operand of a non-constant shift
+			// expression is an untyped constant, the type of the
+			// constant is what it would be if the shift expression
+			// were replaced by its left operand alone.".
+			//
+			// Delay operand checking until we know the final type:
+			// The lhs expression must be in the untyped map, mark
+			// the entry as lhs shift operand.
+			info, found := check.untyped[x.expr]
+			assert(found)
+			info.isLhs = true
+			check.untyped[x.expr] = info
+			// keep x's type
+			x.mode = value
+			return
+		}
+	}
+
+	// constant rhs must be >= 0
+	if y.mode == constant && exact.Sign(y.val) < 0 {
+		check.invalidOp(y.pos(), "shift count %s must not be negative", y)
+	}
+
+	// non-constant shift - lhs must be an integer
+	if !isInteger(x.typ) {
+		check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+		x.mode = invalid
+		return
+	}
+
+	x.mode = value
+}
+
+var binaryOpPredicates = opPredicates{
+	token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
+	token.SUB: isNumeric,
+	token.MUL: isNumeric,
+	token.QUO: isNumeric,
+	token.REM: isInteger,
+
+	token.AND:     isInteger,
+	token.OR:      isInteger,
+	token.XOR:     isInteger,
+	token.AND_NOT: isInteger,
+
+	token.LAND: isBoolean,
+	token.LOR:  isBoolean,
+}
+
+func (check *Checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token) {
+	var y operand
+
+	check.expr(x, lhs)
+	check.expr(&y, rhs)
+
+	if x.mode == invalid {
+		return
+	}
+	if y.mode == invalid {
+		x.mode = invalid
+		x.expr = y.expr
+		return
+	}
+
+	if isShift(op) {
+		check.shift(x, &y, op)
+		return
+	}
+
+	check.convertUntyped(x, y.typ)
+	if x.mode == invalid {
+		return
+	}
+	check.convertUntyped(&y, x.typ)
+	if y.mode == invalid {
+		x.mode = invalid
+		return
+	}
+
+	if isComparison(op) {
+		check.comparison(x, &y, op)
+		return
+	}
+
+	if !Identical(x.typ, y.typ) {
+		// only report an error if we have valid types
+		// (otherwise we had an error reported elsewhere already)
+		if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+			check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+		}
+		x.mode = invalid
+		return
+	}
+
+	if !check.op(binaryOpPredicates, x, op) {
+		x.mode = invalid
+		return
+	}
+
+	if (op == token.QUO || op == token.REM) && (x.mode == constant || isInteger(x.typ)) && y.mode == constant && exact.Sign(y.val) == 0 {
+		check.invalidOp(y.pos(), "division by zero")
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant && y.mode == constant {
+		typ := x.typ.Underlying().(*Basic)
+		// force integer division of integer operands
+		if op == token.QUO && isInteger(typ) {
+			op = token.QUO_ASSIGN
+		}
+		x.val = exact.BinaryOp(x.val, op, y.val)
+		// Typed constants must be representable in
+		// their type after each constant operation.
+		if isTyped(typ) {
+			check.representable(x, typ)
+		}
+		return
+	}
+
+	x.mode = value
+	// x.typ is unchanged
+}
+
+// index checks an index expression for validity.
+// If max >= 0, it is the upper bound for index.
+// If index is valid and the result i >= 0, then i is the constant value of index.
+func (check *Checker) index(index ast.Expr, max int64) (i int64, valid bool) {
+	var x operand
+	check.expr(&x, index)
+	if x.mode == invalid {
+		return
+	}
+
+	// an untyped constant must be representable as Int
+	check.convertUntyped(&x, Typ[Int])
+	if x.mode == invalid {
+		return
+	}
+
+	// the index must be of integer type
+	if !isInteger(x.typ) {
+		check.invalidArg(x.pos(), "index %s must be integer", &x)
+		return
+	}
+
+	// a constant index i must be in bounds
+	if x.mode == constant {
+		if exact.Sign(x.val) < 0 {
+			check.invalidArg(x.pos(), "index %s must not be negative", &x)
+			return
+		}
+		i, valid = exact.Int64Val(x.val)
+		if !valid || max >= 0 && i >= max {
+			check.errorf(x.pos(), "index %s is out of bounds", &x)
+			return i, false
+		}
+		// 0 <= i [ && i < max ]
+		return i, true
+	}
+
+	return -1, true
+}
+
+// indexElts checks the elements (elts) of an array or slice composite literal
+// against the literal's element type (typ), and the element indices against
+// the literal length if known (length >= 0). It returns the length of the
+// literal (maximum index value + 1).
+//
+func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 {
+	visited := make(map[int64]bool, len(elts))
+	var index, max int64
+	for _, e := range elts {
+		// determine and check index
+		validIndex := false
+		eval := e
+		if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+			if i, ok := check.index(kv.Key, length); ok {
+				if i >= 0 {
+					index = i
+					validIndex = true
+				} else {
+					check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
+				}
+			}
+			eval = kv.Value
+		} else if length >= 0 && index >= length {
+			check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
+		} else {
+			validIndex = true
+		}
+
+		// if we have a valid index, check for duplicate entries
+		if validIndex {
+			if visited[index] {
+				check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
+			}
+			visited[index] = true
+		}
+		index++
+		if index > max {
+			max = index
+		}
+
+		// check element against composite literal element type
+		var x operand
+		check.exprWithHint(&x, eval, typ)
+		if !check.assignment(&x, typ) && x.mode != invalid {
+			check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
+		}
+	}
+	return max
+}
+
+// exprKind describes the kind of an expression; the kind
+// determines if an expression is valid in 'statement context'.
+type exprKind int
+
+const (
+	conversion exprKind = iota
+	expression
+	statement
+)
+
+// rawExpr typechecks expression e and initializes x with the expression
+// value or type. If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
+	if trace {
+		check.trace(e.Pos(), "%s", e)
+		check.indent++
+		defer func() {
+			check.indent--
+			check.trace(e.Pos(), "=> %s", x)
+		}()
+	}
+
+	kind := check.exprInternal(x, e, hint)
+
+	// convert x into a user-friendly set of values
+	// TODO(gri) this code can be simplified
+	var typ Type
+	var val exact.Value
+	switch x.mode {
+	case invalid:
+		typ = Typ[Invalid]
+	case novalue:
+		typ = (*Tuple)(nil)
+	case constant:
+		typ = x.typ
+		val = x.val
+	default:
+		typ = x.typ
+	}
+	assert(x.expr != nil && typ != nil)
+
+	if isUntyped(typ) {
+		// delay type and value recording until we know the type
+		// or until the end of type checking
+		check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+	} else {
+		check.recordTypeAndValue(e, x.mode, typ, val)
+	}
+
+	return kind
+}
+
+// exprInternal contains the core of type checking of expressions.
+// Must only be called by rawExpr.
+//
+func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
+	// make sure x has a valid state in case of bailout
+	// (was issue 5770)
+	x.mode = invalid
+	x.typ = Typ[Invalid]
+
+	switch e := e.(type) {
+	case *ast.BadExpr:
+		goto Error // error was reported before
+
+	case *ast.Ident:
+		check.ident(x, e, nil, nil)
+
+	case *ast.Ellipsis:
+		// ellipses are handled explicitly where they are legal
+		// (array composite literals and parameter lists)
+		check.error(e.Pos(), "invalid use of '...'")
+		goto Error
+
+	case *ast.BasicLit:
+		x.setConst(e.Kind, e.Value)
+		if x.mode == invalid {
+			check.invalidAST(e.Pos(), "invalid literal %v", e.Value)
+			goto Error
+		}
+
+	case *ast.FuncLit:
+		if sig, ok := check.typ(e.Type).(*Signature); ok {
+			// Anonymous functions are considered part of the
+			// init expression/func declaration which contains
+			// them: use existing package-level declaration info.
+			check.funcBody(check.decl, "", sig, e.Body)
+			x.mode = value
+			x.typ = sig
+		} else {
+			check.invalidAST(e.Pos(), "invalid function literal %s", e)
+			goto Error
+		}
+
+	case *ast.CompositeLit:
+		typ := hint
+		openArray := false
+		if e.Type != nil {
+			// [...]T array types may only appear with composite literals.
+			// Check for them here so we don't have to handle ... in general.
+			typ = nil
+			if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
+				if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
+					// We have an "open" [...]T array type.
+					// Create a new ArrayType with unknown length (-1)
+					// and finish setting it up after analyzing the literal.
+					typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
+					openArray = true
+				}
+			}
+			if typ == nil {
+				typ = check.typ(e.Type)
+			}
+		}
+		if typ == nil {
+			// TODO(gri) provide better error messages depending on context
+			check.error(e.Pos(), "missing type in composite literal")
+			goto Error
+		}
+
+		switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+		case *Struct:
+			if len(e.Elts) == 0 {
+				break
+			}
+			fields := utyp.fields
+			if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
+				// all elements must have keys
+				visited := make([]bool, len(fields))
+				for _, e := range e.Elts {
+					kv, _ := e.(*ast.KeyValueExpr)
+					if kv == nil {
+						check.error(e.Pos(), "mixture of field:value and value elements in struct literal")
+						continue
+					}
+					key, _ := kv.Key.(*ast.Ident)
+					if key == nil {
+						check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
+						continue
+					}
+					i := fieldIndex(utyp.fields, check.pkg, key.Name)
+					if i < 0 {
+						check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
+						continue
+					}
+					fld := fields[i]
+					check.recordUse(key, fld)
+					// 0 <= i < len(fields)
+					if visited[i] {
+						check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
+						continue
+					}
+					visited[i] = true
+					check.expr(x, kv.Value)
+					etyp := fld.typ
+					if !check.assignment(x, etyp) {
+						if x.mode != invalid {
+							check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+						}
+						continue
+					}
+				}
+			} else {
+				// no element must have a key
+				for i, e := range e.Elts {
+					if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+						check.error(kv.Pos(), "mixture of field:value and value elements in struct literal")
+						continue
+					}
+					check.expr(x, e)
+					if i >= len(fields) {
+						check.error(x.pos(), "too many values in struct literal")
+						break // cannot continue
+					}
+					// i < len(fields)
+					fld := fields[i]
+					if !fld.Exported() && fld.pkg != check.pkg {
+						check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+						continue
+					}
+					etyp := fld.typ
+					if !check.assignment(x, etyp) {
+						if x.mode != invalid {
+							check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+						}
+						continue
+					}
+				}
+				if len(e.Elts) < len(fields) {
+					check.error(e.Rbrace, "too few values in struct literal")
+					// ok to continue
+				}
+			}
+
+		case *Array:
+			n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
+			// if we have an "open" [...]T array, set the length now that we know it
+			if openArray {
+				utyp.len = n
+			}
+
+		case *Slice:
+			check.indexedElts(e.Elts, utyp.elem, -1)
+
+		case *Map:
+			visited := make(map[interface{}][]Type, len(e.Elts))
+			for _, e := range e.Elts {
+				kv, _ := e.(*ast.KeyValueExpr)
+				if kv == nil {
+					check.error(e.Pos(), "missing key in map literal")
+					continue
+				}
+				check.exprWithHint(x, kv.Key, utyp.key)
+				if !check.assignment(x, utyp.key) {
+					if x.mode != invalid {
+						check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key)
+					}
+					continue
+				}
+				if x.mode == constant {
+					duplicate := false
+					// if the key is of interface type, the type is also significant when checking for duplicates
+					if _, ok := utyp.key.Underlying().(*Interface); ok {
+						for _, vtyp := range visited[x.val] {
+							if Identical(vtyp, x.typ) {
+								duplicate = true
+								break
+							}
+						}
+						visited[x.val] = append(visited[x.val], x.typ)
+					} else {
+						_, duplicate = visited[x.val]
+						visited[x.val] = nil
+					}
+					if duplicate {
+						check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
+						continue
+					}
+				}
+				check.exprWithHint(x, kv.Value, utyp.elem)
+				if !check.assignment(x, utyp.elem) {
+					if x.mode != invalid {
+						check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elem)
+					}
+					continue
+				}
+			}
+
+		default:
+			// if utyp is invalid, an error was reported before
+			if utyp != Typ[Invalid] {
+				check.errorf(e.Pos(), "invalid composite literal type %s", typ)
+				goto Error
+			}
+		}
+
+		x.mode = value
+		x.typ = typ
+
+	case *ast.ParenExpr:
+		kind := check.rawExpr(x, e.X, nil)
+		x.expr = e
+		return kind
+
+	case *ast.SelectorExpr:
+		check.selector(x, e)
+
+	case *ast.IndexExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+
+		valid := false
+		length := int64(-1) // valid if >= 0
+		switch typ := x.typ.Underlying().(type) {
+		case *Basic:
+			if isString(typ) {
+				valid = true
+				if x.mode == constant {
+					length = int64(len(exact.StringVal(x.val)))
+				}
+				// an indexed string always yields a byte value
+				// (not a constant) even if the string and the
+				// index are constant
+				x.mode = value
+				x.typ = UniverseByte // use 'byte' name
+			}
+
+		case *Array:
+			valid = true
+			length = typ.len
+			if x.mode != variable {
+				x.mode = value
+			}
+			x.typ = typ.elem
+
+		case *Pointer:
+			if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+				valid = true
+				length = typ.len
+				x.mode = variable
+				x.typ = typ.elem
+			}
+
+		case *Slice:
+			valid = true
+			x.mode = variable
+			x.typ = typ.elem
+
+		case *Map:
+			var key operand
+			check.expr(&key, e.Index)
+			if !check.assignment(&key, typ.key) {
+				if key.mode != invalid {
+					check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key)
+				}
+				goto Error
+			}
+			x.mode = mapindex
+			x.typ = typ.elem
+			x.expr = e
+			return expression
+		}
+
+		if !valid {
+			check.invalidOp(x.pos(), "cannot index %s", x)
+			goto Error
+		}
+
+		if e.Index == nil {
+			check.invalidAST(e.Pos(), "missing index for %s", x)
+			goto Error
+		}
+
+		check.index(e.Index, length)
+		// ok to continue
+
+	case *ast.SliceExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+
+		valid := false
+		length := int64(-1) // valid if >= 0
+		switch typ := x.typ.Underlying().(type) {
+		case *Basic:
+			if isString(typ) {
+				if slice3(e) {
+					check.invalidOp(x.pos(), "3-index slice of string")
+					goto Error
+				}
+				valid = true
+				if x.mode == constant {
+					length = int64(len(exact.StringVal(x.val)))
+				}
+				// spec: "For untyped string operands the result
+				// is a non-constant value of type string."
+				if typ.kind == UntypedString {
+					x.typ = Typ[String]
+				}
+			}
+
+		case *Array:
+			valid = true
+			length = typ.len
+			if x.mode != variable {
+				check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
+				goto Error
+			}
+			x.typ = &Slice{elem: typ.elem}
+
+		case *Pointer:
+			if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+				valid = true
+				length = typ.len
+				x.typ = &Slice{elem: typ.elem}
+			}
+
+		case *Slice:
+			valid = true
+			// x.typ doesn't change
+		}
+
+		if !valid {
+			check.invalidOp(x.pos(), "cannot slice %s", x)
+			goto Error
+		}
+
+		x.mode = value
+
+		// spec: "Only the first index may be omitted; it defaults to 0."
+		if slice3(e) && (e.High == nil || sliceMax(e) == nil) {
+			check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
+			goto Error
+		}
+
+		// check indices
+		var ind [3]int64
+		for i, expr := range []ast.Expr{e.Low, e.High, sliceMax(e)} {
+			x := int64(-1)
+			switch {
+			case expr != nil:
+				// The "capacity" is only known statically for strings, arrays,
+				// and pointers to arrays, and it is the same as the length for
+				// those types.
+				max := int64(-1)
+				if length >= 0 {
+					max = length + 1
+				}
+				if t, ok := check.index(expr, max); ok && t >= 0 {
+					x = t
+				}
+			case i == 0:
+				// default is 0 for the first index
+				x = 0
+			case length >= 0:
+				// default is length (== capacity) otherwise
+				x = length
+			}
+			ind[i] = x
+		}
+
+		// constant indices must be in range
+		// (check.index already checks that existing indices >= 0)
+	L:
+		for i, x := range ind[:len(ind)-1] {
+			if x > 0 {
+				for _, y := range ind[i+1:] {
+					if y >= 0 && x > y {
+						check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
+						break L // only report one error, ok to continue
+					}
+				}
+			}
+		}
+
+	case *ast.TypeAssertExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+		xtyp, _ := x.typ.Underlying().(*Interface)
+		if xtyp == nil {
+			check.invalidOp(x.pos(), "%s is not an interface", x)
+			goto Error
+		}
+		// x.(type) expressions are handled explicitly in type switches
+		if e.Type == nil {
+			check.invalidAST(e.Pos(), "use of .(type) outside type switch")
+			goto Error
+		}
+		T := check.typ(e.Type)
+		if T == Typ[Invalid] {
+			goto Error
+		}
+		check.typeAssertion(x.pos(), x, xtyp, T)
+		x.mode = commaok
+		x.typ = T
+
+	case *ast.CallExpr:
+		return check.call(x, e)
+
+	case *ast.StarExpr:
+		check.exprOrType(x, e.X)
+		switch x.mode {
+		case invalid:
+			goto Error
+		case typexpr:
+			x.typ = &Pointer{base: x.typ}
+		default:
+			if typ, ok := x.typ.Underlying().(*Pointer); ok {
+				x.mode = variable
+				x.typ = typ.base
+			} else {
+				check.invalidOp(x.pos(), "cannot indirect %s", x)
+				goto Error
+			}
+		}
+
+	case *ast.UnaryExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+		check.unary(x, e.Op)
+		if x.mode == invalid {
+			goto Error
+		}
+		if e.Op == token.ARROW {
+			x.expr = e
+			return statement // receive operations may appear in statement context
+		}
+
+	case *ast.BinaryExpr:
+		check.binary(x, e.X, e.Y, e.Op)
+		if x.mode == invalid {
+			goto Error
+		}
+
+	case *ast.KeyValueExpr:
+		// key:value expressions are handled in composite literals
+		check.invalidAST(e.Pos(), "no key:value expected")
+		goto Error
+
+	case *ast.ArrayType, *ast.StructType, *ast.FuncType,
+		*ast.InterfaceType, *ast.MapType, *ast.ChanType:
+		x.mode = typexpr
+		x.typ = check.typ(e)
+		// Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
+		// even though check.typ has already called it. This is fine as both
+		// times the same expression and type are recorded. It is also not a
+		// performance issue because we only reach here for composite literal
+		// types, which are comparatively rare.
+
+	default:
+		panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e))
+	}
+
+	// everything went well
+	x.expr = e
+	return expression
+
+Error:
+	x.mode = invalid
+	x.expr = e
+	return statement // avoid follow-up errors
+}
+
+// typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
+func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) {
+	method, wrongType := assertableTo(xtyp, T)
+	if method == nil {
+		return
+	}
+
+	var msg string
+	if wrongType {
+		msg = "wrong type for method"
+	} else {
+		msg = "missing method"
+	}
+	check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name)
+}
+
+// expr typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) expr(x *operand, e ast.Expr) {
+	check.rawExpr(x, e, nil)
+	var msg string
+	switch x.mode {
+	default:
+		return
+	case novalue:
+		msg = "used as value"
+	case builtin:
+		msg = "must be called"
+	case typexpr:
+		msg = "is not an expression"
+	}
+	check.errorf(x.pos(), "%s %s", x, msg)
+	x.mode = invalid
+}
+
+// exprWithHint typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
+	assert(hint != nil)
+	check.rawExpr(x, e, hint)
+	var msg string
+	switch x.mode {
+	default:
+		return
+	case novalue:
+		msg = "used as value"
+	case builtin:
+		msg = "must be called"
+	case typexpr:
+		msg = "is not an expression"
+	}
+	check.errorf(x.pos(), "%s %s", x, msg)
+	x.mode = invalid
+}
+
+// exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) exprOrType(x *operand, e ast.Expr) {
+	check.rawExpr(x, e, nil)
+	if x.mode == novalue {
+		check.errorf(x.pos(), "%s used as value or type", x)
+		x.mode = invalid
+	}
+}
diff --git a/src/go/types/exprstring.go b/src/go/types/exprstring.go
new file mode 100644
index 0000000..370bdf3
--- /dev/null
+++ b/src/go/types/exprstring.go
@@ -0,0 +1,220 @@
+// Copyright 2013 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.
+
+// This file implements printing of expressions.
+
+package types
+
+import (
+	"bytes"
+	"go/ast"
+)
+
+// ExprString returns the (possibly simplified) string representation for x.
+func ExprString(x ast.Expr) string {
+	var buf bytes.Buffer
+	WriteExpr(&buf, x)
+	return buf.String()
+}
+
+// WriteExpr writes the (possibly simplified) string representation for x to buf.
+func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
+	// The AST preserves source-level parentheses so there is
+	// no need to introduce them here to correct for different
+	// operator precedences. (This assumes that the AST was
+	// generated by a Go parser.)
+
+	switch x := x.(type) {
+	default:
+		buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
+
+	case *ast.Ident:
+		buf.WriteString(x.Name)
+
+	case *ast.Ellipsis:
+		buf.WriteString("...")
+		if x.Elt != nil {
+			WriteExpr(buf, x.Elt)
+		}
+
+	case *ast.BasicLit:
+		buf.WriteString(x.Value)
+
+	case *ast.FuncLit:
+		buf.WriteByte('(')
+		WriteExpr(buf, x.Type)
+		buf.WriteString(" literal)") // simplified
+
+	case *ast.CompositeLit:
+		buf.WriteByte('(')
+		WriteExpr(buf, x.Type)
+		buf.WriteString(" literal)") // simplified
+
+	case *ast.ParenExpr:
+		buf.WriteByte('(')
+		WriteExpr(buf, x.X)
+		buf.WriteByte(')')
+
+	case *ast.SelectorExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte('.')
+		buf.WriteString(x.Sel.Name)
+
+	case *ast.IndexExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte('[')
+		WriteExpr(buf, x.Index)
+		buf.WriteByte(']')
+
+	case *ast.SliceExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte('[')
+		if x.Low != nil {
+			WriteExpr(buf, x.Low)
+		}
+		buf.WriteByte(':')
+		if x.High != nil {
+			WriteExpr(buf, x.High)
+		}
+		if x.Slice3 {
+			buf.WriteByte(':')
+			if x.Max != nil {
+				WriteExpr(buf, x.Max)
+			}
+		}
+		buf.WriteByte(']')
+
+	case *ast.TypeAssertExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteString(".(")
+		WriteExpr(buf, x.Type)
+		buf.WriteByte(')')
+
+	case *ast.CallExpr:
+		WriteExpr(buf, x.Fun)
+		buf.WriteByte('(')
+		for i, arg := range x.Args {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			WriteExpr(buf, arg)
+		}
+		if x.Ellipsis.IsValid() {
+			buf.WriteString("...")
+		}
+		buf.WriteByte(')')
+
+	case *ast.StarExpr:
+		buf.WriteByte('*')
+		WriteExpr(buf, x.X)
+
+	case *ast.UnaryExpr:
+		buf.WriteString(x.Op.String())
+		WriteExpr(buf, x.X)
+
+	case *ast.BinaryExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte(' ')
+		buf.WriteString(x.Op.String())
+		buf.WriteByte(' ')
+		WriteExpr(buf, x.Y)
+
+	case *ast.ArrayType:
+		buf.WriteByte('[')
+		if x.Len != nil {
+			WriteExpr(buf, x.Len)
+		}
+		buf.WriteByte(']')
+		WriteExpr(buf, x.Elt)
+
+	case *ast.StructType:
+		buf.WriteString("struct{")
+		writeFieldList(buf, x.Fields, "; ", false)
+		buf.WriteByte('}')
+
+	case *ast.FuncType:
+		buf.WriteString("func")
+		writeSigExpr(buf, x)
+
+	case *ast.InterfaceType:
+		buf.WriteString("interface{")
+		writeFieldList(buf, x.Methods, "; ", true)
+		buf.WriteByte('}')
+
+	case *ast.MapType:
+		buf.WriteString("map[")
+		WriteExpr(buf, x.Key)
+		buf.WriteByte(']')
+		WriteExpr(buf, x.Value)
+
+	case *ast.ChanType:
+		var s string
+		switch x.Dir {
+		case ast.SEND:
+			s = "chan<- "
+		case ast.RECV:
+			s = "<-chan "
+		default:
+			s = "chan "
+		}
+		buf.WriteString(s)
+		WriteExpr(buf, x.Value)
+	}
+}
+
+func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
+	buf.WriteByte('(')
+	writeFieldList(buf, sig.Params, ", ", false)
+	buf.WriteByte(')')
+
+	res := sig.Results
+	n := res.NumFields()
+	if n == 0 {
+		// no result
+		return
+	}
+
+	buf.WriteByte(' ')
+	if n == 1 && len(res.List[0].Names) == 0 {
+		// single unnamed result
+		WriteExpr(buf, res.List[0].Type)
+		return
+	}
+
+	// multiple or named result(s)
+	buf.WriteByte('(')
+	writeFieldList(buf, res, ", ", false)
+	buf.WriteByte(')')
+}
+
+func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
+	for i, f := range fields.List {
+		if i > 0 {
+			buf.WriteString(sep)
+		}
+
+		// field list names
+		for i, name := range f.Names {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(name.Name)
+		}
+
+		// types of interface methods consist of signatures only
+		if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
+			writeSigExpr(buf, sig)
+			continue
+		}
+
+		// named fields are separated with a blank from the field type
+		if len(f.Names) > 0 {
+			buf.WriteByte(' ')
+		}
+
+		WriteExpr(buf, f.Type)
+
+		// ignore tag
+	}
+}
diff --git a/src/go/types/exprstring_test.go b/src/go/types/exprstring_test.go
new file mode 100644
index 0000000..5110288
--- /dev/null
+++ b/src/go/types/exprstring_test.go
@@ -0,0 +1,94 @@
+// Copyright 2013 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 types_test
+
+import (
+	"go/parser"
+	"testing"
+
+	. "go/types"
+)
+
+var testExprs = []testEntry{
+	// basic type literals
+	dup("x"),
+	dup("true"),
+	dup("42"),
+	dup("3.1415"),
+	dup("2.71828i"),
+	dup(`'a'`),
+	dup(`"foo"`),
+	dup("`bar`"),
+
+	// func and composite literals
+	{"func(){}", "(func() literal)"},
+	{"func(x int) complex128 {}", "(func(x int) complex128 literal)"},
+	{"[]int{1, 2, 3}", "([]int literal)"},
+
+	// non-type expressions
+	dup("(x)"),
+	dup("x.f"),
+	dup("a[i]"),
+
+	dup("s[:]"),
+	dup("s[i:]"),
+	dup("s[:j]"),
+	dup("s[i:j]"),
+	dup("s[:j:k]"),
+	dup("s[i:j:k]"),
+
+	dup("x.(T)"),
+
+	dup("x.([10]int)"),
+	dup("x.([...]int)"),
+
+	dup("x.(struct{})"),
+	dup("x.(struct{x int; y, z float32; E})"),
+
+	dup("x.(func())"),
+	dup("x.(func(x int))"),
+	dup("x.(func() int)"),
+	dup("x.(func(x, y int, z float32) (r int))"),
+	dup("x.(func(a, b, c int))"),
+	dup("x.(func(x ...T))"),
+
+	dup("x.(interface{})"),
+	dup("x.(interface{m(); n(x int); E})"),
+	dup("x.(interface{m(); n(x int) T; E; F})"),
+
+	dup("x.(map[K]V)"),
+
+	dup("x.(chan E)"),
+	dup("x.(<-chan E)"),
+	dup("x.(chan<- chan int)"),
+	dup("x.(chan<- <-chan int)"),
+	dup("x.(<-chan chan int)"),
+	dup("x.(chan (<-chan int))"),
+
+	dup("f()"),
+	dup("f(x)"),
+	dup("int(x)"),
+	dup("f(x, x + y)"),
+	dup("f(s...)"),
+	dup("f(a, s...)"),
+
+	dup("*x"),
+	dup("&x"),
+	dup("x + y"),
+	dup("x + y << (2 * s)"),
+}
+
+func TestExprString(t *testing.T) {
+	for _, test := range testExprs {
+		x, err := parser.ParseExpr(test.src)
+		if err != nil {
+			t.Errorf("%s: %s", test.src, err)
+			continue
+		}
+		if got := ExprString(x); got != test.str {
+			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+		}
+	}
+}
diff --git a/src/go/types/go11.go b/src/go/types/go11.go
new file mode 100644
index 0000000..cf41cab
--- /dev/null
+++ b/src/go/types/go11.go
@@ -0,0 +1,17 @@
+// Copyright 2013 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 !go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+	return false
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+	return nil
+}
diff --git a/src/go/types/go12.go b/src/go/types/go12.go
new file mode 100644
index 0000000..2017442
--- /dev/null
+++ b/src/go/types/go12.go
@@ -0,0 +1,17 @@
+// Copyright 2013 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 go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+	return x.Slice3
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+	return x.Max
+}
diff --git a/src/go/types/hilbert_test.go b/src/go/types/hilbert_test.go
new file mode 100644
index 0000000..cfd51b1
--- /dev/null
+++ b/src/go/types/hilbert_test.go
@@ -0,0 +1,234 @@
+// Copyright 2013 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 types_test
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"io/ioutil"
+	"testing"
+
+	. "go/types"
+)
+
+var (
+	H   = flag.Int("H", 5, "Hilbert matrix size")
+	out = flag.String("out", "", "write generated program to out")
+)
+
+func TestHilbert(t *testing.T) {
+	// generate source
+	src := program(*H, *out)
+	if *out != "" {
+		ioutil.WriteFile(*out, src, 0666)
+		return
+	}
+
+	// parse source
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "hilbert.go", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// type-check file
+	DefPredeclaredTestFuncs() // define assert built-in
+	conf := Config{Importer: importer.Default()}
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func program(n int, out string) []byte {
+	var g gen
+
+	g.p(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
+// (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q)
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+	if !ok {
+		printProduct()
+		return
+	}
+	println("PASS")
+}
+
+`, n, out)
+	g.hilbert(n)
+	g.inverse(n)
+	g.product(n)
+	g.verify(n)
+	g.printProduct(n)
+	g.binomials(2*n - 1)
+	g.factorials(2*n - 1)
+
+	return g.Bytes()
+}
+
+type gen struct {
+	bytes.Buffer
+}
+
+func (g *gen) p(format string, args ...interface{}) {
+	fmt.Fprintf(&g.Buffer, format, args...)
+}
+
+func (g *gen) hilbert(n int) {
+	g.p(`// Hilbert matrix, n = %d
+const (
+`, n)
+	for i := 0; i < n; i++ {
+		g.p("\t")
+		for j := 0; j < n; j++ {
+			if j > 0 {
+				g.p(", ")
+			}
+			g.p("h%d_%d", i, j)
+		}
+		if i == 0 {
+			g.p(" = ")
+			for j := 0; j < n; j++ {
+				if j > 0 {
+					g.p(", ")
+				}
+				g.p("1.0/(iota + %d)", j+1)
+			}
+		}
+		g.p("\n")
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) inverse(n int) {
+	g.p(`// Inverse Hilbert matrix
+const (
+`)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			s := "+"
+			if (i+j)&1 != 0 {
+				s = "-"
+			}
+			g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n",
+				i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i)
+		}
+		g.p("\n")
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) product(n int) {
+	g.p(`// Product matrix
+const (
+`)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			g.p("\tp%d_%d = ", i, j)
+			for k := 0; k < n; k++ {
+				if k > 0 {
+					g.p(" + ")
+				}
+				g.p("h%d_%d*i%d_%d", i, k, k, j)
+			}
+			g.p("\n")
+		}
+		g.p("\n")
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) verify(n int) {
+	g.p(`// Verify that product is the identity matrix
+const ok =
+`)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			if j == 0 {
+				g.p("\t")
+			} else {
+				g.p(" && ")
+			}
+			v := 0
+			if i == j {
+				v = 1
+			}
+			g.p("p%d_%d == %d", i, j, v)
+		}
+		g.p(" &&\n")
+	}
+	g.p("\ttrue\n\n")
+
+	// verify ok at type-check time
+	if *out == "" {
+		g.p("const _ = assert(ok)\n\n")
+	}
+}
+
+func (g *gen) printProduct(n int) {
+	g.p("func printProduct() {\n")
+	for i := 0; i < n; i++ {
+		g.p("\tprintln(")
+		for j := 0; j < n; j++ {
+			if j > 0 {
+				g.p(", ")
+			}
+			g.p("p%d_%d", i, j)
+		}
+		g.p(")\n")
+	}
+	g.p("}\n\n")
+}
+
+func (g *gen) mulRange(a, b int) {
+	if a > b {
+		g.p("1")
+		return
+	}
+	for i := a; i <= b; i++ {
+		if i > a {
+			g.p("*")
+		}
+		g.p("%d", i)
+	}
+}
+
+func (g *gen) binomials(n int) {
+	g.p(`// Binomials
+const (
+`)
+	for j := 0; j <= n; j++ {
+		if j > 0 {
+			g.p("\n")
+		}
+		for k := 0; k <= j; k++ {
+			g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k)
+		}
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) factorials(n int) {
+	g.p(`// Factorials
+const (
+	f0 = 1
+	f1 = 1
+`)
+	for i := 2; i <= n; i++ {
+		g.p("\tf%d = f%d * %d\n", i, i-1, i)
+	}
+	g.p(")\n\n")
+}
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
new file mode 100644
index 0000000..0fd567b
--- /dev/null
+++ b/src/go/types/initorder.go
@@ -0,0 +1,222 @@
+// 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.
+
+package types
+
+import (
+	"container/heap"
+	"fmt"
+)
+
+// initOrder computes the Info.InitOrder for package variables.
+func (check *Checker) initOrder() {
+	// An InitOrder may already have been computed if a package is
+	// built from several calls to (*Checker).Files.  Clear it.
+	check.Info.InitOrder = check.Info.InitOrder[:0]
+
+	// compute the object dependency graph and
+	// initialize a priority queue with the list
+	// of graph nodes
+	pq := nodeQueue(dependencyGraph(check.objMap))
+	heap.Init(&pq)
+
+	const debug = false
+	if debug {
+		fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
+		for _, n := range pq {
+			for _, o := range n.out {
+				fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+			}
+		}
+		fmt.Println()
+		fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+	}
+
+	// determine initialization order by removing the highest priority node
+	// (the one with the fewest dependencies) and its edges from the graph,
+	// repeatedly, until there are no nodes left.
+	// In a valid Go program, those nodes always have zero dependencies (after
+	// removing all incoming dependencies), otherwise there are initialization
+	// cycles.
+	mark := 0
+	emitted := make(map[*declInfo]bool)
+	for len(pq) > 0 {
+		// get the next node
+		n := heap.Pop(&pq).(*objNode)
+
+		// if n still depends on other nodes, we have a cycle
+		if n.in > 0 {
+			mark++ // mark nodes using a different value each time
+			cycle := findPath(n, n, mark)
+			if i := valIndex(cycle); i >= 0 {
+				check.reportCycle(cycle, i)
+			}
+			// ok to continue, but the variable initialization order
+			// will be incorrect at this point since it assumes no
+			// cycle errors
+		}
+
+		// reduce dependency count of all dependent nodes
+		// and update priority queue
+		for _, out := range n.out {
+			out.in--
+			heap.Fix(&pq, out.index)
+		}
+
+		// record the init order for variables with initializers only
+		v, _ := n.obj.(*Var)
+		info := check.objMap[v]
+		if v == nil || !info.hasInitializer() {
+			continue
+		}
+
+		// n:1 variable declarations such as: a, b = f()
+		// introduce a node for each lhs variable (here: a, b);
+		// but they all have the same initializer - emit only
+		// one, for the first variable seen
+		if emitted[info] {
+			continue // initializer already emitted, if any
+		}
+		emitted[info] = true
+
+		infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
+		if infoLhs == nil {
+			infoLhs = []*Var{v}
+		}
+		init := &Initializer{infoLhs, info.init}
+		check.Info.InitOrder = append(check.Info.InitOrder, init)
+
+		if debug {
+			fmt.Printf("\t%s\n", init)
+		}
+	}
+
+	if debug {
+		fmt.Println()
+	}
+}
+
+// findPath returns the (reversed) list of nodes z, ... c, b, a,
+// such that there is a path (list of edges) from a to z.
+// If there is no such path, the result is nil.
+// Nodes marked with the value mark are considered "visited";
+// unvisited nodes are marked during the graph search.
+func findPath(a, z *objNode, mark int) []*objNode {
+	if a.mark == mark {
+		return nil // node already seen
+	}
+	a.mark = mark
+
+	for _, n := range a.out {
+		if n == z {
+			return []*objNode{z}
+		}
+		if P := findPath(n, z, mark); P != nil {
+			return append(P, n)
+		}
+	}
+
+	return nil
+}
+
+// valIndex returns the index of the first constant or variable in a,
+// if any; or a value < 0.
+func valIndex(a []*objNode) int {
+	for i, n := range a {
+		switch n.obj.(type) {
+		case *Const, *Var:
+			return i
+		}
+	}
+	return -1
+}
+
+// reportCycle reports an error for the cycle starting at i.
+func (check *Checker) reportCycle(cycle []*objNode, i int) {
+	obj := cycle[i].obj
+	check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
+	// print cycle
+	for _ = range cycle {
+		check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+		i++
+		if i >= len(cycle) {
+			i = 0
+		}
+		obj = cycle[i].obj
+	}
+	check.errorf(obj.Pos(), "\t%s", obj.Name())
+}
+
+// An objNode represents a node in the object dependency graph.
+// Each node b in a.out represents an edge a->b indicating that
+// b depends on a.
+// Nodes may be marked for cycle detection. A node n is marked
+// if n.mark corresponds to the current mark value.
+type objNode struct {
+	obj   Object     // object represented by this node
+	in    int        // number of nodes this node depends on
+	out   []*objNode // list of nodes that depend on this node
+	index int        // node index in list of nodes
+	mark  int        // for cycle detection
+}
+
+// dependencyGraph computes the transposed object dependency graph
+// from the given objMap. The transposed graph is returned as a list
+// of nodes; an edge d->n indicates that node n depends on node d.
+func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
+	// M maps each object to its corresponding node
+	M := make(map[Object]*objNode, len(objMap))
+	for obj := range objMap {
+		M[obj] = &objNode{obj: obj}
+	}
+
+	// G is the graph of nodes n
+	G := make([]*objNode, len(M))
+	i := 0
+	for obj, n := range M {
+		deps := objMap[obj].deps
+		n.in = len(deps)
+		for d := range deps {
+			d := M[d]                // node n depends on node d
+			d.out = append(d.out, n) // add edge d->n
+		}
+
+		G[i] = n
+		n.index = i
+		i++
+	}
+
+	return G
+}
+
+// nodeQueue implements the container/heap interface;
+// a nodeQueue may be used as a priority queue.
+type nodeQueue []*objNode
+
+func (a nodeQueue) Len() int { return len(a) }
+
+func (a nodeQueue) Swap(i, j int) {
+	x, y := a[i], a[j]
+	a[i], a[j] = y, x
+	x.index, y.index = j, i
+}
+
+func (a nodeQueue) Less(i, j int) bool {
+	x, y := a[i], a[j]
+	// nodes are prioritized by number of incoming dependencies (1st key)
+	// and source order (2nd key)
+	return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
+}
+
+func (a *nodeQueue) Push(x interface{}) {
+	panic("unreachable")
+}
+
+func (a *nodeQueue) Pop() interface{} {
+	n := len(*a)
+	x := (*a)[n-1]
+	x.index = -1 // for safety
+	*a = (*a)[:n-1]
+	return x
+}
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
new file mode 100644
index 0000000..672c78d
--- /dev/null
+++ b/src/go/types/issues_test.go
@@ -0,0 +1,206 @@
+// Copyright 2013 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.
+
+// This file implements tests for various issues.
+
+package types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"sort"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+func TestIssue5770(t *testing.T) {
+	src := `package p; type S struct{T}`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	conf := Config{Importer: importer.Default()}
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
+	want := "undeclared name: T"
+	if err == nil || !strings.Contains(err.Error(), want) {
+		t.Errorf("got: %v; want: %s", err, want)
+	}
+}
+
+func TestIssue5849(t *testing.T) {
+	src := `
+package p
+var (
+	s uint
+	_ = uint8(8)
+	_ = uint16(16) << s
+	_ = uint32(32 << s)
+	_ = uint64(64 << s + s)
+	_ = (interface{})("foo")
+	_ = (interface{})(nil)
+)`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var conf Config
+	types := make(map[ast.Expr]TypeAndValue)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for x, tv := range types {
+		var want Type
+		switch x := x.(type) {
+		case *ast.BasicLit:
+			switch x.Value {
+			case `8`:
+				want = Typ[Uint8]
+			case `16`:
+				want = Typ[Uint16]
+			case `32`:
+				want = Typ[Uint32]
+			case `64`:
+				want = Typ[Uint] // because of "+ s", s is of type uint
+			case `"foo"`:
+				want = Typ[String]
+			}
+		case *ast.Ident:
+			if x.Name == "nil" {
+				want = Typ[UntypedNil]
+			}
+		}
+		if want != nil && !Identical(tv.Type, want) {
+			t.Errorf("got %s; want %s", tv.Type, want)
+		}
+	}
+}
+
+func TestIssue6413(t *testing.T) {
+	src := `
+package p
+func f() int {
+	defer f()
+	go f()
+	return 0
+}
+`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var conf Config
+	types := make(map[ast.Expr]TypeAndValue)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := Typ[Int]
+	n := 0
+	for x, tv := range types {
+		if _, ok := x.(*ast.CallExpr); ok {
+			if tv.Type != want {
+				t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
+			}
+			n++
+		}
+	}
+
+	if n != 2 {
+		t.Errorf("got %d CallExprs; want 2", n)
+	}
+}
+
+func TestIssue7245(t *testing.T) {
+	src := `
+package p
+func (T) m() (res bool) { return }
+type T struct{} // receiver type after method declaration
+`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var conf Config
+	defs := make(map[*ast.Ident]Object)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	m := f.Decls[0].(*ast.FuncDecl)
+	res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
+	res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
+
+	if res1 != res2 {
+		t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
+	}
+}
+
+// This tests that uses of existing vars on the LHS of an assignment
+// are Uses, not Defs; and also that the (illegal) use of a non-var on
+// the LHS of an assignment is a Use nonetheless.
+func TestIssue7827(t *testing.T) {
+	const src = `
+package p
+func _() {
+	const w = 1        // defs w
+        x, y := 2, 3       // defs x, y
+        w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
+        _, _, _ = x, y, z  // uses x, y, z
+}
+`
+	const want = `L3 defs func p._()
+L4 defs const w untyped int
+L5 defs var x int
+L5 defs var y int
+L6 defs var z int
+L6 uses const w untyped int
+L6 uses var x int
+L7 uses var x int
+L7 uses var y int
+L7 uses var z int`
+
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// don't abort at the first error
+	conf := Config{Error: func(err error) { t.Log(err) }}
+	defs := make(map[*ast.Ident]Object)
+	uses := make(map[*ast.Ident]Object)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
+	if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
+		t.Errorf("Check: unexpected error: %s", s)
+	}
+
+	var facts []string
+	for id, obj := range defs {
+		if obj != nil {
+			fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
+			facts = append(facts, fact)
+		}
+	}
+	for id, obj := range uses {
+		fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
+		facts = append(facts, fact)
+	}
+	sort.Strings(facts)
+
+	got := strings.Join(facts, "\n")
+	if got != want {
+		t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
diff --git a/src/go/types/labels.go b/src/go/types/labels.go
new file mode 100644
index 0000000..d6ffc52
--- /dev/null
+++ b/src/go/types/labels.go
@@ -0,0 +1,268 @@
+// Copyright 2013 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 types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+// labels checks correct label use in body.
+func (check *Checker) labels(body *ast.BlockStmt) {
+	// set of all labels in this body
+	all := NewScope(nil, "label")
+
+	fwdJumps := check.blockBranches(all, nil, nil, body.List)
+
+	// If there are any forward jumps left, no label was found for
+	// the corresponding goto statements. Either those labels were
+	// never defined, or they are inside blocks and not reachable
+	// for the respective gotos.
+	for _, jmp := range fwdJumps {
+		var msg string
+		name := jmp.Label.Name
+		if alt := all.Lookup(name); alt != nil {
+			msg = "goto %s jumps into block"
+			alt.(*Label).used = true // avoid another error
+		} else {
+			msg = "label %s not declared"
+		}
+		check.errorf(jmp.Label.Pos(), msg, name)
+	}
+
+	// spec: "It is illegal to define a label that is never used."
+	for _, obj := range all.elems {
+		if lbl := obj.(*Label); !lbl.used {
+			check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+		}
+	}
+}
+
+// A block tracks label declarations in a block and its enclosing blocks.
+type block struct {
+	parent *block                      // enclosing block
+	lstmt  *ast.LabeledStmt            // labeled statement to which this block belongs, or nil
+	labels map[string]*ast.LabeledStmt // allocated lazily
+}
+
+// insert records a new label declaration for the current block.
+// The label must not have been declared before in any block.
+func (b *block) insert(s *ast.LabeledStmt) {
+	name := s.Label.Name
+	if debug {
+		assert(b.gotoTarget(name) == nil)
+	}
+	labels := b.labels
+	if labels == nil {
+		labels = make(map[string]*ast.LabeledStmt)
+		b.labels = labels
+	}
+	labels[name] = s
+}
+
+// gotoTarget returns the labeled statement in the current
+// or an enclosing block with the given label name, or nil.
+func (b *block) gotoTarget(name string) *ast.LabeledStmt {
+	for s := b; s != nil; s = s.parent {
+		if t := s.labels[name]; t != nil {
+			return t
+		}
+	}
+	return nil
+}
+
+// enclosingTarget returns the innermost enclosing labeled
+// statement with the given label name, or nil.
+func (b *block) enclosingTarget(name string) *ast.LabeledStmt {
+	for s := b; s != nil; s = s.parent {
+		if t := s.lstmt; t != nil && t.Label.Name == name {
+			return t
+		}
+	}
+	return nil
+}
+
+// blockBranches processes a block's statement list and returns the set of outgoing forward jumps.
+// all is the scope of all declared labels, parent the set of labels declared in the immediately
+// enclosing block, and lstmt is the labeled statement this block is associated with (or nil).
+func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.LabeledStmt, list []ast.Stmt) []*ast.BranchStmt {
+	b := &block{parent: parent, lstmt: lstmt}
+
+	var (
+		varDeclPos         token.Pos
+		fwdJumps, badJumps []*ast.BranchStmt
+	)
+
+	// All forward jumps jumping over a variable declaration are possibly
+	// invalid (they may still jump out of the block and be ok).
+	// recordVarDecl records them for the given position.
+	recordVarDecl := func(pos token.Pos) {
+		varDeclPos = pos
+		badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps
+	}
+
+	jumpsOverVarDecl := func(jmp *ast.BranchStmt) bool {
+		if varDeclPos.IsValid() {
+			for _, bad := range badJumps {
+				if jmp == bad {
+					return true
+				}
+			}
+		}
+		return false
+	}
+
+	blockBranches := func(lstmt *ast.LabeledStmt, list []ast.Stmt) {
+		// Unresolved forward jumps inside the nested block
+		// become forward jumps in the current block.
+		fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...)
+	}
+
+	var stmtBranches func(ast.Stmt)
+	stmtBranches = func(s ast.Stmt) {
+		switch s := s.(type) {
+		case *ast.DeclStmt:
+			if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR {
+				recordVarDecl(d.Pos())
+			}
+
+		case *ast.LabeledStmt:
+			// declare non-blank label
+			if name := s.Label.Name; name != "_" {
+				lbl := NewLabel(s.Label.Pos(), check.pkg, name)
+				if alt := all.Insert(lbl); alt != nil {
+					check.softErrorf(lbl.pos, "label %s already declared", name)
+					check.reportAltDecl(alt)
+					// ok to continue
+				} else {
+					b.insert(s)
+					check.recordDef(s.Label, lbl)
+				}
+				// resolve matching forward jumps and remove them from fwdJumps
+				i := 0
+				for _, jmp := range fwdJumps {
+					if jmp.Label.Name == name {
+						// match
+						lbl.used = true
+						check.recordUse(jmp.Label, lbl)
+						if jumpsOverVarDecl(jmp) {
+							check.softErrorf(
+								jmp.Label.Pos(),
+								"goto %s jumps over variable declaration at line %d",
+								name,
+								check.fset.Position(varDeclPos).Line,
+							)
+							// ok to continue
+						}
+					} else {
+						// no match - record new forward jump
+						fwdJumps[i] = jmp
+						i++
+					}
+				}
+				fwdJumps = fwdJumps[:i]
+				lstmt = s
+			}
+			stmtBranches(s.Stmt)
+
+		case *ast.BranchStmt:
+			if s.Label == nil {
+				return // checked in 1st pass (check.stmt)
+			}
+
+			// determine and validate target
+			name := s.Label.Name
+			switch s.Tok {
+			case token.BREAK:
+				// spec: "If there is a label, it must be that of an enclosing
+				// "for", "switch", or "select" statement, and that is the one
+				// whose execution terminates."
+				valid := false
+				if t := b.enclosingTarget(name); t != nil {
+					switch t.Stmt.(type) {
+					case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt:
+						valid = true
+					}
+				}
+				if !valid {
+					check.errorf(s.Label.Pos(), "invalid break label %s", name)
+					return
+				}
+
+			case token.CONTINUE:
+				// spec: "If there is a label, it must be that of an enclosing
+				// "for" statement, and that is the one whose execution advances."
+				valid := false
+				if t := b.enclosingTarget(name); t != nil {
+					switch t.Stmt.(type) {
+					case *ast.ForStmt, *ast.RangeStmt:
+						valid = true
+					}
+				}
+				if !valid {
+					check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+					return
+				}
+
+			case token.GOTO:
+				if b.gotoTarget(name) == nil {
+					// label may be declared later - add branch to forward jumps
+					fwdJumps = append(fwdJumps, s)
+					return
+				}
+
+			default:
+				check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name)
+				return
+			}
+
+			// record label use
+			obj := all.Lookup(name)
+			obj.(*Label).used = true
+			check.recordUse(s.Label, obj)
+
+		case *ast.AssignStmt:
+			if s.Tok == token.DEFINE {
+				recordVarDecl(s.Pos())
+			}
+
+		case *ast.BlockStmt:
+			blockBranches(lstmt, s.List)
+
+		case *ast.IfStmt:
+			stmtBranches(s.Body)
+			if s.Else != nil {
+				stmtBranches(s.Else)
+			}
+
+		case *ast.CaseClause:
+			blockBranches(nil, s.Body)
+
+		case *ast.SwitchStmt:
+			stmtBranches(s.Body)
+
+		case *ast.TypeSwitchStmt:
+			stmtBranches(s.Body)
+
+		case *ast.CommClause:
+			blockBranches(nil, s.Body)
+
+		case *ast.SelectStmt:
+			stmtBranches(s.Body)
+
+		case *ast.ForStmt:
+			stmtBranches(s.Body)
+
+		case *ast.RangeStmt:
+			stmtBranches(s.Body)
+		}
+	}
+
+	for _, s := range list {
+		stmtBranches(s)
+	}
+
+	return fwdJumps
+}
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
new file mode 100644
index 0000000..3caca55
--- /dev/null
+++ b/src/go/types/lookup.go
@@ -0,0 +1,341 @@
+// Copyright 2013 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.
+
+// This file implements various field and method lookup functions.
+
+package types
+
+// LookupFieldOrMethod looks up a field or method with given package and name
+// in T and returns the corresponding *Var or *Func, an index sequence, and a
+// bool indicating if there were any pointer indirections on the path to the
+// field or method. If addressable is set, T is the type of an addressable
+// variable (only matters for method lookups).
+//
+// The last index entry is the field or method index in the (possibly embedded)
+// type where the entry was found, either:
+//
+//	1) the list of declared methods of a named type; or
+//	2) the list of all methods (method set) of an interface type; or
+//	3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the anonymous struct fields
+// traversed to get to the found entry, starting at depth 0.
+//
+// If no entry is found, a nil object is returned. In this case, the returned
+// index and indirect values have the following meaning:
+//
+//	- If index != nil, the index sequence points to an ambiguous entry
+//	(the same name appeared more than once at the same embedding level).
+//
+//	- If indirect is set, a method with a pointer receiver type was found
+//      but there was no pointer on the path from the actual receiver type to
+//	the method's formal receiver base type, nor was the receiver addressable.
+//
+func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+	// Methods cannot be associated to a named pointer type
+	// (spec: "The type denoted by T is called the receiver base type;
+	// it must not be a pointer or interface type and it must be declared
+	// in the same package as the method.").
+	// Thus, if we have a named pointer type, proceed with the underlying
+	// pointer type but discard the result if it is a method since we would
+	// not have found it for T (see also issue 8590).
+	if t, _ := T.(*Named); t != nil {
+		if p, _ := t.underlying.(*Pointer); p != nil {
+			obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
+			if _, ok := obj.(*Func); ok {
+				return nil, nil, false
+			}
+			return
+		}
+	}
+
+	return lookupFieldOrMethod(T, addressable, pkg, name)
+}
+
+// TODO(gri) The named type consolidation and seen maps below must be
+//           indexed by unique keys for a given type. Verify that named
+//           types always have only one representation (even when imported
+//           indirectly via different packages.)
+
+func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+	// WARNING: The code in this function is extremely subtle - do not modify casually!
+	//          This function and NewMethodSet should be kept in sync.
+
+	if name == "_" {
+		return // blank fields/methods are never found
+	}
+
+	typ, isPtr := deref(T)
+	named, _ := typ.(*Named)
+
+	// *typ where typ is an interface has no methods.
+	if isPtr {
+		utyp := typ
+		if named != nil {
+			utyp = named.underlying
+		}
+		if _, ok := utyp.(*Interface); ok {
+			return
+		}
+	}
+
+	// Start with typ as single entry at shallowest depth.
+	// If typ is not a named type, insert a nil type instead.
+	current := []embeddedType{{named, nil, isPtr, false}}
+
+	// named types that we have seen already, allocated lazily
+	var seen map[*Named]bool
+
+	// search current depth
+	for len(current) > 0 {
+		var next []embeddedType // embedded types found at current depth
+
+		// look for (pkg, name) in all types at current depth
+		for _, e := range current {
+			// The very first time only, e.typ may be nil.
+			// In this case, we don't have a named type and
+			// we simply continue with the underlying type.
+			if e.typ != nil {
+				if seen[e.typ] {
+					// We have seen this type before, at a more shallow depth
+					// (note that multiples of this type at the current depth
+					// were consolidated before). The type at that depth shadows
+					// this same type at the current depth, so we can ignore
+					// this one.
+					continue
+				}
+				if seen == nil {
+					seen = make(map[*Named]bool)
+				}
+				seen[e.typ] = true
+
+				// look for a matching attached method
+				if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+					// potential match
+					assert(m.typ != nil)
+					index = concat(e.index, i)
+					if obj != nil || e.multiples {
+						return nil, index, false // collision
+					}
+					obj = m
+					indirect = e.indirect
+					continue // we can't have a matching field or interface method
+				}
+
+				// continue with underlying type
+				typ = e.typ.underlying
+			}
+
+			switch t := typ.(type) {
+			case *Struct:
+				// look for a matching field and collect embedded types
+				for i, f := range t.fields {
+					if f.sameId(pkg, name) {
+						assert(f.typ != nil)
+						index = concat(e.index, i)
+						if obj != nil || e.multiples {
+							return nil, index, false // collision
+						}
+						obj = f
+						indirect = e.indirect
+						continue // we can't have a matching interface method
+					}
+					// Collect embedded struct fields for searching the next
+					// lower depth, but only if we have not seen a match yet
+					// (if we have a match it is either the desired field or
+					// we have a name collision on the same depth; in either
+					// case we don't need to look further).
+					// Embedded fields are always of the form T or *T where
+					// T is a named type. If e.typ appeared multiple times at
+					// this depth, f.typ appears multiple times at the next
+					// depth.
+					if obj == nil && f.anonymous {
+						// Ignore embedded basic types - only user-defined
+						// named types can have methods or struct fields.
+						typ, isPtr := deref(f.typ)
+						if t, _ := typ.(*Named); t != nil {
+							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+						}
+					}
+				}
+
+			case *Interface:
+				// look for a matching method
+				// TODO(gri) t.allMethods is sorted - use binary search
+				if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
+					assert(m.typ != nil)
+					index = concat(e.index, i)
+					if obj != nil || e.multiples {
+						return nil, index, false // collision
+					}
+					obj = m
+					indirect = e.indirect
+				}
+			}
+		}
+
+		if obj != nil {
+			// found a potential match
+			// spec: "A method call x.m() is valid if the method set of (the type of) x
+			//        contains m and the argument list can be assigned to the parameter
+			//        list of m. If x is addressable and &x's method set contains m, x.m()
+			//        is shorthand for (&x).m()".
+			if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable {
+				return nil, nil, true // pointer/addressable receiver required
+			}
+			return
+		}
+
+		current = consolidateMultiples(next)
+	}
+
+	return nil, nil, false // not found
+}
+
+// embeddedType represents an embedded named type
+type embeddedType struct {
+	typ       *Named // nil means use the outer typ variable instead
+	index     []int  // embedded field indices, starting with index at depth 0
+	indirect  bool   // if set, there was a pointer indirection on the path to this field
+	multiples bool   // if set, typ appears multiple times at this depth
+}
+
+// consolidateMultiples collects multiple list entries with the same type
+// into a single entry marked as containing multiples. The result is the
+// consolidated list.
+func consolidateMultiples(list []embeddedType) []embeddedType {
+	if len(list) <= 1 {
+		return list // at most one entry - nothing to do
+	}
+
+	n := 0                       // number of entries w/ unique type
+	prev := make(map[*Named]int) // index at which type was previously seen
+	for _, e := range list {
+		if i, found := prev[e.typ]; found {
+			list[i].multiples = true
+			// ignore this entry
+		} else {
+			prev[e.typ] = n
+			list[n] = e
+			n++
+		}
+	}
+	return list[:n]
+}
+
+// MissingMethod returns (nil, false) if V implements T, otherwise it
+// returns a missing method required by T and whether it is missing or
+// just has the wrong type.
+//
+// For non-interface types V, or if static is set, V implements T if all
+// methods of T are present in V. Otherwise (V is an interface and static
+// is not set), MissingMethod only checks that methods of T which are also
+// present in V have matching types (e.g., for a type assertion x.(T) where
+// x is of interface type V).
+//
+func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
+	// fast path for common case
+	if T.Empty() {
+		return
+	}
+
+	// TODO(gri) Consider using method sets here. Might be more efficient.
+
+	if ityp, _ := V.Underlying().(*Interface); ityp != nil {
+		// TODO(gri) allMethods is sorted - can do this more efficiently
+		for _, m := range T.allMethods {
+			_, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
+			switch {
+			case obj == nil:
+				if static {
+					return m, false
+				}
+			case !Identical(obj.Type(), m.typ):
+				return m, true
+			}
+		}
+		return
+	}
+
+	// A concrete type implements T if it implements all methods of T.
+	for _, m := range T.allMethods {
+		obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
+
+		f, _ := obj.(*Func)
+		if f == nil {
+			return m, false
+		}
+
+		if !Identical(f.typ, m.typ) {
+			return m, true
+		}
+	}
+
+	return
+}
+
+// assertableTo reports whether a value of type V can be asserted to have type T.
+// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
+// method required by V and whether it is missing or just has the wrong type.
+func assertableTo(V *Interface, T Type) (method *Func, wrongType bool) {
+	// no static check is required if T is an interface
+	// spec: "If T is an interface type, x.(T) asserts that the
+	//        dynamic type of x implements the interface T."
+	if _, ok := T.Underlying().(*Interface); ok && !strict {
+		return
+	}
+	return MissingMethod(T, V, false)
+}
+
+// deref dereferences typ if it is a *Pointer and returns its base and true.
+// Otherwise it returns (typ, false).
+func deref(typ Type) (Type, bool) {
+	if p, _ := typ.(*Pointer); p != nil {
+		return p.base, true
+	}
+	return typ, false
+}
+
+// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
+// (named or unnamed) struct and returns its base. Otherwise it returns typ.
+func derefStructPtr(typ Type) Type {
+	if p, _ := typ.Underlying().(*Pointer); p != nil {
+		if _, ok := p.base.Underlying().(*Struct); ok {
+			return p.base
+		}
+	}
+	return typ
+}
+
+// concat returns the result of concatenating list and i.
+// The result does not share its underlying array with list.
+func concat(list []int, i int) []int {
+	var t []int
+	t = append(t, list...)
+	return append(t, i)
+}
+
+// fieldIndex returns the index for the field with matching package and name, or a value < 0.
+func fieldIndex(fields []*Var, pkg *Package, name string) int {
+	if name != "_" {
+		for i, f := range fields {
+			if f.sameId(pkg, name) {
+				return i
+			}
+		}
+	}
+	return -1
+}
+
+// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
+func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
+	if name != "_" {
+		for i, m := range methods {
+			if m.sameId(pkg, name) {
+				return i, m
+			}
+		}
+	}
+	return -1, nil
+}
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
new file mode 100644
index 0000000..8aff6f9
--- /dev/null
+++ b/src/go/types/methodset.go
@@ -0,0 +1,271 @@
+// Copyright 2013 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.
+
+// This file implements method sets.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+)
+
+// A MethodSet is an ordered set of concrete or abstract (interface) methods;
+// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id().
+// The zero value for a MethodSet is a ready-to-use empty method set.
+type MethodSet struct {
+	list []*Selection
+}
+
+func (s *MethodSet) String() string {
+	if s.Len() == 0 {
+		return "MethodSet {}"
+	}
+
+	var buf bytes.Buffer
+	fmt.Fprintln(&buf, "MethodSet {")
+	for _, f := range s.list {
+		fmt.Fprintf(&buf, "\t%s\n", f)
+	}
+	fmt.Fprintln(&buf, "}")
+	return buf.String()
+}
+
+// Len returns the number of methods in s.
+func (s *MethodSet) Len() int { return len(s.list) }
+
+// At returns the i'th method in s for 0 <= i < s.Len().
+func (s *MethodSet) At(i int) *Selection { return s.list[i] }
+
+// Lookup returns the method with matching package and name, or nil if not found.
+func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
+	if s.Len() == 0 {
+		return nil
+	}
+
+	key := Id(pkg, name)
+	i := sort.Search(len(s.list), func(i int) bool {
+		m := s.list[i]
+		return m.obj.Id() >= key
+	})
+	if i < len(s.list) {
+		m := s.list[i]
+		if m.obj.Id() == key {
+			return m
+		}
+	}
+	return nil
+}
+
+// Shared empty method set.
+var emptyMethodSet MethodSet
+
+// NewMethodSet returns the method set for the given type T.  It
+// always returns a non-nil method set, even if it is empty.
+//
+// A MethodSetCache handles repeat queries more efficiently.
+//
+func NewMethodSet(T Type) *MethodSet {
+	// WARNING: The code in this function is extremely subtle - do not modify casually!
+	//          This function and lookupFieldOrMethod should be kept in sync.
+
+	// method set up to the current depth, allocated lazily
+	var base methodSet
+
+	typ, isPtr := deref(T)
+	named, _ := typ.(*Named)
+
+	// *typ where typ is an interface has no methods.
+	if isPtr {
+		utyp := typ
+		if named != nil {
+			utyp = named.underlying
+		}
+		if _, ok := utyp.(*Interface); ok {
+			return &emptyMethodSet
+		}
+	}
+
+	// Start with typ as single entry at shallowest depth.
+	// If typ is not a named type, insert a nil type instead.
+	current := []embeddedType{{named, nil, isPtr, false}}
+
+	// named types that we have seen already, allocated lazily
+	var seen map[*Named]bool
+
+	// collect methods at current depth
+	for len(current) > 0 {
+		var next []embeddedType // embedded types found at current depth
+
+		// field and method sets at current depth, allocated lazily
+		var fset fieldSet
+		var mset methodSet
+
+		for _, e := range current {
+			// The very first time only, e.typ may be nil.
+			// In this case, we don't have a named type and
+			// we simply continue with the underlying type.
+			if e.typ != nil {
+				if seen[e.typ] {
+					// We have seen this type before, at a more shallow depth
+					// (note that multiples of this type at the current depth
+					// were consolidated before). The type at that depth shadows
+					// this same type at the current depth, so we can ignore
+					// this one.
+					continue
+				}
+				if seen == nil {
+					seen = make(map[*Named]bool)
+				}
+				seen[e.typ] = true
+
+				mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+
+				// continue with underlying type
+				typ = e.typ.underlying
+			}
+
+			switch t := typ.(type) {
+			case *Struct:
+				for i, f := range t.fields {
+					fset = fset.add(f, e.multiples)
+
+					// Embedded fields are always of the form T or *T where
+					// T is a named type. If typ appeared multiple times at
+					// this depth, f.Type appears multiple times at the next
+					// depth.
+					if f.anonymous {
+						// Ignore embedded basic types - only user-defined
+						// named types can have methods or struct fields.
+						typ, isPtr := deref(f.typ)
+						if t, _ := typ.(*Named); t != nil {
+							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+						}
+					}
+				}
+
+			case *Interface:
+				mset = mset.add(t.allMethods, e.index, true, e.multiples)
+			}
+		}
+
+		// Add methods and collisions at this depth to base if no entries with matching
+		// names exist already.
+		for k, m := range mset {
+			if _, found := base[k]; !found {
+				// Fields collide with methods of the same name at this depth.
+				if _, found := fset[k]; found {
+					m = nil // collision
+				}
+				if base == nil {
+					base = make(methodSet)
+				}
+				base[k] = m
+			}
+		}
+
+		// Multiple fields with matching names collide at this depth and shadow all
+		// entries further down; add them as collisions to base if no entries with
+		// matching names exist already.
+		for k, f := range fset {
+			if f == nil {
+				if _, found := base[k]; !found {
+					if base == nil {
+						base = make(methodSet)
+					}
+					base[k] = nil // collision
+				}
+			}
+		}
+
+		current = consolidateMultiples(next)
+	}
+
+	if len(base) == 0 {
+		return &emptyMethodSet
+	}
+
+	// collect methods
+	var list []*Selection
+	for _, m := range base {
+		if m != nil {
+			m.recv = T
+			list = append(list, m)
+		}
+	}
+	sort.Sort(byUniqueName(list))
+	return &MethodSet{list}
+}
+
+// A fieldSet is a set of fields and name collisions.
+// A collision indicates that multiple fields with the
+// same unique id appeared.
+type fieldSet map[string]*Var // a nil entry indicates a name collision
+
+// Add adds field f to the field set s.
+// If multiples is set, f appears multiple times
+// and is treated as a collision.
+func (s fieldSet) add(f *Var, multiples bool) fieldSet {
+	if s == nil {
+		s = make(fieldSet)
+	}
+	key := f.Id()
+	// if f is not in the set, add it
+	if !multiples {
+		if _, found := s[key]; !found {
+			s[key] = f
+			return s
+		}
+	}
+	s[key] = nil // collision
+	return s
+}
+
+// A methodSet is a set of methods and name collisions.
+// A collision indicates that multiple methods with the
+// same unique id appeared.
+type methodSet map[string]*Selection // a nil entry indicates a name collision
+
+// Add adds all functions in list to the method set s.
+// If multiples is set, every function in list appears multiple times
+// and is treated as a collision.
+func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
+	if len(list) == 0 {
+		return s
+	}
+	if s == nil {
+		s = make(methodSet)
+	}
+	for i, f := range list {
+		key := f.Id()
+		// if f is not in the set, add it
+		if !multiples {
+			// TODO(gri) A found method may not be added because it's not in the method set
+			// (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
+			// set and may not collide with the first one, thus leading to a false positive.
+			// Is that possible? Investigate.
+			if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
+				s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
+				continue
+			}
+		}
+		s[key] = nil // collision
+	}
+	return s
+}
+
+// ptrRecv reports whether the receiver is of the form *T.
+// The receiver must exist.
+func ptrRecv(f *Func) bool {
+	_, isPtr := deref(f.typ.(*Signature).recv.typ)
+	return isPtr
+}
+
+// byUniqueName function lists can be sorted by their unique names.
+type byUniqueName []*Selection
+
+func (a byUniqueName) Len() int           { return len(a) }
+func (a byUniqueName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/src/go/types/methodsetcache.go b/src/go/types/methodsetcache.go
new file mode 100644
index 0000000..5a482e9
--- /dev/null
+++ b/src/go/types/methodsetcache.go
@@ -0,0 +1,69 @@
+// 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.
+
+// This file implements a cache of method sets.
+
+package types
+
+import "sync"
+
+// A MethodSetCache records the method set of each type T for which
+// MethodSet(T) is called so that repeat queries are fast.
+// The zero value is a ready-to-use cache instance.
+type MethodSetCache struct {
+	mu     sync.Mutex
+	named  map[*Named]struct{ value, pointer *MethodSet } // method sets for named N and *N
+	others map[Type]*MethodSet                            // all other types
+}
+
+// MethodSet returns the method set of type T.  It is thread-safe.
+//
+// If cache is nil, this function is equivalent to NewMethodSet(T).
+// Utility functions can thus expose an optional *MethodSetCache
+// parameter to clients that care about performance.
+//
+func (cache *MethodSetCache) MethodSet(T Type) *MethodSet {
+	if cache == nil {
+		return NewMethodSet(T)
+	}
+	cache.mu.Lock()
+	defer cache.mu.Unlock()
+
+	switch T := T.(type) {
+	case *Named:
+		return cache.lookupNamed(T).value
+
+	case *Pointer:
+		if N, ok := T.Elem().(*Named); ok {
+			return cache.lookupNamed(N).pointer
+		}
+	}
+
+	// all other types
+	// (The map uses pointer equivalence, not type identity.)
+	mset := cache.others[T]
+	if mset == nil {
+		mset = NewMethodSet(T)
+		if cache.others == nil {
+			cache.others = make(map[Type]*MethodSet)
+		}
+		cache.others[T] = mset
+	}
+	return mset
+}
+
+func (cache *MethodSetCache) lookupNamed(named *Named) struct{ value, pointer *MethodSet } {
+	if cache.named == nil {
+		cache.named = make(map[*Named]struct{ value, pointer *MethodSet })
+	}
+	// Avoid recomputing mset(*T) for each distinct Pointer
+	// instance whose underlying type is a named type.
+	msets, ok := cache.named[named]
+	if !ok {
+		msets.value = NewMethodSet(named)
+		msets.pointer = NewMethodSet(NewPointer(named))
+		cache.named[named] = msets
+	}
+	return msets
+}
diff --git a/src/go/types/object.go b/src/go/types/object.go
new file mode 100644
index 0000000..2404753
--- /dev/null
+++ b/src/go/types/object.go
@@ -0,0 +1,339 @@
+// Copyright 2013 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 types
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+// TODO(gri) Document factory, accessor methods, and fields. General clean-up.
+
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
+// All objects implement the Object interface.
+//
+type Object interface {
+	Parent() *Scope // scope in which this object is declared
+	Pos() token.Pos // position of object identifier in declaration
+	Pkg() *Package  // nil for objects in the Universe scope and labels
+	Name() string   // package local object name
+	Type() Type     // object type
+	Exported() bool // reports whether the name starts with a capital letter
+	Id() string     // object id (see Id below)
+
+	// String returns a human-readable string of the object.
+	String() string
+
+	// order reflects a package-level object's source order: if object
+	// a is before object b in the source, then a.order() < b.order().
+	// order returns a value > 0 for package-level objects; it returns
+	// 0 for all other objects (including objects in file scopes).
+	order() uint32
+
+	// setOrder sets the order number of the object. It must be > 0.
+	setOrder(uint32)
+
+	// setParent sets the parent scope of the object.
+	setParent(*Scope)
+
+	// sameId reports whether obj.Id() and Id(pkg, name) are the same.
+	sameId(pkg *Package, name string) bool
+}
+
+// Id returns name if it is exported, otherwise it
+// returns the name qualified with the package path.
+func Id(pkg *Package, name string) string {
+	if ast.IsExported(name) {
+		return name
+	}
+	// unexported names need the package path for differentiation
+	// (if there's no package, make sure we don't start with '.'
+	// as that may change the order of methods between a setup
+	// inside a package and outside a package - which breaks some
+	// tests)
+	path := "_"
+	// TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
+	// if pkg == nil {
+	// 	panic("nil package in lookup of unexported name")
+	// }
+	if pkg != nil {
+		path = pkg.path
+		if path == "" {
+			path = "_"
+		}
+	}
+	return path + "." + name
+}
+
+// An object implements the common parts of an Object.
+type object struct {
+	parent *Scope
+	pos    token.Pos
+	pkg    *Package
+	name   string
+	typ    Type
+	order_ uint32
+}
+
+func (obj *object) Parent() *Scope { return obj.parent }
+func (obj *object) Pos() token.Pos { return obj.pos }
+func (obj *object) Pkg() *Package  { return obj.pkg }
+func (obj *object) Name() string   { return obj.name }
+func (obj *object) Type() Type     { return obj.typ }
+func (obj *object) Exported() bool { return ast.IsExported(obj.name) }
+func (obj *object) Id() string     { return Id(obj.pkg, obj.name) }
+func (obj *object) String() string { panic("abstract") }
+func (obj *object) order() uint32  { return obj.order_ }
+
+func (obj *object) setOrder(order uint32)   { assert(order > 0); obj.order_ = order }
+func (obj *object) setParent(parent *Scope) { obj.parent = parent }
+
+func (obj *object) sameId(pkg *Package, name string) bool {
+	// spec:
+	// "Two identifiers are different if they are spelled differently,
+	// or if they appear in different packages and are not exported.
+	// Otherwise, they are the same."
+	if name != obj.name {
+		return false
+	}
+	// obj.Name == name
+	if obj.Exported() {
+		return true
+	}
+	// not exported, so packages must be the same (pkg == nil for
+	// fields in Universe scope; this can only happen for types
+	// introduced via Eval)
+	if pkg == nil || obj.pkg == nil {
+		return pkg == obj.pkg
+	}
+	// pkg != nil && obj.pkg != nil
+	return pkg.path == obj.pkg.path
+}
+
+// A PkgName represents an imported Go package.
+type PkgName struct {
+	object
+	imported *Package
+	used     bool // set if the package was used
+}
+
+func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
+	return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0}, imported, false}
+}
+
+// Imported returns the package that was imported.
+// It is distinct from Pkg(), which is the package containing the import statement.
+func (obj *PkgName) Imported() *Package { return obj.imported }
+
+// A Const represents a declared constant.
+type Const struct {
+	object
+	val     exact.Value
+	visited bool // for initialization cycle detection
+}
+
+func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const {
+	return &Const{object{nil, pos, pkg, name, typ, 0}, val, false}
+}
+
+func (obj *Const) Val() exact.Value { return obj.val }
+
+// A TypeName represents a declared type.
+type TypeName struct {
+	object
+}
+
+func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
+	return &TypeName{object{nil, pos, pkg, name, typ, 0}}
+}
+
+// A Variable represents a declared variable (including function parameters and results, and struct fields).
+type Var struct {
+	object
+	anonymous bool // if set, the variable is an anonymous struct field, and name is the type name
+	visited   bool // for initialization cycle detection
+	isField   bool // var is struct field
+	used      bool // set if the variable was used
+}
+
+func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+	return &Var{object: object{nil, pos, pkg, name, typ, 0}}
+}
+
+func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+	return &Var{object: object{nil, pos, pkg, name, typ, 0}, used: true} // parameters are always 'used'
+}
+
+func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var {
+	return &Var{object: object{nil, pos, pkg, name, typ, 0}, anonymous: anonymous, isField: true}
+}
+
+func (obj *Var) Anonymous() bool { return obj.anonymous }
+
+func (obj *Var) IsField() bool { return obj.isField }
+
+// A Func represents a declared function, concrete method, or abstract
+// (interface) method.  Its Type() is always a *Signature.
+// An abstract method may belong to many interfaces due to embedding.
+type Func struct {
+	object
+}
+
+func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
+	// don't store a nil signature
+	var typ Type
+	if sig != nil {
+		typ = sig
+	}
+	return &Func{object{nil, pos, pkg, name, typ, 0}}
+}
+
+// FullName returns the package- or receiver-type-qualified name of
+// function or method obj.
+func (obj *Func) FullName() string {
+	var buf bytes.Buffer
+	writeFuncName(&buf, nil, obj)
+	return buf.String()
+}
+
+func (obj *Func) Scope() *Scope {
+	return obj.typ.(*Signature).scope
+}
+
+// A Label represents a declared label.
+type Label struct {
+	object
+	used bool // set if the label was used
+}
+
+func NewLabel(pos token.Pos, pkg *Package, name string) *Label {
+	return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false}
+}
+
+// A Builtin represents a built-in function.
+// Builtins don't have a valid type.
+type Builtin struct {
+	object
+	id builtinId
+}
+
+func newBuiltin(id builtinId) *Builtin {
+	return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id}
+}
+
+// Nil represents the predeclared value nil.
+type Nil struct {
+	object
+}
+
+func writeObject(buf *bytes.Buffer, this *Package, obj Object) {
+	typ := obj.Type()
+	switch obj := obj.(type) {
+	case *PkgName:
+		fmt.Fprintf(buf, "package %s", obj.Name())
+		if path := obj.imported.path; path != "" && path != obj.name {
+			fmt.Fprintf(buf, " (%q)", path)
+		}
+		return
+
+	case *Const:
+		buf.WriteString("const")
+
+	case *TypeName:
+		buf.WriteString("type")
+		typ = typ.Underlying()
+
+	case *Var:
+		if obj.isField {
+			buf.WriteString("field")
+		} else {
+			buf.WriteString("var")
+		}
+
+	case *Func:
+		buf.WriteString("func ")
+		writeFuncName(buf, this, obj)
+		if typ != nil {
+			WriteSignature(buf, this, typ.(*Signature))
+		}
+		return
+
+	case *Label:
+		buf.WriteString("label")
+		typ = nil
+
+	case *Builtin:
+		buf.WriteString("builtin")
+		typ = nil
+
+	case *Nil:
+		buf.WriteString("nil")
+		return
+
+	default:
+		panic(fmt.Sprintf("writeObject(%T)", obj))
+	}
+
+	buf.WriteByte(' ')
+
+	// For package-level objects, package-qualify the name,
+	// except for intra-package references (this != nil).
+	if pkg := obj.Pkg(); pkg != nil && this != pkg && pkg.scope.Lookup(obj.Name()) == obj {
+		buf.WriteString(pkg.path)
+		buf.WriteByte('.')
+	}
+	buf.WriteString(obj.Name())
+	if typ != nil {
+		buf.WriteByte(' ')
+		WriteType(buf, this, typ)
+	}
+}
+
+// ObjectString returns the string form of obj.
+// Object and type names are printed package-qualified
+// only if they do not belong to this package.
+//
+func ObjectString(this *Package, obj Object) string {
+	var buf bytes.Buffer
+	writeObject(&buf, this, obj)
+	return buf.String()
+}
+
+func (obj *PkgName) String() string  { return ObjectString(nil, obj) }
+func (obj *Const) String() string    { return ObjectString(nil, obj) }
+func (obj *TypeName) String() string { return ObjectString(nil, obj) }
+func (obj *Var) String() string      { return ObjectString(nil, obj) }
+func (obj *Func) String() string     { return ObjectString(nil, obj) }
+func (obj *Label) String() string    { return ObjectString(nil, obj) }
+func (obj *Builtin) String() string  { return ObjectString(nil, obj) }
+func (obj *Nil) String() string      { return ObjectString(nil, obj) }
+
+func writeFuncName(buf *bytes.Buffer, this *Package, f *Func) {
+	if f.typ != nil {
+		sig := f.typ.(*Signature)
+		if recv := sig.Recv(); recv != nil {
+			buf.WriteByte('(')
+			if _, ok := recv.Type().(*Interface); ok {
+				// gcimporter creates abstract methods of
+				// named interfaces using the interface type
+				// (not the named type) as the receiver.
+				// Don't print it in full.
+				buf.WriteString("interface")
+			} else {
+				WriteType(buf, this, recv.Type())
+			}
+			buf.WriteByte(')')
+			buf.WriteByte('.')
+		} else if f.pkg != nil && f.pkg != this {
+			buf.WriteString(f.pkg.path)
+			buf.WriteByte('.')
+		}
+	}
+	buf.WriteString(f.name)
+}
diff --git a/src/go/types/objset.go b/src/go/types/objset.go
new file mode 100644
index 0000000..55eb74a
--- /dev/null
+++ b/src/go/types/objset.go
@@ -0,0 +1,31 @@
+// Copyright 2013 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.
+
+// This file implements objsets.
+//
+// An objset is similar to a Scope but objset elements
+// are identified by their unique id, instead of their
+// object name.
+
+package types
+
+// An objset is a set of objects identified by their unique id.
+// The zero value for objset is a ready-to-use empty objset.
+type objset map[string]Object // initialized lazily
+
+// insert attempts to insert an object obj into objset s.
+// If s already contains an alternative object alt with
+// the same name, insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj and returns nil.
+func (s *objset) insert(obj Object) Object {
+	id := obj.Id()
+	if alt := (*s)[id]; alt != nil {
+		return alt
+	}
+	if *s == nil {
+		*s = make(map[string]Object)
+	}
+	(*s)[id] = obj
+	return nil
+}
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
new file mode 100644
index 0000000..88c3870
--- /dev/null
+++ b/src/go/types/operand.go
@@ -0,0 +1,286 @@
+// Copyright 2012 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.
+
+// This file defines operands and associated operations.
+
+package types
+
+import (
+	"bytes"
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode byte
+
+const (
+	invalid  operandMode = iota // operand is invalid
+	novalue                     // operand represents no value (result of a function call w/o result)
+	builtin                     // operand is a built-in function
+	typexpr                     // operand is a type
+	constant                    // operand is a constant; the operand's typ is a Basic type
+	variable                    // operand is an addressable variable
+	mapindex                    // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
+	value                       // operand is a computed value
+	commaok                     // like value, but operand may be used in a comma,ok expression
+)
+
+var operandModeString = [...]string{
+	invalid:  "invalid operand",
+	novalue:  "no value",
+	builtin:  "built-in",
+	typexpr:  "type",
+	constant: "constant",
+	variable: "variable",
+	mapindex: "map index expression",
+	value:    "value",
+	commaok:  "comma, ok expression",
+}
+
+// An operand represents an intermediate value during type checking.
+// Operands have an (addressing) mode, the expression evaluating to
+// the operand, the operand's type, a value for constants, and an id
+// for built-in functions.
+// The zero value of operand is a ready to use invalid operand.
+//
+type operand struct {
+	mode operandMode
+	expr ast.Expr
+	typ  Type
+	val  exact.Value
+	id   builtinId
+}
+
+// pos returns the position of the expression corresponding to x.
+// If x is invalid the position is token.NoPos.
+//
+func (x *operand) pos() token.Pos {
+	// x.expr may not be set if x is invalid
+	if x.expr == nil {
+		return token.NoPos
+	}
+	return x.expr.Pos()
+}
+
+// Operand string formats
+// (not all "untyped" cases can appear due to the type system,
+// but they fall out naturally here)
+//
+// mode       format
+//
+// invalid    <expr> (               <mode>                    )
+// novalue    <expr> (               <mode>                    )
+// builtin    <expr> (               <mode>                    )
+// typexpr    <expr> (               <mode>                    )
+//
+// constant   <expr> (<untyped kind> <mode>                    )
+// constant   <expr> (               <mode>       of type <typ>)
+// constant   <expr> (<untyped kind> <mode> <val>              )
+// constant   <expr> (               <mode> <val> of type <typ>)
+//
+// variable   <expr> (<untyped kind> <mode>                    )
+// variable   <expr> (               <mode>       of type <typ>)
+//
+// mapindex   <expr> (<untyped kind> <mode>                    )
+// mapindex   <expr> (               <mode>       of type <typ>)
+//
+// value      <expr> (<untyped kind> <mode>                    )
+// value      <expr> (               <mode>       of type <typ>)
+//
+// commaok    <expr> (<untyped kind> <mode>                    )
+// commaok    <expr> (               <mode>       of type <typ>)
+//
+func operandString(this *Package, x *operand) string {
+	var buf bytes.Buffer
+
+	var expr string
+	if x.expr != nil {
+		expr = ExprString(x.expr)
+	} else {
+		switch x.mode {
+		case builtin:
+			expr = predeclaredFuncs[x.id].name
+		case typexpr:
+			expr = TypeString(this, x.typ)
+		case constant:
+			expr = x.val.String()
+		}
+	}
+
+	// <expr> (
+	if expr != "" {
+		buf.WriteString(expr)
+		buf.WriteString(" (")
+	}
+
+	// <untyped kind>
+	hasType := false
+	switch x.mode {
+	case invalid, novalue, builtin, typexpr:
+		// no type
+	default:
+		// has type
+		if isUntyped(x.typ) {
+			buf.WriteString(x.typ.(*Basic).name)
+			buf.WriteByte(' ')
+			break
+		}
+		hasType = true
+	}
+
+	// <mode>
+	buf.WriteString(operandModeString[x.mode])
+
+	// <val>
+	if x.mode == constant {
+		if s := x.val.String(); s != expr {
+			buf.WriteByte(' ')
+			buf.WriteString(s)
+		}
+	}
+
+	// <typ>
+	if hasType {
+		if x.typ != Typ[Invalid] {
+			buf.WriteString(" of type ")
+			WriteType(&buf, this, x.typ)
+		} else {
+			buf.WriteString(" with invalid type")
+		}
+	}
+
+	// )
+	if expr != "" {
+		buf.WriteByte(')')
+	}
+
+	return buf.String()
+}
+
+func (x *operand) String() string {
+	return operandString(nil, x)
+}
+
+// setConst sets x to the untyped constant for literal lit.
+func (x *operand) setConst(tok token.Token, lit string) {
+	val := exact.MakeFromLiteral(lit, tok, 0)
+	if val == nil {
+		// TODO(gri) Should we make it an unknown constant instead?
+		x.mode = invalid
+		return
+	}
+
+	var kind BasicKind
+	switch tok {
+	case token.INT:
+		kind = UntypedInt
+	case token.FLOAT:
+		kind = UntypedFloat
+	case token.IMAG:
+		kind = UntypedComplex
+	case token.CHAR:
+		kind = UntypedRune
+	case token.STRING:
+		kind = UntypedString
+	}
+
+	x.mode = constant
+	x.typ = Typ[kind]
+	x.val = val
+}
+
+// isNil reports whether x is the nil value.
+func (x *operand) isNil() bool {
+	return x.mode == value && x.typ == Typ[UntypedNil]
+}
+
+// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
+//           checker.representable, and checker.assignment are
+//           overlapping in functionality. Need to simplify and clean up.
+
+// assignableTo reports whether x is assignable to a variable of type T.
+func (x *operand) assignableTo(conf *Config, T Type) bool {
+	if x.mode == invalid || T == Typ[Invalid] {
+		return true // avoid spurious errors
+	}
+
+	V := x.typ
+
+	// x's type is identical to T
+	if Identical(V, T) {
+		return true
+	}
+
+	Vu := V.Underlying()
+	Tu := T.Underlying()
+
+	// T is an interface type and x implements T
+	// (Do this check first as it might succeed early.)
+	if Ti, ok := Tu.(*Interface); ok {
+		if Implements(x.typ, Ti) {
+			return true
+		}
+	}
+
+	// x's type V and T have identical underlying types
+	// and at least one of V or T is not a named type
+	if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+		return true
+	}
+
+	// x is a bidirectional channel value, T is a channel
+	// type, x's type V and T have identical element types,
+	// and at least one of V or T is not a named type
+	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
+		if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
+			return !isNamed(V) || !isNamed(T)
+		}
+	}
+
+	// x is the predeclared identifier nil and T is a pointer,
+	// function, slice, map, channel, or interface type
+	if x.isNil() {
+		switch t := Tu.(type) {
+		case *Basic:
+			if t.kind == UnsafePointer {
+				return true
+			}
+		case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
+			return true
+		}
+		return false
+	}
+
+	// x is an untyped constant representable by a value of type T
+	// TODO(gri) This is borrowing from checker.convertUntyped and
+	//           checker.representable. Need to clean up.
+	if isUntyped(Vu) {
+		switch t := Tu.(type) {
+		case *Basic:
+			if x.mode == constant {
+				return representableConst(x.val, conf, t.kind, nil)
+			}
+			// The result of a comparison is an untyped boolean,
+			// but may not be a constant.
+			if Vb, _ := Vu.(*Basic); Vb != nil {
+				return Vb.kind == UntypedBool && isBoolean(Tu)
+			}
+		case *Interface:
+			return x.isNil() || t.Empty()
+		case *Pointer, *Signature, *Slice, *Map, *Chan:
+			return x.isNil()
+		}
+	}
+
+	return false
+}
+
+// isInteger reports whether x is a (typed or untyped) integer value.
+func (x *operand) isInteger() bool {
+	return x.mode == invalid ||
+		isInteger(x.typ) ||
+		x.mode == constant && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
+}
diff --git a/src/go/types/ordering.go b/src/go/types/ordering.go
new file mode 100644
index 0000000..6bb98f2
--- /dev/null
+++ b/src/go/types/ordering.go
@@ -0,0 +1,127 @@
+// 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.
+
+// This file implements resolveOrder.
+
+package types
+
+import (
+	"go/ast"
+	"sort"
+)
+
+// resolveOrder computes the order in which package-level objects
+// must be type-checked.
+//
+// Interface types appear first in the list, sorted topologically
+// by dependencies on embedded interfaces that are also declared
+// in this package, followed by all other objects sorted in source
+// order.
+//
+// TODO(gri) Consider sorting all types by dependencies here, and
+// in the process check _and_ report type cycles. This may simplify
+// the full type-checking phase.
+//
+func (check *Checker) resolveOrder() []Object {
+	var ifaces, others []Object
+
+	// collect interface types with their dependencies, and all other objects
+	for obj := range check.objMap {
+		if ityp := check.interfaceFor(obj); ityp != nil {
+			ifaces = append(ifaces, obj)
+			// determine dependencies on embedded interfaces
+			for _, f := range ityp.Methods.List {
+				if len(f.Names) == 0 {
+					// Embedded interface: The type must be a (possibly
+					// qualified) identifier denoting another interface.
+					// Imported interfaces are already fully resolved,
+					// so we can ignore qualified identifiers.
+					if ident, _ := f.Type.(*ast.Ident); ident != nil {
+						embedded := check.pkg.scope.Lookup(ident.Name)
+						if check.interfaceFor(embedded) != nil {
+							check.objMap[obj].addDep(embedded)
+						}
+					}
+				}
+			}
+		} else {
+			others = append(others, obj)
+		}
+	}
+
+	// final object order
+	var order []Object
+
+	// sort interface types topologically by dependencies,
+	// and in source order if there are no dependencies
+	sort.Sort(inSourceOrder(ifaces))
+	if debug {
+		for _, obj := range ifaces {
+			assert(check.objMap[obj].mark == 0)
+		}
+	}
+	for _, obj := range ifaces {
+		check.appendInPostOrder(&order, obj)
+	}
+
+	// sort everything else in source order
+	sort.Sort(inSourceOrder(others))
+
+	return append(order, others...)
+}
+
+// interfaceFor returns the AST interface denoted by obj, or nil.
+func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType {
+	tname, _ := obj.(*TypeName)
+	if tname == nil {
+		return nil // not a type
+	}
+	d := check.objMap[obj]
+	if d == nil {
+		check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+		unreachable()
+	}
+	if d.typ == nil {
+		return nil // invalid AST - ignore (will be handled later)
+	}
+	ityp, _ := d.typ.(*ast.InterfaceType)
+	return ityp
+}
+
+func (check *Checker) appendInPostOrder(order *[]Object, obj Object) {
+	d := check.objMap[obj]
+	if d.mark != 0 {
+		// We've already seen this object; either because it's
+		// already added to order, or because we have a cycle.
+		// In both cases we stop. Cycle errors are reported
+		// when type-checking types.
+		return
+	}
+	d.mark = 1
+
+	for _, obj := range orderedSetObjects(d.deps) {
+		check.appendInPostOrder(order, obj)
+	}
+
+	*order = append(*order, obj)
+}
+
+func orderedSetObjects(set map[Object]bool) []Object {
+	list := make([]Object, len(set))
+	i := 0
+	for obj := range set {
+		// we don't care about the map element value
+		list[i] = obj
+		i++
+	}
+	sort.Sort(inSourceOrder(list))
+	return list
+}
+
+// inSourceOrder implements the sort.Sort interface.
+type inSourceOrder []Object
+
+func (a inSourceOrder) Len() int           { return len(a) }
+func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
+func (a inSourceOrder) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/src/go/types/package.go b/src/go/types/package.go
new file mode 100644
index 0000000..366ca39
--- /dev/null
+++ b/src/go/types/package.go
@@ -0,0 +1,58 @@
+// Copyright 2013 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 types
+
+import "fmt"
+
+// A Package describes a Go package.
+type Package struct {
+	path     string
+	name     string
+	scope    *Scope
+	complete bool
+	imports  []*Package
+	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
+}
+
+// NewPackage returns a new Package for the given package path and name;
+// the name must not be the blank identifier.
+// The package is not complete and contains no explicit imports.
+func NewPackage(path, name string) *Package {
+	if name == "_" {
+		panic("invalid package name _")
+	}
+	scope := NewScope(Universe, fmt.Sprintf("package %q", path))
+	return &Package{path: path, name: name, scope: scope}
+}
+
+// Path returns the package path.
+func (pkg *Package) Path() string { return pkg.path }
+
+// Name returns the package name.
+func (pkg *Package) Name() string { return pkg.name }
+
+// Scope returns the (complete or incomplete) package scope
+// holding the objects declared at package level (TypeNames,
+// Consts, Vars, and Funcs).
+func (pkg *Package) Scope() *Scope { return pkg.scope }
+
+// A package is complete if its scope contains (at least) all
+// exported objects; otherwise it is incomplete.
+func (pkg *Package) Complete() bool { return pkg.complete }
+
+// MarkComplete marks a package as complete.
+func (pkg *Package) MarkComplete() { pkg.complete = true }
+
+// Imports returns the list of packages explicitly imported by
+// pkg; the list is in source order. Package unsafe is excluded.
+func (pkg *Package) Imports() []*Package { return pkg.imports }
+
+// SetImports sets the list of explicitly imported packages to list.
+// It is the caller's responsibility to make sure list elements are unique.
+func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }
+
+func (pkg *Package) String() string {
+	return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
+}
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
new file mode 100644
index 0000000..b5c39d9
--- /dev/null
+++ b/src/go/types/predicates.go
@@ -0,0 +1,309 @@
+// Copyright 2012 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.
+
+// This file implements commonly used type predicates.
+
+package types
+
+import "sort"
+
+func isNamed(typ Type) bool {
+	if _, ok := typ.(*Basic); ok {
+		return ok
+	}
+	_, ok := typ.(*Named)
+	return ok
+}
+
+func isBoolean(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsBoolean != 0
+}
+
+func isInteger(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsInteger != 0
+}
+
+func isUnsigned(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsUnsigned != 0
+}
+
+func isFloat(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsFloat != 0
+}
+
+func isComplex(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsComplex != 0
+}
+
+func isNumeric(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsNumeric != 0
+}
+
+func isString(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsString != 0
+}
+
+func isTyped(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return !ok || t.info&IsUntyped == 0
+}
+
+func isUntyped(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsUntyped != 0
+}
+
+func isOrdered(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsOrdered != 0
+}
+
+func isConstType(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsConstType != 0
+}
+
+// IsInterface reports whether typ is an interface type.
+func IsInterface(typ Type) bool {
+	_, ok := typ.Underlying().(*Interface)
+	return ok
+}
+
+// Comparable reports whether values of type T are comparable.
+func Comparable(T Type) bool {
+	switch t := T.Underlying().(type) {
+	case *Basic:
+		// assume invalid types to be comparable
+		// to avoid follow-up errors
+		return t.kind != UntypedNil
+	case *Pointer, *Interface, *Chan:
+		return true
+	case *Struct:
+		for _, f := range t.fields {
+			if !Comparable(f.typ) {
+				return false
+			}
+		}
+		return true
+	case *Array:
+		return Comparable(t.elem)
+	}
+	return false
+}
+
+// hasNil reports whether a type includes the nil value.
+func hasNil(typ Type) bool {
+	switch t := typ.Underlying().(type) {
+	case *Basic:
+		return t.kind == UnsafePointer
+	case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
+		return true
+	}
+	return false
+}
+
+// Identical reports whether x and y are identical.
+func Identical(x, y Type) bool {
+	return identical(x, y, nil)
+}
+
+// An ifacePair is a node in a stack of interface type pairs compared for identity.
+type ifacePair struct {
+	x, y *Interface
+	prev *ifacePair
+}
+
+func (p *ifacePair) identical(q *ifacePair) bool {
+	return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
+}
+
+func identical(x, y Type, p *ifacePair) bool {
+	if x == y {
+		return true
+	}
+
+	switch x := x.(type) {
+	case *Basic:
+		// Basic types are singletons except for the rune and byte
+		// aliases, thus we cannot solely rely on the x == y check
+		// above.
+		if y, ok := y.(*Basic); ok {
+			return x.kind == y.kind
+		}
+
+	case *Array:
+		// Two array types are identical if they have identical element types
+		// and the same array length.
+		if y, ok := y.(*Array); ok {
+			return x.len == y.len && identical(x.elem, y.elem, p)
+		}
+
+	case *Slice:
+		// Two slice types are identical if they have identical element types.
+		if y, ok := y.(*Slice); ok {
+			return identical(x.elem, y.elem, p)
+		}
+
+	case *Struct:
+		// Two struct types are identical if they have the same sequence of fields,
+		// and if corresponding fields have the same names, and identical types,
+		// and identical tags. Two anonymous fields are considered to have the same
+		// name. Lower-case field names from different packages are always different.
+		if y, ok := y.(*Struct); ok {
+			if x.NumFields() == y.NumFields() {
+				for i, f := range x.fields {
+					g := y.fields[i]
+					if f.anonymous != g.anonymous ||
+						x.Tag(i) != y.Tag(i) ||
+						!f.sameId(g.pkg, g.name) ||
+						!identical(f.typ, g.typ, p) {
+						return false
+					}
+				}
+				return true
+			}
+		}
+
+	case *Pointer:
+		// Two pointer types are identical if they have identical base types.
+		if y, ok := y.(*Pointer); ok {
+			return identical(x.base, y.base, p)
+		}
+
+	case *Tuple:
+		// Two tuples types are identical if they have the same number of elements
+		// and corresponding elements have identical types.
+		if y, ok := y.(*Tuple); ok {
+			if x.Len() == y.Len() {
+				if x != nil {
+					for i, v := range x.vars {
+						w := y.vars[i]
+						if !identical(v.typ, w.typ, p) {
+							return false
+						}
+					}
+				}
+				return true
+			}
+		}
+
+	case *Signature:
+		// Two function types are identical if they have the same number of parameters
+		// and result values, corresponding parameter and result types are identical,
+		// and either both functions are variadic or neither is. Parameter and result
+		// names are not required to match.
+		if y, ok := y.(*Signature); ok {
+			return x.variadic == y.variadic &&
+				identical(x.params, y.params, p) &&
+				identical(x.results, y.results, p)
+		}
+
+	case *Interface:
+		// Two interface types are identical if they have the same set of methods with
+		// the same names and identical function types. Lower-case method names from
+		// different packages are always different. The order of the methods is irrelevant.
+		if y, ok := y.(*Interface); ok {
+			a := x.allMethods
+			b := y.allMethods
+			if len(a) == len(b) {
+				// Interface types are the only types where cycles can occur
+				// that are not "terminated" via named types; and such cycles
+				// can only be created via method parameter types that are
+				// anonymous interfaces (directly or indirectly) embedding
+				// the current interface. Example:
+				//
+				//    type T interface {
+				//        m() interface{T}
+				//    }
+				//
+				// If two such (differently named) interfaces are compared,
+				// endless recursion occurs if the cycle is not detected.
+				//
+				// If x and y were compared before, they must be equal
+				// (if they were not, the recursion would have stopped);
+				// search the ifacePair stack for the same pair.
+				//
+				// This is a quadratic algorithm, but in practice these stacks
+				// are extremely short (bounded by the nesting depth of interface
+				// type declarations that recur via parameter types, an extremely
+				// rare occurrence). An alternative implementation might use a
+				// "visited" map, but that is probably less efficient overall.
+				q := &ifacePair{x, y, p}
+				for p != nil {
+					if p.identical(q) {
+						return true // same pair was compared before
+					}
+					p = p.prev
+				}
+				if debug {
+					assert(sort.IsSorted(byUniqueMethodName(a)))
+					assert(sort.IsSorted(byUniqueMethodName(b)))
+				}
+				for i, f := range a {
+					g := b[i]
+					if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+						return false
+					}
+				}
+				return true
+			}
+		}
+
+	case *Map:
+		// Two map types are identical if they have identical key and value types.
+		if y, ok := y.(*Map); ok {
+			return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+		}
+
+	case *Chan:
+		// Two channel types are identical if they have identical value types
+		// and the same direction.
+		if y, ok := y.(*Chan); ok {
+			return x.dir == y.dir && identical(x.elem, y.elem, p)
+		}
+
+	case *Named:
+		// Two named types are identical if their type names originate
+		// in the same type declaration.
+		if y, ok := y.(*Named); ok {
+			return x.obj == y.obj
+		}
+
+	default:
+		unreachable()
+	}
+
+	return false
+}
+
+// defaultType returns the default "typed" type for an "untyped" type;
+// it returns the incoming type for all other types. The default type
+// for untyped nil is untyped nil.
+//
+func defaultType(typ Type) Type {
+	if t, ok := typ.(*Basic); ok {
+		switch t.kind {
+		case UntypedBool:
+			return Typ[Bool]
+		case UntypedInt:
+			return Typ[Int]
+		case UntypedRune:
+			return UniverseRune // use 'rune' name
+		case UntypedFloat:
+			return Typ[Float64]
+		case UntypedComplex:
+			return Typ[Complex128]
+		case UntypedString:
+			return Typ[String]
+		}
+	}
+	return typ
+}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
new file mode 100644
index 0000000..be46b59
--- /dev/null
+++ b/src/go/types/resolver.go
@@ -0,0 +1,438 @@
+// Copyright 2013 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 types
+
+import (
+	"fmt"
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+	pathLib "path"
+	"strconv"
+	"strings"
+	"unicode"
+)
+
+// A declInfo describes a package-level const, type, var, or func declaration.
+type declInfo struct {
+	file  *Scope        // scope of file containing this declaration
+	lhs   []*Var        // lhs of n:1 variable declarations, or nil
+	typ   ast.Expr      // type, or nil
+	init  ast.Expr      // init expression, or nil
+	fdecl *ast.FuncDecl // func declaration, or nil
+
+	deps map[Object]bool // type and init dependencies; lazily allocated
+	mark int             // for dependency analysis
+}
+
+// hasInitializer reports whether the declared object has an initialization
+// expression or function body.
+func (d *declInfo) hasInitializer() bool {
+	return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
+}
+
+// addDep adds obj as a dependency to d.
+func (d *declInfo) addDep(obj Object) {
+	m := d.deps
+	if m == nil {
+		m = make(map[Object]bool)
+		d.deps = m
+	}
+	m[obj] = true
+}
+
+// arityMatch checks that the lhs and rhs of a const or var decl
+// have the appropriate number of names and init exprs. For const
+// decls, init is the value spec providing the init exprs; for
+// var decls, init is nil (the init exprs are in s in this case).
+func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
+	l := len(s.Names)
+	r := len(s.Values)
+	if init != nil {
+		r = len(init.Values)
+	}
+
+	switch {
+	case init == nil && r == 0:
+		// var decl w/o init expr
+		if s.Type == nil {
+			check.errorf(s.Pos(), "missing type or init expr")
+		}
+	case l < r:
+		if l < len(s.Values) {
+			// init exprs from s
+			n := s.Values[l]
+			check.errorf(n.Pos(), "extra init expr %s", n)
+			// TODO(gri) avoid declared but not used error here
+		} else {
+			// init exprs "inherited"
+			check.errorf(s.Pos(), "extra init expr at %s", init.Pos())
+			// TODO(gri) avoid declared but not used error here
+		}
+	case l > r && (init != nil || r != 1):
+		n := s.Names[r]
+		check.errorf(n.Pos(), "missing init expr for %s", n)
+	}
+}
+
+func validatedImportPath(path string) (string, error) {
+	s, err := strconv.Unquote(path)
+	if err != nil {
+		return "", err
+	}
+	if s == "" {
+		return "", fmt.Errorf("empty string")
+	}
+	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+	for _, r := range s {
+		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+			return s, fmt.Errorf("invalid character %#U", r)
+		}
+	}
+	return s, nil
+}
+
+// declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
+// and updates check.objMap. The object must not be a function or method.
+func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
+	assert(ident.Name == obj.Name())
+
+	// spec: "A package-scope or file-scope identifier with name init
+	// may only be declared to be a function with this (func()) signature."
+	if ident.Name == "init" {
+		check.errorf(ident.Pos(), "cannot declare init - must be func")
+		return
+	}
+
+	check.declare(check.pkg.scope, ident, obj)
+	check.objMap[obj] = d
+	obj.setOrder(uint32(len(check.objMap)))
+}
+
+// filename returns a filename suitable for debugging output.
+func (check *Checker) filename(fileNo int) string {
+	file := check.files[fileNo]
+	if pos := file.Pos(); pos.IsValid() {
+		return check.fset.File(pos).Name()
+	}
+	return fmt.Sprintf("file[%d]", fileNo)
+}
+
+// collectObjects collects all file and package objects and inserts them
+// into their respective scopes. It also performs imports and associates
+// methods with receiver base type names.
+func (check *Checker) collectObjects() {
+	pkg := check.pkg
+
+	// pkgImports is the set of packages already imported by any package file seen
+	// so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
+	// it (pkg.imports may not be empty if we are checking test files incrementally).
+	var pkgImports = make(map[*Package]bool)
+	for _, imp := range pkg.imports {
+		pkgImports[imp] = true
+	}
+
+	for fileNo, file := range check.files {
+		// The package identifier denotes the current package,
+		// but there is no corresponding package object.
+		check.recordDef(file.Name, nil)
+
+		fileScope := NewScope(check.pkg.scope, check.filename(fileNo))
+		check.recordScope(file, fileScope)
+
+		for _, decl := range file.Decls {
+			switch d := decl.(type) {
+			case *ast.BadDecl:
+				// ignore
+
+			case *ast.GenDecl:
+				var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+				for iota, spec := range d.Specs {
+					switch s := spec.(type) {
+					case *ast.ImportSpec:
+						// import package
+						var imp *Package
+						path, err := validatedImportPath(s.Path.Value)
+						if err != nil {
+							check.errorf(s.Path.Pos(), "invalid import path (%s)", err)
+							continue
+						}
+						if path == "C" && check.conf.FakeImportC {
+							// TODO(gri) shouldn't create a new one each time
+							imp = NewPackage("C", "C")
+							imp.fake = true
+						} else if path == "unsafe" {
+							// package "unsafe" is known to the language
+							imp = Unsafe
+						} else {
+							if importer := check.conf.Importer; importer != nil {
+								imp, err = importer.Import(path)
+								if imp == nil && err == nil {
+									err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
+								}
+							} else {
+								err = fmt.Errorf("Config.Importer not installed")
+							}
+							if err != nil {
+								check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
+								continue
+							}
+						}
+
+						// add package to list of explicit imports
+						// (this functionality is provided as a convenience
+						// for clients; it is not needed for type-checking)
+						if !pkgImports[imp] {
+							pkgImports[imp] = true
+							if imp != Unsafe {
+								pkg.imports = append(pkg.imports, imp)
+							}
+						}
+
+						// local name overrides imported package name
+						name := imp.name
+						if s.Name != nil {
+							name = s.Name.Name
+							if name == "init" {
+								check.errorf(s.Name.Pos(), "cannot declare init - must be func")
+								continue
+							}
+						}
+
+						obj := NewPkgName(s.Pos(), pkg, name, imp)
+						if s.Name != nil {
+							// in a dot-import, the dot represents the package
+							check.recordDef(s.Name, obj)
+						} else {
+							check.recordImplicit(s, obj)
+						}
+
+						// add import to file scope
+						if name == "." {
+							// merge imported scope with file scope
+							for _, obj := range imp.scope.elems {
+								// A package scope may contain non-exported objects,
+								// do not import them!
+								if obj.Exported() {
+									// TODO(gri) When we import a package, we create
+									// a new local package object. We should do the
+									// same for each dot-imported object. That way
+									// they can have correct position information.
+									// (We must not modify their existing position
+									// information because the same package - found
+									// via Config.Packages - may be dot-imported in
+									// another package!)
+									check.declare(fileScope, nil, obj)
+									check.recordImplicit(s, obj)
+								}
+							}
+							// add position to set of dot-import positions for this file
+							// (this is only needed for "imported but not used" errors)
+							check.addUnusedDotImport(fileScope, imp, s.Pos())
+						} else {
+							// declare imported package object in file scope
+							check.declare(fileScope, nil, obj)
+						}
+
+					case *ast.ValueSpec:
+						switch d.Tok {
+						case token.CONST:
+							// determine which initialization expressions to use
+							switch {
+							case s.Type != nil || len(s.Values) > 0:
+								last = s
+							case last == nil:
+								last = new(ast.ValueSpec) // make sure last exists
+							}
+
+							// declare all constants
+							for i, name := range s.Names {
+								obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
+
+								var init ast.Expr
+								if i < len(last.Values) {
+									init = last.Values[i]
+								}
+
+								d := &declInfo{file: fileScope, typ: last.Type, init: init}
+								check.declarePkgObj(name, obj, d)
+							}
+
+							check.arityMatch(s, last)
+
+						case token.VAR:
+							lhs := make([]*Var, len(s.Names))
+							// If there's exactly one rhs initializer, use
+							// the same declInfo d1 for all lhs variables
+							// so that each lhs variable depends on the same
+							// rhs initializer (n:1 var declaration).
+							var d1 *declInfo
+							if len(s.Values) == 1 {
+								// The lhs elements are only set up after the for loop below,
+								// but that's ok because declareVar only collects the declInfo
+								// for a later phase.
+								d1 = &declInfo{file: fileScope, lhs: lhs, typ: s.Type, init: s.Values[0]}
+							}
+
+							// declare all variables
+							for i, name := range s.Names {
+								obj := NewVar(name.Pos(), pkg, name.Name, nil)
+								lhs[i] = obj
+
+								d := d1
+								if d == nil {
+									// individual assignments
+									var init ast.Expr
+									if i < len(s.Values) {
+										init = s.Values[i]
+									}
+									d = &declInfo{file: fileScope, typ: s.Type, init: init}
+								}
+
+								check.declarePkgObj(name, obj, d)
+							}
+
+							check.arityMatch(s, nil)
+
+						default:
+							check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+						}
+
+					case *ast.TypeSpec:
+						obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+
+					default:
+						check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
+					}
+				}
+
+			case *ast.FuncDecl:
+				name := d.Name.Name
+				obj := NewFunc(d.Name.Pos(), pkg, name, nil)
+				if d.Recv == nil {
+					// regular function
+					if name == "init" {
+						// don't declare init functions in the package scope - they are invisible
+						obj.parent = pkg.scope
+						check.recordDef(d.Name, obj)
+						// init functions must have a body
+						if d.Body == nil {
+							check.softErrorf(obj.pos, "missing function body")
+						}
+					} else {
+						check.declare(pkg.scope, d.Name, obj)
+					}
+				} else {
+					// method
+					check.recordDef(d.Name, obj)
+					// Associate method with receiver base type name, if possible.
+					// Ignore methods that have an invalid receiver, or a blank _
+					// receiver name. They will be type-checked later, with regular
+					// functions.
+					if list := d.Recv.List; len(list) > 0 {
+						typ := list[0].Type
+						if ptr, _ := typ.(*ast.StarExpr); ptr != nil {
+							typ = ptr.X
+						}
+						if base, _ := typ.(*ast.Ident); base != nil && base.Name != "_" {
+							check.assocMethod(base.Name, obj)
+						}
+					}
+				}
+				info := &declInfo{file: fileScope, fdecl: d}
+				check.objMap[obj] = info
+				obj.setOrder(uint32(len(check.objMap)))
+
+			default:
+				check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+			}
+		}
+	}
+
+	// verify that objects in package and file scopes have different names
+	for _, scope := range check.pkg.scope.children /* file scopes */ {
+		for _, obj := range scope.elems {
+			if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
+				if pkg, ok := obj.(*PkgName); ok {
+					check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported())
+					check.reportAltDecl(pkg)
+				} else {
+					check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+					// TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
+					check.reportAltDecl(obj)
+				}
+			}
+		}
+	}
+}
+
+// packageObjects typechecks all package objects in objList, but not function bodies.
+func (check *Checker) packageObjects(objList []Object) {
+	// add new methods to already type-checked types (from a prior Checker.Files call)
+	for _, obj := range objList {
+		if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
+			check.addMethodDecls(obj)
+		}
+	}
+
+	// pre-allocate space for type declaration paths so that the underlying array is reused
+	typePath := make([]*TypeName, 0, 8)
+
+	for _, obj := range objList {
+		check.objDecl(obj, nil, typePath)
+	}
+
+	// At this point we may have a non-empty check.methods map; this means that not all
+	// entries were deleted at the end of typeDecl because the respective receiver base
+	// types were not found. In that case, an error was reported when declaring those
+	// methods. We can now safely discard this map.
+	check.methods = nil
+}
+
+// functionBodies typechecks all function bodies.
+func (check *Checker) functionBodies() {
+	for _, f := range check.funcs {
+		check.funcBody(f.decl, f.name, f.sig, f.body)
+	}
+}
+
+// unusedImports checks for unused imports.
+func (check *Checker) unusedImports() {
+	// if function bodies are not checked, packages' uses are likely missing - don't check
+	if check.conf.IgnoreFuncBodies {
+		return
+	}
+
+	// spec: "It is illegal (...) to directly import a package without referring to
+	// any of its exported identifiers. To import a package solely for its side-effects
+	// (initialization), use the blank identifier as explicit package name."
+
+	// check use of regular imported packages
+	for _, scope := range check.pkg.scope.children /* file scopes */ {
+		for _, obj := range scope.elems {
+			if obj, ok := obj.(*PkgName); ok {
+				// Unused "blank imports" are automatically ignored
+				// since _ identifiers are not entered into scopes.
+				if !obj.used {
+					path := obj.imported.path
+					base := pathLib.Base(path)
+					if obj.name == base {
+						check.softErrorf(obj.pos, "%q imported but not used", path)
+					} else {
+						check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+					}
+				}
+			}
+		}
+	}
+
+	// check use of dot-imported packages
+	for _, unusedDotImports := range check.unusedDotImports {
+		for pkg, pos := range unusedDotImports {
+			check.softErrorf(pos, "%q imported but not used", pkg.path)
+		}
+	}
+}
diff --git a/src/go/types/resolver_test.go b/src/go/types/resolver_test.go
new file mode 100644
index 0000000..5713065
--- /dev/null
+++ b/src/go/types/resolver_test.go
@@ -0,0 +1,208 @@
+// Copyright 2011 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 types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"sort"
+	"testing"
+
+	. "go/types"
+)
+
+var sources = []string{
+	`
+	package p
+	import "fmt"
+	import "math"
+	const pi = math.Pi
+	func sin(x float64) float64 {
+		return math.Sin(x)
+	}
+	var Println = fmt.Println
+	`,
+	`
+	package p
+	import "fmt"
+	type errorStringer struct { fmt.Stringer; error }
+	func f() string {
+		_ = "foo"
+		return fmt.Sprintf("%d", g())
+	}
+	func g() (x int) { return }
+	`,
+	`
+	package p
+	import . "go/parser"
+	import "sync"
+	func h() Mode { return ImportsOnly }
+	var _, x int = 1, 2
+	func init() {}
+	type T struct{ *sync.Mutex; a, b, c int}
+	type I interface{ m() }
+	var _ = T{a: 1, b: 2, c: 3}
+	func (_ T) m() {}
+	func (T) _() {}
+	var i I
+	var _ = i.m
+	func _(s []int) { for i, x := range s { _, _ = i, x } }
+	func _(x interface{}) {
+		switch x := x.(type) {
+		case int:
+			_ = x
+		}
+		switch {} // implicit 'true' tag
+	}
+	`,
+	`
+	package p
+	type S struct{}
+	func (T) _() {}
+	func (T) _() {}
+	`,
+	`
+	package p
+	func _() {
+	L0:
+	L1:
+		goto L0
+		for {
+			goto L1
+		}
+		if true {
+			goto L2
+		}
+	L2:
+	}
+	`,
+}
+
+var pkgnames = []string{
+	"fmt",
+	"math",
+}
+
+type resolveTestImporter struct {
+	importer Importer
+	imported map[string]bool
+}
+
+func (imp *resolveTestImporter) Import(path string) (*Package, error) {
+	if imp.importer == nil {
+		imp.importer = importer.Default()
+		imp.imported = make(map[string]bool)
+	}
+	pkg, err := imp.importer.Import(path)
+	if err != nil {
+		return nil, err
+	}
+	imp.imported[path] = true
+	return pkg, nil
+}
+
+func TestResolveIdents(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// parse package files
+	fset := token.NewFileSet()
+	var files []*ast.File
+	for i, src := range sources {
+		f, err := parser.ParseFile(fset, fmt.Sprintf("sources[%d]", i), src, parser.DeclarationErrors)
+		if err != nil {
+			t.Fatal(err)
+		}
+		files = append(files, f)
+	}
+
+	// resolve and type-check package AST
+	importer := new(resolveTestImporter)
+	conf := Config{Importer: importer}
+	uses := make(map[*ast.Ident]Object)
+	defs := make(map[*ast.Ident]Object)
+	_, err := conf.Check("testResolveIdents", fset, files, &Info{Defs: defs, Uses: uses})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// check that all packages were imported
+	for _, name := range pkgnames {
+		if !importer.imported[name] {
+			t.Errorf("package %s not imported", name)
+		}
+	}
+
+	// check that qualified identifiers are resolved
+	for _, f := range files {
+		ast.Inspect(f, func(n ast.Node) bool {
+			if s, ok := n.(*ast.SelectorExpr); ok {
+				if x, ok := s.X.(*ast.Ident); ok {
+					obj := uses[x]
+					if obj == nil {
+						t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
+						return false
+					}
+					if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil {
+						t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name)
+						return false
+					}
+					return false
+				}
+				return false
+			}
+			return true
+		})
+	}
+
+	for id, obj := range uses {
+		if obj == nil {
+			t.Errorf("%s: Uses[%s] == nil", fset.Position(id.Pos()), id.Name)
+		}
+	}
+
+	// check that each identifier in the source is found in uses or defs or both
+	var both []string
+	for _, f := range files {
+		ast.Inspect(f, func(n ast.Node) bool {
+			if x, ok := n.(*ast.Ident); ok {
+				var objects int
+				if _, found := uses[x]; found {
+					objects |= 1
+					delete(uses, x)
+				}
+				if _, found := defs[x]; found {
+					objects |= 2
+					delete(defs, x)
+				}
+				if objects == 0 {
+					t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name)
+				} else if objects == 3 {
+					both = append(both, x.Name)
+				}
+				return false
+			}
+			return true
+		})
+	}
+
+	// check the expected set of idents that are simultaneously uses and defs
+	sort.Strings(both)
+	if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want {
+		t.Errorf("simultaneous uses/defs = %s, want %s", got, want)
+	}
+
+	// any left-over identifiers didn't exist in the source
+	for x := range uses {
+		t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+	}
+	for x := range defs {
+		t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+	}
+
+	// TODO(gri) add tests to check ImplicitObj callbacks
+}
diff --git a/src/go/types/return.go b/src/go/types/return.go
new file mode 100644
index 0000000..df5a482
--- /dev/null
+++ b/src/go/types/return.go
@@ -0,0 +1,185 @@
+// Copyright 2013 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.
+
+// This file implements isTerminating.
+
+package types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+// isTerminating reports if s is a terminating statement.
+// If s is labeled, label is the label name; otherwise s
+// is "".
+func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
+	switch s := s.(type) {
+	default:
+		unreachable()
+
+	case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt,
+		*ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt,
+		*ast.RangeStmt:
+		// no chance
+
+	case *ast.LabeledStmt:
+		return check.isTerminating(s.Stmt, s.Label.Name)
+
+	case *ast.ExprStmt:
+		// the predeclared (possibly parenthesized) panic() function is terminating
+		if call, _ := unparen(s.X).(*ast.CallExpr); call != nil {
+			if id, _ := call.Fun.(*ast.Ident); id != nil {
+				if _, obj := check.scope.LookupParent(id.Name); obj != nil {
+					if b, _ := obj.(*Builtin); b != nil && b.id == _Panic {
+						return true
+					}
+				}
+			}
+		}
+
+	case *ast.ReturnStmt:
+		return true
+
+	case *ast.BranchStmt:
+		if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH {
+			return true
+		}
+
+	case *ast.BlockStmt:
+		return check.isTerminatingList(s.List, "")
+
+	case *ast.IfStmt:
+		if s.Else != nil &&
+			check.isTerminating(s.Body, "") &&
+			check.isTerminating(s.Else, "") {
+			return true
+		}
+
+	case *ast.SwitchStmt:
+		return check.isTerminatingSwitch(s.Body, label)
+
+	case *ast.TypeSwitchStmt:
+		return check.isTerminatingSwitch(s.Body, label)
+
+	case *ast.SelectStmt:
+		for _, s := range s.Body.List {
+			cc := s.(*ast.CommClause)
+			if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+				return false
+			}
+
+		}
+		return true
+
+	case *ast.ForStmt:
+		if s.Cond == nil && !hasBreak(s.Body, label, true) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool {
+	n := len(list)
+	return n > 0 && check.isTerminating(list[n-1], label)
+}
+
+func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool {
+	hasDefault := false
+	for _, s := range body.List {
+		cc := s.(*ast.CaseClause)
+		if cc.List == nil {
+			hasDefault = true
+		}
+		if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+			return false
+		}
+	}
+	return hasDefault
+}
+
+// TODO(gri) For nested breakable statements, the current implementation of hasBreak
+//	     will traverse the same subtree repeatedly, once for each label. Replace
+//           with a single-pass label/break matching phase.
+
+// hasBreak reports if s is or contains a break statement
+// referring to the label-ed statement or implicit-ly the
+// closest outer breakable statement.
+func hasBreak(s ast.Stmt, label string, implicit bool) bool {
+	switch s := s.(type) {
+	default:
+		unreachable()
+
+	case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt,
+		*ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt,
+		*ast.DeferStmt, *ast.ReturnStmt:
+		// no chance
+
+	case *ast.LabeledStmt:
+		return hasBreak(s.Stmt, label, implicit)
+
+	case *ast.BranchStmt:
+		if s.Tok == token.BREAK {
+			if s.Label == nil {
+				return implicit
+			}
+			if s.Label.Name == label {
+				return true
+			}
+		}
+
+	case *ast.BlockStmt:
+		return hasBreakList(s.List, label, implicit)
+
+	case *ast.IfStmt:
+		if hasBreak(s.Body, label, implicit) ||
+			s.Else != nil && hasBreak(s.Else, label, implicit) {
+			return true
+		}
+
+	case *ast.CaseClause:
+		return hasBreakList(s.Body, label, implicit)
+
+	case *ast.SwitchStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.TypeSwitchStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.CommClause:
+		return hasBreakList(s.Body, label, implicit)
+
+	case *ast.SelectStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.ForStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.RangeStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func hasBreakList(list []ast.Stmt, label string, implicit bool) bool {
+	for _, s := range list {
+		if hasBreak(s, label, implicit) {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/go/types/scope.go b/src/go/types/scope.go
new file mode 100644
index 0000000..8ab0f64
--- /dev/null
+++ b/src/go/types/scope.go
@@ -0,0 +1,145 @@
+// Copyright 2013 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.
+
+// This file implements Scopes.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"sort"
+	"strings"
+)
+
+// TODO(gri) Provide scopes with a name or other mechanism so that
+//           objects can use that information for better printing.
+
+// A Scope maintains a set of objects and links to its containing
+// (parent) and contained (children) scopes. Objects may be inserted
+// and looked up by name. The zero value for Scope is a ready-to-use
+// empty scope.
+type Scope struct {
+	parent   *Scope
+	children []*Scope
+	comment  string            // for debugging only
+	elems    map[string]Object // lazily allocated
+}
+
+// NewScope returns a new, empty scope contained in the given parent
+// scope, if any.  The comment is for debugging only.
+func NewScope(parent *Scope, comment string) *Scope {
+	s := &Scope{parent: parent, comment: comment}
+	// don't add children to Universe scope!
+	if parent != nil && parent != Universe {
+		parent.children = append(parent.children, s)
+	}
+	return s
+}
+
+// Parent returns the scope's containing (parent) scope.
+func (s *Scope) Parent() *Scope { return s.parent }
+
+// Len() returns the number of scope elements.
+func (s *Scope) Len() int { return len(s.elems) }
+
+// Names returns the scope's element names in sorted order.
+func (s *Scope) Names() []string {
+	names := make([]string, len(s.elems))
+	i := 0
+	for name := range s.elems {
+		names[i] = name
+		i++
+	}
+	sort.Strings(names)
+	return names
+}
+
+// NumChildren() returns the number of scopes nested in s.
+func (s *Scope) NumChildren() int { return len(s.children) }
+
+// Child returns the i'th child scope for 0 <= i < NumChildren().
+func (s *Scope) Child(i int) *Scope { return s.children[i] }
+
+// Lookup returns the object in scope s with the given name if such an
+// object exists; otherwise the result is nil.
+func (s *Scope) Lookup(name string) Object {
+	return s.elems[name]
+}
+
+// LookupParent follows the parent chain of scopes starting with s until
+// it finds a scope where Lookup(name) returns a non-nil object, and then
+// returns that scope and object. If no such scope exists, the result is (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Insert, below). This can only happen for dot-imported objects
+// whose scope is the scope of the package that exported them.
+func (s *Scope) LookupParent(name string) (*Scope, Object) {
+	for ; s != nil; s = s.parent {
+		if obj := s.elems[name]; obj != nil {
+			return s, obj
+		}
+	}
+	return nil, nil
+}
+
+// Insert attempts to insert an object obj into scope s.
+// If s already contains an alternative object alt with
+// the same name, Insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj, sets the object's parent scope
+// if not already set, and returns nil.
+func (s *Scope) Insert(obj Object) Object {
+	name := obj.Name()
+	if alt := s.elems[name]; alt != nil {
+		return alt
+	}
+	if s.elems == nil {
+		s.elems = make(map[string]Object)
+	}
+	s.elems[name] = obj
+	if obj.Parent() == nil {
+		obj.setParent(s)
+	}
+	return nil
+}
+
+// WriteTo writes a string representation of the scope to w,
+// with the scope elements sorted by name.
+// The level of indentation is controlled by n >= 0, with
+// n == 0 for no indentation.
+// If recurse is set, it also writes nested (children) scopes.
+func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
+	const ind = ".  "
+	indn := strings.Repeat(ind, n)
+
+	fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s)
+	if len(s.elems) == 0 {
+		fmt.Fprintf(w, "}\n")
+		return
+	}
+
+	fmt.Fprintln(w)
+	indn1 := indn + ind
+	for _, name := range s.Names() {
+		fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
+	}
+
+	if recurse {
+		for _, s := range s.children {
+			fmt.Fprintln(w)
+			s.WriteTo(w, n+1, recurse)
+		}
+	}
+
+	fmt.Fprintf(w, "%s}", indn)
+}
+
+// String returns a string representation of the scope, for debugging.
+func (s *Scope) String() string {
+	var buf bytes.Buffer
+	s.WriteTo(&buf, 0, false)
+	return buf.String()
+}
diff --git a/src/go/types/selection.go b/src/go/types/selection.go
new file mode 100644
index 0000000..1c70165
--- /dev/null
+++ b/src/go/types/selection.go
@@ -0,0 +1,143 @@
+// Copyright 2013 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.
+
+// This file implements Selections.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// SelectionKind describes the kind of a selector expression x.f
+// (excluding qualified identifiers).
+type SelectionKind int
+
+const (
+	FieldVal   SelectionKind = iota // x.f is a struct field selector
+	MethodVal                       // x.f is a method selector
+	MethodExpr                      // x.f is a method expression
+)
+
+// A Selection describes a selector expression x.f.
+// For the declarations:
+//
+//	type T struct{ x int; E }
+//	type E struct{}
+//	func (e E) m() {}
+//	var p *T
+//
+// the following relations exist:
+//
+//	Selector    Kind          Recv    Obj    Type               Index     Indirect
+//
+//	p.x         FieldVal      T       x      int                {0}       true
+//	p.m         MethodVal     *T      m      func (e *T) m()    {1, 0}    true
+//	T.m         MethodExpr    T       m      func m(_ T)        {1, 0}    false
+//
+type Selection struct {
+	kind     SelectionKind
+	recv     Type   // type of x
+	obj      Object // object denoted by x.f
+	index    []int  // path from x to x.f
+	indirect bool   // set if there was any pointer indirection on the path
+}
+
+// Kind returns the selection kind.
+func (s *Selection) Kind() SelectionKind { return s.kind }
+
+// Recv returns the type of x in x.f.
+func (s *Selection) Recv() Type { return s.recv }
+
+// Obj returns the object denoted by x.f; a *Var for
+// a field selection, and a *Func in all other cases.
+func (s *Selection) Obj() Object { return s.obj }
+
+// Type returns the type of x.f, which may be different from the type of f.
+// See Selection for more information.
+func (s *Selection) Type() Type {
+	switch s.kind {
+	case MethodVal:
+		// The type of x.f is a method with its receiver type set
+		// to the type of x.
+		sig := *s.obj.(*Func).typ.(*Signature)
+		recv := *sig.recv
+		recv.typ = s.recv
+		sig.recv = &recv
+		return &sig
+
+	case MethodExpr:
+		// The type of x.f is a function (without receiver)
+		// and an additional first argument with the same type as x.
+		// TODO(gri) Similar code is already in call.go - factor!
+		// TODO(gri) Compute this eagerly to avoid allocations.
+		sig := *s.obj.(*Func).typ.(*Signature)
+		arg0 := *sig.recv
+		sig.recv = nil
+		arg0.typ = s.recv
+		var params []*Var
+		if sig.params != nil {
+			params = sig.params.vars
+		}
+		sig.params = NewTuple(append([]*Var{&arg0}, params...)...)
+		return &sig
+	}
+
+	// In all other cases, the type of x.f is the type of x.
+	return s.obj.Type()
+}
+
+// Index describes the path from x to f in x.f.
+// The last index entry is the field or method index of the type declaring f;
+// either:
+//
+//	1) the list of declared methods of a named type; or
+//	2) the list of methods of an interface type; or
+//	3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the embedded fields implicitly
+// traversed to get from (the type of) x to f, starting at embedding depth 0.
+func (s *Selection) Index() []int { return s.index }
+
+// Indirect reports whether any pointer indirection was required to get from
+// x to f in x.f.
+func (s *Selection) Indirect() bool { return s.indirect }
+
+func (s *Selection) String() string { return SelectionString(nil, s) }
+
+// SelectionString returns the string form of s.
+// Type names are printed package-qualified
+// only if they do not belong to this package.
+//
+// Examples:
+//	"field (T) f int"
+//	"method (T) f(X) Y"
+//	"method expr (T) f(X) Y"
+//
+func SelectionString(this *Package, s *Selection) string {
+	var k string
+	switch s.kind {
+	case FieldVal:
+		k = "field "
+	case MethodVal:
+		k = "method "
+	case MethodExpr:
+		k = "method expr "
+	default:
+		unreachable()
+	}
+	var buf bytes.Buffer
+	buf.WriteString(k)
+	buf.WriteByte('(')
+	WriteType(&buf, this, s.Recv())
+	fmt.Fprintf(&buf, ") %s", s.obj.Name())
+	if T := s.Type(); s.kind == FieldVal {
+		buf.WriteByte(' ')
+		WriteType(&buf, this, T)
+	} else {
+		WriteSignature(&buf, this, T.(*Signature))
+	}
+	return buf.String()
+}
diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go
new file mode 100644
index 0000000..85dc6ae
--- /dev/null
+++ b/src/go/types/self_test.go
@@ -0,0 +1,103 @@
+// Copyright 2013 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 types_test
+
+import (
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"path/filepath"
+	"testing"
+	"time"
+
+	_ "go/internal/gcimporter"
+	. "go/types"
+)
+
+var benchmark = flag.Bool("b", false, "run benchmarks")
+
+func TestSelf(t *testing.T) {
+	fset := token.NewFileSet()
+	files, err := pkgFiles(fset, ".")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	conf := Config{Importer: importer.Default()}
+	_, err = conf.Check("go/types", fset, files, nil)
+	if err != nil {
+		// Importing go/constants 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
+		t.Log(err) // replace w/ t.Fatal eventually
+		return
+	}
+}
+
+func TestBenchmark(t *testing.T) {
+	if !*benchmark {
+		return
+	}
+
+	// We're not using testing's benchmarking mechanism directly
+	// because we want custom output.
+
+	for _, p := range []string{"types", "exact", "gcimporter"} {
+		path := filepath.Join("..", p)
+		runbench(t, path, false)
+		runbench(t, path, true)
+		fmt.Println()
+	}
+}
+
+func runbench(t *testing.T, path string, ignoreFuncBodies bool) {
+	fset := token.NewFileSet()
+	files, err := pkgFiles(fset, path)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	b := testing.Benchmark(func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			conf := Config{IgnoreFuncBodies: ignoreFuncBodies}
+			conf.Check(path, fset, files, nil)
+		}
+	})
+
+	// determine line count
+	lines := 0
+	fset.Iterate(func(f *token.File) bool {
+		lines += f.LineCount()
+		return true
+	})
+
+	d := time.Duration(b.NsPerOp())
+	fmt.Printf(
+		"%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n",
+		filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies,
+	)
+}
+
+func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
+	filenames, err := pkgFilenames(path) // from stdlib_test.go
+	if err != nil {
+		return nil, err
+	}
+
+	var files []*ast.File
+	for _, filename := range filenames {
+		file, err := parser.ParseFile(fset, filename, nil, 0)
+		if err != nil {
+			return nil, err
+		}
+		files = append(files, file)
+	}
+
+	return files, nil
+}
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
new file mode 100644
index 0000000..56fb310
--- /dev/null
+++ b/src/go/types/sizes.go
@@ -0,0 +1,211 @@
+// Copyright 2013 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.
+
+// This file implements Sizes.
+
+package types
+
+// Sizes defines the sizing functions for package unsafe.
+type Sizes interface {
+	// Alignof returns the alignment of a variable of type T.
+	// Alignof must implement the alignment guarantees required by the spec.
+	Alignof(T Type) int64
+
+	// Offsetsof returns the offsets of the given struct fields, in bytes.
+	// Offsetsof must implement the offset guarantees required by the spec.
+	Offsetsof(fields []*Var) []int64
+
+	// Sizeof returns the size of a variable of type T.
+	// Sizeof must implement the size guarantees required by the spec.
+	Sizeof(T Type) int64
+}
+
+// StdSizes is a convenience type for creating commonly used Sizes.
+// It makes the following simplifying assumptions:
+//
+//	- The size of explicitly sized basic types (int16, etc.) is the
+//	  specified size.
+//	- The size of strings and interfaces is 2*WordSize.
+//	- The size of slices is 3*WordSize.
+//	- The size of an array of n elements corresponds to the size of
+//	  a struct of n consecutive fields of the array's element type.
+//      - The size of a struct is the offset of the last field plus that
+//	  field's size. As with all element types, if the struct is used
+//	  in an array its size must first be aligned to a multiple of the
+//	  struct's alignment.
+//	- All other types have size WordSize.
+//	- Arrays and structs are aligned per spec definition; all other
+//	  types are naturally aligned with a maximum alignment MaxAlign.
+//
+// *StdSizes implements Sizes.
+//
+type StdSizes struct {
+	WordSize int64 // word size in bytes - must be >= 4 (32bits)
+	MaxAlign int64 // maximum alignment in bytes - must be >= 1
+}
+
+func (s *StdSizes) Alignof(T Type) int64 {
+	// For arrays and structs, alignment is defined in terms
+	// of alignment of the elements and fields, respectively.
+	switch t := T.Underlying().(type) {
+	case *Array:
+		// spec: "For a variable x of array type: unsafe.Alignof(x)
+		// is the same as unsafe.Alignof(x[0]), but at least 1."
+		return s.Alignof(t.elem)
+	case *Struct:
+		// spec: "For a variable x of struct type: unsafe.Alignof(x)
+		// is the largest of the values unsafe.Alignof(x.f) for each
+		// field f of x, but at least 1."
+		max := int64(1)
+		for _, f := range t.fields {
+			if a := s.Alignof(f.typ); a > max {
+				max = a
+			}
+		}
+		return max
+	}
+	a := s.Sizeof(T) // may be 0
+	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+	if a < 1 {
+		return 1
+	}
+	if a > s.MaxAlign {
+		return s.MaxAlign
+	}
+	return a
+}
+
+func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
+	offsets := make([]int64, len(fields))
+	var o int64
+	for i, f := range fields {
+		a := s.Alignof(f.typ)
+		o = align(o, a)
+		offsets[i] = o
+		o += s.Sizeof(f.typ)
+	}
+	return offsets
+}
+
+var basicSizes = [...]byte{
+	Bool:       1,
+	Int8:       1,
+	Int16:      2,
+	Int32:      4,
+	Int64:      8,
+	Uint8:      1,
+	Uint16:     2,
+	Uint32:     4,
+	Uint64:     8,
+	Float32:    4,
+	Float64:    8,
+	Complex64:  8,
+	Complex128: 16,
+}
+
+func (s *StdSizes) Sizeof(T Type) int64 {
+	switch t := T.Underlying().(type) {
+	case *Basic:
+		assert(isTyped(T))
+		k := t.kind
+		if int(k) < len(basicSizes) {
+			if s := basicSizes[k]; s > 0 {
+				return int64(s)
+			}
+		}
+		if k == String {
+			return s.WordSize * 2
+		}
+	case *Array:
+		n := t.len
+		if n == 0 {
+			return 0
+		}
+		a := s.Alignof(t.elem)
+		z := s.Sizeof(t.elem)
+		return align(z, a)*(n-1) + z
+	case *Slice:
+		return s.WordSize * 3
+	case *Struct:
+		n := t.NumFields()
+		if n == 0 {
+			return 0
+		}
+		offsets := t.offsets
+		if t.offsets == nil {
+			// compute offsets on demand
+			offsets = s.Offsetsof(t.fields)
+			t.offsets = offsets
+		}
+		return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+	case *Interface:
+		return s.WordSize * 2
+	}
+	return s.WordSize // catch-all
+}
+
+// stdSizes is used if Config.Sizes == nil.
+var stdSizes = StdSizes{8, 8}
+
+func (conf *Config) alignof(T Type) int64 {
+	if s := conf.Sizes; s != nil {
+		if a := s.Alignof(T); a >= 1 {
+			return a
+		}
+		panic("Config.Sizes.Alignof returned an alignment < 1")
+	}
+	return stdSizes.Alignof(T)
+}
+
+func (conf *Config) offsetsof(T *Struct) []int64 {
+	offsets := T.offsets
+	if offsets == nil && T.NumFields() > 0 {
+		// compute offsets on demand
+		if s := conf.Sizes; s != nil {
+			offsets = s.Offsetsof(T.fields)
+			// sanity checks
+			if len(offsets) != T.NumFields() {
+				panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+			}
+			for _, o := range offsets {
+				if o < 0 {
+					panic("Config.Sizes.Offsetsof returned an offset < 0")
+				}
+			}
+		} else {
+			offsets = stdSizes.Offsetsof(T.fields)
+		}
+		T.offsets = offsets
+	}
+	return offsets
+}
+
+// offsetof returns the offset of the field specified via
+// the index sequence relative to typ. All embedded fields
+// must be structs (rather than pointer to structs).
+func (conf *Config) offsetof(typ Type, index []int) int64 {
+	var o int64
+	for _, i := range index {
+		s := typ.Underlying().(*Struct)
+		o += conf.offsetsof(s)[i]
+		typ = s.fields[i].typ
+	}
+	return o
+}
+
+func (conf *Config) sizeof(T Type) int64 {
+	if s := conf.Sizes; s != nil {
+		if z := s.Sizeof(T); z >= 0 {
+			return z
+		}
+		panic("Config.Sizes.Sizeof returned a size < 0")
+	}
+	return stdSizes.Sizeof(T)
+}
+
+// align returns the smallest y >= x such that y % a == 0.
+func align(x, a int64) int64 {
+	y := x + a - 1
+	return y - y%a
+}
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
new file mode 100644
index 0000000..d04dd71
--- /dev/null
+++ b/src/go/types/stdlib_test.go
@@ -0,0 +1,275 @@
+// Copyright 2013 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.
+
+// This file tests types.Check by using it to
+// typecheck the standard library and tests.
+
+package types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/importer"
+	"go/parser"
+	"go/scanner"
+	"go/token"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+
+	. "go/types"
+)
+
+var (
+	pkgCount int // number of packages processed
+	start    time.Time
+
+	// Use the same importer for all std lib tests to
+	// avoid repeated importing of the same packages.
+	stdLibImporter = importer.Default()
+)
+
+func TestStdlib(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	start = time.Now()
+	walkDirs(t, filepath.Join(runtime.GOROOT(), "src"))
+	if testing.Verbose() {
+		fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
+	}
+}
+
+// firstComment returns the contents of the first comment in
+// the given file, assuming there's one within the first KB.
+func firstComment(filename string) string {
+	f, err := os.Open(filename)
+	if err != nil {
+		return ""
+	}
+	defer f.Close()
+
+	var src [1 << 10]byte // read at most 1KB
+	n, _ := f.Read(src[:])
+
+	var s scanner.Scanner
+	s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments)
+	for {
+		_, tok, lit := s.Scan()
+		switch tok {
+		case token.COMMENT:
+			// remove trailing */ of multi-line comment
+			if lit[1] == '*' {
+				lit = lit[:len(lit)-2]
+			}
+			return strings.TrimSpace(lit[2:])
+		case token.EOF:
+			return ""
+		}
+	}
+}
+
+func testTestDir(t *testing.T, path string, ignore ...string) {
+	files, err := ioutil.ReadDir(path)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	excluded := make(map[string]bool)
+	for _, filename := range ignore {
+		excluded[filename] = true
+	}
+
+	fset := token.NewFileSet()
+	for _, f := range files {
+		// filter directory contents
+		if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
+			continue
+		}
+
+		// get per-file instructions
+		expectErrors := false
+		filename := filepath.Join(path, f.Name())
+		if cmd := firstComment(filename); cmd != "" {
+			switch cmd {
+			case "skip", "compiledir":
+				continue // ignore this file
+			case "errorcheck":
+				expectErrors = true
+			}
+		}
+
+		// parse and type-check file
+		file, err := parser.ParseFile(fset, filename, nil, 0)
+		if err == nil {
+			conf := Config{Importer: stdLibImporter}
+			_, err = conf.Check(filename, fset, []*ast.File{file}, nil)
+		}
+
+		if expectErrors {
+			if err == nil {
+				t.Errorf("expected errors but found none in %s", filename)
+			}
+		} else {
+			if err != nil {
+				t.Error(err)
+			}
+		}
+	}
+}
+
+func TestStdTest(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// test/recover4.go is only built for Linux and Darwin.
+	// TODO(gri) Remove once tests consider +build tags (issue 10370).
+	if runtime.GOOS != "linux" || runtime.GOOS != "darwin" {
+		return
+	}
+
+	testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
+		"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
+		"sigchld.go",     // don't work on Windows; testTestDir should consult build tags
+	)
+}
+
+func TestStdFixed(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
+		"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
+		"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
+	)
+}
+
+func TestStdKen(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
+}
+
+// Package paths of excluded packages.
+var excluded = map[string]bool{
+	"builtin": true,
+}
+
+// typecheck typechecks the given package files.
+func typecheck(t *testing.T, path string, filenames []string) {
+	fset := token.NewFileSet()
+
+	// parse package files
+	var files []*ast.File
+	for _, filename := range filenames {
+		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+		if err != nil {
+			// the parser error may be a list of individual errors; report them all
+			if list, ok := err.(scanner.ErrorList); ok {
+				for _, err := range list {
+					t.Error(err)
+				}
+				return
+			}
+			t.Error(err)
+			return
+		}
+
+		if testing.Verbose() {
+			if len(files) == 0 {
+				fmt.Println("package", file.Name.Name)
+			}
+			fmt.Println("\t", filename)
+		}
+
+		files = append(files, file)
+	}
+
+	// typecheck package files
+	conf := Config{
+		Error:    func(err error) { t.Error(err) },
+		Importer: stdLibImporter,
+	}
+	info := Info{Uses: make(map[*ast.Ident]Object)}
+	conf.Check(path, fset, files, &info)
+	pkgCount++
+
+	// Perform checks of API invariants.
+
+	// All Objects have a package, except predeclared ones.
+	errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
+	for id, obj := range info.Uses {
+		predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
+		if predeclared == (obj.Pkg() != nil) {
+			posn := fset.Position(id.Pos())
+			if predeclared {
+				t.Errorf("%s: predeclared object with package: %s", posn, obj)
+			} else {
+				t.Errorf("%s: user-defined object without package: %s", posn, obj)
+			}
+		}
+	}
+}
+
+// pkgFilenames returns the list of package filenames for the given directory.
+func pkgFilenames(dir string) ([]string, error) {
+	ctxt := build.Default
+	ctxt.CgoEnabled = false
+	pkg, err := ctxt.ImportDir(dir, 0)
+	if err != nil {
+		if _, nogo := err.(*build.NoGoError); nogo {
+			return nil, nil // no *.go files, not an error
+		}
+		return nil, err
+	}
+	if excluded[pkg.ImportPath] {
+		return nil, nil
+	}
+	var filenames []string
+	for _, name := range pkg.GoFiles {
+		filenames = append(filenames, filepath.Join(pkg.Dir, name))
+	}
+	for _, name := range pkg.TestGoFiles {
+		filenames = append(filenames, filepath.Join(pkg.Dir, name))
+	}
+	return filenames, nil
+}
+
+// Note: Could use filepath.Walk instead of walkDirs but that wouldn't
+//       necessarily be shorter or clearer after adding the code to
+//       terminate early for -short tests.
+
+func walkDirs(t *testing.T, dir string) {
+	// limit run time for short tests
+	if testing.Short() && time.Since(start) >= 750*time.Millisecond {
+		return
+	}
+
+	fis, err := ioutil.ReadDir(dir)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	// typecheck package in directory
+	files, err := pkgFilenames(dir)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if files != nil {
+		typecheck(t, dir, files)
+	}
+
+	// traverse subdirectories, but don't walk into testdata
+	for _, fi := range fis {
+		if fi.IsDir() && fi.Name() != "testdata" {
+			walkDirs(t, filepath.Join(dir, fi.Name()))
+		}
+	}
+}
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
new file mode 100644
index 0000000..8b59df3
--- /dev/null
+++ b/src/go/types/stmt.go
@@ -0,0 +1,731 @@
+// Copyright 2012 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.
+
+// This file implements typechecking of statements.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+)
+
+func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) {
+	if trace {
+		if name == "" {
+			name = "<function literal>"
+		}
+		fmt.Printf("--- %s: %s {\n", name, sig)
+		defer fmt.Println("--- <end>")
+	}
+
+	// save/restore current context and setup function context
+	// (and use 0 indentation at function start)
+	defer func(ctxt context, indent int) {
+		check.context = ctxt
+		check.indent = indent
+	}(check.context, check.indent)
+	check.context = context{
+		decl:  decl,
+		scope: sig.scope,
+		sig:   sig,
+	}
+	check.indent = 0
+
+	check.stmtList(0, body.List)
+
+	if check.hasLabel {
+		check.labels(body)
+	}
+
+	if sig.results.Len() > 0 && !check.isTerminating(body, "") {
+		check.error(body.Rbrace, "missing return")
+	}
+
+	// spec: "Implementation restriction: A compiler may make it illegal to
+	// declare a variable inside a function body if the variable is never used."
+	// (One could check each scope after use, but that distributes this check
+	// over several places because CloseScope is not always called explicitly.)
+	check.usage(sig.scope)
+}
+
+func (check *Checker) usage(scope *Scope) {
+	for _, obj := range scope.elems {
+		if v, _ := obj.(*Var); v != nil && !v.used {
+			check.softErrorf(v.pos, "%s declared but not used", v.name)
+		}
+	}
+	for _, scope := range scope.children {
+		check.usage(scope)
+	}
+}
+
+// stmtContext is a bitset describing which
+// control-flow statements are permissible.
+type stmtContext uint
+
+const (
+	breakOk stmtContext = 1 << iota
+	continueOk
+	fallthroughOk
+)
+
+func (check *Checker) simpleStmt(s ast.Stmt) {
+	if s != nil {
+		check.stmt(0, s)
+	}
+}
+
+func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
+	ok := ctxt&fallthroughOk != 0
+	inner := ctxt &^ fallthroughOk
+	for i, s := range list {
+		inner := inner
+		if ok && i+1 == len(list) {
+			inner |= fallthroughOk
+		}
+		check.stmt(inner, s)
+	}
+}
+
+func (check *Checker) multipleDefaults(list []ast.Stmt) {
+	var first ast.Stmt
+	for _, s := range list {
+		var d ast.Stmt
+		switch c := s.(type) {
+		case *ast.CaseClause:
+			if len(c.List) == 0 {
+				d = s
+			}
+		case *ast.CommClause:
+			if c.Comm == nil {
+				d = s
+			}
+		default:
+			check.invalidAST(s.Pos(), "case/communication clause expected")
+		}
+		if d != nil {
+			if first != nil {
+				check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
+			} else {
+				first = d
+			}
+		}
+	}
+}
+
+func (check *Checker) openScope(s ast.Stmt, comment string) {
+	scope := NewScope(check.scope, comment)
+	check.recordScope(s, scope)
+	check.scope = scope
+}
+
+func (check *Checker) closeScope() {
+	check.scope = check.scope.Parent()
+}
+
+func assignOp(op token.Token) token.Token {
+	// token_test.go verifies the token ordering this function relies on
+	if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
+		return op + (token.ADD - token.ADD_ASSIGN)
+	}
+	return token.ILLEGAL
+}
+
+func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
+	var x operand
+	var msg string
+	switch check.rawExpr(&x, call, nil) {
+	case conversion:
+		msg = "requires function call, not conversion"
+	case expression:
+		msg = "discards result of"
+	case statement:
+		return
+	default:
+		unreachable()
+	}
+	check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
+}
+
+func (check *Checker) caseValues(x operand /* copy argument (not *operand!) */, values []ast.Expr) {
+	// No duplicate checking for now. See issue 4524.
+	for _, e := range values {
+		var y operand
+		check.expr(&y, e)
+		if y.mode == invalid {
+			return
+		}
+		// TODO(gri) The convertUntyped call pair below appears in other places. Factor!
+		// Order matters: By comparing y against x, error positions are at the case values.
+		check.convertUntyped(&y, x.typ)
+		if y.mode == invalid {
+			return
+		}
+		check.convertUntyped(&x, y.typ)
+		if x.mode == invalid {
+			return
+		}
+		check.comparison(&y, &x, token.EQL)
+	}
+}
+
+func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
+L:
+	for _, e := range types {
+		T = check.typOrNil(e)
+		if T == Typ[Invalid] {
+			continue
+		}
+		// complain about duplicate types
+		// TODO(gri) use a type hash to avoid quadratic algorithm
+		for t, pos := range seen {
+			if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
+				// talk about "case" rather than "type" because of nil case
+				check.error(e.Pos(), "duplicate case in type switch")
+				check.errorf(pos, "\tprevious case %s", T) // secondary error, \t indented
+				continue L
+			}
+		}
+		seen[T] = e.Pos()
+		if T != nil {
+			check.typeAssertion(e.Pos(), x, xtyp, T)
+		}
+	}
+	return
+}
+
+// stmt typechecks statement s.
+func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
+	// statements cannot use iota in general
+	// (constant declarations set it explicitly)
+	assert(check.iota == nil)
+
+	// statements must end with the same top scope as they started with
+	if debug {
+		defer func(scope *Scope) {
+			// don't check if code is panicking
+			if p := recover(); p != nil {
+				panic(p)
+			}
+			assert(scope == check.scope)
+		}(check.scope)
+	}
+
+	inner := ctxt &^ fallthroughOk
+	switch s := s.(type) {
+	case *ast.BadStmt, *ast.EmptyStmt:
+		// ignore
+
+	case *ast.DeclStmt:
+		check.declStmt(s.Decl)
+
+	case *ast.LabeledStmt:
+		check.hasLabel = true
+		check.stmt(ctxt, s.Stmt)
+
+	case *ast.ExprStmt:
+		// spec: "With the exception of specific built-in functions,
+		// function and method calls and receive operations can appear
+		// in statement context. Such statements may be parenthesized."
+		var x operand
+		kind := check.rawExpr(&x, s.X, nil)
+		var msg string
+		switch x.mode {
+		default:
+			if kind == statement {
+				return
+			}
+			msg = "is not used"
+		case builtin:
+			msg = "must be called"
+		case typexpr:
+			msg = "is not an expression"
+		}
+		check.errorf(x.pos(), "%s %s", &x, msg)
+
+	case *ast.SendStmt:
+		var ch, x operand
+		check.expr(&ch, s.Chan)
+		check.expr(&x, s.Value)
+		if ch.mode == invalid || x.mode == invalid {
+			return
+		}
+		if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) {
+			if x.mode != invalid {
+				check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
+			}
+		}
+
+	case *ast.IncDecStmt:
+		var op token.Token
+		switch s.Tok {
+		case token.INC:
+			op = token.ADD
+		case token.DEC:
+			op = token.SUB
+		default:
+			check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
+			return
+		}
+		var x operand
+		Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
+		check.binary(&x, s.X, Y, op)
+		if x.mode == invalid {
+			return
+		}
+		check.assignVar(s.X, &x)
+
+	case *ast.AssignStmt:
+		switch s.Tok {
+		case token.ASSIGN, token.DEFINE:
+			if len(s.Lhs) == 0 {
+				check.invalidAST(s.Pos(), "missing lhs in assignment")
+				return
+			}
+			if s.Tok == token.DEFINE {
+				check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
+			} else {
+				// regular assignment
+				check.assignVars(s.Lhs, s.Rhs)
+			}
+
+		default:
+			// assignment operations
+			if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
+				check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
+				return
+			}
+			op := assignOp(s.Tok)
+			if op == token.ILLEGAL {
+				check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
+				return
+			}
+			var x operand
+			check.binary(&x, s.Lhs[0], s.Rhs[0], op)
+			if x.mode == invalid {
+				return
+			}
+			check.assignVar(s.Lhs[0], &x)
+		}
+
+	case *ast.GoStmt:
+		check.suspendedCall("go", s.Call)
+
+	case *ast.DeferStmt:
+		check.suspendedCall("defer", s.Call)
+
+	case *ast.ReturnStmt:
+		res := check.sig.results
+		if res.Len() > 0 {
+			// function returns results
+			// (if one, say the first, result parameter is named, all of them are named)
+			if len(s.Results) == 0 && res.vars[0].name != "" {
+				// spec: "Implementation restriction: A compiler may disallow an empty expression
+				// list in a "return" statement if a different entity (constant, type, or variable)
+				// with the same name as a result parameter is in scope at the place of the return."
+				for _, obj := range res.vars {
+					if _, alt := check.scope.LookupParent(obj.name); alt != nil && alt != obj {
+						check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
+						check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
+						// ok to continue
+					}
+				}
+			} else {
+				// return has results or result parameters are unnamed
+				check.initVars(res.vars, s.Results, s.Return)
+			}
+		} else if len(s.Results) > 0 {
+			check.error(s.Results[0].Pos(), "no result values expected")
+			check.use(s.Results...)
+		}
+
+	case *ast.BranchStmt:
+		if s.Label != nil {
+			check.hasLabel = true
+			return // checked in 2nd pass (check.labels)
+		}
+		switch s.Tok {
+		case token.BREAK:
+			if ctxt&breakOk == 0 {
+				check.error(s.Pos(), "break not in for, switch, or select statement")
+			}
+		case token.CONTINUE:
+			if ctxt&continueOk == 0 {
+				check.error(s.Pos(), "continue not in for statement")
+			}
+		case token.FALLTHROUGH:
+			if ctxt&fallthroughOk == 0 {
+				check.error(s.Pos(), "fallthrough statement out of place")
+			}
+		default:
+			check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
+		}
+
+	case *ast.BlockStmt:
+		check.openScope(s, "block")
+		defer check.closeScope()
+
+		check.stmtList(inner, s.List)
+
+	case *ast.IfStmt:
+		check.openScope(s, "if")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+		var x operand
+		check.expr(&x, s.Cond)
+		if x.mode != invalid && !isBoolean(x.typ) {
+			check.error(s.Cond.Pos(), "non-boolean condition in if statement")
+		}
+		check.stmt(inner, s.Body)
+		if s.Else != nil {
+			check.stmt(inner, s.Else)
+		}
+
+	case *ast.SwitchStmt:
+		inner |= breakOk
+		check.openScope(s, "switch")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+		var x operand
+		if s.Tag != nil {
+			check.expr(&x, s.Tag)
+		} else {
+			// spec: "A missing switch expression is
+			// equivalent to the boolean value true."
+			x.mode = constant
+			x.typ = Typ[Bool]
+			x.val = exact.MakeBool(true)
+			x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
+		}
+
+		check.multipleDefaults(s.Body.List)
+
+		for i, c := range s.Body.List {
+			clause, _ := c.(*ast.CaseClause)
+			if clause == nil {
+				check.invalidAST(c.Pos(), "incorrect expression switch case")
+				continue
+			}
+			if x.mode != invalid {
+				check.caseValues(x, clause.List)
+			}
+			check.openScope(clause, "case")
+			inner := inner
+			if i+1 < len(s.Body.List) {
+				inner |= fallthroughOk
+			}
+			check.stmtList(inner, clause.Body)
+			check.closeScope()
+		}
+
+	case *ast.TypeSwitchStmt:
+		inner |= breakOk
+		check.openScope(s, "type switch")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+
+		// A type switch guard must be of the form:
+		//
+		//     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
+		//
+		// The parser is checking syntactic correctness;
+		// remaining syntactic errors are considered AST errors here.
+		// TODO(gri) better factoring of error handling (invalid ASTs)
+		//
+		var lhs *ast.Ident // lhs identifier or nil
+		var rhs ast.Expr
+		switch guard := s.Assign.(type) {
+		case *ast.ExprStmt:
+			rhs = guard.X
+		case *ast.AssignStmt:
+			if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
+				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+				return
+			}
+
+			lhs, _ = guard.Lhs[0].(*ast.Ident)
+			if lhs == nil {
+				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+				return
+			}
+
+			if lhs.Name == "_" {
+				// _ := x.(type) is an invalid short variable declaration
+				check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
+				lhs = nil // avoid declared but not used error below
+			} else {
+				check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
+			}
+
+			rhs = guard.Rhs[0]
+
+		default:
+			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+			return
+		}
+
+		// rhs must be of the form: expr.(type) and expr must be an interface
+		expr, _ := rhs.(*ast.TypeAssertExpr)
+		if expr == nil || expr.Type != nil {
+			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+			return
+		}
+		var x operand
+		check.expr(&x, expr.X)
+		if x.mode == invalid {
+			return
+		}
+		xtyp, _ := x.typ.Underlying().(*Interface)
+		if xtyp == nil {
+			check.errorf(x.pos(), "%s is not an interface", &x)
+			return
+		}
+
+		check.multipleDefaults(s.Body.List)
+
+		var lhsVars []*Var               // list of implicitly declared lhs variables
+		seen := make(map[Type]token.Pos) // map of seen types to positions
+		for _, s := range s.Body.List {
+			clause, _ := s.(*ast.CaseClause)
+			if clause == nil {
+				check.invalidAST(s.Pos(), "incorrect type switch case")
+				continue
+			}
+			// Check each type in this type switch case.
+			T := check.caseTypes(&x, xtyp, clause.List, seen)
+			check.openScope(clause, "case")
+			// If lhs exists, declare a corresponding variable in the case-local scope.
+			if lhs != nil {
+				// spec: "The TypeSwitchGuard may include a short variable declaration.
+				// When that form is used, the variable is declared at the beginning of
+				// the implicit block in each clause. In clauses with a case listing
+				// exactly one type, the variable has that type; otherwise, the variable
+				// has the type of the expression in the TypeSwitchGuard."
+				if len(clause.List) != 1 || T == nil {
+					T = x.typ
+				}
+				obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
+				check.declare(check.scope, nil, obj)
+				check.recordImplicit(clause, obj)
+				// For the "declared but not used" error, all lhs variables act as
+				// one; i.e., if any one of them is 'used', all of them are 'used'.
+				// Collect them for later analysis.
+				lhsVars = append(lhsVars, obj)
+			}
+			check.stmtList(inner, clause.Body)
+			check.closeScope()
+		}
+
+		// If lhs exists, we must have at least one lhs variable that was used.
+		if lhs != nil {
+			var used bool
+			for _, v := range lhsVars {
+				if v.used {
+					used = true
+				}
+				v.used = true // avoid usage error when checking entire function
+			}
+			if !used {
+				check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
+			}
+		}
+
+	case *ast.SelectStmt:
+		inner |= breakOk
+
+		check.multipleDefaults(s.Body.List)
+
+		for _, s := range s.Body.List {
+			clause, _ := s.(*ast.CommClause)
+			if clause == nil {
+				continue // error reported before
+			}
+
+			// clause.Comm must be a SendStmt, RecvStmt, or default case
+			valid := false
+			var rhs ast.Expr // rhs of RecvStmt, or nil
+			switch s := clause.Comm.(type) {
+			case nil, *ast.SendStmt:
+				valid = true
+			case *ast.AssignStmt:
+				if len(s.Rhs) == 1 {
+					rhs = s.Rhs[0]
+				}
+			case *ast.ExprStmt:
+				rhs = s.X
+			}
+
+			// if present, rhs must be a receive operation
+			if rhs != nil {
+				if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
+					valid = true
+				}
+			}
+
+			if !valid {
+				check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
+				continue
+			}
+
+			check.openScope(s, "case")
+			if clause.Comm != nil {
+				check.stmt(inner, clause.Comm)
+			}
+			check.stmtList(inner, clause.Body)
+			check.closeScope()
+		}
+
+	case *ast.ForStmt:
+		inner |= breakOk | continueOk
+		check.openScope(s, "for")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+		if s.Cond != nil {
+			var x operand
+			check.expr(&x, s.Cond)
+			if x.mode != invalid && !isBoolean(x.typ) {
+				check.error(s.Cond.Pos(), "non-boolean condition in for statement")
+			}
+		}
+		check.simpleStmt(s.Post)
+		// spec: "The init statement may be a short variable
+		// declaration, but the post statement must not."
+		if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
+			check.softErrorf(s.Pos(), "cannot declare in post statement")
+			check.use(s.Lhs...) // avoid follow-up errors
+		}
+		check.stmt(inner, s.Body)
+
+	case *ast.RangeStmt:
+		inner |= breakOk | continueOk
+		check.openScope(s, "for")
+		defer check.closeScope()
+
+		// check expression to iterate over
+		var x operand
+		check.expr(&x, s.X)
+
+		// determine key/value types
+		var key, val Type
+		if x.mode != invalid {
+			switch typ := x.typ.Underlying().(type) {
+			case *Basic:
+				if isString(typ) {
+					key = Typ[Int]
+					val = UniverseRune // use 'rune' name
+				}
+			case *Array:
+				key = Typ[Int]
+				val = typ.elem
+			case *Slice:
+				key = Typ[Int]
+				val = typ.elem
+			case *Pointer:
+				if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+					key = Typ[Int]
+					val = typ.elem
+				}
+			case *Map:
+				key = typ.key
+				val = typ.elem
+			case *Chan:
+				key = typ.elem
+				val = Typ[Invalid]
+				if typ.dir == SendOnly {
+					check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
+					// ok to continue
+				}
+				if s.Value != nil {
+					check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
+					// ok to continue
+				}
+			}
+		}
+
+		if key == nil {
+			check.errorf(x.pos(), "cannot range over %s", &x)
+			// ok to continue
+		}
+
+		// check assignment to/declaration of iteration variables
+		// (irregular assignment, cannot easily map to existing assignment checks)
+
+		// lhs expressions and initialization value (rhs) types
+		lhs := [2]ast.Expr{s.Key, s.Value}
+		rhs := [2]Type{key, val} // key, val may be nil
+
+		if s.Tok == token.DEFINE {
+			// short variable declaration; variable scope starts after the range clause
+			// (the for loop opens a new scope, so variables on the lhs never redeclare
+			// previously declared variables)
+			var vars []*Var
+			for i, lhs := range lhs {
+				if lhs == nil {
+					continue
+				}
+
+				// determine lhs variable
+				var obj *Var
+				if ident, _ := lhs.(*ast.Ident); ident != nil {
+					// declare new variable
+					name := ident.Name
+					obj = NewVar(ident.Pos(), check.pkg, name, nil)
+					check.recordDef(ident, obj)
+					// _ variables don't count as new variables
+					if name != "_" {
+						vars = append(vars, obj)
+					}
+				} else {
+					check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+					obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+				}
+
+				// initialize lhs variable
+				if typ := rhs[i]; typ != nil {
+					x.mode = value
+					x.expr = lhs // we don't have a better rhs expression to use here
+					x.typ = typ
+					check.initVar(obj, &x, false)
+				} else {
+					obj.typ = Typ[Invalid]
+					obj.used = true // don't complain about unused variable
+				}
+			}
+
+			// declare variables
+			if len(vars) > 0 {
+				for _, obj := range vars {
+					check.declare(check.scope, nil /* recordDef already called */, obj)
+				}
+			} else {
+				check.error(s.TokPos, "no new variables on left side of :=")
+			}
+		} else {
+			// ordinary assignment
+			for i, lhs := range lhs {
+				if lhs == nil {
+					continue
+				}
+				if typ := rhs[i]; typ != nil {
+					x.mode = value
+					x.expr = lhs // we don't have a better rhs expression to use here
+					x.typ = typ
+					check.assignVar(lhs, &x)
+				}
+			}
+		}
+
+		check.stmt(inner, s.Body)
+
+	default:
+		check.error(s.Pos(), "invalid statement")
+	}
+}
diff --git a/src/go/types/testdata/blank.src b/src/go/types/testdata/blank.src
new file mode 100644
index 0000000..6a2507f
--- /dev/null
+++ b/src/go/types/testdata/blank.src
@@ -0,0 +1,5 @@
+// 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.
+
+package _ /* ERROR invalid package name */
diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src
new file mode 100644
index 0000000..9eb551dc
--- /dev/null
+++ b/src/go/types/testdata/builtins.src
@@ -0,0 +1,881 @@
+// Copyright 2012 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.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func f0() {}
+
+func append1() {
+	var b byte
+	var x int
+	var s []byte
+	_ = append() // ERROR not enough arguments
+	_ = append("foo" /* ERROR not a slice */ )
+	_ = append(nil /* ERROR not a slice */ , s)
+	_ = append(x /* ERROR not a slice */ , s)
+	_ = append(s)
+	append /* ERROR not used */ (s)
+
+	_ = append(s, b)
+	_ = append(s, x /* ERROR cannot pass argument x */ )
+	_ = append(s, s /* ERROR cannot pass argument s */ )
+	_ = append(s... /* ERROR can only use ... with matching parameter */ )
+	_ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
+	_ = append(s, 1, 2, 3)
+	_ = append(s, 1, 2, 3, x /* ERROR cannot pass argument x */ , 5, 6, 6)
+	_ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
+	_ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
+
+	type S []byte
+	type T string
+	var t T
+	_ = append(s, "foo" /* ERROR cannot convert */ )
+	_ = append(s, "foo"...)
+	_ = append(S(s), "foo" /* ERROR cannot convert */ )
+	_ = append(S(s), "foo"...)
+	_ = append(s, t /* ERROR cannot pass argument t */ )
+	_ = append(s, t...)
+	_ = append(s, T("foo")...)
+	_ = append(S(s), t /* ERROR cannot pass argument t */ )
+	_ = append(S(s), t...)
+	_ = append(S(s), T("foo")...)
+	_ = append([]string{}, t /* ERROR cannot pass argument t */ , "foo")
+	_ = append([]T{}, t, "foo")
+}
+
+// from the spec
+func append2() {
+	s0 := []int{0, 0}
+	s1 := append(s0, 2)                // append a single element     s1 == []int{0, 0, 2}
+	s2 := append(s1, 3, 5, 7)          // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
+	s3 := append(s2, s0...)            // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+	s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
+
+	var t []interface{}
+	t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
+
+	var b []byte
+	b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
+
+	_ = s4
+}
+
+func append3() {
+	f1 := func() (s []int) { return }
+	f2 := func() (s []int, x int) { return }
+	f3 := func() (s []int, x, y int) { return }
+	f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
+	ff := func() (int, float32) { return 0, 0 }
+	_ = append(f0 /* ERROR used as value */ ())
+	_ = append(f1())
+	_ = append(f2())
+	_ = append(f3())
+	_ = append(f5())
+	_ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
+}
+
+func cap1() {
+	var a [10]bool
+	var p *[20]int
+	var c chan string
+	_ = cap() // ERROR not enough arguments
+	_ = cap(1, 2) // ERROR too many arguments
+	_ = cap(42 /* ERROR invalid */)
+	const _3 = cap(a)
+	assert(_3 == 10)
+	const _4 = cap(p)
+	assert(_4 == 20)
+	_ = cap(c)
+	cap /* ERROR not used */ (c)
+
+	// issue 4744
+	type T struct{ a [10]int }
+	const _ = cap(((*T)(nil)).a)
+
+	var s [][]byte
+	_ = cap(s)
+	_ = cap(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func cap2() {
+	f1a := func() (a [10]int) { return }
+	f1s := func() (s []int) { return }
+	f2 := func() (s []int, x int) { return }
+	_ = cap(f0 /* ERROR used as value */ ())
+	_ = cap(f1a())
+	_ = cap(f1s())
+	_ = cap(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func cap3() {
+	var f = func() int { return 0 }
+	var x = f()
+	const (
+		_ = cap([4]int{})
+		_ = cap([4]int{x})
+		_ = cap /* ERROR not constant */ ([4]int{f()})
+		_ = cap /* ERROR not constant */ ([4]int{cap([]int{})})
+		_ = cap([4]int{cap([4]int{})})
+	)
+	var y float64
+	var z complex128
+	const (
+		_ = cap([4]float64{})
+		_ = cap([4]float64{y})
+		_ = cap([4]float64{real(2i)})
+		_ = cap /* ERROR not constant */ ([4]float64{real(z)})
+	)
+	var ch chan [10]int
+	const (
+		_ = cap /* ERROR not constant */ (<-ch)
+		_ = cap /* ERROR not constant */ ([4]int{(<-ch)[0]})
+	)
+}
+
+func close1() {
+	var c chan int
+	var r <-chan int
+	close() // ERROR not enough arguments
+	close(1, 2) // ERROR too many arguments
+	close(42 /* ERROR not a channel */)
+	close(r /* ERROR receive-only channel */)
+	close(c)
+	_ = close /* ERROR used as value */ (c)
+
+	var s []chan int
+	close(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func close2() {
+	f1 := func() (ch chan int) { return }
+	f2 := func() (ch chan int, x int) { return }
+	close(f0 /* ERROR used as value */ ())
+	close(f1())
+	close(f2()) // ERROR too many arguments
+}
+
+func complex1() {
+	var i32 int32
+	var f32 float32
+	var f64 float64
+	var c64 complex64
+	var c128 complex128
+	_ = complex() // ERROR not enough arguments
+	_ = complex(1) // ERROR not enough arguments
+	_ = complex(true /* ERROR invalid argument */ , 0)
+	_ = complex(i32 /* ERROR invalid argument */ , 0)
+	_ = complex("foo" /* ERROR invalid argument */ , 0)
+	_ = complex(c64 /* ERROR invalid argument */ , 0)
+	_ = complex(0, true /* ERROR invalid argument */ )
+	_ = complex(0, i32 /* ERROR invalid argument */ )
+	_ = complex(0, "foo" /* ERROR invalid argument */ )
+	_ = complex(0, c64 /* ERROR invalid argument */ )
+	_ = complex(f32, f32)
+	_ = complex(f32, 1)
+	_ = complex(f32, 1.0)
+	_ = complex(f32, 'a')
+	_ = complex(f64, f64)
+	_ = complex(f64, 1)
+	_ = complex(f64, 1.0)
+	_ = complex(f64, 'a')
+	_ = complex(f32 /* ERROR mismatched types */ , f64)
+	_ = complex(f64 /* ERROR mismatched types */ , f32)
+	_ = complex(1, 1)
+	_ = complex(1, 1.1)
+	_ = complex(1, 'a')
+	complex /* ERROR not used */ (1, 2)
+
+	var _ complex64 = complex(f32, f32)
+	var _ complex64 = complex /* ERROR cannot initialize */ (f64, f64)
+
+	var _ complex128 = complex /* ERROR cannot initialize */ (f32, f32)
+	var _ complex128 = complex(f64, f64)
+
+	// untyped constants
+	const _ int = complex(1, 0)
+	const _ float32 = complex(1, 0)
+	const _ complex64 = complex(1, 0)
+	const _ complex128 = complex(1, 0)
+
+	const _ int = complex /* ERROR int */ (1.1, 0)
+	const _ float32 = complex /* ERROR float32 */ (1, 2)
+
+	// untyped values
+	var s uint
+	_ = complex(1 /* ERROR integer */ <<s, 0)
+	const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
+	var _ int = complex /* ERROR cannot initialize */ (1 /* ERROR integer */ <<s, 0)
+
+	// floating-point argument types must be identical
+	type F32 float32
+	type F64 float64
+	var x32 F32
+	var x64 F64
+	c64 = complex(x32, x32)
+	_ = complex(x32 /* ERROR mismatched types */ , f32)
+	_ = complex(f32 /* ERROR mismatched types */ , x32)
+	c128 = complex(x64, x64)
+	_ = c128
+	_ = complex(x64 /* ERROR mismatched types */ , f64)
+	_ = complex(f64 /* ERROR mismatched types */ , x64)
+
+	var t []float32
+	_ = complex(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func complex2() {
+	f1 := func() (x float32) { return }
+	f2 := func() (x, y float32) { return }
+	f3 := func() (x, y, z float32) { return }
+	_ = complex(f0 /* ERROR used as value */ ())
+	_ = complex(f1()) // ERROR not enough arguments
+	_ = complex(f2())
+	_ = complex(f3()) // ERROR too many arguments
+}
+
+func copy1() {
+	copy() // ERROR not enough arguments
+	copy("foo") // ERROR not enough arguments
+	copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
+	copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
+	copy([ /* ERROR different element types */ ]int8{}, "foo")
+
+	// spec examples
+	var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+	var s = make([]int, 6)
+	var b = make([]byte, 5)
+	n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+	n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+	n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
+	_, _, _ = n1, n2, n3
+
+	var t [][]int
+	copy(t, t)
+	copy(t /* ERROR copy expects slice arguments */ , nil)
+	copy(nil /* ERROR copy expects slice arguments */ , t)
+	copy(nil /* ERROR copy expects slice arguments */ , nil)
+	copy(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func copy2() {
+	f1 := func() (a []int) { return }
+	f2 := func() (a, b []int) { return }
+	f3 := func() (a, b, c []int) { return }
+	copy(f0 /* ERROR used as value */ ())
+	copy(f1()) // ERROR not enough arguments
+	copy(f2())
+	copy(f3()) // ERROR too many arguments
+}
+
+func delete1() {
+	var m map[string]int
+	var s string
+	delete() // ERROR not enough arguments
+	delete(1) // ERROR not enough arguments
+	delete(1, 2, 3) // ERROR too many arguments
+	delete(m, 0 /* ERROR not assignable */)
+	delete(m, s)
+	_ = delete /* ERROR used as value */ (m, s)
+
+	var t []map[string]string
+	delete(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func delete2() {
+	f1 := func() (m map[string]int) { return }
+	f2 := func() (m map[string]int, k string) { return }
+	f3 := func() (m map[string]int, k string, x float32) { return }
+	delete(f0 /* ERROR used as value */ ())
+	delete(f1()) // ERROR not enough arguments
+	delete(f2())
+	delete(f3()) // ERROR too many arguments
+}
+
+func imag1() {
+	var f32 float32
+	var f64 float64
+	var c64 complex64
+	var c128 complex128
+	_ = imag() // ERROR not enough arguments
+	_ = imag(1, 2) // ERROR too many arguments
+	_ = imag(10 /* ERROR must be a complex number */)
+	_ = imag(2.7182818 /* ERROR must be a complex number */)
+	_ = imag("foo" /* ERROR must be a complex number */)
+	const _5 = imag(1 + 2i)
+	assert(_5 == 2)
+	f32 = _5
+	f64 = _5
+	const _6 = imag(0i)
+	assert(_6 == 0)
+	f32 = imag(c64)
+	f64 = imag(c128)
+	f32 = imag /* ERROR cannot assign */ (c128)
+	f64 = imag /* ERROR cannot assign */ (c64)
+	imag /* ERROR not used */ (c64)
+	_, _ = f32, f64
+
+	// complex type may not be predeclared
+	type C64 complex64
+	type C128 complex128
+	var x64 C64
+	var x128 C128
+	f32 = imag(x64)
+	f64 = imag(x128)
+
+	var s []complex64
+	_ = imag(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func imag2() {
+	f1 := func() (x complex128) { return }
+	f2 := func() (x, y complex128) { return }
+	_ = imag(f0 /* ERROR used as value */ ())
+	_ = imag(f1())
+	_ = imag(f2()) // ERROR too many arguments
+}
+
+func len1() {
+	const c = "foobar"
+	var a [10]bool
+	var p *[20]int
+	var m map[string]complex128
+	_ = len() // ERROR not enough arguments
+	_ = len(1, 2) // ERROR too many arguments
+	_ = len(42 /* ERROR invalid */)
+	const _3 = len(c)
+	assert(_3 == 6)
+	const _4 = len(a)
+	assert(_4 == 10)
+	const _5 = len(p)
+	assert(_5 == 20)
+	_ = len(m)
+	len /* ERROR not used */ (c)
+
+	// esoteric case
+	var t string
+	var hash map[interface{}][]*[10]int
+	const n = len /* ERROR not constant */ (hash[recover()][len(t)])
+	assert(n == 10) // ok because n has unknown value and no error is reported
+	var ch <-chan int
+	const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
+
+	// issue 4744
+	type T struct{ a [10]int }
+	const _ = len(((*T)(nil)).a)
+
+	var s [][]byte
+	_ = len(s)
+	_ = len(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func len2() {
+	f1 := func() (x []int) { return }
+	f2 := func() (x, y []int) { return }
+	_ = len(f0 /* ERROR used as value */ ())
+	_ = len(f1())
+	_ = len(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func len3() {
+	var f = func() int { return 0 }
+	var x = f()
+	const (
+		_ = len([4]int{})
+		_ = len([4]int{x})
+		_ = len /* ERROR not constant */ ([4]int{f()})
+		_ = len /* ERROR not constant */ ([4]int{len([]int{})})
+		_ = len([4]int{len([4]int{})})
+	)
+	var y float64
+	var z complex128
+	const (
+		_ = len([4]float64{})
+		_ = len([4]float64{y})
+		_ = len([4]float64{real(2i)})
+		_ = len /* ERROR not constant */ ([4]float64{real(z)})
+	)
+	var ch chan [10]int
+	const (
+		_ = len /* ERROR not constant */ (<-ch)
+		_ = len /* ERROR not constant */ ([4]int{(<-ch)[0]})
+	)
+}
+
+func make1() {
+	var n int
+	var m float32
+	var s uint
+
+	_ = make() // ERROR not enough arguments
+	_ = make(1 /* ERROR not a type */)
+	_ = make(int /* ERROR cannot make */)
+
+	// slices
+	_ = make/* ERROR arguments */ ([]int)
+	_ = make/* ERROR arguments */ ([]int, 2, 3, 4)
+	_ = make([]int, int /* ERROR not an expression */)
+	_ = make([]int, 10, float32 /* ERROR not an expression */)
+	_ = make([]int, "foo" /* ERROR cannot convert */)
+	_ = make([]int, 10, 2.3 /* ERROR truncated */)
+	_ = make([]int, 5, 10.0)
+	_ = make([]int, 0i)
+	_ = make([]int, 1.0)
+	_ = make([]int, 1.0<<s)
+	_ = make([]int, 1.1 /* ERROR int */ <<s)
+	_ = make([]int, - /* ERROR must not be negative */ 1, 10)
+	_ = make([]int, 0, - /* ERROR must not be negative */ 1)
+	_ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
+	_ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
+	_ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
+	_ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
+	_ = make([]int, m /* ERROR must be integer */ )
+        _ = &make /* ERROR cannot take address */ ([]int, 0)
+
+	// maps
+	_ = make /* ERROR arguments */ (map[int]string, 10, 20)
+	_ = make(map[int]float32, int /* ERROR not an expression */)
+	_ = make(map[int]float32, "foo" /* ERROR cannot convert */)
+	_ = make(map[int]float32, 10)
+	_ = make(map[int]float32, n)
+	_ = make(map[int]float32, int64(n))
+	_ = make(map[string]bool, 10.0)
+	_ = make(map[string]bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (map[string]bool)
+
+	// channels
+	_ = make /* ERROR arguments */ (chan int, 10, 20)
+	_ = make(chan int, int /* ERROR not an expression */)
+	_ = make(chan<- int, "foo" /* ERROR cannot convert */)
+	_ = make(chan int, - /* ERROR must not be negative */ 10)
+	_ = make(<-chan float64, 10)
+	_ = make(chan chan int, n)
+	_ = make(chan string, int64(n))
+	_ = make(chan bool, 10.0)
+	_ = make(chan bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (chan bool)
+
+	make /* ERROR not used */ ([]int, 10)
+
+	var t []int
+	_ = make([]int, t[0], t[1])
+	_ = make([]int, t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func make2() {
+	f1 /* ERROR not used */ := func() (x []int) { return }
+	_ = make(f0 /* ERROR not a type */ ())
+	_ = make(f1 /* ERROR not a type */ ())
+}
+
+func new1() {
+	_ = new() // ERROR not enough arguments
+	_ = new(1, 2) // ERROR too many arguments
+	_ = new("foo" /* ERROR not a type */)
+	p := new(float64)
+	_ = new(struct{ x, y int })
+	q := new(*float64)
+	_ = *p == **q
+	new /* ERROR not used */ (int)
+        _ = &new /* ERROR cannot take address */ (int)
+
+	_ = new(int... /* ERROR invalid use of \.\.\. */ )
+}
+
+func new2() {
+	f1 /* ERROR not used */ := func() (x []int) { return }
+	_ = new(f0 /* ERROR not a type */ ())
+	_ = new(f1 /* ERROR not a type */ ())
+}
+
+func panic1() {
+	panic() // ERROR not enough arguments
+	panic(1, 2) // ERROR too many arguments
+	panic(0)
+	panic("foo")
+	panic(false)
+	panic(1<<10)
+	panic(1 /* ERROR overflows */ <<1000)
+	_ = panic /* ERROR used as value */ (0)
+
+	var s []byte
+	panic(s)
+	panic(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func panic2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	panic(f0 /* ERROR used as value */ ())
+	panic(f1())
+	panic(f2()) // ERROR too many arguments
+}
+
+func print1() {
+	print()
+	print(1)
+	print(1, 2)
+	print("foo")
+	print(2.718281828)
+	print(false)
+	print(1<<10)
+	print(1 /* ERROR overflows */ <<1000)
+	println(nil /* ERROR untyped nil */ )
+
+	var s []int
+	print(s... /* ERROR invalid use of \.\.\. */ )
+	_ = print /* ERROR used as value */ ()
+}
+
+func print2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	f3 := func() (x int, y float32, z string) { return }
+	print(f0 /* ERROR used as value */ ())
+	print(f1())
+	print(f2())
+	print(f3())
+}
+
+func println1() {
+	println()
+	println(1)
+	println(1, 2)
+	println("foo")
+	println(2.718281828)
+	println(false)
+	println(1<<10)
+	println(1 /* ERROR overflows */ <<1000)
+	println(nil /* ERROR untyped nil */ )
+
+	var s []int
+	println(s... /* ERROR invalid use of \.\.\. */ )
+	_ = println /* ERROR used as value */ ()
+}
+
+func println2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	f3 := func() (x int, y float32, z string) { return }
+	println(f0 /* ERROR used as value */ ())
+	println(f1())
+	println(f2())
+	println(f3())
+}
+
+func real1() {
+	var f32 float32
+	var f64 float64
+	var c64 complex64
+	var c128 complex128
+	_ = real() // ERROR not enough arguments
+	_ = real(1, 2) // ERROR too many arguments
+	_ = real(10 /* ERROR must be a complex number */)
+	_ = real(2.7182818 /* ERROR must be a complex number */)
+	_ = real("foo" /* ERROR must be a complex number */)
+	const _5 = real(1 + 2i)
+	assert(_5 == 1)
+	f32 = _5
+	f64 = _5
+	const _6 = real(0i)
+	assert(_6 == 0)
+	f32 = real(c64)
+	f64 = real(c128)
+	f32 = real /* ERROR cannot assign */ (c128)
+	f64 = real /* ERROR cannot assign */ (c64)
+	real /* ERROR not used */ (c64)
+
+	// complex type may not be predeclared
+	type C64 complex64
+	type C128 complex128
+	var x64 C64
+	var x128 C128
+	f32 = imag(x64)
+	f64 = imag(x128)
+
+	var s []complex64
+	_ = real(s... /* ERROR invalid use of \.\.\. */ )
+	_, _ = f32, f64
+}
+
+func real2() {
+	f1 := func() (x complex128) { return }
+	f2 := func() (x, y complex128) { return }
+	_ = real(f0 /* ERROR used as value */ ())
+	_ = real(f1())
+	_ = real(f2()) // ERROR too many arguments
+}
+
+func recover1() {
+	_ = recover()
+	_ = recover(10) // ERROR too many arguments
+	recover()
+
+	var s []int
+	recover(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func recover2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	_ = recover(f0 /* ERROR used as value */ ())
+	_ = recover(f1()) // ERROR too many arguments
+	_ = recover(f2()) // ERROR too many arguments
+}
+
+// assuming types.DefaultPtrSize == 8
+type S0 struct{      // offset
+	a bool       //  0
+	b rune       //  4
+	c *int       //  8
+	d bool       // 16
+	e complex128 // 24
+}                    // 40
+
+type S1 struct{   // offset
+	x float32 //  0
+	y string  //  8
+	z *S1     // 24
+	S0        // 32
+}                 // 72
+
+type S2 struct{ // offset
+	*S1     //  0
+}               //  8
+
+type S3 struct { // offset
+	a int64  //  0
+	b int32  //  8
+}                // 12
+
+type S4 struct { // offset
+	S3       //  0
+	int32    // 12
+}                // 16
+
+type S5 struct {   // offset
+	a [3]int32 //  0
+	b int32    // 12
+}                  // 16
+
+func (S2) m() {}
+
+func Alignof1() {
+	var x int
+	_ = unsafe.Alignof() // ERROR not enough arguments
+	_ = unsafe.Alignof(1, 2) // ERROR too many arguments
+	_ = unsafe.Alignof(int /* ERROR not an expression */)
+	_ = unsafe.Alignof(42)
+	_ = unsafe.Alignof(new(struct{}))
+	_ = unsafe.Alignof(1<<10)
+	_ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+	_ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
+	unsafe /* ERROR not used */ .Alignof(x)
+
+	var y S0
+	assert(unsafe.Alignof(y.a) == 1)
+	assert(unsafe.Alignof(y.b) == 4)
+	assert(unsafe.Alignof(y.c) == 8)
+	assert(unsafe.Alignof(y.d) == 1)
+	assert(unsafe.Alignof(y.e) == 8)
+
+	var s []byte
+	_ = unsafe.Alignof(s)
+	_ = unsafe.Alignof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Alignof2() {
+	f1 := func() (x int32) { return }
+	f2 := func() (x, y int32) { return }
+	_ = unsafe.Alignof(f0 /* ERROR used as value */ ())
+	assert(unsafe.Alignof(f1()) == 4)
+	_ = unsafe.Alignof(f2()) // ERROR too many arguments
+}
+
+func Offsetof1() {
+	var x struct{ f int }
+	_ = unsafe.Offsetof() // ERROR not enough arguments
+	_ = unsafe.Offsetof(1, 2) // ERROR too many arguments
+	_ = unsafe.Offsetof(int /* ERROR not a selector expression */ )
+	_ = unsafe.Offsetof(x /* ERROR not a selector expression */ )
+	_ = unsafe.Offsetof(nil /* ERROR not a selector expression */ )
+	_ = unsafe.Offsetof(x.f)
+	_ = unsafe.Offsetof((x.f))
+	_ = unsafe.Offsetof((((((((x))).f)))))
+	unsafe /* ERROR not used */ .Offsetof(x.f)
+
+	var y0 S0
+	assert(unsafe.Offsetof(y0.a) == 0)
+	assert(unsafe.Offsetof(y0.b) == 4)
+	assert(unsafe.Offsetof(y0.c) == 8)
+	assert(unsafe.Offsetof(y0.d) == 16)
+	assert(unsafe.Offsetof(y0.e) == 24)
+
+	var y1 S1
+	assert(unsafe.Offsetof(y1.x) == 0)
+	assert(unsafe.Offsetof(y1.y) == 8)
+	assert(unsafe.Offsetof(y1.z) == 24)
+	assert(unsafe.Offsetof(y1.S0) == 32)
+
+	assert(unsafe.Offsetof(y1.S0.a) == 0) // relative to S0
+	assert(unsafe.Offsetof(y1.a) == 32)   // relative to S1
+	assert(unsafe.Offsetof(y1.b) == 36)   // relative to S1
+	assert(unsafe.Offsetof(y1.c) == 40)   // relative to S1
+	assert(unsafe.Offsetof(y1.d) == 48)   // relative to S1
+	assert(unsafe.Offsetof(y1.e) == 56)   // relative to S1
+
+	var y1p *S1
+	assert(unsafe.Offsetof(y1p.S0) == 32)
+
+	type P *S1
+	var p P = y1p
+	assert(unsafe.Offsetof(p.S0) == 32)
+
+	var y2 S2
+	assert(unsafe.Offsetof(y2.S1) == 0)
+	_ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
+	_ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
+
+	var s []byte
+	_ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Offsetof2() {
+	f1 := func() (x int32) { return }
+	f2 := func() (x, y int32) { return }
+	_ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
+	_ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
+	_ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
+}
+
+func Sizeof1() {
+	var x int
+	_ = unsafe.Sizeof() // ERROR not enough arguments
+	_ = unsafe.Sizeof(1, 2) // ERROR too many arguments
+	_ = unsafe.Sizeof(int /* ERROR not an expression */)
+	_ = unsafe.Sizeof(42)
+	_ = unsafe.Sizeof(new(complex128))
+	_ = unsafe.Sizeof(1<<10)
+	_ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+	_ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
+	unsafe /* ERROR not used */ .Sizeof(x)
+
+	// basic types have size guarantees
+	assert(unsafe.Sizeof(byte(0)) == 1)
+	assert(unsafe.Sizeof(uint8(0)) == 1)
+	assert(unsafe.Sizeof(int8(0)) == 1)
+	assert(unsafe.Sizeof(uint16(0)) == 2)
+	assert(unsafe.Sizeof(int16(0)) == 2)
+	assert(unsafe.Sizeof(uint32(0)) == 4)
+	assert(unsafe.Sizeof(int32(0)) == 4)
+	assert(unsafe.Sizeof(float32(0)) == 4)
+	assert(unsafe.Sizeof(uint64(0)) == 8)
+	assert(unsafe.Sizeof(int64(0)) == 8)
+	assert(unsafe.Sizeof(float64(0)) == 8)
+	assert(unsafe.Sizeof(complex64(0)) == 8)
+	assert(unsafe.Sizeof(complex128(0)) == 16)
+
+	var y0 S0
+	assert(unsafe.Sizeof(y0.a) == 1)
+	assert(unsafe.Sizeof(y0.b) == 4)
+	assert(unsafe.Sizeof(y0.c) == 8)
+	assert(unsafe.Sizeof(y0.d) == 1)
+	assert(unsafe.Sizeof(y0.e) == 16)
+	assert(unsafe.Sizeof(y0) == 40)
+
+	var y1 S1
+	assert(unsafe.Sizeof(y1) == 72)
+
+	var y2 S2
+	assert(unsafe.Sizeof(y2) == 8)
+
+	var y3 S3
+	assert(unsafe.Sizeof(y3) == 12)
+
+	var y4 S4
+	assert(unsafe.Sizeof(y4) == 16)
+
+	var y5 S5
+	assert(unsafe.Sizeof(y5) == 16)
+
+	var a3 [10]S3
+	assert(unsafe.Sizeof(a3) == 156)
+
+	// test case for issue 5670
+	type T struct {
+		a int32
+		_ int32
+		c int32
+	}
+	assert(unsafe.Sizeof(T{}) == 12)
+
+	var s []byte
+	_ = unsafe.Sizeof(s)
+	_ = unsafe.Sizeof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Sizeof2() {
+	f1 := func() (x int64) { return }
+	f2 := func() (x, y int64) { return }
+	_ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
+	assert(unsafe.Sizeof(f1()) == 8)
+	_ = unsafe.Sizeof(f2()) // ERROR too many arguments
+}
+
+// self-testing only
+func assert1() {
+	var x int
+	assert() /* ERROR not enough arguments */
+	assert(1, 2) /* ERROR too many arguments */
+	assert("foo" /* ERROR boolean constant */ )
+	assert(x /* ERROR boolean constant */)
+	assert(true)
+	assert /* ERROR failed */ (false)
+	_ = assert(true)
+
+	var s []byte
+	assert(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func assert2() {
+	f1 := func() (x bool) { return }
+	f2 := func() (x bool) { return }
+	assert(f0 /* ERROR used as value */ ())
+	assert(f1 /* ERROR boolean constant */ ())
+	assert(f2 /* ERROR boolean constant */ ())
+}
+
+// self-testing only
+func trace1() {
+	// Uncomment the code below to test trace - will produce console output
+	// _ = trace /* ERROR no value */ ()
+	// _ = trace(1)
+	// _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+
+	var s []byte
+	trace(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func trace2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x int, y string) { return }
+	f3 := func() (x int, y string, z []int) { return }
+	_ = f1
+	_ = f2
+	_ = f3
+	// Uncomment the code below to test trace - will produce console output
+	// trace(f0())
+	// trace(f1())
+	// trace(f2())
+	// trace(f3())
+	// trace(f0(), 1)
+	// trace(f1(), 1, 2)
+	// trace(f2(), 1, 2, 3)
+	// trace(f3(), 1, 2, 3, 4)
+}
diff --git a/src/go/types/testdata/const0.src b/src/go/types/testdata/const0.src
new file mode 100644
index 0000000..c4419ab
--- /dev/null
+++ b/src/go/types/testdata/const0.src
@@ -0,0 +1,282 @@
+// Copyright 2012 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.
+
+// constant declarations
+
+package const0
+
+// constants declarations must be initialized by constants
+var x = 0
+const c0 = x /* ERROR "not constant" */
+
+// typed constants must have constant types
+const _ interface /* ERROR invalid constant type */ {} = 0
+
+func _ () {
+	const _ interface /* ERROR invalid constant type */ {} = 0
+	for i := 0; i < 10; i++ {} // don't crash with non-nil iota here
+}
+
+// untyped constants
+const (
+	// boolean values
+	ub0 = false
+	ub1 = true
+	ub2 = 2 < 1
+	ub3 = ui1 == uf1
+	ub4 = true /* ERROR "cannot convert" */ == 0
+
+	// integer values
+	ui0 = 0
+	ui1 = 1
+	ui2 = 42
+	ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
+	ui4 = -10
+
+	ui5 = ui0 + ui1
+	ui6 = ui1 - ui1
+	ui7 = ui2 * ui1
+	ui8 = ui3 / ui3
+	ui9 = ui3 % ui3
+
+	ui10 = 1 / 0 /* ERROR "division by zero" */
+	ui11 = ui1 / 0 /* ERROR "division by zero" */
+	ui12 = ui3 / ui0 /* ERROR "division by zero" */
+	ui13 = 1 % 0 /* ERROR "division by zero" */
+	ui14 = ui1 % 0 /* ERROR "division by zero" */
+	ui15 = ui3 % ui0 /* ERROR "division by zero" */
+
+	ui16 = ui2 & ui3
+	ui17 = ui2 | ui3
+	ui18 = ui2 ^ ui3
+	ui19 = 1 /* ERROR "invalid operation" */ % 1.0
+
+	// floating point values
+	uf0 = 0.
+	uf1 = 1.
+	uf2 = 4.2e1
+	uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+	uf4 = 1e-1
+
+	uf5 = uf0 + uf1
+	uf6 = uf1 - uf1
+	uf7 = uf2 * uf1
+	uf8 = uf3 / uf3
+	uf9 = uf3 /* ERROR "not defined" */ % uf3
+
+	uf10 = 1 / 0 /* ERROR "division by zero" */
+	uf11 = uf1 / 0 /* ERROR "division by zero" */
+	uf12 = uf3 / uf0 /* ERROR "division by zero" */
+
+	uf16 = uf2 /* ERROR "not defined" */ & uf3
+	uf17 = uf2 /* ERROR "not defined" */ | uf3
+	uf18 = uf2 /* ERROR "not defined" */ ^ uf3
+
+	// complex values
+	uc0 = 0.i
+	uc1 = 1.i
+	uc2 = 4.2e1i
+	uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+	uc4 = 1e-1i
+
+	uc5 = uc0 + uc1
+	uc6 = uc1 - uc1
+	uc7 = uc2 * uc1
+	uc8 = uc3 / uc3
+	uc9 = uc3 /* ERROR "not defined" */ % uc3
+
+	uc10 = 1 / 0 /* ERROR "division by zero" */
+	uc11 = uc1 / 0 /* ERROR "division by zero" */
+	uc12 = uc3 / uc0 /* ERROR "division by zero" */
+
+	uc16 = uc2 /* ERROR "not defined" */ & uc3
+	uc17 = uc2 /* ERROR "not defined" */ | uc3
+	uc18 = uc2 /* ERROR "not defined" */ ^ uc3
+)
+
+type (
+	mybool bool
+	myint int
+	myfloat float64
+	mycomplex complex128
+)
+
+// typed constants
+const (
+	// boolean values
+	tb0 bool = false
+	tb1 bool = true
+	tb2 mybool = 2 < 1
+	tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
+
+	// integer values
+	ti0 int8 = ui0
+	ti1 int32 = ui1
+	ti2 int64 = ui2
+	ti3 myint = ui3 /* ERROR "overflows" */
+	ti4 myint = ui4
+
+	ti5 = ti0 /* ERROR "mismatched types" */ + ti1
+	ti6 = ti1 - ti1
+	ti7 = ti2 /* ERROR "mismatched types" */ * ti1
+	ti8 = ti3 / ti3
+	ti9 = ti3 % ti3
+
+	ti10 = 1 / 0 /* ERROR "division by zero" */
+	ti11 = ti1 / 0 /* ERROR "division by zero" */
+	ti12 = ti3 /* ERROR "mismatched types" */ / ti0
+	ti13 = 1 % 0 /* ERROR "division by zero" */
+	ti14 = ti1 % 0 /* ERROR "division by zero" */
+	ti15 = ti3 /* ERROR "mismatched types" */ % ti0
+
+	ti16 = ti2 /* ERROR "mismatched types" */ & ti3
+	ti17 = ti2 /* ERROR "mismatched types" */ | ti4
+	ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
+
+	// floating point values
+	tf0 float32 = 0.
+	tf1 float32 = 1.
+	tf2 float64 = 4.2e1
+	tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+	tf4 myfloat = 1e-1
+
+	tf5 = tf0 + tf1
+	tf6 = tf1 - tf1
+	tf7 = tf2 /* ERROR "mismatched types" */ * tf1
+	tf8 = tf3 / tf3
+	tf9 = tf3 /* ERROR "not defined" */ % tf3
+
+	tf10 = 1 / 0 /* ERROR "division by zero" */
+	tf11 = tf1 / 0 /* ERROR "division by zero" */
+	tf12 = tf3 /* ERROR "mismatched types" */ / tf0
+
+	tf16 = tf2 /* ERROR "mismatched types" */ & tf3
+	tf17 = tf2 /* ERROR "mismatched types" */ | tf3
+	tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
+
+	// complex values
+	tc0 = 0.i
+	tc1 = 1.i
+	tc2 = 4.2e1i
+	tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+	tc4 = 1e-1i
+
+	tc5 = tc0 + tc1
+	tc6 = tc1 - tc1
+	tc7 = tc2 * tc1
+	tc8 = tc3 / tc3
+	tc9 = tc3 /* ERROR "not defined" */ % tc3
+
+	tc10 = 1 / 0 /* ERROR "division by zero" */
+	tc11 = tc1 / 0 /* ERROR "division by zero" */
+	tc12 = tc3 / tc0 /* ERROR "division by zero" */
+
+	tc16 = tc2 /* ERROR "not defined" */ & tc3
+	tc17 = tc2 /* ERROR "not defined" */ | tc3
+	tc18 = tc2 /* ERROR "not defined" */ ^ tc3
+)
+
+// initialization cycles
+const (
+	a /* ERROR "initialization cycle" */ = a
+	b /* ERROR "initialization cycle" */ , c /* ERROR "initialization cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
+	f float64 = d
+)
+
+// multiple initialization
+const (
+	a1, a2, a3 = 7, 3.1415926, "foo"
+	b1, b2, b3 = b3, b1, 42
+	c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+	d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+	_p0 = assert(a1 == 7)
+	_p1 = assert(a2 == 3.1415926)
+	_p2 = assert(a3 == "foo")
+	_p3 = assert(b1 == 42)
+	_p4 = assert(b2 == 42)
+	_p5 = assert(b3 == 42)
+)
+
+func _() {
+	const (
+		a1, a2, a3 = 7, 3.1415926, "foo"
+		b1, b2, b3 = b3, b1, 42
+		c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+		d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+		_p0 = assert(a1 == 7)
+		_p1 = assert(a2 == 3.1415926)
+		_p2 = assert(a3 == "foo")
+		_p3 = assert(b1 == 42)
+		_p4 = assert(b2 == 42)
+		_p5 = assert(b3 == 42)
+	)
+}
+
+// iota
+const (
+	iota0 = iota
+	iota1 = iota
+	iota2 = iota*2
+	_a0 = assert(iota0 == 0)
+	_a1 = assert(iota1 == 1)
+	_a2 = assert(iota2 == 4)
+	iota6 = iota*3
+
+	iota7
+	iota8
+	_a3 = assert(iota7 == 21)
+	_a4 = assert(iota8 == 24)
+)
+
+const (
+	_b0 = iota
+	_b1 = assert(iota + iota2 == 5)
+	_b2 = len([iota]int{}) // iota may appear in a type!
+	_b3 = assert(_b2 == 2)
+	_b4 = len(A{})
+)
+
+type A [iota /* ERROR "cannot use iota" */ ]int
+
+// constant expressions with operands accross different
+// constant declarations must use the right iota values
+const (
+	_c0 = iota
+	_c1
+	_c2
+	_x = _c2 + _d1 + _e0 // 3
+)
+
+const (
+	_d0 = iota
+	_d1
+)
+
+const (
+	_e0 = iota
+)
+
+var _ = assert(_x == 3)
+
+// special cases
+const (
+	_n0 = nil /* ERROR "not constant" */
+	_n1 = [ /* ERROR "not constant" */ ]int{}
+)
+
+// iotas must not be usable in expressions outside constant declarations
+type _ [iota /* ERROR "iota outside constant decl" */ ]byte
+var _ = iota /* ERROR "iota outside constant decl" */
+func _() {
+	_ = iota /* ERROR "iota outside constant decl" */
+	const _ = iota
+	_ = iota /* ERROR "iota outside constant decl" */
+}
+
+func _() {
+	iota := 123
+	const x = iota /* ERROR "is not constant" */
+	var y = iota
+	_ = y
+}
diff --git a/src/go/types/testdata/const1.src b/src/go/types/testdata/const1.src
new file mode 100644
index 0000000..88e9fad
--- /dev/null
+++ b/src/go/types/testdata/const1.src
@@ -0,0 +1,314 @@
+// Copyright 2012 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.
+
+// constant conversions
+
+package const1
+
+const(
+	mi = ^int(0)
+	mu = ^uint(0)
+	mp = ^uintptr(0)
+
+	logSizeofInt     = uint(mi>>8&1 + mi>>16&1 + mi>>32&1)
+	logSizeofUint    = uint(mu>>8&1 + mu>>16&1 + mu>>32&1)
+	logSizeofUintptr = uint(mp>>8&1 + mp>>16&1 + mp>>32&1)
+)
+
+const (
+	minInt8 = -1<<(8<<iota - 1)
+	minInt16
+	minInt32
+	minInt64
+	minInt = -1<<(8<<logSizeofInt - 1)
+)
+
+const (
+	maxInt8 = 1<<(8<<iota - 1) - 1
+	maxInt16
+	maxInt32
+	maxInt64
+	maxInt = 1<<(8<<logSizeofInt - 1) - 1
+)
+
+const (
+	maxUint8 = 1<<(8<<iota) - 1
+	maxUint16
+	maxUint32
+	maxUint64
+	maxUint    = 1<<(8<<logSizeofUint) - 1
+	maxUintptr = 1<<(8<<logSizeofUintptr) - 1
+)
+
+const (
+	smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
+	smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
+)
+
+const (
+	_ = assert(smallestFloat32 > 0)
+	_ = assert(smallestFloat64 > 0)
+)
+
+const (
+	maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
+	maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
+)
+
+const (
+	_ int8 = minInt8 /* ERROR "overflows" */ - 1
+	_ int8 = minInt8
+	_ int8 = maxInt8
+	_ int8 = maxInt8 /* ERROR "overflows" */ + 1
+	_ int8 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
+	_ = int8(minInt8)
+	_ = int8(maxInt8)
+	_ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
+	_ = int8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int16 = minInt16 /* ERROR "overflows" */ - 1
+	_ int16 = minInt16
+	_ int16 = maxInt16
+	_ int16 = maxInt16 /* ERROR "overflows" */ + 1
+	_ int16 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
+	_ = int16(minInt16)
+	_ = int16(maxInt16)
+	_ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
+	_ = int16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int32 = minInt32 /* ERROR "overflows" */ - 1
+	_ int32 = minInt32
+	_ int32 = maxInt32
+	_ int32 = maxInt32 /* ERROR "overflows" */ + 1
+	_ int32 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
+	_ = int32(minInt32)
+	_ = int32(maxInt32)
+	_ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
+	_ = int32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int64 = minInt64 /* ERROR "overflows" */ - 1
+	_ int64 = minInt64
+	_ int64 = maxInt64
+	_ int64 = maxInt64 /* ERROR "overflows" */ + 1
+	_ int64 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
+	_ = int64(minInt64)
+	_ = int64(maxInt64)
+	_ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
+	_ = int64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int = minInt /* ERROR "overflows" */ - 1
+	_ int = minInt
+	_ int = maxInt
+	_ int = maxInt /* ERROR "overflows" */ + 1
+	_ int = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int(minInt /* ERROR "cannot convert" */ - 1)
+	_ = int(minInt)
+	_ = int(maxInt)
+	_ = int(maxInt /* ERROR "cannot convert" */ + 1)
+	_ = int(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint8 = 0 /* ERROR "overflows" */ - 1
+	_ uint8 = 0
+	_ uint8 = maxUint8
+	_ uint8 = maxUint8 /* ERROR "overflows" */ + 1
+	_ uint8 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint8(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint8(0)
+	_ = uint8(maxUint8)
+	_ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
+	_ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint16 = 0 /* ERROR "overflows" */ - 1
+	_ uint16 = 0
+	_ uint16 = maxUint16
+	_ uint16 = maxUint16 /* ERROR "overflows" */ + 1
+	_ uint16 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint16(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint16(0)
+	_ = uint16(maxUint16)
+	_ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
+	_ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint32 = 0 /* ERROR "overflows" */ - 1
+	_ uint32 = 0
+	_ uint32 = maxUint32
+	_ uint32 = maxUint32 /* ERROR "overflows" */ + 1
+	_ uint32 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint32(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint32(0)
+	_ = uint32(maxUint32)
+	_ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
+	_ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint64 = 0 /* ERROR "overflows" */ - 1
+	_ uint64 = 0
+	_ uint64 = maxUint64
+	_ uint64 = maxUint64 /* ERROR "overflows" */ + 1
+	_ uint64 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint64(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint64(0)
+	_ = uint64(maxUint64)
+	_ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
+	_ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint = 0 /* ERROR "overflows" */ - 1
+	_ uint = 0
+	_ uint = maxUint
+	_ uint = maxUint /* ERROR "overflows" */ + 1
+	_ uint = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint(0)
+	_ = uint(maxUint)
+	_ = uint(maxUint /* ERROR "cannot convert" */ + 1)
+	_ = uint(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uintptr = 0 /* ERROR "overflows" */ - 1
+	_ uintptr = 0
+	_ uintptr = maxUintptr
+	_ uintptr = maxUintptr /* ERROR "overflows" */ + 1
+	_ uintptr = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uintptr(0 /* ERROR "cannot convert" */ - 1)
+	_ = uintptr(0)
+	_ = uintptr(maxUintptr)
+	_ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
+	_ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ float32 = minInt64
+	_ float64 = minInt64
+	_ complex64 = minInt64
+	_ complex128 = minInt64
+
+	_ = float32(minInt64)
+	_ = float64(minInt64)
+	_ = complex64(minInt64)
+	_ = complex128(minInt64)
+)
+
+const (
+	_ float32 = maxUint64
+	_ float64 = maxUint64
+	_ complex64 = maxUint64
+	_ complex128 = maxUint64
+
+	_ = float32(maxUint64)
+	_ = float64(maxUint64)
+	_ = complex64(maxUint64)
+	_ = complex128(maxUint64)
+)
+
+// TODO(gri) find smaller deltas below
+
+const delta32 = maxFloat32/(1 << 23)
+
+const (
+	_ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+	_ float32 = -maxFloat32
+	_ float32 = maxFloat32
+	_ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+	_ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+	_ = float32(-maxFloat32)
+	_ = float32(maxFloat32)
+	_ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+
+	_ = assert(float32(smallestFloat32) == smallestFloat32)
+	_ = assert(float32(smallestFloat32/2) == 0)
+	_ = assert(float32(smallestFloat64) == 0)
+	_ = assert(float32(smallestFloat64/2) == 0)
+)
+
+const delta64 = maxFloat64/(1 << 52)
+
+const (
+	_ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+	_ float64 = -maxFloat64
+	_ float64 = maxFloat64
+	_ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+	_ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+	_ = float64(-maxFloat64)
+	_ = float64(maxFloat64)
+	_ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+
+	_ = assert(float64(smallestFloat32) == smallestFloat32)
+	_ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
+	_ = assert(float64(smallestFloat64) == smallestFloat64)
+	_ = assert(float64(smallestFloat64/2) == 0)
+)
+
+const (
+	_ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+	_ complex64 = -maxFloat32
+	_ complex64 = maxFloat32
+	_ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+	_ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+	_ = complex64(-maxFloat32)
+	_ = complex64(maxFloat32)
+	_ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+)
+
+const (
+	_ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+	_ complex128 = -maxFloat64
+	_ complex128 = maxFloat64
+	_ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+	_ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+	_ = complex128(-maxFloat64)
+	_ = complex128(maxFloat64)
+	_ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+)
+
+// Initialization of typed constant and conversion are the same:
+const (
+	f32 = 1 + smallestFloat32
+	x32 float32 = f32
+	y32 = float32(f32)
+	_ = assert(x32 - y32 == 0)
+)
+
+const (
+	f64 = 1 + smallestFloat64
+	x64 float64 = f64
+	y64 = float64(f64)
+	_ = assert(x64 - y64 == 0)
+)
diff --git a/src/go/types/testdata/constdecl.src b/src/go/types/testdata/constdecl.src
new file mode 100644
index 0000000..6de9b13
--- /dev/null
+++ b/src/go/types/testdata/constdecl.src
@@ -0,0 +1,97 @@
+// Copyright 2013 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 constdecl
+
+import "math"
+
+var v int
+
+// Const decls must be initialized by constants.
+const _ = v /* ERROR "not constant" */
+const _ = math /* ERROR "not constant" */ .Sin(0)
+const _ = int /* ERROR "not an expression" */
+
+func _() {
+	const _ = v /* ERROR "not constant" */
+	const _ = math /* ERROR "not constant" */ .Sin(0)
+	const _ = int /* ERROR "not an expression" */
+}
+
+// Identifier and expression arity must match.
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+const (
+	_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+	_ = 1, 2 /* ERROR "extra init expr 2" */
+
+	_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+	_ int = 1, 2 /* ERROR "extra init expr 2" */
+)
+
+const (
+	_ = 1
+	_
+	_, _ /* ERROR "missing init expr for _" */
+	_
+)
+
+const (
+	_, _ = 1, 2
+	_, _
+	_ /* ERROR "extra init expr at" */
+	_, _
+	_, _, _ /* ERROR "missing init expr for _" */
+	_, _
+)
+
+func _() {
+	const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+	const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+	const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+	const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+	const (
+		_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+		_ = 1, 2 /* ERROR "extra init expr 2" */
+
+		_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+		_ int = 1, 2 /* ERROR "extra init expr 2" */
+	)
+
+	const (
+		_ = 1
+		_
+		_, _ /* ERROR "missing init expr for _" */
+		_
+	)
+
+	const (
+		_, _ = 1, 2
+		_, _
+		_ /* ERROR "extra init expr at" */
+		_, _
+		_, _, _ /* ERROR "missing init expr for _" */
+		_, _
+	)
+}
+
+// Test case for constant with invalid initialization.
+// Caused panic because the constant value was not set up (gri - 7/8/2014).
+func _() {
+	const (
+	    x string = missing /* ERROR "undeclared name" */
+	    y = x + ""
+	)
+}
+
+// TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/src/go/types/testdata/conversions.src b/src/go/types/testdata/conversions.src
new file mode 100644
index 0000000..4251424
--- /dev/null
+++ b/src/go/types/testdata/conversions.src
@@ -0,0 +1,88 @@
+// Copyright 2012 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.
+
+// conversions
+
+package conversions
+
+import "unsafe"
+
+// argument count
+var (
+	_ = int() /* ERROR "missing argument" */
+	_ = int(1, 2 /* ERROR "too many arguments" */ )
+)
+
+// numeric constant conversions are in const1.src.
+
+func string_conversions() {
+	const A = string(65)
+	assert(A == "A")
+	const E = string(-1)
+	assert(E == "\uFFFD")
+	assert(E == string(1234567890))
+
+	type myint int
+	assert(A == string(myint(65)))
+
+	type mystring string
+	const _ mystring = mystring("foo")
+
+	const _ = string(true /* ERROR "cannot convert" */ )
+	const _ = string(1.2 /* ERROR "cannot convert" */ )
+	const _ = string(nil /* ERROR "cannot convert" */ )
+}
+
+func interface_conversions() {
+	type E interface{}
+
+	type I1 interface{
+		m1()
+	}
+
+	type I2 interface{
+		m1()
+		m2(x int)
+	}
+
+	type I3 interface{
+		m1()
+		m2() int
+	}
+
+	var e E
+	var i1 I1
+	var i2 I2
+	var i3 I3
+
+	_ = E(0)
+	_ = E(nil)
+	_ = E(e)
+	_ = E(i1)
+	_ = E(i2)
+
+	_ = I1(0 /* ERROR "cannot convert" */ )
+	_ = I1(nil)
+	_ = I1(i1)
+	_ = I1(e /* ERROR "cannot convert" */ )
+	_ = I1(i2)
+
+	_ = I2(nil)
+	_ = I2(i1 /* ERROR "cannot convert" */ )
+	_ = I2(i2)
+	_ = I2(i3 /* ERROR "cannot convert" */ )
+
+	_ = I3(nil)
+	_ = I3(i1 /* ERROR "cannot convert" */ )
+	_ = I3(i2 /* ERROR "cannot convert" */ )
+	_ = I3(i3)
+
+	// TODO(gri) add more tests, improve error message
+}
+
+func issue6326() {
+	type T unsafe.Pointer
+	var x T
+	_ = uintptr(x) // see issue 6326
+}
diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src
new file mode 100644
index 0000000..621d83c
--- /dev/null
+++ b/src/go/types/testdata/cycles.src
@@ -0,0 +1,143 @@
+// Copyright 2013 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 cycles
+
+type (
+	T0 int
+	T1 /* ERROR cycle */ T1
+	T2 *T2
+
+	T3 /* ERROR cycle */ T4
+	T4 T5
+	T5 T3
+
+	T6 T7
+	T7 *T8
+	T8 T6
+
+	// arrays
+	A0 /* ERROR cycle */ [10]A0
+	A1 [10]*A1
+
+	A2 /* ERROR cycle */ [10]A3
+	A3 [10]A4
+	A4 A2
+
+	A5 [10]A6
+	A6 *A5
+
+	// slices
+	L0 []L0
+
+	// structs
+	S0 /* ERROR cycle */ struct{ _ S0 }
+	S1 /* ERROR cycle */ struct{ S1 }
+	S2 struct{ _ *S2 }
+	S3 struct{ *S3 }
+
+	S4 /* ERROR cycle */ struct{ S5 }
+	S5 struct{ S6 }
+	S6 S4
+
+	// pointers
+	P0 *P0
+
+	// functions
+	F0 func(F0)
+	F1 func() F1
+	F2 func(F2) F2
+
+	// interfaces
+	I0 /* ERROR cycle */ interface{ I0 }
+
+	I1 interface{ I2 }
+	I2 interface{ I3 }
+	I3 /* ERROR cycle */ interface{ I1 }
+
+	I4 interface{ f(I4) }
+
+	// testcase for issue 5090
+	I5 interface{ f(I6) }
+	I6 interface{ I5 }
+
+	// maps
+	M0 map[M0 /* ERROR invalid map key */ ]M0
+
+	// channels
+	C0 chan C0
+)
+
+func _() {
+	type (
+		t1 /* ERROR cycle */ t1
+		t2 *t2
+
+		t3 t4 /* ERROR undeclared */
+		t4 t5 /* ERROR undeclared */
+		t5 t3
+
+		// arrays
+		a0 /* ERROR cycle */ [10]a0
+		a1 [10]*a1
+
+		// slices
+		l0 []l0
+
+		// structs
+		s0 /* ERROR cycle */ struct{ _ s0 }
+		s1 /* ERROR cycle */ struct{ s1 }
+		s2 struct{ _ *s2 }
+		s3 struct{ *s3 }
+
+		// pointers
+		p0 *p0
+
+		// functions
+		f0 func(f0)
+		f1 func() f1
+		f2 func(f2) f2
+
+		// interfaces
+		i0 /* ERROR cycle */ interface{ i0 }
+
+		// maps
+		m0 map[m0 /* ERROR invalid map key */ ]m0
+
+		// channels
+		c0 chan c0
+	)
+}
+
+// test cases for issue 6667
+
+type A [10]map[A /* ERROR invalid map key */ ]bool
+
+type S struct {
+	m map[S /* ERROR invalid map key */ ]bool
+}
+
+// test cases for issue 7236
+// (cycle detection must not be dependent on starting point of resolution)
+
+type (
+	P1 *T9
+	T9 /* ERROR cycle */ T9
+
+	T10 /* ERROR cycle */ T10
+	P2 *T10
+)
+
+func (T11) m() {}
+
+type T11 /* ERROR cycle */ struct{ T11 }
+
+type T12 /* ERROR cycle */ struct{ T12 }
+
+func (*T12) m() {}
+
+type (
+	P3 *T13
+	T13 /* ERROR cycle */ T13
+)
\ No newline at end of file
diff --git a/src/go/types/testdata/cycles1.src b/src/go/types/testdata/cycles1.src
new file mode 100644
index 0000000..ae2b38eb
--- /dev/null
+++ b/src/go/types/testdata/cycles1.src
@@ -0,0 +1,77 @@
+// Copyright 2013 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 p
+
+type (
+	A interface {
+		a() interface {
+			ABC1
+		}
+	}
+	B interface {
+		b() interface {
+			ABC2
+		}
+	}
+	C interface {
+		c() interface {
+			ABC3
+		}
+	}
+
+	AB interface {
+		A
+		B
+	}
+	BC interface {
+		B
+		C
+	}
+
+	ABC1 interface {
+		A
+		B
+		C
+	}
+	ABC2 interface {
+		AB
+		C
+	}
+	ABC3 interface {
+		A
+		BC
+	}
+)
+
+var (
+	x1 ABC1
+	x2 ABC2
+	x3 ABC3
+)
+
+func _() {
+	// all types have the same method set
+	x1 = x2
+	x2 = x1
+
+	x1 = x3
+	x3 = x1
+
+	x2 = x3
+	x3 = x2
+
+	// all methods return the same type again
+	x1 = x1.a()
+	x1 = x1.b()
+	x1 = x1.c()
+
+	x2 = x2.a()
+	x2 = x2.b()
+	x2 = x2.c()
+
+	x3 = x3.a()
+	x3 = x3.b()
+	x3 = x3.c()
+}
diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src
new file mode 100644
index 0000000..345ab56
--- /dev/null
+++ b/src/go/types/testdata/cycles2.src
@@ -0,0 +1,118 @@
+// Copyright 2013 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 p
+
+import "unsafe"
+
+// Test case for issue 5090
+
+type t interface {
+	f(u)
+}
+
+type u interface {
+	t
+}
+
+func _() {
+	var t t
+	var u u
+
+	t.f(t)
+	t.f(u)
+	
+	u.f(t)
+	u.f(u)
+}
+
+
+// Test case for issue 6589.
+
+type A interface {
+	a() interface {
+		AB
+	}
+}
+
+type B interface {
+	a() interface {
+		AB
+	}
+}
+
+type AB interface {
+	a() interface {
+		A
+		B /* ERROR a redeclared */
+	}
+	b() interface {
+		A
+		B /* ERROR a redeclared */
+	}
+}
+
+var x AB
+var y interface {
+	A
+	B /* ERROR a redeclared */
+}
+var _ = x /* ERROR cannot compare */ == y
+
+
+// Test case for issue 6638.
+
+type T interface {
+	m() [T /* ERROR no value */ (nil).m()[0]]int
+}
+
+// Variations of this test case.
+
+type T1 interface {
+	m() [x1 /* ERROR no value */ .m()[0]]int
+}
+
+var x1 T1
+
+type T2 interface {
+	m() [len(x2 /* ERROR no value */ .m())]int
+}
+
+var x2 T2
+
+type T3 interface {
+	m() [unsafe.Sizeof(x3.m)]int
+}
+
+var x3 T3
+
+// The test case below should also report an error for
+// the cast inside the T4 interface (like it does for the
+// variable initialization). The reason why it does not is
+// that inside T4, the method x4.m depends on T4 which is not
+// fully set up yet. The x4.m method happens to have an empty
+// signature which is why the cast is permitted.
+// TODO(gri) Consider marking methods as incomplete and provide
+// a better error message in that case.
+
+type T4 interface {
+	m() [unsafe.Sizeof(cast4(x4.m))]int
+}
+
+var x4 T4
+var _ = cast4(x4 /* ERROR cannot convert */.m)
+
+type cast4 func()
+
+// This test is symmetric to the T4 case: Here the cast is
+// "correct", but it doesn't work inside the T5 interface.
+
+type T5 interface {
+	m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int
+}
+
+var x5 T5
+var _ = cast5(x5.m)
+
+type cast5 func() [0]int
diff --git a/src/go/types/testdata/cycles3.src b/src/go/types/testdata/cycles3.src
new file mode 100644
index 0000000..3da4fb5
--- /dev/null
+++ b/src/go/types/testdata/cycles3.src
@@ -0,0 +1,60 @@
+// Copyright 2013 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 p
+
+import "unsafe"
+
+var (
+	_ A = A(nil).a().b().c().d().e().f()
+	_ A = A(nil).b().c().d().e().f()
+	_ A = A(nil).c().d().e().f()
+	_ A = A(nil).d().e().f()
+	_ A = A(nil).e().f()
+	_ A = A(nil).f()
+	_ A = A(nil)
+)
+
+type (
+	A interface {
+		a() B
+		B
+	}
+
+	B interface {
+		b() C
+		C
+	}
+
+	C interface {
+		c() D
+		D
+	}
+
+	D interface {
+		d() E
+		E
+	}
+
+	E interface {
+		e() F
+		F
+	}
+
+	F interface {
+		f() A
+	}
+)
+
+type (
+	U interface {
+		V
+	}
+
+	V interface {
+		v() [unsafe.Sizeof(u)]int
+	}
+)
+
+var u U
diff --git a/src/go/types/testdata/cycles4.src b/src/go/types/testdata/cycles4.src
new file mode 100644
index 0000000..445babc
--- /dev/null
+++ b/src/go/types/testdata/cycles4.src
@@ -0,0 +1,110 @@
+// Copyright 2013 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 p
+
+// Check that all methods of T are collected before
+// determining the result type of m (which embeds
+// all methods of T).
+
+type T interface {
+	m() interface {T}
+	E
+}
+
+var _ = T.m(nil).m().e()
+
+type E interface {
+	e() int
+}
+
+// Check that unresolved forward chains are followed
+// (see also comment in resolver.go, checker.typeDecl).
+
+var _ = C.m(nil).m().e()
+
+type A B
+
+type B interface {
+	m() interface{C}
+	E
+}
+
+type C A
+
+// Check that interface type comparison for identity
+// does not recur endlessly.
+
+type T1 interface {
+	m() interface{T1}
+}
+
+type T2 interface {
+	m() interface{T2}
+}
+
+func _(x T1, y T2) {
+	// Checking for assignability of interfaces must check
+	// if all methods of x are present in y, and that they
+	// have identical signatures. The signatures recur via
+	// the result type, which is an interface that embeds
+	// a single method m that refers to the very interface
+	// that contains it. This requires cycle detection in
+	// identity checks for interface types.
+	x = y
+}
+
+type T3 interface {
+	m() interface{T4}
+}
+
+type T4 interface {
+	m() interface{T3}
+}
+
+func _(x T1, y T3) {
+	x = y
+}
+
+// Check that interfaces are type-checked in order of
+// (embedded interface) dependencies (was issue 7158).
+
+var x1 T5 = T7(nil)
+
+type T5 interface {
+	T6
+}
+
+type T6 interface {
+	m() T7
+}
+type T7 interface {
+	T5
+}
+
+// Actual test case from issue 7158.
+
+func wrapNode() Node {
+	return wrapElement()
+}
+
+func wrapElement() Element {
+	return nil
+}
+
+type EventTarget interface {
+	AddEventListener(Event)
+}
+
+type Node interface {
+	EventTarget
+}
+
+type Element interface {
+	Node
+}
+
+type Event interface {
+	Target() Element
+}
diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src
new file mode 100644
index 0000000..f1df3ea
--- /dev/null
+++ b/src/go/types/testdata/decls0.src
@@ -0,0 +1,206 @@
+// Copyright 2011 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.
+
+// type declarations
+
+package decls0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+	N undeclared /* ERROR "undeclared" */
+	B bool
+	I int32
+	A [10]P
+	T struct {
+		x, y P
+	}
+	P *T
+	R (*R)
+	F func(A) I
+	Y interface {
+		f(A) I
+	}
+	S [](((P)))
+	M map[I]F
+	C chan<- I
+
+	// blank types must be typechecked
+	_ pi /* ERROR "not a type" */
+	_ struct{}
+	_ struct{ pi /* ERROR "not a type" */ }
+)
+
+
+// declarations of init
+const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
+type init /* ERROR "cannot declare init" */ struct{}
+var _, init /* ERROR "cannot declare init" */ int
+
+func init() {}
+func init /* ERROR "missing function body" */ ()
+
+func _() { const init = 0 }
+func _() { type init int }
+func _() { var init int; _ = init }
+
+// invalid array types
+type (
+	iA0 [... /* ERROR "invalid use of '...'" */ ]byte
+	iA1 [1 /* ERROR "invalid array length" */ <<100]int
+	iA2 [- /* ERROR "invalid array length" */ 1]complex128
+	iA3 ["foo" /* ERROR "must be integer" */ ]string
+)
+
+
+type (
+	p1 pi /* ERROR "no field or method foo" */ .foo
+	p2 unsafe.Pointer
+)
+
+
+type (
+	Pi pi /* ERROR "not a type" */
+
+	a /* ERROR "illegal cycle" */ a
+	a /* ERROR "redeclared" */ int
+
+	// where the cycle error appears depends on the
+	// order in which declarations are processed
+	// (which depends on the order in which a map
+	// is iterated through)
+	b /* ERROR "illegal cycle" */ c
+	c d
+	d e
+	e b
+
+	t *t
+
+	U V
+	V *W
+	W U
+
+	P1 *S2
+	P2 P1
+
+	S0 struct {
+	}
+	S1 struct {
+		a, b, c int
+		u, v, a /* ERROR "redeclared" */ float32
+	}
+	S2 struct {
+		S0 // anonymous field
+		S0 /* ERROR "redeclared" */ int
+	}
+	S3 struct {
+		x S2
+	}
+	S4/* ERROR "illegal cycle" */ struct {
+		S4
+	}
+	S5 /* ERROR "illegal cycle" */ struct {
+		S6
+	}
+	S6 struct {
+		field S7
+	}
+	S7 struct {
+		S5
+	}
+
+	L1 []L1
+	L2 []int
+
+	A1 [10.0]int
+	A2 /* ERROR "illegal cycle" */ [10]A2
+	A3 /* ERROR "illegal cycle" */ [10]struct {
+		x A4
+	}
+	A4 [10]A3
+
+	F1 func()
+	F2 func(x, y, z float32)
+	F3 func(x, y, x /* ERROR "redeclared" */ float32)
+	F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+	F5 func(x int) (x /* ERROR "redeclared" */ float32)
+	F6 func(x ...int)
+
+	I1 interface{}
+	I2 interface {
+		m1()
+	}
+	I3 interface {
+		m1()
+		m1 /* ERROR "redeclared" */ ()
+	}
+	I4 interface {
+		m1(x, y, x /* ERROR "redeclared" */ float32)
+		m2() (x, y, x /* ERROR "redeclared" */ float32)
+		m3(x int) (x /* ERROR "redeclared" */ float32)
+	}
+	I5 interface {
+		m1(I5)
+	}
+	I6 interface {
+		S0 /* ERROR "not an interface" */
+	}
+	I7 interface {
+		I1
+		I1
+	}
+	I8 /* ERROR "illegal cycle" */ interface {
+		I8
+	}
+	I9 interface {
+		I10
+	}
+	I10 interface {
+		I11
+	}
+	I11 /* ERROR "illegal cycle" */ interface {
+		I9
+	}
+
+	C1 chan int
+	C2 <-chan int
+	C3 chan<- C3
+	C4 chan C5
+	C5 chan C6
+	C6 chan C4
+
+	M1 map[Last]string
+	M2 map[string]M2
+
+	Last int
+)
+
+// cycles in function/method declarations
+// (test cases for issue 5217 and variants)
+func f1(x f1 /* ERROR "not a type" */ ) {}
+func f2(x *f2 /* ERROR "not a type" */ ) {}
+func f3() (x f3 /* ERROR "not a type" */ ) { return }
+func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+
+func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {}
+func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {}
+func (S0) m3() (x S0 /* ERROR "field or method" */ .m3) { return }
+func (S0) m4() (x *S0 /* ERROR "field or method" */ .m4) { return }
+
+// interfaces may not have any blank methods
+type BlankI interface {
+	_ /* ERROR "invalid method name" */ ()
+	_ /* ERROR "invalid method name" */ (float32) int
+	m()
+}
+
+// non-interface types may have multiple blank methods
+type BlankT struct{}
+
+func (BlankT) _() {}
+func (BlankT) _(int) {}
+func (BlankT) _() int { return 0 }
+func (BlankT) _(int) int { return 0}
diff --git a/src/go/types/testdata/decls1.src b/src/go/types/testdata/decls1.src
new file mode 100644
index 0000000..7855e46
--- /dev/null
+++ b/src/go/types/testdata/decls1.src
@@ -0,0 +1,144 @@
+// Copyright 2012 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.
+
+// variable declarations
+
+package decls1
+
+import (
+	"math"
+)
+
+// Global variables without initialization
+var (
+	a, b bool
+	c byte
+	d uint8
+	r rune
+	i int
+	j, k, l int
+	x, y float32
+	xx, yy float64
+	u, v complex64
+	uu, vv complex128
+	s, t string
+	array []byte
+	iface interface{}
+	
+	blank _ /* ERROR "cannot use _" */
+)
+
+// Global variables with initialization
+var (
+	s1 = i + j
+	s2 = i /* ERROR "mismatched types" */ + x
+	s3 = c + d
+	s4 = s + t
+	s5 = s /* ERROR "invalid operation" */ / t
+	s6 = array[t1]
+	s7 = array[x /* ERROR "integer" */]
+	s8 = &a
+	s10 = &42 /* ERROR "cannot take address" */
+	s11 = &v
+	s12 = -(u + *t11) / *&v
+	s13 = a /* ERROR "shifted operand" */ << d
+	s14 = i << j /* ERROR "must be unsigned" */ 
+	s18 = math.Pi * 10.0
+	s19 = s1 /* ERROR "cannot call" */ ()
+ 	s20 = f0 /* ERROR "no value" */ ()
+	s21 = f6(1, s1, i)
+	s22 = f6(1, s1, uu /* ERROR "cannot pass argument" */ )
+	
+	t1 int = i + j
+	t2 int = i /* ERROR "mismatched types" */ + x
+	t3 int = c /* ERROR "cannot initialize" */ + d
+	t4 string = s + t
+	t5 string = s /* ERROR "invalid operation" */ / t
+	t6 byte = array[t1]
+	t7 byte = array[x /* ERROR "must be integer" */]
+	t8 *int = & /* ERROR "cannot initialize" */ a
+	t10 *int = &42 /* ERROR "cannot take address" */
+	t11 *complex64 = &v
+	t12 complex64 = -(u + *t11) / *&v
+	t13 int = a /* ERROR "shifted operand" */ << d
+	t14 int = i << j /* ERROR "must be unsigned" */ 
+	t15 math /* ERROR "not in selector" */
+	t16 math /* ERROR "not declared" */ .xxx
+	t17 math /* ERROR "not a type" */ .Pi
+	t18 float64 = math.Pi * 10.0
+	t19 int = t1 /* ERROR "cannot call" */ ()
+	t20 int = f0 /* ERROR "no value" */ ()
+	t21 int = a /* ERROR "cannot initialize" */
+)
+
+// Various more complex expressions
+var (
+	u1 = x /* ERROR "not an interface" */ .(int)
+	u2 = iface.([]int)
+	u3 = iface.(a /* ERROR "not a type" */ )
+	u4, ok = iface.(int)
+	u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int)
+)
+
+// Constant expression initializations
+var (
+	v1 = 1 /* ERROR "cannot convert" */ + "foo"
+	v2 = c + 255
+	v3 = c + 256 /* ERROR "overflows" */
+	v4 = r + 2147483647
+	v5 = r + 2147483648 /* ERROR "overflows" */
+	v6 = 42
+	v7 = v6 + 9223372036854775807
+	v8 = v6 + 9223372036854775808 /* ERROR "overflows" */
+	v9 = i + 1 << 10
+	v10 byte = 1024 /* ERROR "overflows" */
+	v11 = xx/yy*yy - xx
+	v12 = true && false
+	v13 = nil /* ERROR "use of untyped nil" */
+)
+
+// Multiple assignment expressions
+var (
+	m1a, m1b = 1, 2
+	m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+	m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+)
+
+func _() {
+	var (
+		m1a, m1b = 1, 2
+		m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+		m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+	)
+
+	_, _ = m1a, m1b
+	_, _, _ = m2a, m2b, m2c
+	_, _ = m3a, m3b
+}
+
+// Declaration of parameters and results
+func f0() {}
+func f1(a /* ERROR "not a type" */) {}
+func f2(a, b, c d /* ERROR "not a type" */) {}
+
+func f3() int { return 0 }
+func f4() a /* ERROR "not a type" */ { return 0 }
+func f5() (a, b, c d /* ERROR "not a type" */) { return }
+
+func f6(a, b, c int) complex128 { return 0 }
+
+// Declaration of receivers
+type T struct{}
+
+func (T) m0() {}
+func (*T) m1() {}
+func (x T) m2() {}
+func (x *T) m3() {}
+
+// Initialization functions
+func init() {}
+func /* ERROR "no arguments and no return values" */ init(int) {}
+func /* ERROR "no arguments and no return values" */ init() int { return 0 }
+func /* ERROR "no arguments and no return values" */ init(int) int { return 0 }
+func (T) init(int) int { return 0 }
diff --git a/src/go/types/testdata/decls2a.src b/src/go/types/testdata/decls2a.src
new file mode 100644
index 0000000..bdbecd9
--- /dev/null
+++ b/src/go/types/testdata/decls2a.src
@@ -0,0 +1,111 @@
+// Copyright 2012 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.
+
+// method declarations
+
+package decls2
+
+import "time"
+import "unsafe"
+
+// T1 declared before its methods.
+type T1 struct{
+	f int
+}
+
+func (T1) m() {}
+func (T1) m /* ERROR "already declared" */ () {}
+func (x *T1) f /* ERROR "field and method" */ () {}
+
+// Conflict between embedded field and method name,
+// with the embedded field being a basic type.
+type T1b struct {
+	int
+}
+
+func (T1b) int /* ERROR "field and method" */ () {}
+
+type T1c struct {
+	time.Time
+}
+
+func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
+
+// Disabled for now: LookupFieldOrMethod will find Pointer even though
+// it's double-declared (it would cost extra in the common case to verify
+// this). But the MethodSet computation will not find it due to the name
+// collision caused by the double-declaration, leading to an internal
+// inconsistency while we are verifying one computation against the other.
+// var _ = T1c{}.Pointer
+
+// T2's method declared before the type.
+func (*T2) f /* ERROR "field and method" */ () {}
+
+type T2 struct {
+	f int
+}
+
+// Methods declared without a declared type.
+func (undeclared /* ERROR "undeclared" */) m() {}
+func (x *undeclared /* ERROR "undeclared" */) m() {}
+
+func (pi /* ERROR "not a type" */) m1() {}
+func (x pi /* ERROR "not a type" */) m2() {}
+func (x *pi /* ERROR "not a type" */ ) m3() {}
+
+// Blank types.
+type _ struct { m int }
+type _ struct { m int }
+
+func (_ /* ERROR "cannot use _" */) m() {}
+func m(_ /* ERROR "cannot use _" */) {}
+
+// Methods with receiver base type declared in another file.
+func (T3) m1() {}
+func (*T3) m2() {}
+func (x T3) m3() {}
+func (x *T3) f /* ERROR "field and method" */ () {}
+
+// Methods of non-struct type.
+type T4 func()
+
+func (self T4) m() func() { return self }
+
+// Methods associated with an interface.
+type T5 interface {
+	m() int
+}
+
+func (T5 /* ERROR "invalid receiver" */ ) m1() {}
+func (T5 /* ERROR "invalid receiver" */ ) m2() {}
+
+// Methods associated with a named pointer type.
+type ptr *int
+func (ptr /* ERROR "invalid receiver" */ ) _() {}
+func (* /* ERROR "invalid receiver" */ ptr) _() {}
+
+// Methods with zero or multiple receivers.
+func ( /* ERROR "missing receiver" */ ) _() {}
+func (T3, * /* ERROR "exactly one receiver" */ T3) _() {}
+func (T3, T3, T3 /* ERROR "exactly one receiver" */ ) _() {}
+func (a, b /* ERROR "exactly one receiver" */ T3) _() {}
+func (a, b, c /* ERROR "exactly one receiver" */ T3) _() {}
+
+// Methods associated with non-local or unnamed types.
+func (int /* ERROR "invalid receiver" */ ) m() {}
+func ([ /* ERROR "invalid receiver" */ ]int) m() {}
+func (time /* ERROR "invalid receiver" */ .Time) m() {}
+func (* /* ERROR "invalid receiver" */ time.Time) m() {}
+func (x /* ERROR "invalid receiver" */ interface{}) m() {}
+
+// Unsafe.Pointer is treated like a pointer when used as receiver type.
+type UP unsafe.Pointer
+func (UP /* ERROR "invalid" */ ) m1() {}
+func (* /* ERROR "invalid" */ UP) m2() {}
+
+// Double declarations across package files
+const c_double = 0
+type t_double int
+var v_double int
+func f_double() {}
diff --git a/src/go/types/testdata/decls2b.src b/src/go/types/testdata/decls2b.src
new file mode 100644
index 0000000..e7bc394
--- /dev/null
+++ b/src/go/types/testdata/decls2b.src
@@ -0,0 +1,65 @@
+// Copyright 2012 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.
+
+// method declarations
+
+package decls2
+
+import "io"
+
+const pi = 3.1415
+
+func (T1) m /* ERROR "already declared" */ () {}
+func (T2) m(io.Writer) {}
+
+type T3 struct {
+	f *T3
+}
+
+type T6 struct {
+	x int
+}
+
+func (t *T6) m1() int {
+	return t.x
+}
+
+func f() {
+	var t *T6
+	t.m1()
+}
+
+// Double declarations across package files
+const c_double /* ERROR "redeclared" */ = 0
+type t_double  /* ERROR "redeclared" */ int
+var v_double /* ERROR "redeclared" */ int
+func f_double /* ERROR "redeclared" */ () {}
+
+// Blank methods need to be type-checked.
+// Verify by checking that errors are reported.
+func (T /* ERROR "undeclared" */ ) _() {}
+func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
+func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Methods with undeclared receiver type can still be checked.
+// Verify by checking that errors are reported.
+func (Foo /* ERROR "undeclared" */ ) m() {}
+func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+
+func (Foo /* ERROR "undeclared" */ ) _() {}
+func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Receiver declarations are regular parameter lists;
+// receiver types may use parentheses, and the list
+// may have a trailing comma.
+type T7 struct {}
+
+func (T7) m1() {}
+func ((T7)) m2() {}
+func ((*T7)) m3() {}
+func (x *(T7),) m4() {}
+func (x (*(T7)),) m5() {}
+func (x ((*((T7)))),) m6() {}
diff --git a/src/go/types/testdata/decls3.src b/src/go/types/testdata/decls3.src
new file mode 100644
index 0000000..80d2bc8
--- /dev/null
+++ b/src/go/types/testdata/decls3.src
@@ -0,0 +1,309 @@
+// Copyright 2012 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.
+
+// embedded types
+
+package decls3
+
+import "unsafe"
+import "fmt"
+
+// fields with the same name at the same level cancel each other out
+
+func _() {
+	type (
+		T1 struct { X int }
+		T2 struct { X int }
+		T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
+	)
+
+	var t T3
+	_ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+	type (
+		T1 struct { X int }
+		T2 struct { T1 }
+		T3 struct { T1 }
+		T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
+	)
+
+	var t T4
+	_ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func issue4355() {
+	type (
+	    T1 struct {X int}
+	    T2 struct {T1}
+	    T3 struct {T2}
+	    T4 struct {T2}
+	    T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
+	)	
+
+	var t T5
+	_ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+	type State int
+	type A struct{ State }
+	type B struct{ fmt.State }
+	type T struct{ A; B }
+
+	var t T
+	_ = t /* ERROR "ambiguous selector" */ .State
+}
+
+// Embedded fields can be predeclared types.
+
+func _() {
+	type T0 struct{
+		int
+		float32
+		f int
+	}
+	var x T0
+	_ = x.int
+	_ = x.float32
+	_ = x.f
+
+	type T1 struct{
+		T0
+	}
+	var y T1
+	_ = y.int
+	_ = y.float32
+	_ = y.f
+}
+
+// Restrictions on embedded field types.
+
+func _() {
+	type I1 interface{}
+	type I2 interface{}
+	type P1 *int
+	type P2 *int
+	type UP unsafe.Pointer
+
+	type T1 struct {
+		I1
+		* /* ERROR "cannot be a pointer to an interface" */ I2
+		* /* ERROR "cannot be a pointer to an interface" */ error
+		P1 /* ERROR "cannot be a pointer" */
+		* /* ERROR "cannot be a pointer" */ P2
+	}
+
+	// unsafe.Pointers are treated like regular pointers when embedded
+	type T2 struct {
+		unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
+		*/* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer
+		UP /* ERROR "cannot be unsafe.Pointer" */
+		* /* ERROR "cannot be unsafe.Pointer" */ UP
+	}
+}
+
+// Named types that are pointers.
+
+type S struct{ x int }
+func (*S) m() {}
+type P *S
+
+func _() {
+	var s *S
+	_ = s.x
+	_ = s.m
+
+	var p P
+	_ = p.x
+	_ = p /* ERROR "no field or method" */ .m
+	_ = P /* ERROR "no field or method" */ .m
+}
+
+// Borrowed from the FieldByName test cases in reflect/all_test.go.
+
+type D1 struct {
+	d int
+}
+type D2 struct {
+	d int
+}
+
+type S0 struct {
+	A, B, C int
+	D1
+	D2
+}
+
+type S1 struct {
+	B int
+	S0
+}
+
+type S2 struct {
+	A int
+	*S1
+}
+
+type S1x struct {
+	S1
+}
+
+type S1y struct {
+	S1
+}
+
+type S3 struct {
+	S1x
+	S2
+	D, E int
+	*S1y
+}
+
+type S4 struct {
+	*S4
+	A int
+}
+
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+	S6
+	S7
+	S8
+}
+
+type S6 struct {
+	X int
+}
+
+type S7 S6
+
+type S8 struct {
+	S9
+}
+
+type S9 struct {
+	X int
+	Y int
+}
+
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+	S11
+	S12
+	S13
+}
+
+type S11 struct {
+	S6
+}
+
+type S12 struct {
+	S6
+}
+
+type S13 struct {
+	S8
+}
+
+func _() {
+	_ = struct /* ERROR "no field or method" */ {}{}.Foo
+	_ = S0{}.A
+	_ = S0 /* ERROR "no field or method" */ {}.D
+	_ = S1{}.A
+	_ = S1{}.B
+	_ = S1{}.S0
+	_ = S1{}.C
+	_ = S2{}.A
+	_ = S2{}.S1
+	_ = S2{}.B
+	_ = S2{}.C
+	_ = S2 /* ERROR "no field or method" */ {}.D
+	_ = S3 /* ERROR "ambiguous selector" */ {}.S1
+	_ = S3{}.A
+	_ = S3 /* ERROR "ambiguous selector" */ {}.B
+	_ = S3{}.D
+	_ = S3{}.E
+	_ = S4{}.A
+	_ = S4 /* ERROR "no field or method" */ {}.B
+	_ = S5 /* ERROR "ambiguous selector" */ {}.X
+	_ = S5{}.Y
+	_ = S10 /* ERROR "ambiguous selector" */ {}.X
+	_ = S10{}.Y
+}
+
+// Borrowed from the FieldByName benchmark in reflect/all_test.go.
+
+type R0 struct {
+	*R1
+	*R2
+	*R3
+	*R4
+}
+
+type R1 struct {
+	*R5
+	*R6
+	*R7
+	*R8
+}
+
+type R2 R1
+type R3 R1
+type R4 R1
+
+type R5 struct {
+	*R9
+	*R10
+	*R11
+	*R12
+}
+
+type R6 R5
+type R7 R5
+type R8 R5
+
+type R9 struct {
+	*R13
+	*R14
+	*R15
+	*R16
+}
+
+type R10 R9
+type R11 R9
+type R12 R9
+
+type R13 struct {
+	*R17
+	*R18
+	*R19
+	*R20
+}
+
+type R14 R13
+type R15 R13
+type R16 R13
+
+type R17 struct {
+	*R21
+	*R22
+	*R23
+	*R24
+}
+
+type R18 R17
+type R19 R17
+type R20 R17
+
+type R21 struct {
+	X int
+}
+
+type R22 R21
+type R23 R21
+type R24 R21
+
+var _ = R0 /* ERROR "ambiguous selector" */ {}.X
\ No newline at end of file
diff --git a/src/go/types/testdata/errors.src b/src/go/types/testdata/errors.src
new file mode 100644
index 0000000..45bd45a
--- /dev/null
+++ b/src/go/types/testdata/errors.src
@@ -0,0 +1,55 @@
+// Copyright 2013 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 errors
+
+// Testing precise operand formatting in error messages
+// (matching messages are regular expressions, hence the \'s).
+func f(x int, m map[string]int) {
+	// no values
+	_ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m)
+
+	// built-ins
+	_ = println /* ERROR "println \(built-in\) must be called" */
+
+	// types
+	_ = complex128 /* ERROR "complex128 \(type\) is not an expression" */
+
+	// constants
+	const c1 = 991
+	const c2 float32 = 0.5
+	0 /* ERROR "0 \(untyped int constant\) is not used" */
+	c1 /* ERROR "c1 \(untyped int constant 991\) is not used" */
+	c2 /* ERROR "c2 \(constant 1/2 of type float32\) is not used" */
+	c1 /* ERROR "c1 \+ c2 \(constant 1983/2 of type float32\) is not used" */ + c2
+
+	// variables
+	x /* ERROR "x \(variable of type int\) is not used" */
+
+	// values
+	x /* ERROR "x != x \(untyped bool value\) is not used" */ != x
+	x /* ERROR "x \+ x \(value of type int\) is not used" */ + x
+
+	// value, ok's
+	const s = "foo"
+	m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s]
+}
+
+// Valid ERROR comments can have a variety of forms.
+func _() {
+	0 /* ERROR "0 .* is not used" */
+	0 /* ERROR 0 .* is not used */
+	0 // ERROR "0 .* is not used"
+	0 // ERROR 0 .* is not used
+}
+
+// Don't report spurious errors as a consequence of earlier errors.
+// Add more tests as needed.
+func _() {
+	if err := foo /* ERROR undeclared */ (); err != nil /* no error here */ {}
+}
+
+// Use unqualified names for package-local objects.
+type T struct{}
+var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T
diff --git a/src/go/types/testdata/expr0.src b/src/go/types/testdata/expr0.src
new file mode 100644
index 0000000..5afb5d7
--- /dev/null
+++ b/src/go/types/testdata/expr0.src
@@ -0,0 +1,168 @@
+// Copyright 2012 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.
+
+// unary expressions
+
+package expr0 
+
+type mybool bool
+
+var (
+	// bool
+	b0 = true
+	b1 bool = b0
+	b2 = !true
+	b3 = !b1
+	b4 bool = !true
+	b5 bool = !b4
+	b6 = +b0 /* ERROR "not defined" */
+	b7 = -b0 /* ERROR "not defined" */
+	b8 = ^b0 /* ERROR "not defined" */
+	b9 = *b0 /* ERROR "cannot indirect" */
+	b10 = &true /* ERROR "cannot take address" */
+	b11 = &b0
+	b12 = <-b0 /* ERROR "cannot receive" */
+	b13 = & & /* ERROR "cannot take address" */ b0
+
+	// int
+	i0 = 1
+	i1 int = i0
+	i2 = +1
+	i3 = +i0
+	i4 int = +1
+	i5 int = +i4
+	i6 = -1
+	i7 = -i0
+	i8 int = -1
+	i9 int = -i4
+	i10 = !i0 /* ERROR "not defined" */
+	i11 = ^1
+	i12 = ^i0
+	i13 int = ^1
+	i14 int = ^i4
+	i15 = *i0 /* ERROR "cannot indirect" */
+	i16 = &i0
+	i17 = *i16
+	i18 = <-i16 /* ERROR "cannot receive" */
+
+	// uint
+	u0 = uint(1)
+	u1 uint = u0
+	u2 = +1
+	u3 = +u0
+	u4 uint = +1
+	u5 uint = +u4
+	u6 = -1
+	u7 = -u0
+	u8 uint = - /* ERROR "overflows" */ 1
+	u9 uint = -u4
+	u10 = !u0 /* ERROR "not defined" */
+	u11 = ^1
+	u12 = ^i0
+	u13 uint = ^ /* ERROR "overflows" */ 1
+	u14 uint = ^u4
+	u15 = *u0 /* ERROR "cannot indirect" */
+	u16 = &u0
+	u17 = *u16
+	u18 = <-u16 /* ERROR "cannot receive" */
+	u19 = ^uint(0)
+
+	// float64
+	f0 = float64(1)
+	f1 float64 = f0
+	f2 = +1
+	f3 = +f0
+	f4 float64 = +1
+	f5 float64 = +f4
+	f6 = -1
+	f7 = -f0
+	f8 float64 = -1
+	f9 float64 = -f4
+	f10 = !f0 /* ERROR "not defined" */
+	f11 = ^1
+	f12 = ^i0
+	f13 float64 = ^1
+	f14 float64 = ^f4 /* ERROR "not defined" */
+	f15 = *f0 /* ERROR "cannot indirect" */
+	f16 = &f0
+	f17 = *u16
+	f18 = <-u16 /* ERROR "cannot receive" */
+
+	// complex128
+	c0 = complex128(1)
+	c1 complex128 = c0
+	c2 = +1
+	c3 = +c0
+	c4 complex128 = +1
+	c5 complex128 = +c4
+	c6 = -1
+	c7 = -c0
+	c8 complex128 = -1
+	c9 complex128 = -c4
+	c10 = !c0 /* ERROR "not defined" */
+	c11 = ^1
+	c12 = ^i0
+	c13 complex128 = ^1
+	c14 complex128 = ^c4 /* ERROR "not defined" */
+	c15 = *c0 /* ERROR "cannot indirect" */
+	c16 = &c0
+	c17 = *u16
+	c18 = <-u16 /* ERROR "cannot receive" */
+
+	// string
+	s0 = "foo"
+	s1 = +"foo" /* ERROR "not defined" */
+	s2 = -s0 /* ERROR "not defined" */
+	s3 = !s0 /* ERROR "not defined" */
+	s4 = ^s0 /* ERROR "not defined" */
+	s5 = *s4
+	s6 = &s4
+	s7 = *s6
+	s8 = <-s7
+
+	// channel
+	ch chan int
+	rc <-chan float64
+	sc chan <- string
+	ch0 = +ch /* ERROR "not defined" */
+	ch1 = -ch /* ERROR "not defined" */
+	ch2 = !ch /* ERROR "not defined" */
+	ch3 = ^ch /* ERROR "not defined" */
+	ch4 = *ch /* ERROR "cannot indirect" */
+	ch5 = &ch
+	ch6 = *ch5
+	ch7 = <-ch
+	ch8 = <-rc
+	ch9 = <-sc /* ERROR "cannot receive" */
+	ch10, ok = <-ch
+	// ok is of type bool
+	ch11, myok = <-ch
+	_ mybool = myok /* ERROR "cannot initialize" */
+)
+
+// address of composite literals
+type T struct{x, y int}
+
+func f() T { return T{} }
+
+var (
+	_ = &T{1, 2}
+	_ = &[...]int{}
+	_ = &[]int{}
+	_ = &[]int{}
+	_ = &map[string]T{}
+	_ = &(T{1, 2})
+	_ = &((((T{1, 2}))))
+	_ = &f /* ERROR "cannot take address" */ ()
+)
+
+// recursive pointer types
+type P *P
+
+var (
+	p1 P = new(P)
+	p2 P = *p1
+	p3 P = &p2
+)
+
diff --git a/src/go/types/testdata/expr1.src b/src/go/types/testdata/expr1.src
new file mode 100644
index 0000000..8ef0aed
--- /dev/null
+++ b/src/go/types/testdata/expr1.src
@@ -0,0 +1,7 @@
+// Copyright 2012 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.
+
+// binary expressions
+
+package expr1
diff --git a/src/go/types/testdata/expr2.src b/src/go/types/testdata/expr2.src
new file mode 100644
index 0000000..31dc5f0
--- /dev/null
+++ b/src/go/types/testdata/expr2.src
@@ -0,0 +1,247 @@
+// Copyright 2012 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.
+
+// comparisons
+
+package expr2
+
+func _bool() {
+	const t = true == true
+	const f = true == false
+	_ = t /* ERROR "cannot compare" */ < f
+	_ = 0 /* ERROR "cannot convert" */ == t
+	var b bool
+	var x, y float32
+	b = x < y
+	_ = b
+	_ = struct{b bool}{x < y}
+}
+
+// corner cases
+var (
+	v0 = nil /* ERROR "cannot compare" */ == nil
+)
+
+func arrays() {
+	// basics
+	var a, b [10]int
+	_ = a == b
+	_ = a != b
+	_ = a /* ERROR < not defined */ < b
+	_ = a == nil /* ERROR cannot convert */
+
+	type C [10]int
+	var c C
+	_ = a == c
+
+	type D [10]int
+	var d D
+	_ = c /* ERROR mismatched types */ == d
+
+	var e [10]func() int
+	_ = e /* ERROR == not defined */ == e
+}
+
+func structs() {
+	// basics
+	var s, t struct {
+		x int
+		a [10]float32
+		_ bool
+	}
+	_ = s == t
+	_ = s != t
+	_ = s /* ERROR < not defined */ < t
+	_ = s == nil /* ERROR cannot convert */
+
+	type S struct {
+		x int
+		a [10]float32
+		_ bool
+	}
+	type T struct {
+		x int
+		a [10]float32
+		_ bool
+	}
+	var ss S
+	var tt T
+	_ = s == ss
+	_ = ss /* ERROR mismatched types */ == tt
+
+	var u struct {
+		x int
+		a [10]map[string]int
+	}
+	_ = u /* ERROR cannot compare */ == u
+}
+
+func pointers() {
+	// nil
+	_ = nil /* ERROR == not defined */ == nil
+	_ = nil /* ERROR != not defined */ != nil
+	_ = nil /* ERROR < not defined */ < nil
+	_ = nil /* ERROR <= not defined */ <= nil
+	_ = nil /* ERROR > not defined */ > nil
+	_ = nil /* ERROR >= not defined */ >= nil
+
+	// basics
+	var p, q *int
+	_ = p == q
+	_ = p != q
+
+	_ = p == nil
+	_ = p != nil
+	_ = nil == q
+	_ = nil != q
+
+	_ = p /* ERROR < not defined */ < q
+	_ = p /* ERROR <= not defined */ <= q
+	_ = p /* ERROR > not defined */ > q
+	_ = p /* ERROR >= not defined */ >= q
+
+	// various element types
+	type (
+		S1 struct{}
+		S2 struct{}
+		P1 *S1
+		P2 *S2
+	)
+	var (
+		ps1 *S1
+		ps2 *S2
+		p1 P1
+		p2 P2
+	)
+	_ = ps1 == ps1
+	_ = ps1 /* ERROR mismatched types */ == ps2
+	_ = ps2 /* ERROR mismatched types */ == ps1
+
+	_ = p1 == p1
+	_ = p1 /* ERROR mismatched types */ == p2
+
+	_ = p1 == ps1
+}
+
+func channels() {
+	// basics
+	var c, d chan int
+	_ = c == d
+	_ = c != d
+	_ = c == nil
+	_ = c /* ERROR < not defined */ < d
+
+	// various element types (named types)
+	type (
+		C1 chan int
+		C1r <-chan int
+		C1s chan<- int
+		C2 chan float32
+	)
+	var (
+		c1 C1
+		c1r C1r
+		c1s C1s
+		c1a chan int
+		c2 C2
+	)
+	_ = c1 == c1
+	_ = c1 /* ERROR mismatched types */ == c1r
+	_ = c1 /* ERROR mismatched types */ == c1s
+	_ = c1r /* ERROR mismatched types */ == c1s
+	_ = c1 == c1a
+	_ = c1a == c1
+	_ = c1 /* ERROR mismatched types */ == c2
+	_ = c1a /* ERROR mismatched types */ == c2
+
+	// various element types (unnamed types)
+	var (
+		d1 chan int
+		d1r <-chan int
+		d1s chan<- int
+		d1a chan<- int
+		d2 chan float32
+	)
+	_ = d1 == d1
+	_ = d1 == d1r
+	_ = d1 == d1s
+	_ = d1r /* ERROR mismatched types */ == d1s
+	_ = d1 == d1a
+	_ = d1a == d1
+	_ = d1 /* ERROR mismatched types */ == d2
+	_ = d1a /* ERROR mismatched types */ == d2
+}
+
+// for interfaces test
+type S1 struct{}
+type S11 struct{}
+type S2 struct{}
+func (*S1) m() int
+func (*S11) m() int
+func (*S11) n()
+func (*S2) m() float32
+
+func interfaces() {
+	// basics
+	var i, j interface{ m() int }
+	_ = i == j
+	_ = i != j
+	_ = i == nil
+	_ = i /* ERROR < not defined */ < j
+
+	// various interfaces
+	var ii interface { m() int; n() }
+	var k interface { m() float32 }
+	_ = i == ii
+	_ = i /* ERROR mismatched types */ == k
+
+	// interfaces vs values
+	var s1 S1
+	var s11 S11
+	var s2 S2
+
+	_ = i == 0 /* ERROR cannot convert */
+	_ = i /* ERROR mismatched types */ == s1
+	_ = i == &s1
+	_ = i == &s11
+
+	_ = i /* ERROR mismatched types */ == s2
+	_ = i /* ERROR mismatched types */ == &s2
+}
+
+func slices() {
+	// basics
+	var s []int
+	_ = s == nil
+	_ = s != nil
+	_ = s /* ERROR < not defined */ < nil
+
+	// slices are not otherwise comparable
+	_ = s /* ERROR == not defined */ == s
+	_ = s /* ERROR < not defined */ < s
+}
+
+func maps() {
+	// basics
+	var m map[string]int
+	_ = m == nil
+	_ = m != nil
+	_ = m /* ERROR < not defined */ < nil
+
+	// maps are not otherwise comparable
+	_ = m /* ERROR == not defined */ == m
+	_ = m /* ERROR < not defined */ < m
+}
+
+func funcs() {
+	// basics
+	var f func(int) float32
+	_ = f == nil
+	_ = f != nil
+	_ = f /* ERROR < not defined */ < nil
+
+	// funcs are not otherwise comparable
+	_ = f /* ERROR == not defined */ == f
+	_ = f /* ERROR < not defined */ < f
+}
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
new file mode 100644
index 0000000..5772095
--- /dev/null
+++ b/src/go/types/testdata/expr3.src
@@ -0,0 +1,534 @@
+// Copyright 2012 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 expr3
+
+import "time"
+
+func indexes() {
+	_ = 1 /* ERROR "cannot index" */ [0]
+	_ = indexes /* ERROR "cannot index" */ [0]
+	_ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
+
+	var a [10]int
+	_ = a[true /* ERROR "cannot convert" */ ]
+	_ = a["foo" /* ERROR "cannot convert" */ ]
+	_ = a[1.1 /* ERROR "truncated" */ ]
+	_ = a[1.0]
+	_ = a[- /* ERROR "negative" */ 1]
+	_ = a[- /* ERROR "negative" */ 1 :]
+	_ = a[: - /* ERROR "negative" */ 1]
+	_ = a[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+	_ = a[0: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+	_ = a[0: /* ERROR "2nd index required" */ :10]
+	_ = a[:10:10]
+
+	var a0 int
+	a0 = a[0]
+	_ = a0
+	var a1 int32
+	a1 = a /* ERROR "cannot assign" */ [1]
+	_ = a1
+
+	_ = a[9]
+	_ = a[10 /* ERROR "index .* out of bounds" */ ]
+	_ = a[1 /* ERROR "overflows" */ <<100]
+	_ = a[10:]
+	_ = a[:10]
+	_ = a[10:10]
+	_ = a[11 /* ERROR "index .* out of bounds" */ :]
+	_ = a[: 11 /* ERROR "index .* out of bounds" */ ]
+	_ = a[: 1 /* ERROR "overflows" */ <<100]
+	_ = a[:10:10]
+	_ = a[:11 /* ERROR "index .* out of bounds" */ :10]
+	_ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
+	_ = a[10:0:10] /* ERROR "invalid slice indices" */
+	_ = a[0:10:0] /* ERROR "invalid slice indices" */
+	_ = a[10:0:0] /* ERROR "invalid slice indices" */
+	_ = &a /* ERROR "cannot take address" */ [:10]
+
+	pa := &a
+	_ = pa[9]
+	_ = pa[10 /* ERROR "index .* out of bounds" */ ]
+	_ = pa[1 /* ERROR "overflows" */ <<100]
+	_ = pa[10:]
+	_ = pa[:10]
+	_ = pa[10:10]
+	_ = pa[11 /* ERROR "index .* out of bounds" */ :]
+	_ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
+	_ = pa[: 1 /* ERROR "overflows" */ <<100]
+	_ = pa[:10:10]
+	_ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
+	_ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
+	_ = pa[10:0:10] /* ERROR "invalid slice indices" */
+	_ = pa[0:10:0] /* ERROR "invalid slice indices" */
+	_ = pa[10:0:0] /* ERROR "invalid slice indices" */
+	_ = &pa /* ERROR "cannot take address" */ [:10]
+
+	var b [0]int
+	_ = b[0 /* ERROR "index .* out of bounds" */ ]
+	_ = b[:]
+	_ = b[0:]
+	_ = b[:0]
+	_ = b[0:0]
+	_ = b[0:0:0]
+	_ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
+
+	var s []int
+	_ = s[- /* ERROR "negative" */ 1]
+	_ = s[- /* ERROR "negative" */ 1 :]
+	_ = s[: - /* ERROR "negative" */ 1]
+	_ = s[0]
+	_ = s[1:2]
+	_ = s[2:1] /* ERROR "invalid slice indices" */
+	_ = s[2:]
+	_ = s[: 1 /* ERROR "overflows" */ <<100]
+	_ = s[1 /* ERROR "overflows" */ <<100 :]
+	_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
+	_ = s[: /* ERROR "2nd index required" */ :  /* ERROR "3rd index required" */ ]
+	_ = s[:10:10]
+	_ = s[10:0:10] /* ERROR "invalid slice indices" */
+	_ = s[0:10:0] /* ERROR "invalid slice indices" */
+	_ = s[10:0:0] /* ERROR "invalid slice indices" */
+	_ = &s /* ERROR "cannot take address" */ [:10]
+
+	var m map[string]int
+	_ = m[0 /* ERROR "cannot convert" */ ]
+	_ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
+	_ = m["foo"]
+	// ok is of type bool
+	type mybool bool
+	var ok mybool
+	_, ok = m["bar"]
+	_ = ok
+
+	var t string
+	_ = t[- /* ERROR "negative" */ 1]
+	_ = t[- /* ERROR "negative" */ 1 :]
+	_ = t[: - /* ERROR "negative" */ 1]
+	_ = t /* ERROR "3-index slice of string" */ [1:2:3]
+	_ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
+	var t0 byte
+	t0 = t[0]
+	_ = t0
+	var t1 rune
+	t1 = t /* ERROR "cannot assign" */ [2]
+	_ = t1
+	_ = ("foo" + "bar")[5]
+	_ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
+
+	const c = "foo"
+	_ = c[- /* ERROR "negative" */ 1]
+	_ = c[- /* ERROR "negative" */ 1 :]
+	_ = c[: - /* ERROR "negative" */ 1]
+	var c0 byte
+	c0 = c[0]
+	_ = c0
+	var c2 float32
+	c2 = c /* ERROR "cannot assign" */ [2]
+	_ = c[3 /* ERROR "index .* out of bounds" */ ]
+	_ = ""[0 /* ERROR "index .* out of bounds" */ ]
+	_ = c2
+
+	_ = s[1<<30] // no compile-time error here
+
+	// issue 4913
+	type mystring string
+	var ss string
+	var ms mystring
+	var i, j int
+	ss = "foo"[1:2]
+	ss = "foo"[i:j]
+	ms = "foo" /* ERROR "cannot assign" */ [1:2]
+	ms = "foo" /* ERROR "cannot assign" */ [i:j]
+	_, _ = ss, ms
+}
+
+type T struct {
+	x int
+	y func()
+}
+
+func (*T) m() {}
+
+func method_expressions() {
+	_ = T /* ERROR "no field or method" */ .a
+	_ = T /* ERROR "has no method" */ .x
+	_ = T /* ERROR "not in method set" */ .m
+	_ = (*T).m
+
+	var f func(*T) = T /* ERROR "not in method set" */ .m
+	var g func(*T) = (*T).m
+	_, _ = f, g
+
+	_ = T /* ERROR "has no method" */ .y
+	_ = ( /* ERROR "has no method" */ *T).y
+}
+
+func struct_literals() {
+	type T0 struct {
+		a, b, c int
+	}
+
+	type T1 struct {
+		T0
+		a, b int
+		u float64
+		s string
+	}
+
+	// keyed elements
+	_ = T1{}
+	_ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
+	_ = T1{aa /* ERROR "unknown field" */ : 0}
+	_ = T1{1 /* ERROR "invalid field name" */ : 0}
+	_ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
+	_ = T1{a: "foo" /* ERROR "cannot convert" */ }
+	_ = T1{c /* ERROR "unknown field" */ : 0}
+	_ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
+	_ = T1{T0: T0{}}
+	_ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
+
+	// unkeyed elements
+	_ = T0{1, 2, 3}
+	_ = T0{1, b /* ERROR "mixture" */ : 2, 3}
+	_ = T0{1, 2} /* ERROR "too few values" */
+	_ = T0{1, 2, 3, 4  /* ERROR "too many values" */ }
+	_ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4  /* ERROR "truncated" */}
+
+	// invalid type
+	type P *struct{
+		x int
+	}
+	_ = P /* ERROR "invalid composite literal type" */ {}
+
+	// unexported fields
+	_ = time.Time{}
+	_ = time.Time{sec /* ERROR "unknown field" */ : 0}
+	_ = time.Time{
+		0 /* ERROR implicit assignment to unexported field sec in time.Time literal */,
+		0 /* ERROR implicit assignment */ ,
+		nil /* ERROR implicit assignment */ ,
+	}
+}
+
+func array_literals() {
+	type A0 [0]int
+	_ = A0{}
+	_ = A0{0 /* ERROR "index .* out of bounds" */}
+	_ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
+
+	type A1 [10]int
+	_ = A1{}
+	_ = A1{0, 1, 2}
+	_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+	_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+	_ = A1{- /* ERROR "negative" */ 1: 0}
+	_ = A1{8: 8, 9}
+	_ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+	_ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+	_ = A1{5: 5, 6, 7, 3: 3, 4}
+	_ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+	_ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
+	_ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+	_ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+	_ = A1{2.0}
+	_ = A1{2.1 /* ERROR "truncated" */ }
+	_ = A1{"foo" /* ERROR "cannot convert" */ }
+
+	// indices must be integer constants
+	i := 1
+	const f = 2.1
+	const s = "foo"
+	_ = A1{i /* ERROR "index i must be integer constant" */ : 0}
+	_ = A1{f /* ERROR "truncated" */ : 0}
+	_ = A1{s /* ERROR "cannot convert" */ : 0}
+
+	a0 := [...]int{}
+	assert(len(a0) == 0)
+
+	a1 := [...]int{0, 1, 2}
+	assert(len(a1) == 3)
+	var a13 [3]int
+	var a14 [4]int
+	a13 = a1
+	a14 = a1 /* ERROR "cannot assign" */
+	_, _ = a13, a14
+
+	a2 := [...]int{- /* ERROR "negative" */ 1: 0}
+	_ = a2
+
+	a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+	assert(len(a3) == 5) // somewhat arbitrary
+
+	a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
+	assert(len(a4) == 1024)
+
+	// composite literal element types may be elided
+	type T []int
+	_ = [10]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+	a6 := [...]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+	assert(len(a6) == 8)
+
+	// recursively so
+	_ = [10][10]T{{}, [10]T{{}}, {{1, 2, 3}}}
+
+	// from the spec
+	type Point struct { x, y float32 }
+	_ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+	_ = [...]Point{{1.5, -3.5}, {0, 0}}
+	_ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
+	_ = [][]int{{1, 2, 3}, {4, 5}}
+	_ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+	_ = [...]*Point{{1.5, -3.5}, {0, 0}}
+}
+
+func slice_literals() {
+	type S0 []int
+	_ = S0{}
+	_ = S0{0, 1, 2}
+	_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+	_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+	_ = S0{- /* ERROR "negative" */ 1: 0}
+	_ = S0{8: 8, 9}
+	_ = S0{8: 8, 9, 10}
+	_ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+	_ = S0{5: 5, 6, 7, 3: 3, 4}
+	_ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+	_ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
+	_ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+	_ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+	_ = S0{2.0}
+	_ = S0{2.1 /* ERROR "truncated" */ }
+	_ = S0{"foo" /* ERROR "cannot convert" */ }
+
+	// indices must be resolved correctly
+	const index1 = 1
+	_ = S0{index1: 1}
+	_ = S0{index2: 2}
+	_ = S0{index3 /* ERROR "undeclared name" */ : 3}
+
+	// indices must be integer constants
+	i := 1
+	const f = 2.1
+	const s = "foo"
+	_ = S0{i /* ERROR "index i must be integer constant" */ : 0}
+	_ = S0{f /* ERROR "truncated" */ : 0}
+	_ = S0{s /* ERROR "cannot convert" */ : 0}
+
+	// composite literal element types may be elided
+	type T []int
+	_ = []T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+	_ = [][]int{{1, 2, 3}, {4, 5}}
+
+	// recursively so
+	_ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+}
+
+const index2 int = 2
+
+type N int
+func (N) f() {}
+
+func map_literals() {
+	type M0 map[string]int
+	type M1 map[bool]int
+	type M2 map[*int]int
+
+	_ = M0{}
+	_ = M0{1 /* ERROR "missing key" */ }
+	_ = M0{1 /* ERROR "cannot convert" */ : 2}
+	_ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+	_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
+
+	_ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
+	_ = map[interface{}]int{int(2): 1, int16(2): 1}
+	_ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1}
+
+	type S string
+
+	_ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1}
+	_ = map[interface{}]int{"a": 1, S("a"): 1}
+	_ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1}
+
+	type I interface {
+		f()
+	}
+
+	_ = map[I]int{N(0): 1, N(2): 1}
+	_ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1}
+
+	// map keys must be resolved correctly
+	key1 := "foo"
+	_ = M0{key1: 1}
+	_ = M0{key2: 2}
+	_ = M0{key3 /* ERROR "undeclared name" */ : 2}
+
+	var value int
+	_ = M1{true: 1, false: 0}
+	_ = M2{nil: 0, &value: 1}
+
+	// composite literal element types may be elided
+	type T [2]int
+	_ = map[int]T{0: T{3, 4}, 1: {5, 6}}
+
+	// recursively so
+	_ = map[int][]T{0: {}, 1: {{}, T{1, 2}}}
+
+	// composite literal key types may be elided
+	_ = map[T]int{T{3, 4}: 0, {5, 6}: 1}
+
+	// recursively so
+	_ = map[[2]T]int{{}: 0, {{}}: 1, [2]T{{}}: 2, {T{1, 2}}: 3}
+
+	// composite literal element and key types may be elided
+	_ = map[T]T{{}: {}, {1, 2}: T{3, 4}, T{4, 5}: {}}
+	_ = map[T]M0{{} : {}, T{1, 2}: M0{"foo": 0}, {1, 3}: {"foo": 1}}
+
+	// recursively so
+	_ = map[[2]T][]T{{}: {}, {{}}: {{}, T{1, 2}}, [2]T{{}}: nil, {T{1, 2}}: {{}, {}}}
+
+	// from the spec
+	type Point struct { x, y float32 }
+	_ = map[string]Point{"orig": {0, 0}}
+	_ = map[*Point]string{{0, 0}: "orig"}
+}
+
+var key2 string = "bar"
+
+type I interface {
+	m()
+}
+
+type I2 interface {
+	m(int)
+}
+
+type T1 struct{}
+type T2 struct{}
+
+func (T2) m(int) {}
+
+type mybool bool
+
+func type_asserts() {
+	var x int
+	_ = x /* ERROR "not an interface" */ .(int)
+
+	var e interface{}
+	var ok bool
+	x, ok = e.(int)
+	_ = ok
+
+	// ok value is of type bool
+	var myok mybool
+	_, myok = e.(int)
+	_ = myok
+
+	var t I
+	_ = t /* ERROR "use of .* outside type switch" */ .(type)
+	_ = t /* ERROR "missing method m" */ .(T)
+	_ = t.(*T)
+	_ = t /* ERROR "missing method m" */ .(T1)
+	_ = t /* ERROR "wrong type for method m" */ .(T2)
+	_ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
+
+	// e doesn't statically have an m, but may have one dynamically.
+	_ = e.(I2)
+}
+
+func f0() {}
+func f1(x int) {}
+func f2(u float32, s string) {}
+func fs(s []byte) {}
+func fv(x ...int) {}
+func fi(x ... interface{}) {}
+func (T) fm(x ...int)
+
+func g0() {}
+func g1() int { return 0}
+func g2() (u float32, s string) { return }
+func gs() []byte { return nil }
+
+func _calls() {
+	var x int
+	var y float32
+	var s []int
+
+	f0()
+	_ = f0 /* ERROR "used as value" */ ()
+	f0(g0 /* ERROR "too many arguments" */ )
+
+	f1(0)
+	f1(x)
+	f1(10.0)
+	f1() /* ERROR "too few arguments" */
+	f1(x, y /* ERROR "too many arguments" */ )
+	f1(s /* ERROR "cannot pass" */ )
+	f1(x ... /* ERROR "cannot use ..." */ )
+	f1(g0 /* ERROR "used as value" */ ())
+	f1(g1())
+	// f1(g2()) // TODO(gri) missing position in error message
+
+	f2() /* ERROR "too few arguments" */
+	f2(3.14) /* ERROR "too few arguments" */
+	f2(3.14, "foo")
+	f2(x /* ERROR "cannot pass" */ , "foo")
+	f2(g0 /* ERROR "used as value" */ ())
+	f2(g1 /* ERROR "cannot pass" */ ()) /* ERROR "too few arguments" */
+	f2(g2())
+
+	fs() /* ERROR "too few arguments" */
+	fs(g0 /* ERROR "used as value" */ ())
+	fs(g1 /* ERROR "cannot pass" */ ())
+	fs(g2 /* ERROR "cannot pass" */ /* ERROR "too many arguments" */ ())
+	fs(gs())
+
+	fv()
+	fv(1, 2.0, x)
+	fv(s /* ERROR "cannot pass" */ )
+	fv(s...)
+	fv(x /* ERROR "cannot use" */ ...)
+	fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
+	fv(gs /* ERROR "cannot pass" */ ())
+	fv(gs /* ERROR "cannot pass" */ ()...)
+
+	var t T
+	t.fm()
+	t.fm(1, 2.0, x)
+	t.fm(s /* ERROR "cannot pass" */ )
+	t.fm(g1())
+	t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+	t.fm(gs /* ERROR "cannot pass" */ ())
+	t.fm(gs /* ERROR "cannot pass" */ ()...)
+
+	T.fm(t, )
+	T.fm(t, 1, 2.0, x)
+	T.fm(t, s /* ERROR "cannot pass" */ )
+	T.fm(t, g1())
+	T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
+	T.fm(t, gs /* ERROR "cannot pass" */ ())
+	T.fm(t, gs /* ERROR "cannot pass" */ ()...)
+
+	var i interface{ fm(x ...int) } = t
+	i.fm()
+	i.fm(1, 2.0, x)
+	i.fm(s /* ERROR "cannot pass" */ )
+	i.fm(g1())
+	i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+	i.fm(gs /* ERROR "cannot pass" */ ())
+	i.fm(gs /* ERROR "cannot pass" */ ()...)
+
+	fi()
+	fi(1, 2.0, x, 3.14, "foo")
+	fi(g2())
+	fi(0, g2)
+	fi(0, g2 /* ERROR "2-valued expression" */ ())
+}
+
+func issue6344() {
+	type T []interface{}
+	var x T
+	fi(x...) // ... applies also to named slices
+}
diff --git a/src/go/types/testdata/gotos.src b/src/go/types/testdata/gotos.src
new file mode 100644
index 0000000..0c7ee44
--- /dev/null
+++ b/src/go/types/testdata/gotos.src
@@ -0,0 +1,560 @@
+// Copyright 2011 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.
+
+// This file is a modified copy of $GOROOT/test/goto.go.
+
+package gotos
+
+var (
+	i, n int
+	x    []int
+	c    chan int
+	m    map[int]int
+	s    string
+)
+
+// goto after declaration okay
+func _() {
+	x := 1
+	goto L
+L:
+	_ = x
+}
+
+// goto before declaration okay
+func _() {
+	goto L
+L:
+	x := 1
+	_ = x
+}
+
+// goto across declaration not okay
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration at line 36" */
+	x := 1
+	_ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+	goto L
+	{
+		x := 1
+		_ = x
+	}
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration at line 58" */
+	{
+		x := 1
+		_ = x
+	}
+	x := 1
+	_ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+	x := 1
+	_ = x
+	goto L
+}
+
+func _() {
+L: L1:
+	x := 1
+	_ = x
+	goto L
+	goto L1
+}
+
+// error shows first offending variable
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration at line 84" */
+	x := 1
+	_ = x
+	y := 1
+	_ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration" */
+	x := 1
+	_ = x
+	y := 1
+	_ = y
+	return
+L:
+}
+
+// goto into outer block okay
+func _() {
+	{
+		goto L
+	}
+L:
+}
+
+func _() {
+	{
+		goto L
+		goto L1
+	}
+L: L1:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+	{
+		goto L
+	}
+}
+
+func _() {
+L: L1:
+	{
+		goto L
+		goto L1
+	}
+}
+
+// goto into inner block not okay
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	{
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	goto L1 /* ERROR "goto L1 jumps into block" */
+	{
+	L: L1:
+	}
+}
+
+// goto backward into inner block still not okay
+func _() {
+	{
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	{
+	L: L1:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+	goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+// error shows first (outermost) offending block
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	{
+		{
+			{
+			L:
+			}
+		}
+	}
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	x := 1
+	_ = x
+	{
+	L:
+	}
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+	if true {
+		goto L
+	}
+}
+
+func _() {
+L:
+	if true {
+		goto L
+	} else {
+	}
+}
+
+func _() {
+L:
+	if false {
+	} else {
+		goto L
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	if true {
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	if true {
+	L:
+	} else {
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	if true {
+	} else {
+	L:
+	}
+}
+
+func _() {
+	if false {
+	L:
+	} else {
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else {
+	L:
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else if false {
+	L:
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else if false {
+	L:
+	} else {
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else if false {
+	} else {
+	L:
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else {
+		L:
+	}
+}
+
+func _() {
+	if true {
+		L:
+	} else {
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
+
+// for
+
+func _() {
+	for {
+		goto L
+	}
+L:
+}
+
+func _() {
+	for {
+		goto L
+	L:
+	}
+}
+
+func _() {
+	for {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for {
+		goto L
+	L1:
+	}
+L:
+	goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+func _() {
+	for i < n {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = 0; i < n; i++ {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range x {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range c {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range m {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range s {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+// switch
+
+func _() {
+L:
+	switch i {
+	case 0:
+		goto L
+	}
+}
+
+func _() {
+L:
+	switch i {
+	case 0:
+
+	default:
+		goto L
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+
+	default:
+	L:
+		goto L
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+
+	default:
+		goto L
+	L:
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+		goto L
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	switch i {
+	case 0:
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	switch i {
+	case 0:
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	switch i {
+	case 0:
+	default:
+	L:
+	}
+}
+
+func _() {
+	switch i {
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	case 0:
+	L:
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+	L:
+		;
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
+
+// select
+// different from switch.  the statement has no implicit block around it.
+
+func _() {
+L:
+	select {
+	case <-c:
+		goto L
+	}
+}
+
+func _() {
+L:
+	select {
+	case c <- 1:
+
+	default:
+		goto L
+	}
+}
+
+func _() {
+	select {
+	case <-c:
+
+	default:
+	L:
+		goto L
+	}
+}
+
+func _() {
+	select {
+	case c <- 1:
+
+	default:
+		goto L
+	L:
+	}
+}
+
+func _() {
+	select {
+	case <-c:
+		goto L
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	select {
+	case c <- 1:
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	select {
+	case c <- 1:
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	select {
+	case <-c:
+	default:
+	L:
+	}
+}
+
+func _() {
+	select {
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	case <-c:
+	L:
+	}
+}
+
+func _() {
+	select {
+	case <-c:
+	L:
+		;
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
diff --git a/src/go/types/testdata/importdecl0a.src b/src/go/types/testdata/importdecl0a.src
new file mode 100644
index 0000000..463dcd0
--- /dev/null
+++ b/src/go/types/testdata/importdecl0a.src
@@ -0,0 +1,53 @@
+// Copyright 2013 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 importdecl0
+
+import ()
+
+import (
+	// we can have multiple blank imports (was bug)
+	_ "math"
+	_ "net/rpc"
+	init /* ERROR "cannot declare init" */ "fmt"
+	// reflect defines a type "flag" which shows up in the gc export data
+	"reflect"
+	. /* ERROR "imported but not used" */ "reflect"
+)
+
+import "math" /* ERROR "imported but not used" */
+import m /* ERROR "imported but not used as m" */ "math"
+import _ "math"
+
+import (
+	"math/big" /* ERROR "imported but not used" */
+	b /* ERROR "imported but not used" */ "math/big"
+	_ "math/big"
+)
+
+import "fmt"
+import f1 "fmt"
+import f2 "fmt"
+
+// reflect.flag must not be visible in this package
+type flag int
+type _ reflect /* ERROR "not exported" */ .flag
+
+// imported package name may conflict with local objects
+type reflect /* ERROR "reflect already declared" */ int
+
+// dot-imported exported objects may conflict with local objects
+type Value /* ERROR "Value already declared through dot-import of package reflect" */ struct{}
+
+var _ = fmt.Println // use "fmt"
+
+func _() {
+	f1.Println() // use "fmt"
+}
+
+func _() {
+	_ = func() {
+		f2.Println() // use "fmt"
+	}
+}
diff --git a/src/go/types/testdata/importdecl0b.src b/src/go/types/testdata/importdecl0b.src
new file mode 100644
index 0000000..6844e70
--- /dev/null
+++ b/src/go/types/testdata/importdecl0b.src
@@ -0,0 +1,33 @@
+// Copyright 2013 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 importdecl0
+
+import "math"
+import m "math"
+
+import . "testing" // declares T in file scope
+import . /* ERROR "imported but not used" */ "unsafe"
+import . "fmt"     // declares Println in file scope
+
+import (
+	// TODO(gri) At the moment, 2 errors are reported because both go/parser
+	// and the type checker report it. Eventually, this test should not be
+	// done by the parser anymore.
+	"" /* ERROR invalid import path */ /* ERROR invalid import path */
+	"a!b" /* ERROR invalid import path */ /* ERROR invalid import path */
+	"abc\xffdef" /* ERROR invalid import path */ /* ERROR invalid import path */
+)
+
+// using "math" in this file doesn't affect its use in other files
+const Pi0 = math.Pi
+const Pi1 = m.Pi
+
+type _ T // use "testing"
+
+func _() func() interface{} {
+	return func() interface{} {
+		return Println // use "fmt"
+	}
+}
diff --git a/src/go/types/testdata/importdecl1a.src b/src/go/types/testdata/importdecl1a.src
new file mode 100644
index 0000000..8301820
--- /dev/null
+++ b/src/go/types/testdata/importdecl1a.src
@@ -0,0 +1,11 @@
+// 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.
+
+// Test case for issue 8969.
+
+package importdecl1
+
+import . "unsafe"
+
+var _ Pointer // use dot-imported package unsafe
diff --git a/src/go/types/testdata/importdecl1b.src b/src/go/types/testdata/importdecl1b.src
new file mode 100644
index 0000000..f24bb9a
--- /dev/null
+++ b/src/go/types/testdata/importdecl1b.src
@@ -0,0 +1,7 @@
+// 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.
+
+package importdecl1
+
+import . /* ERROR "imported but not used" */ "unsafe"
diff --git a/src/go/types/testdata/init0.src b/src/go/types/testdata/init0.src
new file mode 100644
index 0000000..ef0349c
--- /dev/null
+++ b/src/go/types/testdata/init0.src
@@ -0,0 +1,106 @@
+// Copyright 2013 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.
+
+// initialization cycles
+
+package init0
+
+// initialization cycles (we don't know the types)
+const (
+	s0 /* ERROR initialization cycle */ = s0
+
+	x0 /* ERROR initialization cycle */ = y0
+	y0 = x0
+
+	a0 = b0
+	b0 /* ERROR initialization cycle */ = c0
+	c0 = d0
+	d0 = b0
+)
+
+var (
+	s1 /* ERROR initialization cycle */ = s1
+
+	x1 /* ERROR initialization cycle */ = y1
+	y1 = x1
+
+	a1 = b1
+	b1 /* ERROR initialization cycle */ = c1
+	c1 = d1
+	d1 = b1
+)
+
+// initialization cycles (we know the types)
+const (
+	s2 /* ERROR initialization cycle */ int = s2
+
+	x2 /* ERROR initialization cycle */ int = y2
+	y2 = x2
+
+	a2 = b2
+	b2 /* ERROR initialization cycle */ int = c2
+	c2 = d2
+	d2 = b2
+)
+
+var (
+	s3 /* ERROR initialization cycle */ int = s3
+
+	x3 /* ERROR initialization cycle */ int = y3
+	y3 = x3
+
+	a3 = b3
+	b3 /* ERROR initialization cycle */ int = c3
+	c3 = d3
+	d3 = b3
+)
+
+// cycles via struct fields
+
+type S1 struct {
+	f int
+}
+const cx3 S1 /* ERROR invalid constant type */ = S1{cx3.f}
+var vx3 /* ERROR initialization cycle */ S1 = S1{vx3.f}
+
+// cycles via functions
+
+var x4 = x5
+var x5 /* ERROR initialization cycle */ = f1()
+func f1() int { return x5*10 }
+
+var x6, x7 /* ERROR initialization cycle */ = f2()
+var x8 = x7
+func f2() (int, int) { return f3() + f3(), 0 }
+func f3() int { return x8 }
+
+// cycles via closures
+
+var x9 /* ERROR initialization cycle */ = func() int { return x9 }()
+
+var x10 /* ERROR initialization cycle */ = f4()
+
+func f4() int {
+	_ = func() {
+		_ = x10
+	}
+	return 0
+}
+
+// cycles via method expressions
+
+type T1 struct{}
+
+func (T1) m() bool { _ = x11; return false }
+
+var x11 /* ERROR initialization cycle */ = T1.m(T1{})
+
+// cycles via method values
+
+type T2 struct{}
+
+func (T2) m() bool { _ = x12; return false }
+
+var t1 T2
+var x12 /* ERROR initialization cycle */ = t1.m
diff --git a/src/go/types/testdata/init1.src b/src/go/types/testdata/init1.src
new file mode 100644
index 0000000..39ca314
--- /dev/null
+++ b/src/go/types/testdata/init1.src
@@ -0,0 +1,97 @@
+// Copyright 2013 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.
+
+// initialization cycles
+
+package init1
+
+// issue 6683 (marked as WorkingAsIntended)
+
+type T0 struct{}
+
+func (T0) m() int { return y0 }
+
+var x0 = T0{}
+
+var y0 /* ERROR initialization cycle */ = x0.m()
+
+type T1 struct{}
+
+func (T1) m() int { return y1 }
+
+var x1 interface {
+	m() int
+} = T1{}
+
+var y1 = x1.m() // no cycle reported, x1 is of interface type
+
+// issue 6703 (modified)
+
+var x2 /* ERROR initialization cycle */ = T2.m
+
+var y2 = x2
+
+type T2 struct{}
+
+func (T2) m() int {
+	_ = y2
+	return 0
+}
+
+var x3 /* ERROR initialization cycle */ = T3.m(T3{}) // <<<< added (T3{})
+
+var y3 = x3
+
+type T3 struct{}
+
+func (T3) m() int {
+	_ = y3
+	return 0
+}
+
+var x4 /* ERROR initialization cycle */ = T4{}.m // <<<< added {}
+
+var y4 = x4
+
+type T4 struct{}
+
+func (T4) m() int {
+	_ = y4
+	return 0
+}
+
+var x5 /* ERROR initialization cycle */ = T5{}.m() // <<<< added ()
+
+var y5 = x5
+
+type T5 struct{}
+
+func (T5) m() int {
+	_ = y5
+	return 0
+}
+
+// issue 4847
+// simplified test case
+
+var x6 = f6
+var y6 /* ERROR initialization cycle */ = f6
+func f6() { _ = y6 }
+
+// full test case
+
+type (
+      E int
+      S int
+)
+
+type matcher func(s *S) E
+
+func matchList(s *S) E { return matcher(matchAnyFn)(s) }
+
+var foo = matcher(matchList)
+
+var matchAny /* ERROR initialization cycle */ = matcher(matchList)
+
+func matchAnyFn(s *S) (err E) { return matchAny(s) }
\ No newline at end of file
diff --git a/src/go/types/testdata/init2.src b/src/go/types/testdata/init2.src
new file mode 100644
index 0000000..614db6c
--- /dev/null
+++ b/src/go/types/testdata/init2.src
@@ -0,0 +1,139 @@
+// 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.
+
+// initialization cycles
+
+package init2
+
+// cycles through functions
+
+func f1() int { _ = x1; return 0 }
+var x1 /* ERROR initialization cycle */ = f1
+
+func f2() int { _ = x2; return 0 }
+var x2 /* ERROR initialization cycle */ = f2()
+
+// cycles through method expressions
+
+type T3 int
+func (T3) m() int { _ = x3; return 0 }
+var x3 /* ERROR initialization cycle */ = T3.m
+
+type T4 int
+func (T4) m() int { _ = x4; return 0 }
+var x4 /* ERROR initialization cycle */ = T4.m(0)
+
+type T3p int
+func (*T3p) m() int { _ = x3p; return 0 }
+var x3p /* ERROR initialization cycle */ = (*T3p).m
+
+type T4p int
+func (*T4p) m() int { _ = x4p; return 0 }
+var x4p /* ERROR initialization cycle */ = (*T4p).m(nil)
+
+// cycles through method expressions of embedded methods
+
+type T5 struct { E5 }
+type E5 int
+func (E5) m() int { _ = x5; return 0 }
+var x5 /* ERROR initialization cycle */ = T5.m
+
+type T6 struct { E6 }
+type E6 int
+func (E6) m() int { _ = x6; return 0 }
+var x6 /* ERROR initialization cycle */ = T6.m(T6{0})
+
+type T5p struct { E5p }
+type E5p int
+func (*E5p) m() int { _ = x5p; return 0 }
+var x5p /* ERROR initialization cycle */ = (*T5p).m
+
+type T6p struct { E6p }
+type E6p int
+func (*E6p) m() int { _ = x6p; return 0 }
+var x6p /* ERROR initialization cycle */ = (*T6p).m(nil)
+
+// cycles through method values
+
+type T7 int
+func (T7) m() int { _ = x7; return 0 }
+var x7 /* ERROR initialization cycle */ = T7(0).m
+
+type T8 int
+func (T8) m() int { _ = x8; return 0 }
+var x8 /* ERROR initialization cycle */ = T8(0).m()
+
+type T7p int
+func (*T7p) m() int { _ = x7p; return 0 }
+var x7p /* ERROR initialization cycle */ = new(T7p).m
+
+type T8p int
+func (*T8p) m() int { _ = x8p; return 0 }
+var x8p /* ERROR initialization cycle */ = new(T8p).m()
+
+type T7v int
+func (T7v) m() int { _ = x7v; return 0 }
+var x7var T7v
+var x7v /* ERROR initialization cycle */ = x7var.m
+
+type T8v int
+func (T8v) m() int { _ = x8v; return 0 }
+var x8var T8v
+var x8v /* ERROR initialization cycle */ = x8var.m()
+
+type T7pv int
+func (*T7pv) m() int { _ = x7pv; return 0 }
+var x7pvar *T7pv
+var x7pv /* ERROR initialization cycle */ = x7pvar.m
+
+type T8pv int
+func (*T8pv) m() int { _ = x8pv; return 0 }
+var x8pvar *T8pv
+var x8pv /* ERROR initialization cycle */ = x8pvar.m()
+
+// cycles through method values of embedded methods
+
+type T9 struct { E9 }
+type E9 int
+func (E9) m() int { _ = x9; return 0 }
+var x9 /* ERROR initialization cycle */ = T9{0}.m
+
+type T10 struct { E10 }
+type E10 int
+func (E10) m() int { _ = x10; return 0 }
+var x10 /* ERROR initialization cycle */ = T10{0}.m()
+
+type T9p struct { E9p }
+type E9p int
+func (*E9p) m() int { _ = x9p; return 0 }
+var x9p /* ERROR initialization cycle */ = new(T9p).m
+
+type T10p struct { E10p }
+type E10p int
+func (*E10p) m() int { _ = x10p; return 0 }
+var x10p /* ERROR initialization cycle */ = new(T10p).m()
+
+type T9v struct { E9v }
+type E9v int
+func (E9v) m() int { _ = x9v; return 0 }
+var x9var T9v
+var x9v /* ERROR initialization cycle */ = x9var.m
+
+type T10v struct { E10v }
+type E10v int
+func (E10v) m() int { _ = x10v; return 0 }
+var x10var T10v
+var x10v /* ERROR initialization cycle */ = x10var.m()
+
+type T9pv struct { E9pv }
+type E9pv int
+func (*E9pv) m() int { _ = x9pv; return 0 }
+var x9pvar *T9pv
+var x9pv /* ERROR initialization cycle */ = x9pvar.m
+
+type T10pv struct { E10pv }
+type E10pv int
+func (*E10pv) m() int { _ = x10pv; return 0 }
+var x10pvar *T10pv
+var x10pv /* ERROR initialization cycle */ = x10pvar.m()
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
new file mode 100644
index 0000000..d08e0fd
--- /dev/null
+++ b/src/go/types/testdata/issues.src
@@ -0,0 +1,73 @@
+// 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.
+
+package issues
+
+import "fmt"
+
+func issue7035() {
+	type T struct{ X int }
+	_ = func() {
+		fmt.Println() // must refer to imported fmt rather than the fmt below
+	}
+	fmt := new(T)
+	_ = fmt.X
+}
+
+func issue8066() {
+	const (
+		// TODO(gri) Enable test below for releases 1.4 and higher
+		// _ = float32(340282356779733661637539395458142568447)
+		_ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ )
+	)
+}
+
+// Check that a missing identifier doesn't lead to a spurious error cascade.
+func issue8799a() {
+	x, ok := missing /* ERROR undeclared */ ()
+	_ = !ok
+	_ = x
+}
+
+func issue8799b(x int, ok bool) {
+	x, ok = missing /* ERROR undeclared */ ()
+	_ = !ok
+	_ = x
+}
+
+func issue9182() {
+	type Point C /* ERROR undeclared */ .Point
+	// no error for composite literal based on unknown type
+	_ = Point{x: 1, y: 2}
+}
+
+func f0() (a []int)         { return }
+func f1() (a []int, b int)  { return }
+func f2() (a, b []int)      { return }
+
+func append_([]int, ...int) {}
+
+func issue9473(a []int, b ...int) {
+	// variadic builtin function
+	_ = append(f0())
+	_ = append(f0(), f0()...)
+	_ = append(f1())
+	_ = append(f2 /* ERROR cannot pass argument */ ())
+	_ = append(f2()... /* ERROR cannot use ... */ )
+	_ = append(f0(), f1 /* ERROR 2-valued expression */ ())
+	_ = append(f0(), f2 /* ERROR 2-valued expression */ ())
+	_ = append(f0(), f1()... /* ERROR cannot use ... */ )
+	_ = append(f0(), f2()... /* ERROR cannot use ... */ )
+
+	// variadic user-defined function
+	append_(f0())
+	append_(f0(), f0()...)
+	append_(f1())
+	append_(f2 /* ERROR cannot pass argument */ ())
+	append_(f2()... /* ERROR cannot use ... */ )
+	append_(f0(), f1 /* ERROR 2-valued expression */ ())
+	append_(f0(), f2 /* ERROR 2-valued expression */ ())
+	append_(f0(), f1()... /* ERROR cannot use */ )
+	append_(f0(), f2()... /* ERROR cannot use */ )
+}
diff --git a/src/go/types/testdata/labels.src b/src/go/types/testdata/labels.src
new file mode 100644
index 0000000..102ffc7
--- /dev/null
+++ b/src/go/types/testdata/labels.src
@@ -0,0 +1,207 @@
+// Copyright 2011 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.
+
+// This file is a modified concatenation of the files
+// $GOROOT/test/label.go and $GOROOT/test/label1.go.
+
+package labels
+
+var x int
+
+func f0() {
+L1 /* ERROR "label L1 declared but not used" */ :
+	for {
+	}
+L2 /* ERROR "label L2 declared but not used" */ :
+	select {
+	}
+L3 /* ERROR "label L3 declared but not used" */ :
+	switch {
+	}
+L4 /* ERROR "label L4 declared but not used" */ :
+	if true {
+	}
+L5 /* ERROR "label L5 declared but not used" */ :
+	f0()
+L6:
+	f0()
+L6 /* ERROR "label L6 already declared" */ :
+	f0()
+	if x == 20 {
+		goto L6
+	}
+
+L7:
+	for {
+		break L7
+		break L8 /* ERROR "invalid break label L8" */
+	}
+
+// A label must be directly associated with a switch, select, or
+// for statement; it cannot be the label of a labeled statement.
+
+L7a /* ERROR "declared but not used" */ : L7b:
+	for {
+		break L7a /* ERROR "invalid break label L7a" */
+		continue L7a /* ERROR "invalid continue label L7a" */
+		continue L7b
+	}
+
+L8:
+	for {
+		if x == 21 {
+			continue L8
+			continue L7 /* ERROR "invalid continue label L7" */
+		}
+	}
+
+L9:
+	switch {
+	case true:
+		break L9
+	defalt /* ERROR "label defalt declared but not used" */ :
+	}
+
+L10:
+	select {
+	default:
+		break L10
+		break L9 /* ERROR "invalid break label L9" */
+	}
+
+	goto L10a
+L10a: L10b:
+	select {
+	default:
+		break L10a /* ERROR "invalid break label L10a" */
+		break L10b
+		continue L10b /* ERROR "invalid continue label L10b" */
+	}
+}
+
+func f1() {
+L1:
+	for {
+		if x == 0 {
+			break L1
+		}
+		if x == 1 {
+			continue L1
+		}
+		goto L1
+	}
+
+L2:
+	select {
+	default:
+		if x == 0 {
+			break L2
+		}
+		if x == 1 {
+			continue L2 /* ERROR "invalid continue label L2" */
+		}
+		goto L2
+	}
+
+L3:
+	switch {
+	case x > 10:
+		if x == 11 {
+			break L3
+		}
+		if x == 12 {
+			continue L3 /* ERROR "invalid continue label L3" */
+		}
+		goto L3
+	}
+
+L4:
+	if true {
+		if x == 13 {
+			break L4 /* ERROR "invalid break label L4" */
+		}
+		if x == 14 {
+			continue L4 /* ERROR "invalid continue label L4" */
+		}
+		if x == 15 {
+			goto L4
+		}
+	}
+
+L5:
+	f1()
+	if x == 16 {
+		break L5 /* ERROR "invalid break label L5" */
+	}
+	if x == 17 {
+		continue L5 /* ERROR "invalid continue label L5" */
+	}
+	if x == 18 {
+		goto L5
+	}
+
+	for {
+		if x == 19 {
+			break L1 /* ERROR "invalid break label L1" */
+		}
+		if x == 20 {
+			continue L1 /* ERROR "invalid continue label L1" */
+		}
+		if x == 21 {
+			goto L1
+		}
+	}
+}
+
+// Additional tests not in the original files.
+
+func f2() {
+L1 /* ERROR "label L1 declared but not used" */ :
+	if x == 0 {
+		for {
+			continue L1 /* ERROR "invalid continue label L1" */
+		}
+	}
+}
+
+func f3() {
+L1:
+L2:
+L3:
+	for {
+		break L1 /* ERROR "invalid break label L1" */
+		break L2 /* ERROR "invalid break label L2" */
+		break L3
+		continue L1 /* ERROR "invalid continue label L1" */
+		continue L2 /* ERROR "invalid continue label L2" */
+		continue L3
+		goto L1
+		goto L2
+		goto L3
+	}
+}
+
+// Blank labels are never declared.
+
+func f4() {
+_:
+_: // multiple blank labels are ok
+	goto _ /* ERROR "label _ not declared" */
+}
+
+func f5() {
+_:
+	for {
+		break _ /* ERROR "invalid break label _" */
+		continue _ /* ERROR "invalid continue label _" */
+	}
+}
+
+func f6() {
+_:
+	switch {
+	default:
+		break _ /* ERROR "invalid break label _" */
+	}
+}
diff --git a/src/go/types/testdata/methodsets.src b/src/go/types/testdata/methodsets.src
new file mode 100644
index 0000000..8921146
--- /dev/null
+++ b/src/go/types/testdata/methodsets.src
@@ -0,0 +1,214 @@
+// Copyright 2013 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 methodsets
+
+type T0 struct {}
+
+func (T0) v0() {}
+func (*T0) p0() {}
+
+type T1 struct {} // like T0 with different method names
+
+func (T1) v1() {}
+func (*T1) p1() {}
+
+type T2 interface {
+	v2()
+	p2()
+}
+
+type T3 struct {
+	T0
+	*T1
+	T2
+}
+
+// Method expressions
+func _() {
+	var (
+		_ func(T0) = T0.v0
+		_ = T0 /* ERROR "not in method set" */ .p0
+
+		_ func (*T0) = (*T0).v0
+		_ func (*T0) = (*T0).p0
+
+		// T1 is like T0
+
+		_ func(T2) = T2.v2
+		_ func(T2) = T2.p2
+
+		_ func(T3) = T3.v0
+		_ func(T3) = T3 /* ERROR "not in method set" */ .p0
+		_ func(T3) = T3.v1
+		_ func(T3) = T3.p1
+		_ func(T3) = T3.v2
+		_ func(T3) = T3.p2
+
+		_ func(*T3) = (*T3).v0
+		_ func(*T3) = (*T3).p0
+		_ func(*T3) = (*T3).v1
+		_ func(*T3) = (*T3).p1
+		_ func(*T3) = (*T3).v2
+		_ func(*T3) = (*T3).p2
+	)
+}
+
+// Method values with addressable receivers
+func _() {
+	var (
+		v0 T0
+		_ func() = v0.v0
+		_ func() = v0.p0
+	)
+
+	var (
+		p0 *T0
+		_ func() = p0.v0
+		_ func() = p0.p0
+	)
+
+	// T1 is like T0
+
+	var (
+		v2 T2
+		_ func() = v2.v2
+		_ func() = v2.p2
+	)
+
+	var (
+		v4 T3
+		_ func() = v4.v0
+		_ func() = v4.p0
+		_ func() = v4.v1
+		_ func() = v4.p1
+		_ func() = v4.v2
+		_ func() = v4.p2
+	)
+
+	var (
+		p4 *T3
+		_ func() = p4.v0
+		_ func() = p4.p0
+		_ func() = p4.v1
+		_ func() = p4.p1
+		_ func() = p4.v2
+		_ func() = p4.p2
+	)
+}
+
+// Method calls with addressable receivers
+func _() {
+	var v0 T0
+	v0.v0()
+	v0.p0()
+
+	var p0 *T0
+	p0.v0()
+	p0.p0()
+
+	// T1 is like T0
+
+	var v2 T2
+	v2.v2()
+	v2.p2()
+
+	var v4 T3
+	v4.v0()
+	v4.p0()
+	v4.v1()
+	v4.p1()
+	v4.v2()
+	v4.p2()
+
+	var p4 *T3
+	p4.v0()
+	p4.p0()
+	p4.v1()
+	p4.p1()
+	p4.v2()
+	p4.p2()
+}
+
+// Method values with value receivers
+func _() {
+	var (
+		_ func() = T0{}.v0
+		_ func() = T0 /* ERROR "not in method set" */ {}.p0
+
+		_ func() = (&T0{}).v0
+		_ func() = (&T0{}).p0
+
+		// T1 is like T0
+
+		// no values for T2
+
+		_ func() = T3{}.v0
+		_ func() = T3 /* ERROR "not in method set" */ {}.p0
+		_ func() = T3{}.v1
+		_ func() = T3{}.p1
+		_ func() = T3{}.v2
+		_ func() = T3{}.p2
+
+		_ func() = (&T3{}).v0
+		_ func() = (&T3{}).p0
+		_ func() = (&T3{}).v1
+		_ func() = (&T3{}).p1
+		_ func() = (&T3{}).v2
+		_ func() = (&T3{}).p2
+	)
+}
+
+// Method calls with value receivers
+func _() {
+	T0{}.v0()
+	T0 /* ERROR "not in method set" */ {}.p0()
+
+	(&T0{}).v0()
+	(&T0{}).p0()
+
+	// T1 is like T0
+
+	// no values for T2
+
+	T3{}.v0()
+	T3 /* ERROR "not in method set" */ {}.p0()
+	T3{}.v1()
+	T3{}.p1()
+	T3{}.v2()
+	T3{}.p2()
+
+	(&T3{}).v0()
+	(&T3{}).p0()
+	(&T3{}).v1()
+	(&T3{}).p1()
+	(&T3{}).v2()
+	(&T3{}).p2()
+}
+
+// *T has no methods if T is an interface type
+func issue5918() {
+	var (
+		err error
+		_ = err.Error()
+		_ func() string = err.Error
+		_ func(error) string = error.Error
+
+		perr = &err
+		_ = perr /* ERROR "no field or method" */ .Error()
+		_ func() string = perr /* ERROR "no field or method" */ .Error
+		_ func(*error) string = ( /* ERROR "no field or method" */ *error).Error
+	)
+
+	type T *interface{ m() int }
+	var (
+		x T
+		_ = (*x).m()
+		_ = (*x).m
+
+		_ = x /* ERROR "no field or method" */ .m()
+		_ = x /* ERROR "no field or method" */ .m
+		_ = T /* ERROR "no field or method" */ .m
+	)
+}
diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src
new file mode 100644
index 0000000..7f8ed06f
--- /dev/null
+++ b/src/go/types/testdata/shifts.src
@@ -0,0 +1,321 @@
+// Copyright 2013 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 shifts
+
+func shifts0() {
+	// basic constant shifts
+	const (
+		s = 10
+		_ = 0<<0
+		_ = 1<<s
+		_ = 1<<- /* ERROR "stupid shift" */ 1
+		_ = 1<<1075 /* ERROR "stupid shift" */
+		_ = 2.0<<1
+
+		_ int = 2<<s
+		_ float32 = 2<<s
+		_ complex64 = 2<<s
+
+		_ int = 2.0<<s
+		_ float32 = 2.0<<s
+		_ complex64 = 2.0<<s
+
+		_ int = 'a'<<s
+		_ float32 = 'a'<<s
+		_ complex64 = 'a'<<s
+	)
+}
+
+func shifts1() {
+	// basic non-constant shifts
+	var (
+		i int
+		u uint
+
+		_ = 1<<0
+		_ = 1<<i /* ERROR "must be unsigned" */
+		_ = 1<<u
+		_ = 1<<"foo" /* ERROR "cannot convert" */
+		_ = i<<0
+		_ = i<<- /* ERROR "must not be negative" */ 1
+		_ = 1 /* ERROR "overflows" */ <<100
+
+		_ uint = 1 << 0
+		_ uint = 1 << u
+		_ float32 = 1 /* ERROR "must be integer" */ << u
+	)
+}
+
+func shifts2() {
+	// from the spec
+	var (
+		s uint = 33
+		i = 1<<s           // 1 has type int
+		j int32 = 1<<s     // 1 has type int32; j == 0
+		k = uint64(1<<s)   // 1 has type uint64; k == 1<<33
+		m int = 1.0<<s     // 1.0 has type int
+		n = 1.0<<s != i    // 1.0 has type int; n == false if ints are 32bits in size
+		o = 1<<s == 2<<s   // 1 and 2 have type int; o == true if ints are 32bits in size
+		p = 1<<s == 1<<33  // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
+		u = 1.0 /* ERROR "must be integer" */ <<s         // illegal: 1.0 has type float64, cannot shift
+		u1 = 1.0 /* ERROR "must be integer" */ <<s != 0   // illegal: 1.0 has type float64, cannot shift
+		u2 = 1 /* ERROR "must be integer" */ <<s != 1.0   // illegal: 1 has type float64, cannot shift
+		v float32 = 1 /* ERROR "must be integer" */ <<s   // illegal: 1 has type float32, cannot shift
+		w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
+	)
+	_, _, _, _, _, _, _, _, _, _, _, _ = i, j, k, m, n, o, p, u, u1, u2, v, w
+}
+
+func shifts3(a int16, b float32) {
+	// random tests
+	var (
+		s uint = 11
+		u = 1 /* ERROR "must be integer" */ <<s + 1.0
+		v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
+	)
+	x := 1.0 /* ERROR "must be integer" */ <<s + 1
+	shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
+	_, _, _ = u, v, x
+}
+
+func shifts4() {
+	// shifts in comparisons w/ untyped operands
+	var s uint
+
+	_ = 1<<s == 1
+	_ = 1 /* ERROR "integer" */ <<s == 1.
+	_ = 1. /* ERROR "integer" */ <<s == 1
+	_ = 1. /* ERROR "integer" */ <<s == 1.
+
+	_ = 1<<s + 1 == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1 == 1.
+	_ = 1 /* ERROR "integer" */ <<s + 1. == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1. == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1 == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1 == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1. == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1. == 1.
+
+	_ = 1<<s == 1<<s
+	_ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+
+	_ = 1<<s + 1<<s == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+
+	_ = 1<<s + 1<<s == 1<<s + 1<<s
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+}
+
+func shifts5() {
+	// shifts in comparisons w/ typed operands
+	var s uint
+	var x int
+
+	_ = 1<<s == x
+	_ = 1.<<s == x
+	_ = 1.1 /* ERROR "int" */ <<s == x
+
+	_ = 1<<s + x == 1
+	_ = 1<<s + x == 1.
+	_ = 1<<s + x == 1.1 /* ERROR "int" */
+	_ = 1.<<s + x == 1
+	_ = 1.<<s + x == 1.
+	_ = 1.<<s + x == 1.1 /* ERROR "int" */
+	_ = 1.1 /* ERROR "int" */ <<s + x == 1
+	_ = 1.1 /* ERROR "int" */ <<s + x == 1.
+	_ = 1.1 /* ERROR "int" */ <<s + x == 1.1
+
+	_ = 1<<s == x<<s
+	_ = 1.<<s == x<<s
+	_ = 1.1  /* ERROR "int" */ <<s == x<<s
+}
+
+func shifts6() {
+	// shifts as operands in non-arithmetic operations and as arguments
+	var a [10]int
+	var s uint
+
+	_ = a[1<<s]
+	_ = a[1.0]
+	_ = a[1.0<<s]
+
+	_ = make([]int, 1.0)
+	_ = make([]int, 1.0<<s)
+	_ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
+
+	_ = float32(1)
+	_ = float32(1 /* ERROR "must be integer" */ <<s)
+	_ = float32(1.0)
+	_ = float32(1.0 /* ERROR "must be integer" */ <<s)
+	_ = float32(1.1 /* ERROR "must be integer" */ <<s)
+
+	var b []int
+	_ = append(b, 1<<s)
+	_ = append(b, 1.0<<s)
+	_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+	_ = append(b, 1<<s)
+	_ = append(b, 1.0<<s) // should fail - see TODO in append code
+	_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+	_ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
+	_ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
+	_ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
+	_ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
+
+	// TODO(gri) The delete below is not type-checked correctly yet.
+	// var m1 map[int]string
+	// delete(m1, 1<<s)
+}
+
+func shifts7() {
+	// shifts of shifts
+	var s uint
+	var x int
+	_ = x
+
+	_ = 1<<(1<<s)
+	_ = 1<<(1.<<s)
+	_ = 1. /* ERROR "integer" */ <<(1<<s)
+	_ = 1. /* ERROR "integer" */ <<(1.<<s)
+
+	x = 1<<(1<<s)
+	x = 1<<(1.<<s)
+	x = 1.<<(1<<s)
+	x = 1.<<(1.<<s)
+
+	_ = (1<<s)<<(1<<s)
+	_ = (1<<s)<<(1.<<s)
+	_ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+	_ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+
+	x = (1<<s)<<(1<<s)
+	x = (1<<s)<<(1.<<s)
+	x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+	x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+}
+
+func shifts8() {
+	// shift examples from shift discussion: better error messages
+	var s uint
+	_ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+	_ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+	// additional cases
+	_ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+	_ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+	_ = int(1.<<s)
+	_ = int(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+	_ = float32(1 /* ERROR "shifted operand .* must be integer" */ <<s)
+	_ = float32(1. /* ERROR "shifted operand .* must be integer" */ <<s)
+	_ = float32(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+	// TODO(gri) the error messages for these two are incorrect - disabled for now
+	// _ = complex64(1<<s)
+	// _ = complex64(1.<<s)
+	_ = complex64(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+}
+
+func shifts9() {
+	// various originally failing snippets of code from the std library
+	// from src/compress/lzw/reader.go:90
+	{
+		var d struct {
+			bits     uint32
+			width    uint
+		}
+		_ = uint16(d.bits & (1<<d.width - 1))
+	}
+
+	// from src/debug/dwarf/buf.go:116
+	{
+		var ux uint64
+		var bits uint
+		x := int64(ux)
+		if x&(1<<(bits-1)) != 0 {}
+	}
+
+	// from src/encoding/asn1/asn1.go:160
+	{
+		var bytes []byte
+		if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
+	}
+
+	// from src/math/big/rat.go:140
+	{
+		var exp int
+		var mantissa uint64
+		shift := uint64(-1022 - (exp - 1)) // [1..53)
+		_ = mantissa & (1<<shift - 1)
+	}
+
+	// from src/net/interface.go:51
+	{
+		type Flags uint
+		var f Flags
+		var i int
+		if f&(1<<uint(i)) != 0 {}
+	}
+
+	// from src/runtime/softfloat64.go:234
+	{
+		var gm uint64
+		var shift uint
+		_ = gm & (1<<shift - 1)
+	}
+
+	// from src/strconv/atof.go:326
+	{
+		var mant uint64
+		var mantbits uint
+		if mant == 2<<mantbits {}
+	}
+
+	// from src/route_bsd.go:82
+	{
+		var Addrs int32
+		const rtaRtMask = 1
+		var i uint
+		if Addrs&rtaRtMask&(1<<i) == 0 {}
+	}
+
+	// from src/text/scanner/scanner.go:540
+	{
+		var s struct { Whitespace uint64 }
+		var ch rune
+		for s.Whitespace&(1<<uint(ch)) != 0 {}
+	}
+}
+
+func issue5895() {
+	var x = 'a' << 1 // type of x must be rune
+	var _ rune = x
+}
diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src
new file mode 100644
index 0000000..fd1ddba
--- /dev/null
+++ b/src/go/types/testdata/stmt0.src
@@ -0,0 +1,833 @@
+// Copyright 2012 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.
+
+// statements
+
+package stmt0
+
+func assignments0() (int, int) {
+	var a, b, c int
+	var ch chan int
+	f0 := func() {}
+	f1 := func() int { return 1 }
+	f2 := func() (int, int) { return 1, 2 }
+	f3 := func() (int, int, int) { return 1, 2, 3 }
+
+	a, b, c = 1, 2, 3
+	a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
+	a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
+	_, _, _ = a, b, c
+
+	a = f0 /* ERROR "used as value" */ ()
+	a = f1()
+	a = f2 /* ERROR "assignment count mismatch" */ ()
+	a, b = f2()
+	a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
+	a, b, c = f3()
+	a, b = f3 /* ERROR "assignment count mismatch" */ ()
+
+	a, b, c = <- /* ERROR "assignment count mismatch" */ ch
+
+	return /* ERROR "wrong number of return values" */
+	return /* ERROR "wrong number of return values" */ 1
+	return 1, 2
+	return /* ERROR "wrong number of return values" */ 1, 2, 3
+}
+
+func assignments1() {
+	b, i, f, c, s := false, 1, 1.0, 1i, "foo"
+	b = i /* ERROR "cannot assign" */
+	i = f /* ERROR "cannot assign" */
+	f = c /* ERROR "cannot assign" */
+	c = s /* ERROR "cannot assign" */
+	s = b /* ERROR "cannot assign" */
+
+	v0, v1, v2 := 1 /* ERROR "mismatch" */ , 2, 3, 4
+	_, _, _ = v0, v1, v2
+
+	b = true
+
+	i += 1
+	i += "foo" /* ERROR "cannot convert.*int" */
+
+	f -= 1
+	f /= 0
+	f = float32(0)/0 /* ERROR "division by zero" */
+	f -= "foo" /* ERROR "cannot convert.*float64" */
+
+	c *= 1
+	c /= 0
+
+	s += "bar"
+	s += 1 /* ERROR "cannot convert.*string" */
+
+	var u64 uint64
+	u64 += 1<<u64
+
+	undeclared /* ERROR "undeclared" */ = 991
+
+	// test cases for issue 5800
+	var (
+		_ int = nil /* ERROR "untyped nil value" */
+		_ [10]int = nil /* ERROR "untyped nil value" */
+		_ []byte = nil
+		_ struct{} = nil /* ERROR "untyped nil value" */
+		_ func() = nil
+		_ map[int]string = nil
+		_ chan int = nil
+	)
+
+	// test cases for issue 5500
+	_ = func() (int, bool) {
+		var m map[int]int
+		return /* ERROR "wrong number of return values" */ m[0]
+	}
+
+	g := func(int, bool){}
+	var m map[int]int
+	g(m[0]) /* ERROR "too few arguments" */
+
+	// assignments to _
+	_ = nil /* ERROR "use of untyped nil" */
+	_ = 1 /* ERROR overflow */ <<1000
+	(_) = 0
+}
+
+func assignments2() {
+	type mybool bool
+	var m map[string][]bool
+	var s []bool
+	var b bool
+	var d mybool
+	_ = s
+	_ = b
+	_ = d
+
+	// assignments to map index expressions are ok
+	s, b = m["foo"]
+	_, d = m["bar"]
+	m["foo"] = nil
+	m["foo"] = nil /* ERROR assignment count mismatch */ , false
+	_ = append(m["foo"])
+	_ = append(m["foo"], true)
+
+	var c chan int
+	_, b = <-c
+	_, d = <-c
+	<- /* ERROR cannot assign */ c = 0
+	<-c = 0 /* ERROR assignment count mismatch */ , false
+
+	var x interface{}
+	_, b = x.(int)
+	x /* ERROR cannot assign */ .(int) = 0
+	x.(int) = 0 /* ERROR assignment count mismatch */ , false
+
+	assignments2 /* ERROR used as value */ () = nil
+	int /* ERROR not an expression */ = 0
+}
+
+func issue6487() {
+	type S struct{x int}
+	_ = &S /* ERROR "cannot take address" */ {}.x
+	_ = &( /* ERROR "cannot take address" */ S{}.x)
+	_ = (&S{}).x
+	S /* ERROR "cannot assign" */ {}.x = 0
+	(&S{}).x = 0
+
+	type M map[string]S
+	var m M
+	m /* ERROR "cannot assign" */ ["foo"].x = 0
+	_ = &( /* ERROR "cannot take address" */ m["foo"].x)
+	_ = &m /* ERROR "cannot take address" */ ["foo"].x
+}
+
+func issue6766a() {
+	a, a /* ERROR redeclared */ := 1, 2
+	_ = a
+	a, b, b /* ERROR redeclared */ := 1, 2, 3
+	_ = b
+	c, c /* ERROR redeclared */, b := 1, 2, 3
+	_ = c
+	a, b := /* ERROR no new variables */ 1, 2
+}
+
+func shortVarDecls1() {
+	const c = 0
+	type d int
+	a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */  := 1, "zwei", 3.0, 4
+	var _ int = a // a is of type int
+	var _ string = b // b is of type string
+}
+
+func incdecs() {
+	const c = 3.14
+	c /* ERROR "cannot assign" */ ++
+	s := "foo"
+	s /* ERROR "cannot convert" */ --
+	3.14 /* ERROR "cannot assign" */ ++
+	var (
+		x int
+		y float32
+		z complex128
+	)
+	x++
+	y--
+	z++
+}
+
+func sends() {
+	var ch chan int
+	var rch <-chan int
+	var x int
+	x /* ERROR "cannot send" */ <- x
+	rch /* ERROR "cannot send" */ <- x
+	ch <- "foo" /* ERROR "cannot convert" */
+	ch <- x
+}
+
+func selects() {
+	select {}
+	var (
+		ch chan int
+		sc chan <- bool
+	)
+	select {
+	case <-ch:
+	case (<-ch):
+	case t := <-ch:
+		_ = t
+	case t := (<-ch):
+		_ = t
+	case t, ok := <-ch:
+		_, _ = t, ok
+	case t, ok := (<-ch):
+		_, _ = t, ok
+	case <-sc /* ERROR "cannot receive from send-only channel" */ :
+	}
+	select {
+	default:
+	default /* ERROR "multiple defaults" */ :
+	}
+	select {
+	case a, b := <-ch:
+		_, b = a, b
+	case x /* ERROR send or receive */ :
+	case a /* ERROR send or receive */ := ch:
+	}
+
+	// test for issue 9570: ch2 in second case falsely resolved to
+	// ch2 declared in body of first case
+	ch1 := make(chan int)
+	ch2 := make(chan int)
+	select {
+	case <-ch1:
+		var ch2 /* ERROR ch2 declared but not used */ chan bool
+	case i := <-ch2:
+		print(i + 1)
+	}
+}
+
+func gos() {
+	go 1 /* ERROR HERE "function must be invoked" */
+	go int /* ERROR "go requires function call, not conversion" */ (0)
+	go gos()
+	var c chan int
+	go close(c)
+	go len /* ERROR "go discards result" */ (c)
+}
+
+func defers() {
+	defer 1 /* ERROR HERE "function must be invoked" */
+	defer int /* ERROR "defer requires function call, not conversion" */ (0)
+	defer defers()
+	var c chan int
+	defer close(c)
+	defer len /* ERROR "defer discards result" */ (c)
+}
+
+func breaks() {
+	var x, y int
+
+	break /* ERROR "break" */
+	{
+		break /* ERROR "break" */
+	}
+	if x < y {
+		break /* ERROR "break" */
+	}
+
+	switch x {
+	case 0:
+		break
+	case 1:
+		if x == y {
+			break
+		}
+	default:
+		break
+		break
+	}
+
+	var z interface{}
+	switch z.(type) {
+	case int:
+		break
+	}
+
+	for {
+		break
+	}
+
+	var a []int
+	for _ = range a {
+		break
+	}
+
+	for {
+		if x == y {
+			break
+		}
+	}
+
+	var ch chan int
+	select {
+	case <-ch:
+		break
+	}
+
+	select {
+	case <-ch:
+		if x == y {
+			break
+		}
+	default:
+		break
+	}
+}
+
+func continues() {
+	var x, y int
+
+	continue /* ERROR "continue" */
+	{
+		continue /* ERROR "continue" */
+	}
+
+	if x < y {
+		continue /* ERROR "continue" */
+	}
+
+	switch x {
+	case 0:
+		continue /* ERROR "continue" */
+	}
+
+	var z interface{}
+	switch z.(type) {
+	case int:
+		continue /* ERROR "continue" */
+	}
+
+	var ch chan int
+	select {
+	case <-ch:
+		continue /* ERROR "continue" */
+	}
+
+	for i := 0; i < 10; i++ {
+		continue
+		if x < y {
+			continue
+			break
+		}
+		switch x {
+		case y:
+			continue
+		default:
+			break
+		}
+		select {
+		case <-ch:
+			continue
+		}
+	}
+
+	var a []int
+	for _ = range a {
+		continue
+		if x < y {
+			continue
+			break
+		}
+		switch x {
+		case y:
+			continue
+		default:
+			break
+		}
+		select {
+		case <-ch:
+			continue
+		}
+	}
+}
+
+func returns0() {
+	return
+	return 0 /* ERROR no result values expected */
+}
+
+func returns1(x float64) (int, *float64) {
+	return 0, &x
+	return /* ERROR wrong number of return values */
+	return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot return" */
+	return /* ERROR wrong number of return values */ 0, &x, 1
+}
+
+func returns2() (a, b int) {
+	return
+	return 1, "foo" /* ERROR cannot convert */
+	return /* ERROR wrong number of return values */ 1, 2, 3
+	{
+		type a int
+		return 1, 2
+		return /* ERROR a not in scope at return */
+	}
+}
+
+func returns3() (_ int) {
+	return
+	{
+		var _ int // blank (_) identifiers never shadow since they are in no scope
+		return
+	}
+}
+
+func switches0() {
+	var x int
+
+	switch x {
+	}
+
+	switch x {
+	default:
+	default /* ERROR "multiple defaults" */ :
+	}
+
+	switch {
+	case 1  /* ERROR "cannot convert" */ :
+	}
+
+	true := "false"
+	_ = true
+	// A tagless switch is equivalent to the bool 
+        // constant true, not the identifier 'true'.
+	switch {
+	case "false" /* ERROR "cannot convert" */:
+	}
+
+	switch int32(x) {
+	case 1, 2:
+	case x /* ERROR "cannot compare" */ :
+	}
+
+	switch x {
+	case 1 /* ERROR "overflows" */ << 100:
+	}
+
+	switch x {
+	case 1:
+	case 1 /* DISABLED "duplicate case" */ :
+	case 2, 3, 4:
+	case 1 /* DISABLED "duplicate case" */ :
+	}
+
+	switch uint64(x) {
+	case 1 /* DISABLED duplicate case */ <<64-1:
+	case 1 /* DISABLED duplicate case */ <<64-1:
+	}
+}
+
+func switches1() {
+	fallthrough /* ERROR "fallthrough statement out of place" */
+
+	var x int
+	switch x {
+	case 0:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+		break
+	case 1:
+		fallthrough
+	case 2:
+	default:
+		fallthrough
+	case 3:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+	}
+
+	var y interface{}
+	switch y.(type) {
+	case int:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+	default:
+	}
+
+	switch x {
+	case 0:
+		if x == 0 {
+			fallthrough /* ERROR "fallthrough statement out of place" */
+		}
+	}
+
+	switch x {
+	case 0:
+		goto L1
+		L1: fallthrough
+	case 1:
+		goto L2
+		goto L3
+		goto L4
+		L2: L3: L4: fallthrough
+	default:
+	}
+
+	switch x {
+	case 0:
+		goto L5
+		L5: fallthrough
+	default:
+		goto L6
+		goto L7
+		goto L8
+		L6: L7: L8: fallthrough /* ERROR "fallthrough statement out of place" */
+	}
+
+	switch x {
+	case 0:
+		{
+			fallthrough /* ERROR "fallthrough statement out of place" */
+		}
+	default:
+	}
+}
+
+type I interface {
+	m()
+}
+
+type I2 interface {
+	m(int)
+}
+
+type T struct{}
+type T1 struct{}
+type T2 struct{}
+
+func (T) m() {}
+func (T2) m(int) {}
+
+func typeswitches() {
+	var i int
+	var x interface{}
+
+	switch x.(type) {}
+	switch (x /* ERROR "outside type switch" */ .(type)) {}
+
+	switch x.(type) {
+	default:
+	default /* ERROR "multiple defaults" */ :
+	}
+
+	switch x /* ERROR "declared but not used" */ := x.(type) {}
+	switch _ /* ERROR "no new variable on left side of :=" */ := x.(type) {}
+
+	switch x := x.(type) {
+	case int:
+		var y int = x
+		_ = y
+	}
+
+	switch x := i /* ERROR "not an interface" */ .(type) {}
+
+	switch t := x.(type) {
+	case nil:
+		var v bool = t /* ERROR "cannot initialize" */
+		_ = v
+	case int:
+		var v int = t
+		_ = v
+	case float32, complex64:
+		var v float32 = t /* ERROR "cannot initialize" */
+		_ = v
+	default:
+		var v float32 = t /* ERROR "cannot initialize" */
+		_ = v
+	}
+
+	var t I
+	switch t.(type) {
+	case T:
+	case T1 /* ERROR "missing method m" */ :
+	case T2 /* ERROR "wrong type for method m" */ :
+	case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
+	}
+}
+
+// Test that each case clause uses the correct type of the variable
+// declared by the type switch (issue 5504).
+func typeswitch0() {
+	switch y := interface{}(nil).(type) {
+	case int:
+		func() int { return y + 0 }()
+	case float32:
+		func() float32 { return y }()
+	}
+}
+
+// Test correct scope setup.
+// (no redeclaration errors expected in the type switch)
+func typeswitch1() {
+	var t I
+	switch t := t; t := t.(type) {
+	case nil:
+		var _ I = t
+	case T:
+		var _ T = t
+	default:
+		var _ I = t
+	}
+}
+
+// Test correct typeswitch against interface types.
+type A interface { a() }
+type B interface { b() }
+type C interface { a(int) }
+
+func typeswitch2() {
+	switch A(nil).(type) {
+	case A:
+	case B:
+	case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561)
+	}
+}
+
+func typeswitch3(x interface{}) {
+	switch x.(type) {
+	case int:
+	case float64:
+	case int /* ERROR duplicate case */ :
+	}
+
+	switch x.(type) {
+	case nil:
+	case int:
+	case nil /* ERROR duplicate case */ , nil /* ERROR duplicate case */ :
+	}
+
+	type F func(int)
+	switch x.(type) {
+	case nil:
+	case int, func(int):
+	case float32, func /* ERROR duplicate case */ (x int):
+	case F:
+	}
+}
+
+func fors1() {
+	for {}
+	var i string
+	_ = i
+	for i := 0; i < 10; i++ {}
+	for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
+}
+
+func rangeloops1() {
+	var (
+		x int
+		a [10]float32
+		b []string
+		p *[10]complex128
+		pp **[10]complex128
+		s string
+		m map[int]bool
+		c chan int
+		sc chan<- int
+		rc <-chan int
+	)
+
+	for range x /* ERROR "cannot range over" */ {}
+	for _ = range x /* ERROR "cannot range over" */ {}
+	for i := range x /* ERROR "cannot range over" */ {}
+
+	for range a {}
+	for i := range a {
+		var ii int
+		ii = i
+		_ = ii
+	}
+	for i, x := range a {
+		var ii int
+		ii = i
+		_ = ii
+		var xx float64
+		xx = x /* ERROR "cannot assign" */
+		_ = xx
+	}
+	var ii int
+	var xx float32
+	for ii, xx = range a {}
+	_, _ = ii, xx
+
+	for range b {}
+	for i := range b {
+		var ii int
+		ii = i
+		_ = ii
+	}
+	for i, x := range b {
+		var ii int
+		ii = i
+		_ = ii
+		var xx string
+		xx = x
+		_ = xx
+	}
+
+	for range s {}
+	for i := range s {
+		var ii int
+		ii = i
+		_ = ii
+	}
+	for i, x := range s {
+		var ii int
+		ii = i
+		_ = ii
+		var xx rune
+		xx = x
+		_ = xx
+	}
+
+	for range p {}
+	for _, x := range p {
+		var xx complex128
+		xx = x
+		_ = xx
+	}
+
+	for range pp /* ERROR "cannot range over" */ {}
+	for _, x := range pp /* ERROR "cannot range over" */ {}
+
+	for range m {}
+	for k := range m {
+		var kk int32
+		kk = k /* ERROR "cannot assign" */
+		_ = kk
+	}
+	for k, v := range m {
+		var kk int
+		kk = k
+		_ = kk
+		if v {}
+	}
+
+	for range c {}
+	for _, _ /* ERROR "only one iteration variable" */ = range c {}
+	for e := range c {
+		var ee int
+		ee = e
+		_ = ee
+	}
+	for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
+	for _ = range rc {}
+
+	// constant strings
+	const cs = "foo"
+	for range cs {}
+	for range "" {}
+	for i, x := range cs { _, _ = i, x }
+	for i, x := range "" {
+		var ii int
+		ii = i
+		_ = ii
+		var xx rune
+		xx = x
+		_ = xx
+	}
+}
+
+func rangeloops2() {
+	type I int
+	type R rune
+
+	var a [10]int
+	var i I
+	_ = i
+	for i /* ERROR cannot assign */ = range a {}
+	for i /* ERROR cannot assign */ = range &a {}
+	for i /* ERROR cannot assign */ = range a[:] {}
+
+	var s string
+	var r R
+	_ = r
+	for i /* ERROR cannot assign */ = range s {}
+	for i /* ERROR cannot assign */ = range "foo" {}
+	for _, r /* ERROR cannot assign */ = range s {}
+	for _, r /* ERROR cannot assign */ = range "foo" {}
+}
+
+func issue6766b() {
+	for _ := /* ERROR no new variables */ range "" {}
+	for a, a /* ERROR redeclared */ := range "" { _ = a }
+	var a int
+	_ = a
+	for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
+}
+
+// Test that despite errors in the range clause,
+// the loop body is still type-checked (and thus
+// errors reported).
+func issue10148() {
+	for y /* ERROR declared but not used */ := range "" {
+		_ = "" /* ERROR cannot convert */ + 1
+	}
+	for range 1 /* ERROR cannot range over 1 */ {
+		_ = "" /* ERROR cannot convert */ + 1
+	}
+	for y := range 1 /* ERROR cannot range over 1 */ {
+		_ = "" /* ERROR cannot convert */ + 1
+	}
+}
+
+func labels0() {
+	goto L0
+	goto L1
+	L0:
+	L1:
+	L1 /* ERROR "already declared" */ :
+	if true {
+		goto L2		
+		L2:
+		L0 /* ERROR "already declared" */ :
+	}
+	_ = func() {
+		goto L0
+		goto L1
+		goto L2
+		L0:
+		L1:
+		L2:
+	}
+}
+
+func expression_statements(ch chan int) {
+	expression_statements(ch)
+	<-ch
+	println()
+
+	0 /* ERROR "not used" */
+	1 /* ERROR "not used" */ +2
+	cap /* ERROR "not used" */ (ch)
+	println /* ERROR "must be called" */
+}
diff --git a/src/go/types/testdata/stmt1.src b/src/go/types/testdata/stmt1.src
new file mode 100644
index 0000000..a2955e6
--- /dev/null
+++ b/src/go/types/testdata/stmt1.src
@@ -0,0 +1,165 @@
+// Copyright 2013 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.
+
+// terminating statements
+
+package stmt1
+
+func _() {}
+
+func _() int {} /* ERROR "missing return" */
+
+func _() int { panic(0) }
+func _() int { (panic(0)) }
+
+// block statements
+func _(x, y int) (z int) {
+	{
+		return
+	}
+}
+
+func _(x, y int) (z int) {
+	{
+	}
+} /* ERROR "missing return" */
+
+// if statements
+func _(x, y int) (z int) {
+	if x < y { return }
+	return 1
+}
+
+func _(x, y int) (z int) {
+	if x < y { return }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	if x < y {
+	} else { return 1
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	if x < y { return
+	} else { return
+	}
+}
+
+// for statements
+func _(x, y int) (z int) {
+	for x < y {
+		return
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	for {
+		return
+	}
+}
+
+func _(x, y int) (z int) {
+	for {
+		return
+		break
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	for {
+		for { break }
+		return
+	}
+}
+
+func _(x, y int) (z int) {
+L:	for {
+		for { break L }
+		return
+	}
+} /* ERROR "missing return" */
+
+// switch statements
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	default: return
+	}
+}
+
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	case 1: break
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	default:
+		switch y {
+		case 0: break
+		}
+		panic(0)
+	}
+}
+
+func _(x, y int) (z int) {
+L:	switch x {
+	case 0: return
+	default:
+		switch y {
+		case 0: break L
+		}
+		panic(0)
+	}
+} /* ERROR "missing return" */
+
+// select statements
+func _(ch chan int) (z int) {
+	select {}
+} // nice!
+
+func _(ch chan int) (z int) {
+	select {
+	default: break
+	}
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+	select {
+	case <-ch: return
+	default: break
+	}
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+	select {
+	case <-ch: return
+	default:
+		for i := 0; i < 10; i++ {
+			break
+		}
+		return
+	}
+}
+
+func _(ch chan int) (z int) {
+L:	select {
+	case <-ch: return
+	default:
+		for i := 0; i < 10; i++ {
+			break L
+		}
+		return
+	}
+} /* ERROR "missing return" */
diff --git a/src/go/types/testdata/vardecl.src b/src/go/types/testdata/vardecl.src
new file mode 100644
index 0000000..fb6b5f7
--- /dev/null
+++ b/src/go/types/testdata/vardecl.src
@@ -0,0 +1,186 @@
+// Copyright 2013 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 vardecl
+
+// Prerequisites.
+import "math"
+func f() {}
+func g() (x, y int) { return }
+var m map[string]int
+
+// Var decls must have a type or an initializer.
+var _ int
+var _, _ int
+
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _, _
+
+// The initializer must be an expression.
+var _ = int /* ERROR "not an expression" */
+var _ = f /* ERROR "used as value" */ ()
+
+// Identifier and expression arity must match.
+var _, _ = 1, 2
+var _ = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+var _ = g /* ERROR "2-valued expr" */ ()
+var _, _ = g()
+var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+var _ = m["foo"]
+var _, _ = m["foo"]
+var _, _, _ = m  /* ERROR "assignment count mismatch" */ ["foo"]
+
+var _, _ int = 1, 2
+var _ int = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ int = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+
+var (
+	_, _ = 1, 2
+	_ = 1, 2 /* ERROR "extra init expr 2" */
+	_, _ = 1 /* ERROR "assignment count mismatch" */
+	_, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+	_ = g /* ERROR "2-valued expr" */ ()
+	_, _ = g()
+	_, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+	_ = m["foo"]
+	_, _ = m["foo"]
+	_, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+	_, _ int = 1, 2
+	_ int = 1, 2 /* ERROR "extra init expr 2" */
+	_, _ int = 1 /* ERROR "assignment count mismatch" */
+	_, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+)
+
+// Variables declared in function bodies must be 'used'.
+type T struct{}
+func (r T) _(a, b, c int) (u, v, w int) {
+	var x1 /* ERROR "declared but not used" */ int
+	var x2 /* ERROR "declared but not used" */ int
+	x1 = 1
+	(x2) = 2
+
+	y1 /* ERROR "declared but not used" */ := 1
+	y2 /* ERROR "declared but not used" */ := 2
+	y1 = 1
+	(y1) = 2
+
+	{
+		var x1 /* ERROR "declared but not used" */ int
+		var x2 /* ERROR "declared but not used" */ int
+		x1 = 1
+		(x2) = 2
+
+		y1 /* ERROR "declared but not used" */ := 1
+		y2 /* ERROR "declared but not used" */ := 2
+		y1 = 1
+		(y1) = 2
+	}
+
+	if x /* ERROR "declared but not used" */ := 0; a < b {}
+
+	switch x /* ERROR "declared but not used" */, y := 0, 1; a {
+	case 0:
+		_ = y
+	case 1:
+		x /* ERROR "declared but not used" */ := 0
+	}
+
+	var t interface{}
+	switch t /* ERROR "declared but not used" */ := t.(type) {}
+
+	switch t /* ERROR "declared but not used" */ := t.(type) {
+	case int:
+	}
+
+	switch t /* ERROR "declared but not used" */ := t.(type) {
+	case int:
+	case float32, complex64:
+		t = nil
+	}
+
+	switch t := t.(type) {
+	case int:
+	case float32, complex64:
+		_ = t
+	}
+
+	switch t := t.(type) {
+	case int:
+	case float32:
+	case string:
+		_ = func() string {
+			return t
+		}
+	}
+
+	switch t := t; t /* ERROR "declared but not used" */ := t.(type) {}
+
+	var z1 /* ERROR "declared but not used" */ int
+	var z2 int
+	_ = func(a, b, c int) (u, v, w int) {
+		z1 = a
+		(z1) = b
+		a = z2
+		return
+	}
+
+	var s []int
+	var i /* ERROR "declared but not used" */ , j int
+	for i, j = range s {
+		_ = j
+	}
+
+	for i, j /* ERROR "declared but not used" */ := range s {
+		_ = func() int {
+			return i
+		}
+	}
+	return
+}
+
+// Invalid (unused) expressions must not lead to spurious "declared but not used errors"
+func _() {
+	var a, b, c int
+	var x, y int
+	x, y = a /* ERROR assignment count mismatch */ , b, c
+	_ = x
+	_ = y
+}
+
+func _() {
+	var x int
+	return x /* ERROR no result values expected */
+	return math /* ERROR no result values expected */ .Sin(0)
+}
+
+func _() int {
+	var x, y int
+	return /* ERROR wrong number of return values */ x, y
+}
+
+// Short variable declarations must declare at least one new non-blank variable.
+func _() {
+	_ := /* ERROR no new variables */ 0
+	_, a := 0, 1
+	_, a := /* ERROR no new variables */ 0, 1
+	_, a, b := 0, 1, 2
+	_, _, _ := /* ERROR no new variables */ 0, 1, 2
+
+	_ = a
+	_ = b
+}
+
+// TODO(gri) consolidate other var decl checks in this file
\ No newline at end of file
diff --git a/src/go/types/token_test.go b/src/go/types/token_test.go
new file mode 100644
index 0000000..705bb29
--- /dev/null
+++ b/src/go/types/token_test.go
@@ -0,0 +1,47 @@
+// Copyright 2013 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.
+
+// This file checks invariants of token.Token ordering that we rely on
+// since package go/token doesn't provide any guarantees at the moment.
+
+package types
+
+import (
+	"go/token"
+	"testing"
+)
+
+var assignOps = map[token.Token]token.Token{
+	token.ADD_ASSIGN:     token.ADD,
+	token.SUB_ASSIGN:     token.SUB,
+	token.MUL_ASSIGN:     token.MUL,
+	token.QUO_ASSIGN:     token.QUO,
+	token.REM_ASSIGN:     token.REM,
+	token.AND_ASSIGN:     token.AND,
+	token.OR_ASSIGN:      token.OR,
+	token.XOR_ASSIGN:     token.XOR,
+	token.SHL_ASSIGN:     token.SHL,
+	token.SHR_ASSIGN:     token.SHR,
+	token.AND_NOT_ASSIGN: token.AND_NOT,
+}
+
+func TestZeroTok(t *testing.T) {
+	// zero value for token.Token must be token.ILLEGAL
+	var zero token.Token
+	if token.ILLEGAL != zero {
+		t.Errorf("%s == %d; want 0", token.ILLEGAL, zero)
+	}
+}
+
+func TestAssignOp(t *testing.T) {
+	// there are fewer than 256 tokens
+	for i := 0; i < 256; i++ {
+		tok := token.Token(i)
+		got := assignOp(tok)
+		want := assignOps[tok]
+		if got != want {
+			t.Errorf("for assignOp(%s): got %s; want %s", tok, got, want)
+		}
+	}
+}
diff --git a/src/go/types/type.go b/src/go/types/type.go
new file mode 100644
index 0000000..4b4e5f6
--- /dev/null
+++ b/src/go/types/type.go
@@ -0,0 +1,452 @@
+// Copyright 2011 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 types
+
+import "sort"
+
+// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
+
+// A Type represents a type of Go.
+// All types implement the Type interface.
+type Type interface {
+	// Underlying returns the underlying type of a type.
+	Underlying() Type
+
+	// String returns a string representation of a type.
+	String() string
+}
+
+// BasicKind describes the kind of basic type.
+type BasicKind int
+
+const (
+	Invalid BasicKind = iota // type is invalid
+
+	// predeclared types
+	Bool
+	Int
+	Int8
+	Int16
+	Int32
+	Int64
+	Uint
+	Uint8
+	Uint16
+	Uint32
+	Uint64
+	Uintptr
+	Float32
+	Float64
+	Complex64
+	Complex128
+	String
+	UnsafePointer
+
+	// types for untyped values
+	UntypedBool
+	UntypedInt
+	UntypedRune
+	UntypedFloat
+	UntypedComplex
+	UntypedString
+	UntypedNil
+
+	// aliases
+	Byte = Uint8
+	Rune = Int32
+)
+
+// BasicInfo is a set of flags describing properties of a basic type.
+type BasicInfo int
+
+// Properties of basic types.
+const (
+	IsBoolean BasicInfo = 1 << iota
+	IsInteger
+	IsUnsigned
+	IsFloat
+	IsComplex
+	IsString
+	IsUntyped
+
+	IsOrdered   = IsInteger | IsFloat | IsString
+	IsNumeric   = IsInteger | IsFloat | IsComplex
+	IsConstType = IsBoolean | IsNumeric | IsString
+)
+
+// A Basic represents a basic type.
+type Basic struct {
+	kind BasicKind
+	info BasicInfo
+	name string
+}
+
+// Kind returns the kind of basic type b.
+func (b *Basic) Kind() BasicKind { return b.kind }
+
+// Info returns information about properties of basic type b.
+func (b *Basic) Info() BasicInfo { return b.info }
+
+// Name returns the name of basic type b.
+func (b *Basic) Name() string { return b.name }
+
+// An Array represents an array type.
+type Array struct {
+	len  int64
+	elem Type
+}
+
+// NewArray returns a new array type for the given element type and length.
+func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
+
+// Len returns the length of array a.
+func (a *Array) Len() int64 { return a.len }
+
+// Elem returns element type of array a.
+func (a *Array) Elem() Type { return a.elem }
+
+// A Slice represents a slice type.
+type Slice struct {
+	elem Type
+}
+
+// NewSlice returns a new slice type for the given element type.
+func NewSlice(elem Type) *Slice { return &Slice{elem} }
+
+// Elem returns the element type of slice s.
+func (s *Slice) Elem() Type { return s.elem }
+
+// A Struct represents a struct type.
+type Struct struct {
+	fields []*Var
+	tags   []string // field tags; nil if there are no tags
+	// TODO(gri) access to offsets is not threadsafe - fix this
+	offsets []int64 // field offsets in bytes, lazily initialized
+}
+
+// NewStruct returns a new struct with the given fields and corresponding field tags.
+// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
+// only as long as required to hold the tag with the largest index i. Consequently,
+// if no field has a tag, tags may be nil.
+func NewStruct(fields []*Var, tags []string) *Struct {
+	var fset objset
+	for _, f := range fields {
+		if f.name != "_" && fset.insert(f) != nil {
+			panic("multiple fields with the same name")
+		}
+	}
+	if len(tags) > len(fields) {
+		panic("more tags than fields")
+	}
+	return &Struct{fields: fields, tags: tags}
+}
+
+// NumFields returns the number of fields in the struct (including blank and anonymous fields).
+func (s *Struct) NumFields() int { return len(s.fields) }
+
+// Field returns the i'th field for 0 <= i < NumFields().
+func (s *Struct) Field(i int) *Var { return s.fields[i] }
+
+// Tag returns the i'th field tag for 0 <= i < NumFields().
+func (s *Struct) Tag(i int) string {
+	if i < len(s.tags) {
+		return s.tags[i]
+	}
+	return ""
+}
+
+// A Pointer represents a pointer type.
+type Pointer struct {
+	base Type // element type
+}
+
+// NewPointer returns a new pointer type for the given element (base) type.
+func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
+
+// Elem returns the element type for the given pointer p.
+func (p *Pointer) Elem() Type { return p.base }
+
+// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple.
+// Tuples are used as components of signatures and to represent the type of multiple
+// assignments; they are not first class types of Go.
+type Tuple struct {
+	vars []*Var
+}
+
+// NewTuple returns a new tuple for the given variables.
+func NewTuple(x ...*Var) *Tuple {
+	if len(x) > 0 {
+		return &Tuple{x}
+	}
+	return nil
+}
+
+// Len returns the number variables of tuple t.
+func (t *Tuple) Len() int {
+	if t != nil {
+		return len(t.vars)
+	}
+	return 0
+}
+
+// At returns the i'th variable of tuple t.
+func (t *Tuple) At(i int) *Var { return t.vars[i] }
+
+// A Signature represents a (non-builtin) function or method type.
+type Signature struct {
+	scope    *Scope // function scope, always present
+	recv     *Var   // nil if not a method
+	params   *Tuple // (incoming) parameters from left to right; or nil
+	results  *Tuple // (outgoing) results from left to right; or nil
+	variadic bool   // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+}
+
+// NewSignature returns a new function type for the given receiver, parameters,
+// and results, either of which may be nil. If variadic is set, the function
+// is variadic, it must have at least one parameter, and the last parameter
+// must be of unnamed slice type.
+func NewSignature(scope *Scope, recv *Var, params, results *Tuple, variadic bool) *Signature {
+	// TODO(gri) Should we rely on the correct (non-nil) incoming scope
+	//           or should this function allocate and populate a scope?
+	if variadic {
+		n := params.Len()
+		if n == 0 {
+			panic("types.NewSignature: variadic function must have at least one parameter")
+		}
+		if _, ok := params.At(n - 1).typ.(*Slice); !ok {
+			panic("types.NewSignature: variadic parameter must be of unnamed slice type")
+		}
+	}
+	return &Signature{scope, recv, params, results, variadic}
+}
+
+// Recv returns the receiver of signature s (if a method), or nil if a
+// function.
+//
+// For an abstract method, Recv returns the enclosing interface either
+// as a *Named or an *Interface.  Due to embedding, an interface may
+// contain methods whose receiver type is a different interface.
+func (s *Signature) Recv() *Var { return s.recv }
+
+// Params returns the parameters of signature s, or nil.
+func (s *Signature) Params() *Tuple { return s.params }
+
+// Results returns the results of signature s, or nil.
+func (s *Signature) Results() *Tuple { return s.results }
+
+// Variadic reports whether the signature s is variadic.
+func (s *Signature) Variadic() bool { return s.variadic }
+
+// An Interface represents an interface type.
+type Interface struct {
+	methods   []*Func  // ordered list of explicitly declared methods
+	embeddeds []*Named // ordered list of explicitly embedded types
+
+	allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
+}
+
+// NewInterface returns a new interface for the given methods and embedded types.
+func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
+	typ := new(Interface)
+
+	var mset objset
+	for _, m := range methods {
+		if mset.insert(m) != nil {
+			panic("multiple methods with the same name")
+		}
+		// set receiver
+		// TODO(gri) Ideally, we should use a named type here instead of
+		// typ, for less verbose printing of interface method signatures.
+		m.typ.(*Signature).recv = NewVar(m.pos, m.pkg, "", typ)
+	}
+	sort.Sort(byUniqueMethodName(methods))
+
+	if embeddeds == nil {
+		sort.Sort(byUniqueTypeName(embeddeds))
+	}
+
+	typ.methods = methods
+	typ.embeddeds = embeddeds
+	return typ
+}
+
+// NumExplicitMethods returns the number of explicitly declared methods of interface t.
+func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
+
+// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
+
+// NumEmbeddeds returns the number of embedded types in interface t.
+func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
+
+// Embedded returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
+// The types are ordered by the corresponding TypeName's unique Id.
+func (t *Interface) Embedded(i int) *Named { return t.embeddeds[i] }
+
+// NumMethods returns the total number of methods of interface t.
+func (t *Interface) NumMethods() int { return len(t.allMethods) }
+
+// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
+
+// Empty returns true if t is the empty interface.
+func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
+
+// Complete computes the interface's method set. It must be called by users of
+// NewInterface after the interface's embedded types are fully defined and
+// before using the interface type in any way other than to form other types.
+// Complete returns the receiver.
+func (t *Interface) Complete() *Interface {
+	if t.allMethods != nil {
+		return t
+	}
+
+	var allMethods []*Func
+	if t.embeddeds == nil {
+		if t.methods == nil {
+			allMethods = make([]*Func, 0, 1)
+		} else {
+			allMethods = t.methods
+		}
+	} else {
+		allMethods = append(allMethods, t.methods...)
+		for _, et := range t.embeddeds {
+			it := et.Underlying().(*Interface)
+			it.Complete()
+			for _, tm := range it.allMethods {
+				// Make a copy of the method and adjust its receiver type.
+				newm := *tm
+				newmtyp := *tm.typ.(*Signature)
+				newm.typ = &newmtyp
+				newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t)
+				allMethods = append(allMethods, &newm)
+			}
+		}
+		sort.Sort(byUniqueMethodName(allMethods))
+	}
+	t.allMethods = allMethods
+
+	return t
+}
+
+// A Map represents a map type.
+type Map struct {
+	key, elem Type
+}
+
+// NewMap returns a new map for the given key and element types.
+func NewMap(key, elem Type) *Map {
+	return &Map{key, elem}
+}
+
+// Key returns the key type of map m.
+func (m *Map) Key() Type { return m.key }
+
+// Elem returns the element type of map m.
+func (m *Map) Elem() Type { return m.elem }
+
+// A Chan represents a channel type.
+type Chan struct {
+	dir  ChanDir
+	elem Type
+}
+
+// A ChanDir value indicates a channel direction.
+type ChanDir int
+
+// The direction of a channel is indicated by one of the following constants.
+const (
+	SendRecv ChanDir = iota
+	SendOnly
+	RecvOnly
+)
+
+// NewChan returns a new channel type for the given direction and element type.
+func NewChan(dir ChanDir, elem Type) *Chan {
+	return &Chan{dir, elem}
+}
+
+// Dir returns the direction of channel c.
+func (c *Chan) Dir() ChanDir { return c.dir }
+
+// Elem returns the element type of channel c.
+func (c *Chan) Elem() Type { return c.elem }
+
+// A Named represents a named type.
+type Named struct {
+	obj        *TypeName // corresponding declared object
+	underlying Type      // possibly a *Named during setup; never a *Named once set up completely
+	methods    []*Func   // methods declared for this type (not the method set of this type)
+}
+
+// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
+// The underlying type must not be a *Named.
+func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+	if _, ok := underlying.(*Named); ok {
+		panic("types.NewNamed: underlying type must not be *Named")
+	}
+	typ := &Named{obj: obj, underlying: underlying, methods: methods}
+	if obj.typ == nil {
+		obj.typ = typ
+	}
+	return typ
+}
+
+// TypeName returns the type name for the named type t.
+func (t *Named) Obj() *TypeName { return t.obj }
+
+// NumMethods returns the number of explicit methods whose receiver is named type t.
+func (t *Named) NumMethods() int { return len(t.methods) }
+
+// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
+func (t *Named) Method(i int) *Func { return t.methods[i] }
+
+// SetUnderlying sets the underlying type and marks t as complete.
+// TODO(gri) determine if there's a better solution rather than providing this function
+func (t *Named) SetUnderlying(underlying Type) {
+	if underlying == nil {
+		panic("types.Named.SetUnderlying: underlying type must not be nil")
+	}
+	if _, ok := underlying.(*Named); ok {
+		panic("types.Named.SetUnderlying: underlying type must not be *Named")
+	}
+	t.underlying = underlying
+}
+
+// AddMethod adds method m unless it is already in the method list.
+// TODO(gri) find a better solution instead of providing this function
+func (t *Named) AddMethod(m *Func) {
+	if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
+		t.methods = append(t.methods, m)
+	}
+}
+
+// Implementations for Type methods.
+
+func (t *Basic) Underlying() Type     { return t }
+func (t *Array) Underlying() Type     { return t }
+func (t *Slice) Underlying() Type     { return t }
+func (t *Struct) Underlying() Type    { return t }
+func (t *Pointer) Underlying() Type   { return t }
+func (t *Tuple) Underlying() Type     { return t }
+func (t *Signature) Underlying() Type { return t }
+func (t *Interface) Underlying() Type { return t }
+func (t *Map) Underlying() Type       { return t }
+func (t *Chan) Underlying() Type      { return t }
+func (t *Named) Underlying() Type     { return t.underlying }
+
+func (t *Basic) String() string     { return TypeString(nil, t) }
+func (t *Array) String() string     { return TypeString(nil, t) }
+func (t *Slice) String() string     { return TypeString(nil, t) }
+func (t *Struct) String() string    { return TypeString(nil, t) }
+func (t *Pointer) String() string   { return TypeString(nil, t) }
+func (t *Tuple) String() string     { return TypeString(nil, t) }
+func (t *Signature) String() string { return TypeString(nil, t) }
+func (t *Interface) String() string { return TypeString(nil, t) }
+func (t *Map) String() string       { return TypeString(nil, t) }
+func (t *Chan) String() string      { return TypeString(nil, t) }
+func (t *Named) String() string     { return TypeString(nil, t) }
diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go
new file mode 100644
index 0000000..9a537e8
--- /dev/null
+++ b/src/go/types/typestring.go
@@ -0,0 +1,266 @@
+// Copyright 2013 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.
+
+// This file implements printing of types.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// If GcCompatibilityMode is set, printing of types is modified
+// to match the representation of some types in the gc compiler:
+//
+//	- byte and rune lose their alias name and simply stand for
+//	  uint8 and int32 respectively
+//	- embedded interfaces get flattened (the embedding info is lost,
+//	  and certain recursive interface types cannot be printed anymore)
+//
+// This makes it easier to compare packages computed with the type-
+// checker vs packages imported from gc export data.
+//
+// Caution: This flag affects all uses of WriteType, globally.
+// It is only provided for testing in conjunction with
+// gc-generated data. It may be removed at any time.
+var GcCompatibilityMode bool
+
+// TypeString returns the string representation of typ.
+// Named types are printed package-qualified if they
+// do not belong to this package.
+func TypeString(this *Package, typ Type) string {
+	var buf bytes.Buffer
+	WriteType(&buf, this, typ)
+	return buf.String()
+}
+
+// WriteType writes the string representation of typ to buf.
+// Named types are printed package-qualified if they
+// do not belong to this package.
+func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
+	writeType(buf, this, typ, make([]Type, 8))
+}
+
+func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
+	// Theoretically, this is a quadratic lookup algorithm, but in
+	// practice deeply nested composite types with unnamed component
+	// types are uncommon. This code is likely more efficient than
+	// using a map.
+	for _, t := range visited {
+		if t == typ {
+			fmt.Fprintf(buf, "○%T", typ) // cycle to typ
+			return
+		}
+	}
+	visited = append(visited, typ)
+
+	switch t := typ.(type) {
+	case nil:
+		buf.WriteString("<nil>")
+
+	case *Basic:
+		if t.kind == UnsafePointer {
+			buf.WriteString("unsafe.")
+		}
+		if GcCompatibilityMode {
+			// forget the alias names
+			switch t.kind {
+			case Byte:
+				t = Typ[Uint8]
+			case Rune:
+				t = Typ[Int32]
+			}
+		}
+		buf.WriteString(t.name)
+
+	case *Array:
+		fmt.Fprintf(buf, "[%d]", t.len)
+		writeType(buf, this, t.elem, visited)
+
+	case *Slice:
+		buf.WriteString("[]")
+		writeType(buf, this, t.elem, visited)
+
+	case *Struct:
+		buf.WriteString("struct{")
+		for i, f := range t.fields {
+			if i > 0 {
+				buf.WriteString("; ")
+			}
+			if !f.anonymous {
+				buf.WriteString(f.name)
+				buf.WriteByte(' ')
+			}
+			writeType(buf, this, f.typ, visited)
+			if tag := t.Tag(i); tag != "" {
+				fmt.Fprintf(buf, " %q", tag)
+			}
+		}
+		buf.WriteByte('}')
+
+	case *Pointer:
+		buf.WriteByte('*')
+		writeType(buf, this, t.base, visited)
+
+	case *Tuple:
+		writeTuple(buf, this, t, false, visited)
+
+	case *Signature:
+		buf.WriteString("func")
+		writeSignature(buf, this, t, visited)
+
+	case *Interface:
+		// We write the source-level methods and embedded types rather
+		// than the actual method set since resolved method signatures
+		// may have non-printable cycles if parameters have anonymous
+		// interface types that (directly or indirectly) embed the
+		// current interface. For instance, consider the result type
+		// of m:
+		//
+		//     type T interface{
+		//         m() interface{ T }
+		//     }
+		//
+		buf.WriteString("interface{")
+		if GcCompatibilityMode {
+			// print flattened interface
+			// (useful to compare against gc-generated interfaces)
+			for i, m := range t.allMethods {
+				if i > 0 {
+					buf.WriteString("; ")
+				}
+				buf.WriteString(m.name)
+				writeSignature(buf, this, m.typ.(*Signature), visited)
+			}
+		} else {
+			// print explicit interface methods and embedded types
+			for i, m := range t.methods {
+				if i > 0 {
+					buf.WriteString("; ")
+				}
+				buf.WriteString(m.name)
+				writeSignature(buf, this, m.typ.(*Signature), visited)
+			}
+			for i, typ := range t.embeddeds {
+				if i > 0 || len(t.methods) > 0 {
+					buf.WriteString("; ")
+				}
+				writeType(buf, this, typ, visited)
+			}
+		}
+		buf.WriteByte('}')
+
+	case *Map:
+		buf.WriteString("map[")
+		writeType(buf, this, t.key, visited)
+		buf.WriteByte(']')
+		writeType(buf, this, t.elem, visited)
+
+	case *Chan:
+		var s string
+		var parens bool
+		switch t.dir {
+		case SendRecv:
+			s = "chan "
+			// chan (<-chan T) requires parentheses
+			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
+				parens = true
+			}
+		case SendOnly:
+			s = "chan<- "
+		case RecvOnly:
+			s = "<-chan "
+		default:
+			panic("unreachable")
+		}
+		buf.WriteString(s)
+		if parens {
+			buf.WriteByte('(')
+		}
+		writeType(buf, this, t.elem, visited)
+		if parens {
+			buf.WriteByte(')')
+		}
+
+	case *Named:
+		s := "<Named w/o object>"
+		if obj := t.obj; obj != nil {
+			if pkg := obj.pkg; pkg != nil && pkg != this {
+				buf.WriteString(pkg.path)
+				buf.WriteByte('.')
+			}
+			// TODO(gri): function-local named types should be displayed
+			// differently from named types at package level to avoid
+			// ambiguity.
+			s = obj.name
+		}
+		buf.WriteString(s)
+
+	default:
+		// For externally defined implementations of Type.
+		buf.WriteString(t.String())
+	}
+}
+
+func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, visited []Type) {
+	buf.WriteByte('(')
+	if tup != nil {
+		for i, v := range tup.vars {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			if v.name != "" {
+				buf.WriteString(v.name)
+				buf.WriteByte(' ')
+			}
+			typ := v.typ
+			if variadic && i == len(tup.vars)-1 {
+				if s, ok := typ.(*Slice); ok {
+					buf.WriteString("...")
+					typ = s.elem
+				} else {
+					// special case:
+					// append(s, "foo"...) leads to signature func([]byte, string...)
+					if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
+						panic("internal error: string type expected")
+					}
+					writeType(buf, this, typ, visited)
+					buf.WriteString("...")
+					continue
+				}
+			}
+			writeType(buf, this, typ, visited)
+		}
+	}
+	buf.WriteByte(')')
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// Named types are printed package-qualified if they
+// do not belong to this package.
+func WriteSignature(buf *bytes.Buffer, this *Package, sig *Signature) {
+	writeSignature(buf, this, sig, make([]Type, 8))
+}
+
+func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []Type) {
+	writeTuple(buf, this, sig.params, sig.variadic, visited)
+
+	n := sig.results.Len()
+	if n == 0 {
+		// no result
+		return
+	}
+
+	buf.WriteByte(' ')
+	if n == 1 && sig.results.vars[0].name == "" {
+		// single unnamed result
+		writeType(buf, this, sig.results.vars[0].typ, visited)
+		return
+	}
+
+	// multiple or named result(s)
+	writeTuple(buf, this, sig.results, false, visited)
+}
diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go
new file mode 100644
index 0000000..ecc4ba8
--- /dev/null
+++ b/src/go/types/typestring_test.go
@@ -0,0 +1,161 @@
+// Copyright 2012 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 types_test
+
+import (
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"testing"
+
+	. "go/types"
+)
+
+const filename = "<src>"
+
+func makePkg(t *testing.T, src string) (*Package, error) {
+	fset := token.NewFileSet()
+	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
+	if err != nil {
+		return nil, err
+	}
+	// use the package name as package path
+	conf := Config{Importer: importer.Default()}
+	return conf.Check(file.Name.Name, fset, []*ast.File{file}, nil)
+}
+
+type testEntry struct {
+	src, str string
+}
+
+// dup returns a testEntry where both src and str are the same.
+func dup(s string) testEntry {
+	return testEntry{s, s}
+}
+
+// types that don't depend on any other type declarations
+var independentTestTypes = []testEntry{
+	// basic types
+	dup("int"),
+	dup("float32"),
+	dup("string"),
+
+	// arrays
+	dup("[10]int"),
+
+	// slices
+	dup("[]int"),
+	dup("[][]int"),
+
+	// structs
+	dup("struct{}"),
+	dup("struct{x int}"),
+	{`struct {
+		x, y int
+		z float32 "foo"
+	}`, `struct{x int; y int; z float32 "foo"}`},
+	{`struct {
+		string
+		elems []complex128
+	}`, `struct{string; elems []complex128}`},
+
+	// pointers
+	dup("*int"),
+	dup("***struct{}"),
+	dup("*struct{a int; b float32}"),
+
+	// functions
+	dup("func()"),
+	dup("func(x int)"),
+	{"func(x, y int)", "func(x int, y int)"},
+	{"func(x, y int, z string)", "func(x int, y int, z string)"},
+	dup("func(int)"),
+	{"func(int, string, byte)", "func(int, string, byte)"},
+
+	dup("func() int"),
+	{"func() (string)", "func() string"},
+	dup("func() (u int)"),
+	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},
+
+	dup("func(int) string"),
+	dup("func(x int) string"),
+	dup("func(x int) (u string)"),
+	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},
+
+	dup("func(...int) string"),
+	dup("func(x ...int) string"),
+	dup("func(x ...int) (u string)"),
+	{"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},
+
+	// interfaces
+	dup("interface{}"),
+	dup("interface{m()}"),
+	dup(`interface{String() string; m(int) float32}`),
+
+	// maps
+	dup("map[string]int"),
+	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
+
+	// channels
+	dup("chan<- chan int"),
+	dup("chan<- <-chan int"),
+	dup("<-chan <-chan int"),
+	dup("chan (<-chan int)"),
+	dup("chan<- func()"),
+	dup("<-chan []func() int"),
+}
+
+// types that depend on other type declarations (src in TestTypes)
+var dependentTestTypes = []testEntry{
+	// interfaces
+	dup(`interface{io.Reader; io.Writer}`),
+	dup(`interface{m() int; io.Writer}`),
+	{`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
+}
+
+func TestTypeString(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	var tests []testEntry
+	tests = append(tests, independentTestTypes...)
+	tests = append(tests, dependentTestTypes...)
+
+	for _, test := range tests {
+		src := `package p; import "io"; type _ io.Writer; type T ` + test.src
+		pkg, err := makePkg(t, src)
+		if err != nil {
+			t.Errorf("%s: %s", src, err)
+			continue
+		}
+		typ := pkg.Scope().Lookup("T").Type().Underlying()
+		if got := typ.String(); got != test.str {
+			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+		}
+	}
+}
+
+func TestQualifiedTypeString(t *testing.T) {
+	p, _ := pkgFor("p.go", "package p; type T int", nil)
+	q, _ := pkgFor("q.go", "package q", nil)
+
+	pT := p.Scope().Lookup("T").Type()
+	for _, test := range []struct {
+		typ  Type
+		this *Package
+		want string
+	}{
+		{pT, nil, "p.T"},
+		{pT, p, "T"},
+		{pT, q, "p.T"},
+		{NewPointer(pT), p, "*T"},
+		{NewPointer(pT), q, "*p.T"},
+	} {
+		if got := TypeString(test.this, test.typ); got != test.want {
+			t.Errorf("TypeString(%s, %s) = %s, want %s",
+				test.this, test.typ, got, test.want)
+		}
+	}
+}
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
new file mode 100644
index 0000000..afd1dab
--- /dev/null
+++ b/src/go/types/typexpr.go
@@ -0,0 +1,720 @@
+// Copyright 2013 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.
+
+// This file implements type-checking of identifiers and type expressions.
+
+package types
+
+import (
+	"go/ast"
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+	"sort"
+	"strconv"
+)
+
+// ident type-checks identifier e and initializes x with the value or type of e.
+// If an error occurred, x.mode is set to invalid.
+// For the meaning of def and path, see check.typ, below.
+//
+func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) {
+	x.mode = invalid
+	x.expr = e
+
+	scope, obj := check.scope.LookupParent(e.Name)
+	if obj == nil {
+		if e.Name == "_" {
+			check.errorf(e.Pos(), "cannot use _ as value or type")
+		} else {
+			check.errorf(e.Pos(), "undeclared name: %s", e.Name)
+		}
+		return
+	}
+	check.recordUse(e, obj)
+
+	check.objDecl(obj, def, path)
+	typ := obj.Type()
+	assert(typ != nil)
+
+	// The object may be dot-imported: If so, remove its package from
+	// the map of unused dot imports for the respective file scope.
+	// (This code is only needed for dot-imports. Without them,
+	// we only have to mark variables, see *Var case below).
+	if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
+		delete(check.unusedDotImports[scope], pkg)
+	}
+
+	switch obj := obj.(type) {
+	case *PkgName:
+		check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
+		return
+
+	case *Const:
+		check.addDeclDep(obj)
+		if typ == Typ[Invalid] {
+			return
+		}
+		if obj == universeIota {
+			if check.iota == nil {
+				check.errorf(e.Pos(), "cannot use iota outside constant declaration")
+				return
+			}
+			x.val = check.iota
+		} else {
+			x.val = obj.val
+		}
+		assert(x.val != nil)
+		x.mode = constant
+
+	case *TypeName:
+		x.mode = typexpr
+		// check for cycle
+		// (it's ok to iterate forward because each named type appears at most once in path)
+		for i, prev := range path {
+			if prev == obj {
+				check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
+				// print cycle
+				for _, obj := range path[i:] {
+					check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+				}
+				check.errorf(obj.Pos(), "\t%s", obj.Name())
+				// maintain x.mode == typexpr despite error
+				typ = Typ[Invalid]
+				break
+			}
+		}
+
+	case *Var:
+		if obj.pkg == check.pkg {
+			obj.used = true
+		}
+		check.addDeclDep(obj)
+		if typ == Typ[Invalid] {
+			return
+		}
+		x.mode = variable
+
+	case *Func:
+		check.addDeclDep(obj)
+		x.mode = value
+
+	case *Builtin:
+		x.id = obj.id
+		x.mode = builtin
+
+	case *Nil:
+		x.mode = value
+
+	default:
+		unreachable()
+	}
+
+	x.typ = typ
+}
+
+// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
+// If def != nil, e is the type specification for the named type def, declared
+// in a type declaration, and def.underlying will be set to the type of e before
+// any components of e are type-checked. Path contains the path of named types
+// referring to this type.
+//
+func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
+	if trace {
+		check.trace(e.Pos(), "%s", e)
+		check.indent++
+		defer func() {
+			check.indent--
+			check.trace(e.Pos(), "=> %s", T)
+		}()
+	}
+
+	T = check.typExprInternal(e, def, path)
+	assert(isTyped(T))
+	check.recordTypeAndValue(e, typexpr, T, nil)
+
+	return
+}
+
+func (check *Checker) typ(e ast.Expr) Type {
+	return check.typExpr(e, nil, nil)
+}
+
+// funcType type-checks a function or method type and returns its signature.
+func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) *Signature {
+	scope := NewScope(check.scope, "function")
+	check.recordScope(ftyp, scope)
+
+	recvList, _ := check.collectParams(scope, recvPar, false)
+	params, variadic := check.collectParams(scope, ftyp.Params, true)
+	results, _ := check.collectParams(scope, ftyp.Results, false)
+
+	if recvPar != nil {
+		// recv parameter list present (may be empty)
+		// spec: "The receiver is specified via an extra parameter section preceeding the
+		// method name. That parameter section must declare a single parameter, the receiver."
+		var recv *Var
+		switch len(recvList) {
+		case 0:
+			check.error(recvPar.Pos(), "method is missing receiver")
+			recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
+		default:
+			// more than one receiver
+			check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+			fallthrough // continue with first receiver
+		case 1:
+			recv = recvList[0]
+		}
+		// spec: "The receiver type must be of the form T or *T where T is a type name."
+		// (ignore invalid types - error was reported before)
+		if t, _ := deref(recv.typ); t != Typ[Invalid] {
+			var err string
+			if T, _ := t.(*Named); T != nil {
+				// spec: "The type denoted by T is called the receiver base type; it must not
+				// be a pointer or interface type and it must be declared in the same package
+				// as the method."
+				if T.obj.pkg != check.pkg {
+					err = "type not defined in this package"
+				} else {
+					// TODO(gri) This is not correct if the underlying type is unknown yet.
+					switch u := T.underlying.(type) {
+					case *Basic:
+						// unsafe.Pointer is treated like a regular pointer
+						if u.kind == UnsafePointer {
+							err = "unsafe.Pointer"
+						}
+					case *Pointer, *Interface:
+						err = "pointer or interface type"
+					}
+				}
+			} else {
+				err = "basic or unnamed type"
+			}
+			if err != "" {
+				check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
+				// ok to continue
+			}
+		}
+		sig.recv = recv
+	}
+
+	sig.scope = scope
+	sig.params = NewTuple(params...)
+	sig.results = NewTuple(results...)
+	sig.variadic = variadic
+
+	return sig
+}
+
+// typExprInternal drives type checking of types.
+// Must only be called by typExpr.
+//
+func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type {
+	switch e := e.(type) {
+	case *ast.BadExpr:
+		// ignore - error reported before
+
+	case *ast.Ident:
+		var x operand
+		check.ident(&x, e, def, path)
+
+		switch x.mode {
+		case typexpr:
+			typ := x.typ
+			def.setUnderlying(typ)
+			return typ
+		case invalid:
+			// ignore - error reported before
+		case novalue:
+			check.errorf(x.pos(), "%s used as type", &x)
+		default:
+			check.errorf(x.pos(), "%s is not a type", &x)
+		}
+
+	case *ast.SelectorExpr:
+		var x operand
+		check.selector(&x, e)
+
+		switch x.mode {
+		case typexpr:
+			typ := x.typ
+			def.setUnderlying(typ)
+			return typ
+		case invalid:
+			// ignore - error reported before
+		case novalue:
+			check.errorf(x.pos(), "%s used as type", &x)
+		default:
+			check.errorf(x.pos(), "%s is not a type", &x)
+		}
+
+	case *ast.ParenExpr:
+		return check.typExpr(e.X, def, path)
+
+	case *ast.ArrayType:
+		if e.Len != nil {
+			typ := new(Array)
+			def.setUnderlying(typ)
+			typ.len = check.arrayLength(e.Len)
+			typ.elem = check.typExpr(e.Elt, nil, path)
+			return typ
+
+		} else {
+			typ := new(Slice)
+			def.setUnderlying(typ)
+			typ.elem = check.typ(e.Elt)
+			return typ
+		}
+
+	case *ast.StructType:
+		typ := new(Struct)
+		def.setUnderlying(typ)
+		check.structType(typ, e, path)
+		return typ
+
+	case *ast.StarExpr:
+		typ := new(Pointer)
+		def.setUnderlying(typ)
+		typ.base = check.typ(e.X)
+		return typ
+
+	case *ast.FuncType:
+		typ := new(Signature)
+		def.setUnderlying(typ)
+		check.funcType(typ, nil, e)
+		return typ
+
+	case *ast.InterfaceType:
+		typ := new(Interface)
+		def.setUnderlying(typ)
+		check.interfaceType(typ, e, def, path)
+		return typ
+
+	case *ast.MapType:
+		typ := new(Map)
+		def.setUnderlying(typ)
+
+		typ.key = check.typ(e.Key)
+		typ.elem = check.typ(e.Value)
+
+		// spec: "The comparison operators == and != must be fully defined
+		// for operands of the key type; thus the key type must not be a
+		// function, map, or slice."
+		//
+		// Delay this check because it requires fully setup types;
+		// it is safe to continue in any case (was issue 6667).
+		check.delay(func() {
+			if !Comparable(typ.key) {
+				check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
+			}
+		})
+
+		return typ
+
+	case *ast.ChanType:
+		typ := new(Chan)
+		def.setUnderlying(typ)
+
+		dir := SendRecv
+		switch e.Dir {
+		case ast.SEND | ast.RECV:
+			// nothing to do
+		case ast.SEND:
+			dir = SendOnly
+		case ast.RECV:
+			dir = RecvOnly
+		default:
+			check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
+			// ok to continue
+		}
+
+		typ.dir = dir
+		typ.elem = check.typ(e.Value)
+		return typ
+
+	default:
+		check.errorf(e.Pos(), "%s is not a type", e)
+	}
+
+	typ := Typ[Invalid]
+	def.setUnderlying(typ)
+	return typ
+}
+
+// typeOrNil type-checks the type expression (or nil value) e
+// and returns the typ of e, or nil.
+// If e is neither a type nor nil, typOrNil returns Typ[Invalid].
+//
+func (check *Checker) typOrNil(e ast.Expr) Type {
+	var x operand
+	check.rawExpr(&x, e, nil)
+	switch x.mode {
+	case invalid:
+		// ignore - error reported before
+	case novalue:
+		check.errorf(x.pos(), "%s used as type", &x)
+	case typexpr:
+		return x.typ
+	case value:
+		if x.isNil() {
+			return nil
+		}
+		fallthrough
+	default:
+		check.errorf(x.pos(), "%s is not a type", &x)
+	}
+	return Typ[Invalid]
+}
+
+func (check *Checker) arrayLength(e ast.Expr) int64 {
+	var x operand
+	check.expr(&x, e)
+	if x.mode != constant {
+		if x.mode != invalid {
+			check.errorf(x.pos(), "array length %s must be constant", &x)
+		}
+		return 0
+	}
+	if !x.isInteger() {
+		check.errorf(x.pos(), "array length %s must be integer", &x)
+		return 0
+	}
+	n, ok := exact.Int64Val(x.val)
+	if !ok || n < 0 {
+		check.errorf(x.pos(), "invalid array length %s", &x)
+		return 0
+	}
+	return n
+}
+
+func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
+	if list == nil {
+		return
+	}
+
+	var named, anonymous bool
+	for i, field := range list.List {
+		ftype := field.Type
+		if t, _ := ftype.(*ast.Ellipsis); t != nil {
+			ftype = t.Elt
+			if variadicOk && i == len(list.List)-1 {
+				variadic = true
+			} else {
+				check.invalidAST(field.Pos(), "... not permitted")
+				// ignore ... and continue
+			}
+		}
+		typ := check.typ(ftype)
+		// The parser ensures that f.Tag is nil and we don't
+		// care if a constructed AST contains a non-nil tag.
+		if len(field.Names) > 0 {
+			// named parameter
+			for _, name := range field.Names {
+				if name.Name == "" {
+					check.invalidAST(name.Pos(), "anonymous parameter")
+					// ok to continue
+				}
+				par := NewParam(name.Pos(), check.pkg, name.Name, typ)
+				check.declare(scope, name, par)
+				params = append(params, par)
+			}
+			named = true
+		} else {
+			// anonymous parameter
+			par := NewParam(ftype.Pos(), check.pkg, "", typ)
+			check.recordImplicit(field, par)
+			params = append(params, par)
+			anonymous = true
+		}
+	}
+
+	if named && anonymous {
+		check.invalidAST(list.Pos(), "list contains both named and anonymous parameters")
+		// ok to continue
+	}
+
+	// For a variadic function, change the last parameter's type from T to []T.
+	if variadic && len(params) > 0 {
+		last := params[len(params)-1]
+		last.typ = &Slice{elem: last.typ}
+	}
+
+	return
+}
+
+func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
+	if alt := oset.insert(obj); alt != nil {
+		check.errorf(pos, "%s redeclared", obj.Name())
+		check.reportAltDecl(alt)
+		return false
+	}
+	return true
+}
+
+func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, path []*TypeName) {
+	// empty interface: common case
+	if ityp.Methods == nil {
+		return
+	}
+
+	// The parser ensures that field tags are nil and we don't
+	// care if a constructed AST contains non-nil tags.
+
+	// use named receiver type if available (for better error messages)
+	var recvTyp Type = iface
+	if def != nil {
+		recvTyp = def
+	}
+
+	// Phase 1: Collect explicitly declared methods, the corresponding
+	//          signature (AST) expressions, and the list of embedded
+	//          type (AST) expressions. Do not resolve signatures or
+	//          embedded types yet to avoid cycles referring to this
+	//          interface.
+
+	var (
+		mset       objset
+		signatures []ast.Expr // list of corresponding method signatures
+		embedded   []ast.Expr // list of embedded types
+	)
+	for _, f := range ityp.Methods.List {
+		if len(f.Names) > 0 {
+			// The parser ensures that there's only one method
+			// and we don't care if a constructed AST has more.
+			name := f.Names[0]
+			pos := name.Pos()
+			// spec: "As with all method sets, in an interface type,
+			// each method must have a unique non-blank name."
+			if name.Name == "_" {
+				check.errorf(pos, "invalid method name _")
+				continue
+			}
+			// Don't type-check signature yet - use an
+			// empty signature now and update it later.
+			// Since we know the receiver, set it up now
+			// (required to avoid crash in ptrRecv; see
+			// e.g. test case for issue 6638).
+			// TODO(gri) Consider marking methods signatures
+			// as incomplete, for better error messages. See
+			// also the T4 and T5 tests in testdata/cycles2.src.
+			sig := new(Signature)
+			sig.recv = NewVar(pos, check.pkg, "", recvTyp)
+			m := NewFunc(pos, check.pkg, name.Name, sig)
+			if check.declareInSet(&mset, pos, m) {
+				iface.methods = append(iface.methods, m)
+				iface.allMethods = append(iface.allMethods, m)
+				signatures = append(signatures, f.Type)
+				check.recordDef(name, m)
+			}
+		} else {
+			// embedded type
+			embedded = append(embedded, f.Type)
+		}
+	}
+
+	// Phase 2: Resolve embedded interfaces. Because an interface must not
+	//          embed itself (directly or indirectly), each embedded interface
+	//          can be fully resolved without depending on any method of this
+	//          interface (if there is a cycle or another error, the embedded
+	//          type resolves to an invalid type and is ignored).
+	//          In particular, the list of methods for each embedded interface
+	//          must be complete (it cannot depend on this interface), and so
+	//          those methods can be added to the list of all methods of this
+	//          interface.
+
+	for _, e := range embedded {
+		pos := e.Pos()
+		typ := check.typExpr(e, nil, path)
+		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)
+		if embed == nil {
+			if u != Typ[Invalid] {
+				check.errorf(pos, "%s is not an interface", named)
+			}
+			continue
+		}
+		iface.embeddeds = append(iface.embeddeds, named)
+		// collect embedded methods
+		for _, m := range embed.allMethods {
+			if check.declareInSet(&mset, pos, m) {
+				iface.allMethods = append(iface.allMethods, m)
+			}
+		}
+	}
+
+	// Phase 3: At this point all methods have been collected for this interface.
+	//          It is now safe to type-check the signatures of all explicitly
+	//          declared methods, even if they refer to this interface via a cycle
+	//          and embed the methods of this interface in a parameter of interface
+	//          type.
+
+	for i, m := range iface.methods {
+		expr := signatures[i]
+		typ := check.typ(expr)
+		sig, _ := typ.(*Signature)
+		if sig == nil {
+			if typ != Typ[Invalid] {
+				check.invalidAST(expr.Pos(), "%s is not a method signature", typ)
+			}
+			continue // keep method with empty method signature
+		}
+		// update signature, but keep recv that was set up before
+		old := m.typ.(*Signature)
+		sig.recv = old.recv
+		*old = *sig // update signature (don't replace it!)
+	}
+
+	// TODO(gri) The list of explicit methods is only sorted for now to
+	// produce the same Interface as NewInterface. We may be able to
+	// claim source order in the future. Revisit.
+	sort.Sort(byUniqueMethodName(iface.methods))
+
+	// TODO(gri) The list of embedded types is only sorted for now to
+	// produce the same Interface as NewInterface. We may be able to
+	// claim source order in the future. Revisit.
+	sort.Sort(byUniqueTypeName(iface.embeddeds))
+
+	sort.Sort(byUniqueMethodName(iface.allMethods))
+}
+
+// byUniqueTypeName named type lists can be sorted by their unique type names.
+type byUniqueTypeName []*Named
+
+func (a byUniqueTypeName) Len() int           { return len(a) }
+func (a byUniqueTypeName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueTypeName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+// byUniqueMethodName method lists can be sorted by their unique method names.
+type byUniqueMethodName []*Func
+
+func (a byUniqueMethodName) Len() int           { return len(a) }
+func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
+func (a byUniqueMethodName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+func (check *Checker) tag(t *ast.BasicLit) string {
+	if t != nil {
+		if t.Kind == token.STRING {
+			if val, err := strconv.Unquote(t.Value); err == nil {
+				return val
+			}
+		}
+		check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
+	}
+	return ""
+}
+
+func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) {
+	list := e.Fields
+	if list == nil {
+		return
+	}
+
+	// struct fields and tags
+	var fields []*Var
+	var tags []string
+
+	// for double-declaration checks
+	var fset objset
+
+	// current field typ and tag
+	var typ Type
+	var tag string
+	// anonymous != nil indicates an anonymous field.
+	add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) {
+		if tag != "" && tags == nil {
+			tags = make([]string, len(fields))
+		}
+		if tags != nil {
+			tags = append(tags, tag)
+		}
+
+		name := ident.Name
+		fld := NewField(pos, check.pkg, name, typ, anonymous != nil)
+		// spec: "Within a struct, non-blank field names must be unique."
+		if name == "_" || check.declareInSet(&fset, pos, fld) {
+			fields = append(fields, fld)
+			check.recordDef(ident, fld)
+		}
+		if anonymous != nil {
+			check.recordUse(ident, anonymous)
+		}
+	}
+
+	for _, f := range list.List {
+		typ = check.typExpr(f.Type, nil, path)
+		tag = check.tag(f.Tag)
+		if len(f.Names) > 0 {
+			// named fields
+			for _, name := range f.Names {
+				add(f, name, nil, name.Pos())
+			}
+		} else {
+			// anonymous field
+			name := anonymousFieldIdent(f.Type)
+			pos := f.Type.Pos()
+			t, isPtr := deref(typ)
+			switch t := t.(type) {
+			case *Basic:
+				if t == Typ[Invalid] {
+					// error was reported before
+					continue
+				}
+				// unsafe.Pointer is treated like a regular pointer
+				if t.kind == UnsafePointer {
+					check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+					continue
+				}
+				add(f, name, Universe.Lookup(t.name).(*TypeName), pos)
+
+			case *Named:
+				// spec: "An embedded type must be specified as a type name
+				// T or as a pointer to a non-interface type name *T, and T
+				// itself may not be a pointer type."
+				switch u := t.underlying.(type) {
+				case *Basic:
+					// unsafe.Pointer is treated like a regular pointer
+					if u.kind == UnsafePointer {
+						check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+						continue
+					}
+				case *Pointer:
+					check.errorf(pos, "anonymous field type cannot be a pointer")
+					continue
+				case *Interface:
+					if isPtr {
+						check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
+						continue
+					}
+				}
+				add(f, name, t.obj, pos)
+
+			default:
+				check.invalidAST(pos, "anonymous field type %s must be named", typ)
+			}
+		}
+	}
+
+	styp.fields = fields
+	styp.tags = tags
+}
+
+func anonymousFieldIdent(e ast.Expr) *ast.Ident {
+	switch e := e.(type) {
+	case *ast.Ident:
+		return e
+	case *ast.StarExpr:
+		return anonymousFieldIdent(e.X)
+	case *ast.SelectorExpr:
+		return e.Sel
+	}
+	return nil // invalid anonymous field
+}
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
new file mode 100644
index 0000000..c02543e
--- /dev/null
+++ b/src/go/types/universe.go
@@ -0,0 +1,223 @@
+// Copyright 2011 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.
+
+// This file implements the universe and unsafe package scopes.
+
+package types
+
+import (
+	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	"go/token"
+	"strings"
+)
+
+var (
+	Universe     *Scope
+	Unsafe       *Package
+	universeIota *Const
+	UniverseByte *Basic // uint8 alias, but has name "byte"
+	UniverseRune *Basic // int32 alias, but has name "rune"
+)
+
+var Typ = [...]*Basic{
+	Invalid: {Invalid, 0, "invalid type"},
+
+	Bool:          {Bool, IsBoolean, "bool"},
+	Int:           {Int, IsInteger, "int"},
+	Int8:          {Int8, IsInteger, "int8"},
+	Int16:         {Int16, IsInteger, "int16"},
+	Int32:         {Int32, IsInteger, "int32"},
+	Int64:         {Int64, IsInteger, "int64"},
+	Uint:          {Uint, IsInteger | IsUnsigned, "uint"},
+	Uint8:         {Uint8, IsInteger | IsUnsigned, "uint8"},
+	Uint16:        {Uint16, IsInteger | IsUnsigned, "uint16"},
+	Uint32:        {Uint32, IsInteger | IsUnsigned, "uint32"},
+	Uint64:        {Uint64, IsInteger | IsUnsigned, "uint64"},
+	Uintptr:       {Uintptr, IsInteger | IsUnsigned, "uintptr"},
+	Float32:       {Float32, IsFloat, "float32"},
+	Float64:       {Float64, IsFloat, "float64"},
+	Complex64:     {Complex64, IsComplex, "complex64"},
+	Complex128:    {Complex128, IsComplex, "complex128"},
+	String:        {String, IsString, "string"},
+	UnsafePointer: {UnsafePointer, 0, "Pointer"},
+
+	UntypedBool:    {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
+	UntypedInt:     {UntypedInt, IsInteger | IsUntyped, "untyped int"},
+	UntypedRune:    {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
+	UntypedFloat:   {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
+	UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
+	UntypedString:  {UntypedString, IsString | IsUntyped, "untyped string"},
+	UntypedNil:     {UntypedNil, IsUntyped, "untyped nil"},
+}
+
+var aliases = [...]*Basic{
+	{Byte, IsInteger | IsUnsigned, "byte"},
+	{Rune, IsInteger, "rune"},
+}
+
+func defPredeclaredTypes() {
+	for _, t := range Typ {
+		def(NewTypeName(token.NoPos, nil, t.name, t))
+	}
+	for _, t := range aliases {
+		def(NewTypeName(token.NoPos, nil, t.name, t))
+	}
+
+	// Error has a nil package in its qualified name since it is in no package
+	res := NewVar(token.NoPos, nil, "", Typ[String])
+	sig := &Signature{results: NewTuple(res)}
+	err := NewFunc(token.NoPos, nil, "Error", sig)
+	typ := &Named{underlying: NewInterface([]*Func{err}, nil).Complete()}
+	sig.recv = NewVar(token.NoPos, nil, "", typ)
+	def(NewTypeName(token.NoPos, nil, "error", typ))
+}
+
+var predeclaredConsts = [...]struct {
+	name string
+	kind BasicKind
+	val  exact.Value
+}{
+	{"true", UntypedBool, exact.MakeBool(true)},
+	{"false", UntypedBool, exact.MakeBool(false)},
+	{"iota", UntypedInt, exact.MakeInt64(0)},
+}
+
+func defPredeclaredConsts() {
+	for _, c := range predeclaredConsts {
+		def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val))
+	}
+}
+
+func defPredeclaredNil() {
+	def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}})
+}
+
+// A builtinId is the id of a builtin function.
+type builtinId int
+
+const (
+	// universe scope
+	_Append builtinId = iota
+	_Cap
+	_Close
+	_Complex
+	_Copy
+	_Delete
+	_Imag
+	_Len
+	_Make
+	_New
+	_Panic
+	_Print
+	_Println
+	_Real
+	_Recover
+
+	// package unsafe
+	_Alignof
+	_Offsetof
+	_Sizeof
+
+	// testing support
+	_Assert
+	_Trace
+)
+
+var predeclaredFuncs = [...]struct {
+	name     string
+	nargs    int
+	variadic bool
+	kind     exprKind
+}{
+	_Append:  {"append", 1, true, expression},
+	_Cap:     {"cap", 1, false, expression},
+	_Close:   {"close", 1, false, statement},
+	_Complex: {"complex", 2, false, expression},
+	_Copy:    {"copy", 2, false, statement},
+	_Delete:  {"delete", 2, false, statement},
+	_Imag:    {"imag", 1, false, expression},
+	_Len:     {"len", 1, false, expression},
+	_Make:    {"make", 1, true, expression},
+	_New:     {"new", 1, false, expression},
+	_Panic:   {"panic", 1, false, statement},
+	_Print:   {"print", 0, true, statement},
+	_Println: {"println", 0, true, statement},
+	_Real:    {"real", 1, false, expression},
+	_Recover: {"recover", 0, false, statement},
+
+	_Alignof:  {"Alignof", 1, false, expression},
+	_Offsetof: {"Offsetof", 1, false, expression},
+	_Sizeof:   {"Sizeof", 1, false, expression},
+
+	_Assert: {"assert", 1, false, statement},
+	_Trace:  {"trace", 0, true, statement},
+}
+
+func defPredeclaredFuncs() {
+	for i := range predeclaredFuncs {
+		id := builtinId(i)
+		if id == _Assert || id == _Trace {
+			continue // only define these in testing environment
+		}
+		def(newBuiltin(id))
+	}
+}
+
+// DefPredeclaredTestFuncs defines the assert and trace built-ins.
+// These built-ins are intended for debugging and testing of this
+// package only.
+func DefPredeclaredTestFuncs() {
+	if Universe.Lookup("assert") != nil {
+		return // already defined
+	}
+	def(newBuiltin(_Assert))
+	def(newBuiltin(_Trace))
+}
+
+func init() {
+	Universe = NewScope(nil, "universe")
+	Unsafe = NewPackage("unsafe", "unsafe")
+	Unsafe.complete = true
+
+	defPredeclaredTypes()
+	defPredeclaredConsts()
+	defPredeclaredNil()
+	defPredeclaredFuncs()
+
+	universeIota = Universe.Lookup("iota").(*Const)
+	UniverseByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
+	UniverseRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
+}
+
+// Objects with names containing blanks are internal and not entered into
+// a scope. Objects with exported names are inserted in the unsafe package
+// scope; other objects are inserted in the universe scope.
+//
+func def(obj Object) {
+	name := obj.Name()
+	if strings.Index(name, " ") >= 0 {
+		return // nothing to do
+	}
+	// fix Obj link for named types
+	if typ, ok := obj.Type().(*Named); ok {
+		typ.obj = obj.(*TypeName)
+	}
+	// exported identifiers go into package unsafe
+	scope := Universe
+	if obj.Exported() {
+		scope = Unsafe.scope
+		// set Pkg field
+		switch obj := obj.(type) {
+		case *TypeName:
+			obj.pkg = Unsafe
+		case *Builtin:
+			obj.pkg = Unsafe
+		default:
+			unreachable()
+		}
+	}
+	if scope.Insert(obj) != nil {
+		panic("internal error: double declaration")
+	}
+}
diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go
index 6a6b947..10867a7 100644
--- a/src/hash/crc32/crc32.go
+++ b/src/hash/crc32/crc32.go
@@ -5,6 +5,11 @@
 // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32,
 // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
 // information.
+//
+// Polynomials are represented in LSB-first form also known as reversed representation.
+//
+// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials
+// for information.
 package crc32
 
 import (
diff --git a/src/hash/crc32/example_test.go b/src/hash/crc32/example_test.go
new file mode 100644
index 0000000..621bf83
--- /dev/null
+++ b/src/hash/crc32/example_test.go
@@ -0,0 +1,28 @@
+// 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 crc32_test
+
+import (
+	"fmt"
+	"hash/crc32"
+)
+
+func ExampleMakeTable() {
+	// In this package, the CRC polynomial is represented in reversed notation,
+	// or LSB-first representation.
+	//
+	// LSB-first representation is a hexadecimal number with n bits, in which the
+	// most significant bit represents the coefficient of x⁰ and the least significant
+	// bit represents the coefficient of xⁿ⁻¹ (the coefficient for xⁿ is implicit).
+	//
+	// For example, CRC32-Q, as defined by the following polynomial,
+	//	x³²+ x³¹+ x²⁴+ x²²+ x¹⁶+ x¹⁴+ x⁸+ x⁷+ x⁵+ x³+ x¹+ x⁰
+	// has the reversed notation 0b11010101100000101000001010000001, so the value
+	// that should be passed to MakeTable is 0xD5828281.
+	crc32q := crc32.MakeTable(0xD5828281)
+	fmt.Printf("%08x\n", crc32.Checksum([]byte("Hello world"), crc32q))
+	// Output:
+	// 2964d064
+}
diff --git a/src/html/template/template.go b/src/html/template/template.go
index 64c0041..bb9140a 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -51,6 +51,29 @@
 	return m
 }
 
+// Option sets options for the template. Options are described by
+// strings, either a simple string or "key=value". There can be at
+// most one equals sign in an option string. If the option string
+// is unrecognized or otherwise invalid, Option panics.
+//
+// Known options:
+//
+// missingkey: Control the behavior during execution if a map is
+// indexed with a key that is not present in the map.
+//	"missingkey=default" or "missingkey=invalid"
+//		The default behavior: Do nothing and continue execution.
+//		If printed, the result of the index operation is the string
+//		"<no value>".
+//	"missingkey=zero"
+//		The operation returns the zero value for the map type's element.
+//	"missingkey=error"
+//		Execution stops immediately with an error.
+//
+func (t *Template) Option(opt ...string) *Template {
+	t.text.Option(opt...)
+	return t
+}
+
 // escape escapes all associated templates.
 func (t *Template) escape() error {
 	t.nameSpace.mu.Lock()
diff --git a/src/html/template/transition.go b/src/html/template/transition.go
index b486fcd..d2e0287 100644
--- a/src/html/template/transition.go
+++ b/src/html/template/transition.go
@@ -183,24 +183,54 @@
 
 // specialTagEndMarkers maps element types to the character sequence that
 // case-insensitively signals the end of the special tag body.
-var specialTagEndMarkers = [...]string{
-	elementScript:   "</script",
-	elementStyle:    "</style",
-	elementTextarea: "</textarea",
-	elementTitle:    "</title",
+var specialTagEndMarkers = [...][]byte{
+	elementScript:   []byte("script"),
+	elementStyle:    []byte("style"),
+	elementTextarea: []byte("textarea"),
+	elementTitle:    []byte("title"),
 }
 
+var (
+	specialTagEndPrefix = []byte("</")
+	tagEndSeparators    = []byte("> \t\n\f/")
+)
+
 // tSpecialTagEnd is the context transition function for raw text and RCDATA
 // element states.
 func tSpecialTagEnd(c context, s []byte) (context, int) {
 	if c.element != elementNone {
-		if i := strings.Index(strings.ToLower(string(s)), specialTagEndMarkers[c.element]); i != -1 {
+		if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 {
 			return context{}, i
 		}
 	}
 	return c, len(s)
 }
 
+// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1
+func indexTagEnd(s []byte, tag []byte) int {
+	res := 0
+	plen := len(specialTagEndPrefix)
+	for len(s) > 0 {
+		// Try to find the tag end prefix first
+		i := bytes.Index(s, specialTagEndPrefix)
+		if i == -1 {
+			return i
+		}
+		s = s[i+plen:]
+		// Try to match the actual tag if there is still space for it
+		if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) {
+			s = s[len(tag):]
+			// Check the tag is followed by a proper separator
+			if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 {
+				return res + i
+			}
+			res += len(tag)
+		}
+		res += i + plen
+	}
+	return -1
+}
+
 // tAttr is the context transition function for the attribute state.
 func tAttr(c context, s []byte) (context, int) {
 	return c, len(s)
diff --git a/src/html/template/transition_test.go b/src/html/template/transition_test.go
new file mode 100644
index 0000000..412a4c7
--- /dev/null
+++ b/src/html/template/transition_test.go
@@ -0,0 +1,60 @@
+// Copyright 2011 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 template
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+)
+
+func TestFindEndTag(t *testing.T) {
+	tests := []struct {
+		s, tag string
+		want   int
+	}{
+		{"", "tag", -1},
+		{"hello </textarea> hello", "textarea", 6},
+		{"hello </TEXTarea> hello", "textarea", 6},
+		{"hello </textAREA>", "textarea", 6},
+		{"hello </textarea", "textareax", -1},
+		{"hello </textarea>", "tag", -1},
+		{"hello tag </textarea", "tag", -1},
+		{"hello </tag> </other> </textarea> <other>", "textarea", 22},
+		{"</textarea> <other>", "textarea", 0},
+		{"<div> </div> </TEXTAREA>", "textarea", 13},
+		{"<div> </div> </TEXTAREA\t>", "textarea", 13},
+		{"<div> </div> </TEXTAREA >", "textarea", 13},
+		{"<div> </div> </TEXTAREAfoo", "textarea", -1},
+		{"</TEXTAREAfoo </textarea>", "textarea", 14},
+		{"<</script >", "script", 1},
+		{"</script>", "textarea", -1},
+	}
+	for _, test := range tests {
+		if got := indexTagEnd([]byte(test.s), []byte(test.tag)); test.want != got {
+			t.Errorf("%q/%q: want\n\t%d\nbut got\n\t%d", test.s, test.tag, test.want, got)
+		}
+	}
+}
+
+func BenchmarkTemplateSpecialTags(b *testing.B) {
+
+	r := struct {
+		Name, Gift string
+	}{"Aunt Mildred", "bone china tea set"}
+
+	h1 := "<textarea> Hello Hello Hello </textarea> "
+	h2 := "<textarea> <p> Dear {{.Name}},\n{{with .Gift}}Thank you for the lovely {{.}}. {{end}}\nBest wishes. </p>\n</textarea>"
+	html := strings.Repeat(h1, 100) + h2 + strings.Repeat(h1, 100) + h2
+
+	var buf bytes.Buffer
+	for i := 0; i < b.N; i++ {
+		tmpl := Must(New("foo").Parse(html))
+		if err := tmpl.Execute(&buf, r); err != nil {
+			b.Fatal(err)
+		}
+		buf.Reset()
+	}
+}
diff --git a/src/image/color/color.go b/src/image/color/color.go
index 00bd8fd..cae059b 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -271,32 +271,39 @@
 }
 
 // Index returns the index of the palette color closest to c in Euclidean
-// R,G,B space.
+// R,G,B,A space.
 func (p Palette) Index(c Color) int {
 	// A batch version of this computation is in image/draw/draw.go.
 
-	cr, cg, cb, _ := c.RGBA()
-	ret, bestSSD := 0, uint32(1<<32-1)
+	cr, cg, cb, ca := c.RGBA()
+	ret, bestSum := 0, uint32(1<<32-1)
 	for i, v := range p {
-		vr, vg, vb, _ := v.RGBA()
-		// We shift by 1 bit to avoid potential uint32 overflow in
-		// sum-squared-difference.
-		delta := (int32(cr) - int32(vr)) >> 1
-		ssd := uint32(delta * delta)
-		delta = (int32(cg) - int32(vg)) >> 1
-		ssd += uint32(delta * delta)
-		delta = (int32(cb) - int32(vb)) >> 1
-		ssd += uint32(delta * delta)
-		if ssd < bestSSD {
-			if ssd == 0 {
+		vr, vg, vb, va := v.RGBA()
+		sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
+		if sum < bestSum {
+			if sum == 0 {
 				return i
 			}
-			ret, bestSSD = i, ssd
+			ret, bestSum = i, sum
 		}
 	}
 	return ret
 }
 
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y uint32) uint32 {
+	var d uint32
+	if x > y {
+		d = x - y
+	} else {
+		d = y - x
+	}
+	return (d * d) >> 2
+}
+
 // Standard colors.
 var (
 	Black       = Gray16{0}
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index bbaaf7e..f8c1326 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -158,11 +158,11 @@
 
 // CMYKToRGB converts a CMYK quadruple to an RGB triple.
 func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
-	w := uint32(0xff - k)
-	r := uint32(0xff-c) * w / 0xff
-	g := uint32(0xff-m) * w / 0xff
-	b := uint32(0xff-y) * w / 0xff
-	return uint8(r), uint8(g), uint8(b)
+	w := uint32(0xffff - uint32(k)*0x101)
+	r := uint32(0xffff-uint32(c)*0x101) * w / 0xffff
+	g := uint32(0xffff-uint32(m)*0x101) * w / 0xffff
+	b := uint32(0xffff-uint32(y)*0x101) * w / 0xffff
+	return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
 }
 
 // CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,
@@ -174,8 +174,14 @@
 }
 
 func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
-	r, g, b := CMYKToRGB(c.C, c.M, c.Y, c.K)
-	return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+	// This code is a copy of the CMYKToRGB function above, except that it
+	// returns values in the range [0, 0xffff] instead of [0, 0xff].
+
+	w := uint32(0xffff - uint32(c.K)*0x101)
+	r := uint32(0xffff-uint32(c.C)*0x101) * w / 0xffff
+	g := uint32(0xffff-uint32(c.M)*0x101) * w / 0xffff
+	b := uint32(0xffff-uint32(c.Y)*0x101) * w / 0xffff
+	return uint32(r), uint32(g), uint32(b), 0xffff
 }
 
 // CMYKModel is the Model for CMYK colors.
diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go
index 94c23dd..6bf53f1 100644
--- a/src/image/color/ycbcr_test.go
+++ b/src/image/color/ycbcr_test.go
@@ -18,14 +18,34 @@
 // TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr
 // and back to within 1/256 tolerance.
 func TestYCbCrRoundtrip(t *testing.T) {
-	for r := 0; r < 255; r += 7 {
-		for g := 0; g < 255; g += 5 {
-			for b := 0; b < 255; b += 3 {
+	for r := 0; r < 256; r += 7 {
+		for g := 0; g < 256; g += 5 {
+			for b := 0; b < 256; b += 3 {
 				r0, g0, b0 := uint8(r), uint8(g), uint8(b)
 				y, cb, cr := RGBToYCbCr(r0, g0, b0)
 				r1, g1, b1 := YCbCrToRGB(y, cb, cr)
 				if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
-					t.Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+					t.Fatalf("\nr0, g0, b0 = %d, %d, %d\nr1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+				}
+			}
+		}
+	}
+}
+
+// TestYCbCrToRGBConsistency tests that calling the RGBA method (16 bit color)
+// then truncating to 8 bits is equivalent to calling the YCbCrToRGB function (8
+// bit color).
+func TestYCbCrToRGBConsistency(t *testing.T) {
+	for y := 0; y < 256; y += 7 {
+		for cb := 0; cb < 256; cb += 5 {
+			for cr := 0; cr < 256; cr += 3 {
+				x := YCbCr{uint8(y), uint8(cb), uint8(cr)}
+				r0, g0, b0, _ := x.RGBA()
+				r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
+				r2, g2, b2 := YCbCrToRGB(x.Y, x.Cb, x.Cr)
+				if r1 != r2 || g1 != g2 || b1 != b2 {
+					t.Fatalf("y, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
+						y, cb, cr, r1, g1, b1, r2, g2, b2)
 				}
 			}
 		}
@@ -35,16 +55,64 @@
 // TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK
 // and back to within 1/256 tolerance.
 func TestCMYKRoundtrip(t *testing.T) {
-	for r := 0; r < 255; r += 7 {
-		for g := 0; g < 255; g += 5 {
-			for b := 0; b < 255; b += 3 {
+	for r := 0; r < 256; r += 7 {
+		for g := 0; g < 256; g += 5 {
+			for b := 0; b < 256; b += 3 {
 				r0, g0, b0 := uint8(r), uint8(g), uint8(b)
 				c, m, y, k := RGBToCMYK(r0, g0, b0)
 				r1, g1, b1 := CMYKToRGB(c, m, y, k)
 				if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
-					t.Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+					t.Fatalf("\nr0, g0, b0 = %d, %d, %d\nr1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
 				}
 			}
 		}
 	}
 }
+
+// TestCMYKToRGBConsistency tests that calling the RGBA method (16 bit color)
+// then truncating to 8 bits is equivalent to calling the CMYKToRGB function (8
+// bit color).
+func TestCMYKToRGBConsistency(t *testing.T) {
+	for c := 0; c < 256; c += 7 {
+		for m := 0; m < 256; m += 5 {
+			for y := 0; y < 256; y += 3 {
+				for k := 0; k < 256; k += 11 {
+					x := CMYK{uint8(c), uint8(m), uint8(y), uint8(k)}
+					r0, g0, b0, _ := x.RGBA()
+					r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
+					r2, g2, b2 := CMYKToRGB(x.C, x.M, x.Y, x.K)
+					if r1 != r2 || g1 != g2 || b1 != b2 {
+						t.Fatalf("c, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
+							c, m, y, k, r1, g1, b1, r2, g2, b2)
+					}
+				}
+			}
+		}
+	}
+}
+
+func TestPalette(t *testing.T) {
+	p := Palette{
+		RGBA{0xff, 0xff, 0xff, 0xff},
+		RGBA{0x80, 0x00, 0x00, 0xff},
+		RGBA{0x7f, 0x00, 0x00, 0x7f},
+		RGBA{0x00, 0x00, 0x00, 0x7f},
+		RGBA{0x00, 0x00, 0x00, 0x00},
+		RGBA{0x40, 0x40, 0x40, 0x40},
+	}
+	// Check that, for a Palette with no repeated colors, the closest color to
+	// each element is itself.
+	for i, c := range p {
+		j := p.Index(c)
+		if i != j {
+			t.Errorf("Index(%v): got %d (color = %v), want %d", c, j, p[j], i)
+		}
+	}
+	// Check that finding the closest color considers alpha, not just red,
+	// green and blue.
+	got := p.Convert(RGBA{0x80, 0x00, 0x00, 0x80})
+	want := RGBA{0x7f, 0x00, 0x00, 0x7f}
+	if got != want {
+		t.Errorf("got %v, want %v", got, want)
+	}
+}
diff --git a/src/image/draw/clip_test.go b/src/image/draw/clip_test.go
index 5903338..0abf53e 100644
--- a/src/image/draw/clip_test.go
+++ b/src/image/draw/clip_test.go
@@ -185,17 +185,17 @@
 		}
 
 		// Check that the clipped rectangle is contained by the dst / src / mask
-		// rectangles, in their respective co-ordinate spaces.
+		// rectangles, in their respective coordinate spaces.
 		if !r.In(c.dr) {
 			t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
 		}
-		// sr is r translated into src's co-ordinate space.
+		// sr is r translated into src's coordinate space.
 		sr := r.Add(c.sp.Sub(c.dr.Min))
 		if !sr.In(c.sr) {
 			t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
 		}
 		if !c.nilMask {
-			// mr is r translated into mask's co-ordinate space.
+			// mr is r translated into mask's coordinate space.
 			mr := r.Add(c.mp.Sub(c.dr.Min))
 			if !mr.In(c.mr) {
 				t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index 420fd05..ee1126c 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -68,7 +68,7 @@
 }
 
 // clip clips r against each image's bounds (after translating into the
-// destination image's co-ordinate space) and shifts the points sp and mp by
+// destination image's coordinate space) and shifts the points sp and mp by
 // the same amount as the change in r.Min.
 func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
 	orig := r.Min
@@ -336,9 +336,11 @@
 		ddelta = dst.Stride
 		sdelta = src.Stride
 	} else {
-		// If the source start point is higher than the destination start point, then we compose the rows
-		// in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
-		// check the x co-ordinates because the built-in copy function can handle overlapping slices.
+		// If the source start point is higher than the destination start
+		// point, then we compose the rows in bottom-up order instead of
+		// top-down. Unlike the drawCopyOver function, we don't have to check
+		// the x coordinates because the built-in copy function can handle
+		// overlapping slices.
 		d0 += (dy - 1) * dst.Stride
 		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
@@ -552,6 +554,20 @@
 	return i
 }
 
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y int32) uint32 {
+	var d uint32
+	if x > y {
+		d = uint32(x - y)
+	} else {
+		d = uint32(y - x)
+	}
+	return (d * d) >> 2
+}
+
 func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
 	// TODO(nigeltao): handle the case where the dst and src overlap.
 	// Does it even make sense to try and do Floyd-Steinberg whilst
@@ -561,14 +577,15 @@
 	// dst.At. The dst.Set equivalent is a batch version of the algorithm
 	// used by color.Palette's Index method in image/color/color.go, plus
 	// optional Floyd-Steinberg error diffusion.
-	palette, pix, stride := [][3]int32(nil), []byte(nil), 0
+	palette, pix, stride := [][4]int32(nil), []byte(nil), 0
 	if p, ok := dst.(*image.Paletted); ok {
-		palette = make([][3]int32, len(p.Palette))
+		palette = make([][4]int32, len(p.Palette))
 		for i, col := range p.Palette {
-			r, g, b, _ := col.RGBA()
+			r, g, b, a := col.RGBA()
 			palette[i][0] = int32(r)
 			palette[i][1] = int32(g)
 			palette[i][2] = int32(b)
+			palette[i][3] = int32(a)
 		}
 		pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
 	}
@@ -576,10 +593,10 @@
 	// quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization
 	// errors that have been propagated to the pixels in the current and next
 	// rows. The +2 simplifies calculation near the edges.
-	var quantErrorCurr, quantErrorNext [][3]int32
+	var quantErrorCurr, quantErrorNext [][4]int32
 	if floydSteinberg {
-		quantErrorCurr = make([][3]int32, r.Dx()+2)
-		quantErrorNext = make([][3]int32, r.Dx()+2)
+		quantErrorCurr = make([][4]int32, r.Dx()+2)
+		quantErrorNext = make([][4]int32, r.Dx()+2)
 	}
 
 	// Loop over each source pixel.
@@ -588,30 +605,25 @@
 		for x := 0; x != r.Dx(); x++ {
 			// er, eg and eb are the pixel's R,G,B values plus the
 			// optional Floyd-Steinberg error.
-			sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA()
-			er, eg, eb := int32(sr), int32(sg), int32(sb)
+			sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
+			er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
 			if floydSteinberg {
 				er = clamp(er + quantErrorCurr[x+1][0]/16)
 				eg = clamp(eg + quantErrorCurr[x+1][1]/16)
 				eb = clamp(eb + quantErrorCurr[x+1][2]/16)
+				ea = clamp(ea + quantErrorCurr[x+1][3]/16)
 			}
 
 			if palette != nil {
-				// Find the closest palette color in Euclidean R,G,B space: the
-				// one that minimizes sum-squared-difference. We shift by 1 bit
-				// to avoid potential uint32 overflow in sum-squared-difference.
+				// Find the closest palette color in Euclidean R,G,B,A space:
+				// the one that minimizes sum-squared-difference.
 				// TODO(nigeltao): consider smarter algorithms.
-				bestIndex, bestSSD := 0, uint32(1<<32-1)
+				bestIndex, bestSum := 0, uint32(1<<32-1)
 				for index, p := range palette {
-					delta := (er - p[0]) >> 1
-					ssd := uint32(delta * delta)
-					delta = (eg - p[1]) >> 1
-					ssd += uint32(delta * delta)
-					delta = (eb - p[2]) >> 1
-					ssd += uint32(delta * delta)
-					if ssd < bestSSD {
-						bestIndex, bestSSD = index, ssd
-						if ssd == 0 {
+					sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
+					if sum < bestSum {
+						bestIndex, bestSum = index, sum
+						if sum == 0 {
 							break
 						}
 					}
@@ -624,11 +636,13 @@
 				er -= int32(palette[bestIndex][0])
 				eg -= int32(palette[bestIndex][1])
 				eb -= int32(palette[bestIndex][2])
+				ea -= int32(palette[bestIndex][3])
 
 			} else {
 				out.R = uint16(er)
 				out.G = uint16(eg)
 				out.B = uint16(eb)
+				out.A = uint16(ea)
 				// The third argument is &out instead of out (and out is
 				// declared outside of the inner loop) to avoid the implicit
 				// conversion to color.Color here allocating memory in the
@@ -638,32 +652,37 @@
 				if !floydSteinberg {
 					continue
 				}
-				sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
+				sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
 				er -= int32(sr)
 				eg -= int32(sg)
 				eb -= int32(sb)
+				ea -= int32(sa)
 			}
 
 			// Propagate the Floyd-Steinberg quantization error.
 			quantErrorNext[x+0][0] += er * 3
 			quantErrorNext[x+0][1] += eg * 3
 			quantErrorNext[x+0][2] += eb * 3
+			quantErrorNext[x+0][3] += ea * 3
 			quantErrorNext[x+1][0] += er * 5
 			quantErrorNext[x+1][1] += eg * 5
 			quantErrorNext[x+1][2] += eb * 5
+			quantErrorNext[x+1][3] += ea * 5
 			quantErrorNext[x+2][0] += er * 1
 			quantErrorNext[x+2][1] += eg * 1
 			quantErrorNext[x+2][2] += eb * 1
+			quantErrorNext[x+2][3] += ea * 1
 			quantErrorCurr[x+2][0] += er * 7
 			quantErrorCurr[x+2][1] += eg * 7
 			quantErrorCurr[x+2][2] += eb * 7
+			quantErrorCurr[x+2][3] += ea * 7
 		}
 
 		// Recycle the quantization error buffers.
 		if floydSteinberg {
 			quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
 			for i := range quantErrorNext {
-				quantErrorNext[i] = [3]int32{}
+				quantErrorNext[i] = [4]int32{}
 			}
 		}
 	}
diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go
index 5a863e2..b71e041 100644
--- a/src/image/gif/reader.go
+++ b/src/image/gif/reader.go
@@ -32,15 +32,20 @@
 // Masks etc.
 const (
 	// Fields.
-	fColorMapFollows = 1 << 7
-
-	// Image fields.
-	ifLocalColorTable = 1 << 7
-	ifInterlace       = 1 << 6
-	ifPixelSizeMask   = 7
+	fColorTable         = 1 << 7
+	fInterlace          = 1 << 6
+	fColorTableBitsMask = 7
 
 	// Graphic control flags.
 	gcTransparentColorSet = 1 << 0
+	gcDisposalMethodMask  = 7 << 2
+)
+
+// Disposal Methods.
+const (
+	DisposalNone       = 0x01
+	DisposalBackground = 0x02
+	DisposalPrevious   = 0x03
 )
 
 // Section indicators.
@@ -66,14 +71,10 @@
 	vers            string
 	width           int
 	height          int
-	flags           byte
-	headerFields    byte
-	backgroundIndex byte
 	loopCount       int
 	delayTime       int
-
-	// Unused from header.
-	aspect byte
+	backgroundIndex byte
+	disposalMethod  byte
 
 	// From image descriptor.
 	imageFields byte
@@ -83,13 +84,13 @@
 	hasTransparentIndex bool
 
 	// Computed.
-	pixelSize      uint
-	globalColorMap color.Palette
+	globalColorTable color.Palette
 
 	// Used when decoding.
-	delay []int
-	image []*image.Paletted
-	tmp   [1024]byte // must be at least 768 so we can read color map
+	delay    []int
+	disposal []byte
+	image    []*image.Paletted
+	tmp      [1024]byte // must be at least 768 so we can read color table
 }
 
 // blockReader parses the block structure of GIF image data, which
@@ -122,7 +123,7 @@
 			b.err = io.EOF
 			return 0, b.err
 		}
-		b.slice = b.tmp[0:blockLen]
+		b.slice = b.tmp[:blockLen]
 		if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
 			return 0, b.err
 		}
@@ -149,12 +150,6 @@
 		return nil
 	}
 
-	if d.headerFields&fColorMapFollows != 0 {
-		if d.globalColorMap, err = d.readColorMap(); err != nil {
-			return err
-		}
-	}
-
 	for {
 		c, err := d.r.ReadByte()
 		if err != nil {
@@ -171,19 +166,19 @@
 			if err != nil {
 				return err
 			}
-			useLocalColorMap := d.imageFields&fColorMapFollows != 0
-			if useLocalColorMap {
-				m.Palette, err = d.readColorMap()
+			useLocalColorTable := d.imageFields&fColorTable != 0
+			if useLocalColorTable {
+				m.Palette, err = d.readColorTable(d.imageFields)
 				if err != nil {
 					return err
 				}
 			} else {
-				m.Palette = d.globalColorMap
+				m.Palette = d.globalColorTable
 			}
 			if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
-				if !useLocalColorMap {
-					// Clone the global color map.
-					m.Palette = append(color.Palette(nil), d.globalColorMap...)
+				if !useLocalColorTable {
+					// Clone the global color table.
+					m.Palette = append(color.Palette(nil), d.globalColorTable...)
 				}
 				m.Palette[d.transparentIndex] = color.RGBA{}
 			}
@@ -229,12 +224,13 @@
 			}
 
 			// Undo the interlacing if necessary.
-			if d.imageFields&ifInterlace != 0 {
+			if d.imageFields&fInterlace != 0 {
 				uninterlace(m)
 			}
 
 			d.image = append(d.image, m)
 			d.delay = append(d.delay, d.delayTime)
+			d.disposal = append(d.disposal, d.disposalMethod)
 			// The GIF89a spec, Section 23 (Graphic Control Extension) says:
 			// "The scope of this extension is the first graphic rendering block
 			// to follow." We therefore reset the GCE fields to zero.
@@ -254,44 +250,40 @@
 }
 
 func (d *decoder) readHeaderAndScreenDescriptor() error {
-	_, err := io.ReadFull(d.r, d.tmp[0:13])
+	_, err := io.ReadFull(d.r, d.tmp[:13])
 	if err != nil {
 		return err
 	}
-	d.vers = string(d.tmp[0:6])
+	d.vers = string(d.tmp[:6])
 	if d.vers != "GIF87a" && d.vers != "GIF89a" {
 		return fmt.Errorf("gif: can't recognize format %s", d.vers)
 	}
 	d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
 	d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
-	d.headerFields = d.tmp[10]
-	d.backgroundIndex = d.tmp[11]
-	d.aspect = d.tmp[12]
+	if fields := d.tmp[10]; fields&fColorTable != 0 {
+		d.backgroundIndex = d.tmp[11]
+		// readColorTable overwrites the contents of d.tmp, but that's OK.
+		if d.globalColorTable, err = d.readColorTable(fields); err != nil {
+			return err
+		}
+	}
+	// d.tmp[12] is the Pixel Aspect Ratio, which is ignored.
 	d.loopCount = -1
-	d.pixelSize = uint(d.headerFields&7) + 1
 	return nil
 }
 
-func (d *decoder) readColorMap() (color.Palette, error) {
-	if d.pixelSize > 8 {
-		return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
-	}
-	numColors := 1 << d.pixelSize
-	if d.imageFields&ifLocalColorTable != 0 {
-		numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
-	}
-	numValues := 3 * numColors
-	_, err := io.ReadFull(d.r, d.tmp[0:numValues])
+func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
+	n := 1 << (1 + uint(fields&fColorTableBitsMask))
+	_, err := io.ReadFull(d.r, d.tmp[:3*n])
 	if err != nil {
-		return nil, fmt.Errorf("gif: short read on color map: %s", err)
+		return nil, fmt.Errorf("gif: short read on color table: %s", err)
 	}
-	colorMap := make(color.Palette, numColors)
-	j := 0
-	for i := range colorMap {
-		colorMap[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
+	j, p := 0, make(color.Palette, n)
+	for i := range p {
+		p[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
 		j += 3
 	}
-	return colorMap, nil
+	return p, nil
 }
 
 func (d *decoder) readExtension() error {
@@ -318,7 +310,7 @@
 		return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
 	}
 	if size > 0 {
-		if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
+		if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil {
 			return err
 		}
 	}
@@ -343,12 +335,13 @@
 }
 
 func (d *decoder) readGraphicControl() error {
-	if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
+	if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
 		return fmt.Errorf("gif: can't read graphic control: %s", err)
 	}
-	d.flags = d.tmp[1]
+	flags := d.tmp[1]
+	d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
 	d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
-	if d.flags&gcTransparentColorSet != 0 {
+	if flags&gcTransparentColorSet != 0 {
 		d.transparentIndex = d.tmp[4]
 		d.hasTransparentIndex = true
 	}
@@ -356,7 +349,7 @@
 }
 
 func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
-	if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
+	if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil {
 		return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
 	}
 	left := int(d.tmp[0]) + int(d.tmp[1])<<8
@@ -380,7 +373,7 @@
 	if n == 0 || err != nil {
 		return 0, err
 	}
-	return io.ReadFull(d.r, d.tmp[0:n])
+	return io.ReadFull(d.r, d.tmp[:n])
 }
 
 // interlaceScan defines the ordering for a pass of the interlace algorithm.
@@ -429,6 +422,24 @@
 	Image     []*image.Paletted // The successive images.
 	Delay     []int             // The successive delay times, one per frame, in 100ths of a second.
 	LoopCount int               // The loop count.
+	// Disposal is the successive disposal methods, one per frame. For
+	// backwards compatibility, a nil Disposal is valid to pass to EncodeAll,
+	// and implies that each frame's disposal method is 0 (no disposal
+	// specified).
+	Disposal []byte
+	// Config is the global color table (palette), width and height. A nil or
+	// empty-color.Palette Config.ColorModel means that each frame has its own
+	// color table and there is no global color table. Each frame's bounds must
+	// be within the rectangle defined by the two points (0, 0) and
+	// (Config.Width, Config.Height).
+	//
+	// For backwards compatibility, a zero-valued Config is valid to pass to
+	// EncodeAll, and implies that the overall GIF's width and height equals
+	// the first frame's bounds' Rectangle.Max point.
+	Config image.Config
+	// BackgroundIndex is the background index in the global color table, for
+	// use with the DisposalBackground disposal method.
+	BackgroundIndex byte
 }
 
 // DecodeAll reads a GIF image from r and returns the sequential frames
@@ -442,6 +453,13 @@
 		Image:     d.image,
 		LoopCount: d.loopCount,
 		Delay:     d.delay,
+		Disposal:  d.disposal,
+		Config: image.Config{
+			ColorModel: d.globalColorTable,
+			Width:      d.width,
+			Height:     d.height,
+		},
+		BackgroundIndex: d.backgroundIndex,
 	}
 	return gif, nil
 }
@@ -454,7 +472,7 @@
 		return image.Config{}, err
 	}
 	return image.Config{
-		ColorModel: d.globalColorMap,
+		ColorModel: d.globalColorTable,
 		Width:      d.width,
 		Height:     d.height,
 	}, nil
diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go
index 7b6f504..94bd0a7 100644
--- a/src/image/gif/reader_test.go
+++ b/src/image/gif/reader_test.go
@@ -17,8 +17,8 @@
 const (
 	headerStr = "GIF89a" +
 		"\x02\x00\x01\x00" + // width=2, height=1
-		"\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
-	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
+		"\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect
+	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette
 	trailerStr = "\x3b"
 )
 
@@ -141,7 +141,7 @@
 	'G', 'I', 'F', '8', '9', 'a',
 	1, 0, 1, 0, // w=1, h=1 (6)
 	128, 0, 0, // headerFields, bg, aspect (10)
-	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
+	0, 0, 0, 1, 1, 1, // color table and graphics control (13)
 	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
 	// frame 1 (0,0 - 1,1)
 	0x2c,
diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go
index 49abde7..dd31790 100644
--- a/src/image/gif/writer.go
+++ b/src/image/gif/writer.go
@@ -6,6 +6,7 @@
 
 import (
 	"bufio"
+	"bytes"
 	"compress/lzw"
 	"errors"
 	"image"
@@ -52,9 +53,13 @@
 	w   writer
 	err error
 	// g is a reference to the data that is being encoded.
-	g *GIF
-	// buf is a scratch buffer. It must be at least 768 so we can write the color map.
-	buf [1024]byte
+	g GIF
+	// globalCT is the size in bytes of the global color table.
+	globalCT int
+	// buf is a scratch buffer. It must be at least 256 for the blockWriter.
+	buf              [256]byte
+	globalColorTable [3 * 256]byte
+	localColorTable  [3 * 256]byte
 }
 
 // blockWriter writes the block structure of GIF image data, which
@@ -116,18 +121,27 @@
 		return
 	}
 
-	pm := e.g.Image[0]
 	// Logical screen width and height.
-	writeUint16(e.buf[0:2], uint16(pm.Bounds().Dx()))
-	writeUint16(e.buf[2:4], uint16(pm.Bounds().Dy()))
+	writeUint16(e.buf[0:2], uint16(e.g.Config.Width))
+	writeUint16(e.buf[2:4], uint16(e.g.Config.Height))
 	e.write(e.buf[:4])
 
-	// All frames have a local color table, so a global color table
-	// is not needed.
-	e.buf[0] = 0x00
-	e.buf[1] = 0x00 // Background Color Index.
-	e.buf[2] = 0x00 // Pixel Aspect Ratio.
-	e.write(e.buf[:3])
+	if p, ok := e.g.Config.ColorModel.(color.Palette); ok && len(p) > 0 {
+		paddedSize := log2(len(p)) // Size of Global Color Table: 2^(1+n).
+		e.buf[0] = fColorTable | uint8(paddedSize)
+		e.buf[1] = e.g.BackgroundIndex
+		e.buf[2] = 0x00 // Pixel Aspect Ratio.
+		e.write(e.buf[:3])
+		e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+		e.write(e.globalColorTable[:e.globalCT])
+	} else {
+		// All frames have a local color table, so a global color table
+		// is not needed.
+		e.buf[0] = 0x00
+		e.buf[1] = 0x00 // Background Color Index.
+		e.buf[2] = 0x00 // Pixel Aspect Ratio.
+		e.write(e.buf[:3])
+	}
 
 	// Add animation info if necessary.
 	if len(e.g.Image) > 1 {
@@ -147,28 +161,25 @@
 	}
 }
 
-func (e *encoder) writeColorTable(p color.Palette, size int) {
-	if e.err != nil {
-		return
-	}
-
-	for i := 0; i < log2Lookup[size]; i++ {
+func encodeColorTable(dst []byte, p color.Palette, size int) int {
+	n := log2Lookup[size]
+	for i := 0; i < n; i++ {
 		if i < len(p) {
 			r, g, b, _ := p[i].RGBA()
-			e.buf[3*i+0] = uint8(r >> 8)
-			e.buf[3*i+1] = uint8(g >> 8)
-			e.buf[3*i+2] = uint8(b >> 8)
+			dst[3*i+0] = uint8(r >> 8)
+			dst[3*i+1] = uint8(g >> 8)
+			dst[3*i+2] = uint8(b >> 8)
 		} else {
 			// Pad with black.
-			e.buf[3*i+0] = 0x00
-			e.buf[3*i+1] = 0x00
-			e.buf[3*i+2] = 0x00
+			dst[3*i+0] = 0x00
+			dst[3*i+1] = 0x00
+			dst[3*i+2] = 0x00
 		}
 	}
-	e.write(e.buf[:3*log2Lookup[size]])
+	return 3 * n
 }
 
-func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
+func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
 	if e.err != nil {
 		return
 	}
@@ -179,10 +190,14 @@
 	}
 
 	b := pm.Bounds()
-	if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 {
+	if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 {
 		e.err = errors.New("gif: image block is too large to encode")
 		return
 	}
+	if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) {
+		e.err = errors.New("gif: image block is out of bounds")
+		return
+	}
 
 	transparentIndex := -1
 	for i, c := range pm.Palette {
@@ -192,14 +207,14 @@
 		}
 	}
 
-	if delay > 0 || transparentIndex != -1 {
+	if delay > 0 || disposal != 0 || transparentIndex != -1 {
 		e.buf[0] = sExtension  // Extension Introducer.
 		e.buf[1] = gcLabel     // Graphic Control Label.
 		e.buf[2] = gcBlockSize // Block Size.
 		if transparentIndex != -1 {
-			e.buf[3] = 0x01
+			e.buf[3] = 0x01 | disposal<<2
 		} else {
-			e.buf[3] = 0x00
+			e.buf[3] = 0x00 | disposal<<2
 		}
 		writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second)
 
@@ -220,11 +235,15 @@
 	e.write(e.buf[:9])
 
 	paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
-	// Interlacing is not supported.
-	e.writeByte(0x80 | uint8(paddedSize))
-
-	// Local Color Table.
-	e.writeColorTable(pm.Palette, paddedSize)
+	ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
+	if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
+		// Use a local color table.
+		e.writeByte(fColorTable | uint8(paddedSize))
+		e.write(e.localColorTable[:ct])
+	} else {
+		// Use the global color table.
+		e.writeByte(0)
+	}
 
 	litWidth := paddedSize + 1
 	if litWidth < 2 {
@@ -281,7 +300,23 @@
 		g.LoopCount = 0
 	}
 
-	e := encoder{g: g}
+	e := encoder{g: *g}
+	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
+	// in Go 1.5. Valid Go 1.4 code, such as when the Disposal field is omitted
+	// in a GIF struct literal, should still produce valid GIFs.
+	if e.g.Disposal != nil && len(e.g.Image) != len(e.g.Disposal) {
+		return errors.New("gif: mismatched image and disposal lengths")
+	}
+	if e.g.Config == (image.Config{}) {
+		p := g.Image[0].Bounds().Max
+		e.g.Config.Width = p.X
+		e.g.Config.Height = p.Y
+	} else if e.g.Config.ColorModel != nil {
+		if _, ok := e.g.Config.ColorModel.(color.Palette); !ok {
+			return errors.New("gif: GIF color model must be a color.Palette")
+		}
+	}
+
 	if ww, ok := w.(writer); ok {
 		e.w = ww
 	} else {
@@ -290,7 +325,11 @@
 
 	e.writeHeader()
 	for i, pm := range g.Image {
-		e.writeImageBlock(pm, g.Delay[i])
+		disposal := uint8(0)
+		if g.Disposal != nil {
+			disposal = g.Disposal[i]
+		}
+		e.writeImageBlock(pm, g.Delay[i], disposal)
 	}
 	e.writeByte(sTrailer)
 	e.flush()
@@ -326,8 +365,22 @@
 		opts.Drawer.Draw(pm, b, m, image.ZP)
 	}
 
+	// When calling Encode instead of EncodeAll, the single-frame image is
+	// translated such that its top-left corner is (0, 0), so that the single
+	// frame completely fills the overall GIF's bounds.
+	if pm.Rect.Min != (image.Point{}) {
+		dup := *pm
+		dup.Rect = dup.Rect.Sub(dup.Rect.Min)
+		pm = &dup
+	}
+
 	return EncodeAll(w, &GIF{
 		Image: []*image.Paletted{pm},
 		Delay: []int{0},
+		Config: image.Config{
+			ColorModel: pm.Palette,
+			Width:      b.Dx(),
+			Height:     b.Dy(),
+		},
 	})
 }
diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go
index 93306ff..db61a5c 100644
--- a/src/image/gif/writer_test.go
+++ b/src/image/gif/writer_test.go
@@ -8,10 +8,12 @@
 	"bytes"
 	"image"
 	"image/color"
+	"image/color/palette"
 	_ "image/png"
 	"io/ioutil"
 	"math/rand"
 	"os"
+	"reflect"
 	"testing"
 )
 
@@ -125,55 +127,317 @@
 	}
 }
 
+// palettesEqual reports whether two color.Palette values are equal, ignoring
+// any trailing opaque-black palette entries.
+func palettesEqual(p, q color.Palette) bool {
+	n := len(p)
+	if n > len(q) {
+		n = len(q)
+	}
+	for i := 0; i < n; i++ {
+		if p[i] != q[i] {
+			return false
+		}
+	}
+	for i := n; i < len(p); i++ {
+		r, g, b, a := p[i].RGBA()
+		if r != 0 || g != 0 || b != 0 || a != 0xffff {
+			return false
+		}
+	}
+	for i := n; i < len(q); i++ {
+		r, g, b, a := q[i].RGBA()
+		if r != 0 || g != 0 || b != 0 || a != 0xffff {
+			return false
+		}
+	}
+	return true
+}
+
 var frames = []string{
 	"../testdata/video-001.gif",
 	"../testdata/video-005.gray.gif",
 }
 
-func TestEncodeAll(t *testing.T) {
+func testEncodeAll(t *testing.T, go1Dot5Fields bool, useGlobalColorModel bool) {
+	const width, height = 150, 103
+
 	g0 := &GIF{
 		Image:     make([]*image.Paletted, len(frames)),
 		Delay:     make([]int, len(frames)),
 		LoopCount: 5,
 	}
 	for i, f := range frames {
-		m, err := readGIF(f)
+		g, err := readGIF(f)
 		if err != nil {
 			t.Fatal(f, err)
 		}
-		g0.Image[i] = m.Image[0]
+		m := g.Image[0]
+		if m.Bounds().Dx() != width || m.Bounds().Dy() != height {
+			t.Fatalf("frame %d had unexpected bounds: got %v, want width/height = %d/%d",
+				i, m.Bounds(), width, height)
+		}
+		g0.Image[i] = m
 	}
+	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
+	// in Go 1.5. Valid Go 1.4 or earlier code should still produce valid GIFs.
+	//
+	// On the following line, color.Model is an interface type, and
+	// color.Palette is a concrete (slice) type.
+	globalColorModel, backgroundIndex := color.Model(color.Palette(nil)), uint8(0)
+	if useGlobalColorModel {
+		globalColorModel, backgroundIndex = color.Palette(palette.WebSafe), uint8(1)
+	}
+	if go1Dot5Fields {
+		g0.Disposal = make([]byte, len(g0.Image))
+		for i := range g0.Disposal {
+			g0.Disposal[i] = DisposalNone
+		}
+		g0.Config = image.Config{
+			ColorModel: globalColorModel,
+			Width:      width,
+			Height:     height,
+		}
+		g0.BackgroundIndex = backgroundIndex
+	}
+
 	var buf bytes.Buffer
 	if err := EncodeAll(&buf, g0); err != nil {
 		t.Fatal("EncodeAll:", err)
 	}
-	g1, err := DecodeAll(&buf)
+	encoded := buf.Bytes()
+	config, err := DecodeConfig(bytes.NewReader(encoded))
+	if err != nil {
+		t.Fatal("DecodeConfig:", err)
+	}
+	g1, err := DecodeAll(bytes.NewReader(encoded))
 	if err != nil {
 		t.Fatal("DecodeAll:", err)
 	}
+
+	if !reflect.DeepEqual(config, g1.Config) {
+		t.Errorf("DecodeConfig inconsistent with DecodeAll")
+	}
+	if !palettesEqual(g1.Config.ColorModel.(color.Palette), globalColorModel.(color.Palette)) {
+		t.Errorf("unexpected global color model")
+	}
+	if w, h := g1.Config.Width, g1.Config.Height; w != width || h != height {
+		t.Errorf("got config width * height = %d * %d, want %d * %d", w, h, width, height)
+	}
+
 	if g0.LoopCount != g1.LoopCount {
 		t.Errorf("loop counts differ: %d and %d", g0.LoopCount, g1.LoopCount)
 	}
+	if backgroundIndex != g1.BackgroundIndex {
+		t.Errorf("background indexes differ: %d and %d", backgroundIndex, g1.BackgroundIndex)
+	}
+	if len(g0.Image) != len(g1.Image) {
+		t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
+	}
+	if len(g1.Image) != len(g1.Delay) {
+		t.Fatalf("image and delay lengths differ: %d and %d", len(g1.Image), len(g1.Delay))
+	}
+	if len(g1.Image) != len(g1.Disposal) {
+		t.Fatalf("image and disposal lengths differ: %d and %d", len(g1.Image), len(g1.Disposal))
+	}
+
 	for i := range g0.Image {
 		m0, m1 := g0.Image[i], g1.Image[i]
 		if m0.Bounds() != m1.Bounds() {
-			t.Errorf("%s, bounds differ: %v and %v", frames[i], m0.Bounds(), m1.Bounds())
+			t.Errorf("frame %d: bounds differ: %v and %v", i, m0.Bounds(), m1.Bounds())
 		}
 		d0, d1 := g0.Delay[i], g1.Delay[i]
 		if d0 != d1 {
-			t.Errorf("%s: delay values differ: %d and %d", frames[i], d0, d1)
+			t.Errorf("frame %d: delay values differ: %d and %d", i, d0, d1)
+		}
+		p0, p1 := uint8(0), g1.Disposal[i]
+		if go1Dot5Fields {
+			p0 = DisposalNone
+		}
+		if p0 != p1 {
+			t.Errorf("frame %d: disposal values differ: %d and %d", i, p0, p1)
 		}
 	}
+}
 
-	g1.Delay = make([]int, 1)
-	if err := EncodeAll(ioutil.Discard, g1); err == nil {
+func TestEncodeAllGo1Dot4(t *testing.T)                 { testEncodeAll(t, false, false) }
+func TestEncodeAllGo1Dot5(t *testing.T)                 { testEncodeAll(t, true, false) }
+func TestEncodeAllGo1Dot5GlobalColorModel(t *testing.T) { testEncodeAll(t, true, true) }
+
+func TestEncodeMismatchDelay(t *testing.T) {
+	images := make([]*image.Paletted, 2)
+	for i := range images {
+		images[i] = image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9)
+	}
+
+	g0 := &GIF{
+		Image: images,
+		Delay: make([]int, 1),
+	}
+	if err := EncodeAll(ioutil.Discard, g0); err == nil {
 		t.Error("expected error from mismatched delay and image slice lengths")
 	}
+
+	g1 := &GIF{
+		Image:    images,
+		Delay:    make([]int, len(images)),
+		Disposal: make([]byte, 1),
+	}
+	for i := range g1.Disposal {
+		g1.Disposal[i] = DisposalNone
+	}
+	if err := EncodeAll(ioutil.Discard, g1); err == nil {
+		t.Error("expected error from mismatched disposal and image slice lengths")
+	}
+}
+
+func TestEncodeZeroGIF(t *testing.T) {
 	if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil {
 		t.Error("expected error from providing empty gif")
 	}
 }
 
+func TestEncodeAllFramesOutOfBounds(t *testing.T) {
+	images := []*image.Paletted{
+		image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9),
+		image.NewPaletted(image.Rect(2, 2, 8, 8), palette.Plan9),
+		image.NewPaletted(image.Rect(3, 3, 4, 4), palette.Plan9),
+	}
+	for _, upperBound := range []int{6, 10} {
+		g := &GIF{
+			Image:    images,
+			Delay:    make([]int, len(images)),
+			Disposal: make([]byte, len(images)),
+			Config: image.Config{
+				Width:  upperBound,
+				Height: upperBound,
+			},
+		}
+		err := EncodeAll(ioutil.Discard, g)
+		if upperBound >= 8 {
+			if err != nil {
+				t.Errorf("upperBound=%d: %v", upperBound, err)
+			}
+		} else {
+			if err == nil {
+				t.Errorf("upperBound=%d: got nil error, want non-nil", upperBound)
+			}
+		}
+	}
+}
+
+func TestEncodeNonZeroMinPoint(t *testing.T) {
+	points := []image.Point{
+		image.Point{-8, -9},
+		image.Point{-4, -4},
+		image.Point{-3, +3},
+		image.Point{+0, +0},
+		image.Point{+2, +2},
+	}
+	for _, p := range points {
+		src := image.NewPaletted(image.Rectangle{Min: p, Max: p.Add(image.Point{6, 6})}, palette.Plan9)
+		var buf bytes.Buffer
+		if err := Encode(&buf, src, nil); err != nil {
+			t.Errorf("p=%v: Encode: %v", p, err)
+			continue
+		}
+		m, err := Decode(&buf)
+		if err != nil {
+			t.Errorf("p=%v: Decode: %v", p, err)
+			continue
+		}
+		if got, want := m.Bounds(), image.Rect(0, 0, 6, 6); got != want {
+			t.Errorf("p=%v: got %v, want %v", p, got, want)
+		}
+	}
+}
+
+func TestEncodeImplicitConfigSize(t *testing.T) {
+	// For backwards compatibility for Go 1.4 and earlier code, the Config
+	// field is optional, and if zero, the width and height is implied by the
+	// first (and in this case only) frame's width and height.
+	//
+	// A Config only specifies a width and height (two integers) while an
+	// image.Image's Bounds method returns an image.Rectangle (four integers).
+	// For a gif.GIF, the overall bounds' top-left point is always implicitly
+	// (0, 0), and any frame whose bounds have a negative X or Y will be
+	// outside those overall bounds, so encoding should fail.
+	for _, lowerBound := range []int{-1, 0, 1} {
+		images := []*image.Paletted{
+			image.NewPaletted(image.Rect(lowerBound, lowerBound, 4, 4), palette.Plan9),
+		}
+		g := &GIF{
+			Image: images,
+			Delay: make([]int, len(images)),
+		}
+		err := EncodeAll(ioutil.Discard, g)
+		if lowerBound >= 0 {
+			if err != nil {
+				t.Errorf("lowerBound=%d: %v", lowerBound, err)
+			}
+		} else {
+			if err == nil {
+				t.Errorf("lowerBound=%d: got nil error, want non-nil", lowerBound)
+			}
+		}
+	}
+}
+
+func TestEncodePalettes(t *testing.T) {
+	const w, h = 5, 5
+	pals := []color.Palette{{
+		color.RGBA{0x00, 0x00, 0x00, 0xff},
+		color.RGBA{0x01, 0x00, 0x00, 0xff},
+		color.RGBA{0x02, 0x00, 0x00, 0xff},
+	}, {
+		color.RGBA{0x00, 0x00, 0x00, 0xff},
+		color.RGBA{0x00, 0x01, 0x00, 0xff},
+	}, {
+		color.RGBA{0x00, 0x00, 0x03, 0xff},
+		color.RGBA{0x00, 0x00, 0x02, 0xff},
+		color.RGBA{0x00, 0x00, 0x01, 0xff},
+		color.RGBA{0x00, 0x00, 0x00, 0xff},
+	}, {
+		color.RGBA{0x10, 0x07, 0xf0, 0xff},
+		color.RGBA{0x20, 0x07, 0xf0, 0xff},
+		color.RGBA{0x30, 0x07, 0xf0, 0xff},
+		color.RGBA{0x40, 0x07, 0xf0, 0xff},
+		color.RGBA{0x50, 0x07, 0xf0, 0xff},
+	}}
+	g0 := &GIF{
+		Image: []*image.Paletted{
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[0]),
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[1]),
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[2]),
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[3]),
+		},
+		Delay:    make([]int, len(pals)),
+		Disposal: make([]byte, len(pals)),
+		Config: image.Config{
+			ColorModel: pals[2],
+			Width:      w,
+			Height:     h,
+		},
+	}
+
+	var buf bytes.Buffer
+	if err := EncodeAll(&buf, g0); err != nil {
+		t.Fatalf("EncodeAll: %v", err)
+	}
+	g1, err := DecodeAll(&buf)
+	if err != nil {
+		t.Fatalf("DecodeAll: %v", err)
+	}
+	if len(g0.Image) != len(g1.Image) {
+		t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
+	}
+	for i, m := range g1.Image {
+		if got, want := m.Palette, pals[i]; !palettesEqual(got, want) {
+			t.Errorf("frame %d:\ngot  %v\nwant %v", i, got, want)
+		}
+	}
+}
+
 func BenchmarkEncode(b *testing.B) {
 	b.StopTimer()
 
diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go
index cde05ad..6779b49 100644
--- a/src/image/internal/imageutil/gen.go
+++ b/src/image/internal/imageutil/gen.go
@@ -54,7 +54,7 @@
 // successful. If it returns false, no dst pixels were changed.
 //
 // This function assumes that r is entirely within dst's bounds and the
-// translation of r from dst co-ordinate space to src co-ordinate space is
+// translation of r from dst coordinate space to src coordinate space is
 // entirely within src's bounds.
 func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
 	// This function exists in the image/internal/imageutil package because it
diff --git a/src/image/internal/imageutil/impl.go b/src/image/internal/imageutil/impl.go
index d4bd325..d5dee46 100644
--- a/src/image/internal/imageutil/impl.go
+++ b/src/image/internal/imageutil/impl.go
@@ -11,7 +11,7 @@
 // successful. If it returns false, no dst pixels were changed.
 //
 // This function assumes that r is entirely within dst's bounds and the
-// translation of r from dst co-ordinate space to src co-ordinate space is
+// translation of r from dst coordinate space to src coordinate space is
 // entirely within src's bounds.
 func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
 	// This function exists in the image/internal/imageutil package because it
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index 6a86472..7729532 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -170,7 +170,7 @@
 // can happen when expecting to read a 0xff 0x00 byte-stuffed byte.
 func (d *decoder) unreadByteStuffedByte() {
 	if d.bytes.nUnreadable == 0 {
-		panic("jpeg: unreadByteStuffedByte call cannot be fulfilled")
+		return
 	}
 	d.bytes.i -= d.bytes.nUnreadable
 	d.bytes.nUnreadable = 0
@@ -217,18 +217,19 @@
 		return 0xff, nil
 	}
 
+	d.bytes.nUnreadable = 0
+
 	x, err = d.readByte()
 	if err != nil {
 		return 0, err
 	}
+	d.bytes.nUnreadable = 1
 	if x != 0xff {
-		d.bytes.nUnreadable = 1
 		return x, nil
 	}
 
 	x, err = d.readByte()
 	if err != nil {
-		d.bytes.nUnreadable = 1
 		return 0, err
 	}
 	d.bytes.nUnreadable = 2
@@ -242,12 +243,7 @@
 // stuffing.
 func (d *decoder) readFull(p []byte) error {
 	// Unread the overshot bytes, if any.
-	if d.bytes.nUnreadable != 0 {
-		if d.bits.n >= 8 {
-			d.unreadByteStuffedByte()
-		}
-		d.bytes.nUnreadable = 0
-	}
+	d.unreadByteStuffedByte()
 
 	for {
 		n := copy(p, d.bytes.buf[d.bytes.i:d.bytes.j])
@@ -269,12 +265,7 @@
 // ignore ignores the next n bytes.
 func (d *decoder) ignore(n int) error {
 	// Unread the overshot bytes, if any.
-	if d.bytes.nUnreadable != 0 {
-		if d.bits.n >= 8 {
-			d.unreadByteStuffedByte()
-		}
-		d.bytes.nUnreadable = 0
-	}
+	d.unreadByteStuffedByte()
 
 	for {
 		m := d.bytes.j - d.bytes.i
@@ -298,6 +289,9 @@
 
 // Specified in section B.2.2.
 func (d *decoder) processSOF(n int) error {
+	if d.nComp != 0 {
+		return FormatError("multiple SOF markers")
+	}
 	switch n {
 	case 6 + 3*1: // Grayscale image.
 		d.nComp = 1
diff --git a/src/image/jpeg/reader_test.go b/src/image/jpeg/reader_test.go
index c5a36cb..7737615 100644
--- a/src/image/jpeg/reader_test.go
+++ b/src/image/jpeg/reader_test.go
@@ -15,6 +15,7 @@
 	"os"
 	"strings"
 	"testing"
+	"time"
 )
 
 // TestDecodeProgressive tests that decoding the baseline and progressive
@@ -186,6 +187,81 @@
 	return s.String()
 }
 
+func TestTruncatedSOSDataDoesntPanic(t *testing.T) {
+	b, err := ioutil.ReadFile("../testdata/video-005.gray.q50.jpeg")
+	if err != nil {
+		t.Fatal(err)
+	}
+	sosMarker := []byte{0xff, 0xda}
+	i := bytes.Index(b, sosMarker)
+	if i < 0 {
+		t.Fatal("SOS marker not found")
+	}
+	i += len(sosMarker)
+	j := i + 10
+	if j > len(b) {
+		j = len(b)
+	}
+	for ; i < j; i++ {
+		Decode(bytes.NewReader(b[:i]))
+	}
+}
+
+func TestLargeImageWithShortData(t *testing.T) {
+	// This input is an invalid JPEG image, based on the fuzzer-generated image
+	// in issue 10413. It is only 504 bytes, and shouldn't take long for Decode
+	// to return an error. The Start Of Frame marker gives the image dimensions
+	// as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug
+	// doesn't technically lead to an infinite loop, such a bug can still cause
+	// an unreasonably long loop for such a short input.
+	const input = "" +
+		"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" +
+		"\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" +
+		"\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" +
+		"\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" +
+		"\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" +
+		"\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" +
+		"\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" +
+		"\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" +
+		"\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" +
+		"\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" +
+		"\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" +
+		"\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" +
+		"\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" +
+		"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" +
+		"\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" +
+		"\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" +
+		"\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" +
+		"\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" +
+		"\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" +
+		"\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" +
+		"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" +
+		"\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" +
+		"\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" +
+		"\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" +
+		"\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" +
+		"\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" +
+		"\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" +
+		"\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" +
+		"\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" +
+		"\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" +
+		"\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" +
+		"\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9"
+	c := make(chan error, 1)
+	go func() {
+		_, err := Decode(strings.NewReader(input))
+		c <- err
+	}()
+	select {
+	case err := <-c:
+		if err == nil {
+			t.Fatalf("got nil error, want non-nil")
+		}
+	case <-time.After(3 * time.Second):
+		t.Fatalf("timed out")
+	}
+}
+
 func TestExtraneousData(t *testing.T) {
 	// Encode a 1x1 red image.
 	src := image.NewRGBA(image.Rect(0, 0, 1, 1))
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 0a40ca1..33218e1 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -47,6 +47,10 @@
 	cbTCA16
 )
 
+func cbPaletted(cb int) bool {
+	return cbP1 <= cb && cb <= cbP8
+}
+
 // Filter type, as per the PNG spec.
 const (
 	ftNone    = 0
@@ -81,15 +85,16 @@
 }
 
 // Decoding stage.
-// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
-// chunks must appear in that order. There may be multiple IDAT chunks, and
-// IDAT chunks must be sequential (i.e. they may not have any other chunks
-// between them).
+// The PNG specification says that the IHDR, PLTE (if present), tRNS (if
+// present), IDAT and IEND chunks must appear in that order. There may be
+// multiple IDAT chunks, and IDAT chunks must be sequential (i.e. they may not
+// have any other chunks between them).
 // http://www.w3.org/TR/PNG/#5ChunkOrdering
 const (
 	dsStart = iota
 	dsSeenIHDR
 	dsSeenPLTE
+	dsSeentRNS
 	dsSeenIDAT
 	dsSeenIEND
 )
@@ -321,9 +326,15 @@
 	var img image.Image
 	if d.interlace == itNone {
 		img, err = d.readImagePass(r, 0, false)
+		if err != nil {
+			return nil, err
+		}
 	} else if d.interlace == itAdam7 {
 		// Allocate a blank image of the full size.
 		img, err = d.readImagePass(nil, 0, true)
+		if err != nil {
+			return nil, err
+		}
 		for pass := 0; pass < 7; pass++ {
 			imagePass, err := d.readImagePass(r, pass, false)
 			if err != nil {
@@ -425,6 +436,9 @@
 		// Read the decompressed bytes.
 		_, err := io.ReadFull(r, cr)
 		if err != nil {
+			if err == io.EOF || err == io.ErrUnexpectedEOF {
+				return nil, FormatError("not enough pixel data")
+			}
 			return nil, err
 		}
 
@@ -687,9 +701,10 @@
 		if d.stage != dsSeenPLTE {
 			return chunkOrderError
 		}
+		d.stage = dsSeentRNS
 		return d.parsetRNS(length)
 	case "IDAT":
-		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
+		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
 			return chunkOrderError
 		}
 		d.stage = dsSeenIDAT
@@ -779,7 +794,7 @@
 			}
 			return image.Config{}, err
 		}
-		paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1
+		paletted := cbPaletted(d.cb)
 		if d.stage == dsSeenIHDR && !paletted {
 			break
 		}
diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go
index ce772eb..1f92f8c 100644
--- a/src/image/png/reader_test.go
+++ b/src/image/png/reader_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"bufio"
+	"bytes"
 	"fmt"
 	"image"
 	"image/color"
@@ -319,6 +320,79 @@
 	}
 }
 
+func TestIncompleteIDATOnRowBoundary(t *testing.T) {
+	// The following is an invalid 1x2 grayscale PNG image. The header is OK,
+	// but the zlib-compressed IDAT payload contains two bytes "\x02\x00",
+	// which is only one row of data (the leading "\x02" is a row filter).
+	const (
+		ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb"
+		idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+		iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+	)
+	_, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend))
+	if err == nil {
+		t.Fatal("got nil error, want non-nil")
+	}
+}
+
+func TestMultipletRNSChunks(t *testing.T) {
+	/*
+		The following is a valid 1x1 paletted PNG image with a 1-element palette
+		containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}:
+			0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
+			0000010: 0000 0001 0000 0001 0803 0000 0028 cb34  .............(.4
+			0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937  .....PLTE......7
+			0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000  ....tRNS..\.....
+			0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00  .IDATx.bb.......
+			0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae  .....Y.....IEND.
+			0000060: 4260 82                                  B`.
+		Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f.
+	*/
+	const (
+		ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb"
+		plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37"
+		trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb"
+		idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+		iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+	)
+	for i := 0; i < 4; i++ {
+		var b []byte
+		b = append(b, pngHeader...)
+		b = append(b, ihdr...)
+		b = append(b, plte...)
+		for j := 0; j < i; j++ {
+			b = append(b, trns...)
+		}
+		b = append(b, idat...)
+		b = append(b, iend...)
+
+		var want color.Color
+		m, err := Decode(bytes.NewReader(b))
+		switch i {
+		case 0:
+			if err != nil {
+				t.Errorf("%d tRNS chunks: %v", i, err)
+				continue
+			}
+			want = color.RGBA{0xff, 0x00, 0x00, 0xff}
+		case 1:
+			if err != nil {
+				t.Errorf("%d tRNS chunks: %v", i, err)
+				continue
+			}
+			want = color.NRGBA{0xff, 0x00, 0x00, 0x7f}
+		default:
+			if err == nil {
+				t.Errorf("%d tRNS chunks: got nil error, want non-nil", i)
+			}
+			continue
+		}
+		if got := m.At(0, 0); got != want {
+			t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want)
+		}
+	}
+}
+
 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
 	b.StopTimer()
 	data, err := ioutil.ReadFile(filename)
diff --git a/src/net/singleflight.go b/src/internal/singleflight/singleflight.go
similarity index 72%
rename from src/net/singleflight.go
rename to src/internal/singleflight/singleflight.go
index bf599f0..f4cb2d6 100644
--- a/src/net/singleflight.go
+++ b/src/internal/singleflight/singleflight.go
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package net
+// Package singleflight provides a duplicate function call suppression
+// mechanism.
+package singleflight
 
 import "sync"
 
@@ -19,22 +21,22 @@
 	// mutex held before the WaitGroup is done, and are read but
 	// not written after the WaitGroup is done.
 	dups  int
-	chans []chan<- singleflightResult
+	chans []chan<- Result
 }
 
-// singleflight represents a class of work and forms a namespace in
+// Group represents a class of work and forms a namespace in
 // which units of work can be executed with duplicate suppression.
-type singleflight struct {
+type Group struct {
 	mu sync.Mutex       // protects m
 	m  map[string]*call // lazily initialized
 }
 
-// singleflightResult holds the results of Do, so they can be passed
+// Result holds the results of Do, so they can be passed
 // on a channel.
-type singleflightResult struct {
-	v      interface{}
-	err    error
-	shared bool
+type Result struct {
+	Val    interface{}
+	Err    error
+	Shared bool
 }
 
 // Do executes and returns the results of the given function, making
@@ -42,7 +44,7 @@
 // time. If a duplicate comes in, the duplicate caller waits for the
 // original to complete and receives the same results.
 // The return value shared indicates whether v was given to multiple callers.
-func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
+func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
 	g.mu.Lock()
 	if g.m == nil {
 		g.m = make(map[string]*call)
@@ -64,8 +66,8 @@
 
 // DoChan is like Do but returns a channel that will receive the
 // results when they are ready.
-func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult {
-	ch := make(chan singleflightResult, 1)
+func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
+	ch := make(chan Result, 1)
 	g.mu.Lock()
 	if g.m == nil {
 		g.m = make(map[string]*call)
@@ -76,7 +78,7 @@
 		g.mu.Unlock()
 		return ch
 	}
-	c := &call{chans: []chan<- singleflightResult{ch}}
+	c := &call{chans: []chan<- Result{ch}}
 	c.wg.Add(1)
 	g.m[key] = c
 	g.mu.Unlock()
@@ -87,14 +89,14 @@
 }
 
 // doCall handles the single call for a key.
-func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) {
+func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
 	c.val, c.err = fn()
 	c.wg.Done()
 
 	g.mu.Lock()
 	delete(g.m, key)
 	for _, ch := range c.chans {
-		ch <- singleflightResult{c.val, c.err, c.dups > 0}
+		ch <- Result{c.val, c.err, c.dups > 0}
 	}
 	g.mu.Unlock()
 }
@@ -102,7 +104,7 @@
 // Forget tells the singleflight to forget about a key.  Future calls
 // to Do for this key will call the function rather than waiting for
 // an earlier call to complete.
-func (g *singleflight) Forget(key string) {
+func (g *Group) Forget(key string) {
 	g.mu.Lock()
 	delete(g.m, key)
 	g.mu.Unlock()
diff --git a/src/internal/singleflight/singleflight_test.go b/src/internal/singleflight/singleflight_test.go
new file mode 100644
index 0000000..30ba7f7
--- /dev/null
+++ b/src/internal/singleflight/singleflight_test.go
@@ -0,0 +1,73 @@
+// Copyright 2013 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 singleflight
+
+import (
+	"errors"
+	"fmt"
+	"sync"
+	"sync/atomic"
+	"testing"
+	"time"
+)
+
+func TestDo(t *testing.T) {
+	var g Group
+	v, err, _ := g.Do("key", func() (interface{}, error) {
+		return "bar", nil
+	})
+	if got, want := fmt.Sprintf("%v (%T)", v, v), "bar (string)"; got != want {
+		t.Errorf("Do = %v; want %v", got, want)
+	}
+	if err != nil {
+		t.Errorf("Do error = %v", err)
+	}
+}
+
+func TestDoErr(t *testing.T) {
+	var g Group
+	someErr := errors.New("Some error")
+	v, err, _ := g.Do("key", func() (interface{}, error) {
+		return nil, someErr
+	})
+	if err != someErr {
+		t.Errorf("Do error = %v; want someErr %v", err, someErr)
+	}
+	if v != nil {
+		t.Errorf("unexpected non-nil value %#v", v)
+	}
+}
+
+func TestDoDupSuppress(t *testing.T) {
+	var g Group
+	c := make(chan string)
+	var calls int32
+	fn := func() (interface{}, error) {
+		atomic.AddInt32(&calls, 1)
+		return <-c, nil
+	}
+
+	const n = 10
+	var wg sync.WaitGroup
+	for i := 0; i < n; i++ {
+		wg.Add(1)
+		go func() {
+			v, err, _ := g.Do("key", fn)
+			if err != nil {
+				t.Errorf("Do error: %v", err)
+			}
+			if v.(string) != "bar" {
+				t.Errorf("got %q; want %q", v, "bar")
+			}
+			wg.Done()
+		}()
+	}
+	time.Sleep(100 * time.Millisecond) // let goroutines above block
+	c <- "bar"
+	wg.Wait()
+	if got := atomic.LoadInt32(&calls); got != 1 {
+		t.Errorf("number of calls = %d; want 1", got)
+	}
+}
diff --git a/src/internal/syscall/getrandom_linux.go b/src/internal/syscall/unix/getrandom_linux.go
similarity index 87%
rename from src/internal/syscall/getrandom_linux.go
rename to src/internal/syscall/unix/getrandom_linux.go
index 36d5a1c..7388271 100644
--- a/src/internal/syscall/getrandom_linux.go
+++ b/src/internal/syscall/unix/getrandom_linux.go
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package syscall
+package unix
 
 import (
 	"runtime"
 	"sync/atomic"
-	stdsyscall "syscall"
+	"syscall"
 	"unsafe"
 )
 
@@ -36,20 +36,20 @@
 // See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895
 func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
 	if randomTrap == 0 {
-		return 0, stdsyscall.ENOSYS
+		return 0, syscall.ENOSYS
 	}
 	if len(p) == 0 {
 		return 0, nil
 	}
 	if atomic.LoadInt32(&randomUnsupported) != 0 {
-		return 0, stdsyscall.ENOSYS
+		return 0, syscall.ENOSYS
 	}
-	r1, _, errno := stdsyscall.Syscall(randomTrap,
+	r1, _, errno := syscall.Syscall(randomTrap,
 		uintptr(unsafe.Pointer(&p[0])),
 		uintptr(len(p)),
 		uintptr(flags))
 	if errno != 0 {
-		if errno == stdsyscall.ENOSYS {
+		if errno == syscall.ENOSYS {
 			atomic.StoreInt32(&randomUnsupported, 1)
 		}
 		return 0, errno
diff --git a/src/internal/syscall/windows/registry/key.go b/src/internal/syscall/windows/registry/key.go
new file mode 100644
index 0000000..62144d3
--- /dev/null
+++ b/src/internal/syscall/windows/registry/key.go
@@ -0,0 +1,175 @@
+// 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 provides access to the Windows registry.
+//
+// Here is a simple example, opening a registry key and reading a string value from it.
+//
+//	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
+//	if err != nil {
+//		log.Fatal(err)
+//	}
+//	defer k.Close()
+//
+//	s, _, err := k.GetStringValue("SystemRoot")
+//	if err != nil {
+//		log.Fatal(err)
+//	}
+//	fmt.Printf("Windows system root is %q\n", s)
+//
+// NOTE: This package is a copy of golang.org/x/sys/windows/registry
+// with KeyInfo.ModTime removed to prevent dependency cycles.
+//
+package registry
+
+import (
+	"io"
+	"syscall"
+)
+
+const (
+	// Registry key security and access rights.
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
+	// for details.
+	ALL_ACCESS         = 0xf003f
+	CREATE_LINK        = 0x00020
+	CREATE_SUB_KEY     = 0x00004
+	ENUMERATE_SUB_KEYS = 0x00008
+	EXECUTE            = 0x20019
+	NOTIFY             = 0x00010
+	QUERY_VALUE        = 0x00001
+	READ               = 0x20019
+	SET_VALUE          = 0x00002
+	WOW64_32KEY        = 0x00200
+	WOW64_64KEY        = 0x00100
+	WRITE              = 0x20006
+)
+
+// Key is a handle to an open Windows registry key.
+// Keys can be obtained by calling OpenKey; there are
+// also some predefined root keys such as CURRENT_USER.
+// Keys can be used directly in the Windows API.
+type Key syscall.Handle
+
+const (
+	// Windows defines some predefined root keys that are always open.
+	// An application can use these keys as entry points to the registry.
+	// Normally these keys are used in OpenKey to open new keys,
+	// but they can also be used anywhere a Key is required.
+	CLASSES_ROOT   = Key(syscall.HKEY_CLASSES_ROOT)
+	CURRENT_USER   = Key(syscall.HKEY_CURRENT_USER)
+	LOCAL_MACHINE  = Key(syscall.HKEY_LOCAL_MACHINE)
+	USERS          = Key(syscall.HKEY_USERS)
+	CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
+)
+
+// Close closes open key k.
+func (k Key) Close() error {
+	return syscall.RegCloseKey(syscall.Handle(k))
+}
+
+// OpenKey opens a new key with path name relative to key k.
+// It accepts any open key, including CURRENT_USER and others,
+// and returns the new key and an error.
+// The access parameter specifies desired access rights to the
+// key to be opened.
+func OpenKey(k Key, path string, access uint32) (Key, error) {
+	p, err := syscall.UTF16PtrFromString(path)
+	if err != nil {
+		return 0, err
+	}
+	var subkey syscall.Handle
+	err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
+	if err != nil {
+		return 0, err
+	}
+	return Key(subkey), nil
+}
+
+// ReadSubKeyNames returns the names of subkeys of key k.
+// The parameter n controls the number of returned names,
+// analogous to the way os.File.Readdirnames works.
+func (k Key) ReadSubKeyNames(n int) ([]string, error) {
+	ki, err := k.Stat()
+	if err != nil {
+		return nil, err
+	}
+	names := make([]string, 0, ki.SubKeyCount)
+	buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte
+loopItems:
+	for i := uint32(0); ; i++ {
+		if n > 0 {
+			if len(names) == n {
+				return names, nil
+			}
+		}
+		l := uint32(len(buf))
+		for {
+			err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
+			if err == nil {
+				break
+			}
+			if err == syscall.ERROR_MORE_DATA {
+				// Double buffer size and try again.
+				l = uint32(2 * len(buf))
+				buf = make([]uint16, l)
+				continue
+			}
+			if err == _ERROR_NO_MORE_ITEMS {
+				break loopItems
+			}
+			return names, err
+		}
+		names = append(names, syscall.UTF16ToString(buf[:l]))
+	}
+	if n > len(names) {
+		return names, io.EOF
+	}
+	return names, nil
+}
+
+// CreateKey creates a key named path under open key k.
+// CreateKey returns the new key and a boolean flag that reports
+// whether the key already existed.
+// The access parameter specifies the access rights for the key
+// to be created.
+func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
+	var h syscall.Handle
+	var d uint32
+	err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
+		0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
+	if err != nil {
+		return 0, false, err
+	}
+	return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
+}
+
+// DeleteKey deletes the subkey path of key k and its values.
+func DeleteKey(k Key, path string) error {
+	return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
+}
+
+// A KeyInfo describes the statistics of a key. It is returned by Stat.
+type KeyInfo struct {
+	SubKeyCount     uint32
+	MaxSubKeyLen    uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
+	ValueCount      uint32
+	MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
+	MaxValueLen     uint32 // longest data component among the key's values, in bytes
+	lastWriteTime   syscall.Filetime
+}
+
+// Stat retrieves information about the open key k.
+func (k Key) Stat() (*KeyInfo, error) {
+	var ki KeyInfo
+	err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
+		&ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
+		&ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
+	if err != nil {
+		return nil, err
+	}
+	return &ki, nil
+}
diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go
new file mode 100644
index 0000000..5f75feb
--- /dev/null
+++ b/src/internal/syscall/windows/registry/registry_test.go
@@ -0,0 +1,613 @@
+// 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_test
+
+import (
+	"bytes"
+	"crypto/rand"
+	"os"
+	"syscall"
+	"testing"
+
+	"internal/syscall/windows/registry"
+)
+
+func randKeyName(prefix string) string {
+	const numbers = "0123456789"
+	buf := make([]byte, 10)
+	rand.Read(buf)
+	for i, b := range buf {
+		buf[i] = numbers[b%byte(len(numbers))]
+	}
+	return prefix + string(buf)
+}
+
+func TestReadSubKeyNames(t *testing.T) {
+	k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	names, err := k.ReadSubKeyNames(-1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var foundStdOle bool
+	for _, name := range names {
+		// Every PC has "stdole 2.0 OLE Automation" library installed.
+		if name == "{00020430-0000-0000-C000-000000000046}" {
+			foundStdOle = true
+		}
+	}
+	if !foundStdOle {
+		t.Fatal("could not find stdole 2.0 OLE Automation")
+	}
+}
+
+func TestCreateOpenDeleteKey(t *testing.T) {
+	k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	testKName := randKeyName("TestCreateOpenDeleteKey_")
+
+	testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testK.Close()
+
+	if exist {
+		t.Fatalf("key %q already exists", testKName)
+	}
+
+	testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testKAgain.Close()
+
+	if !exist {
+		t.Fatalf("key %q should already exist", testKName)
+	}
+
+	testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testKOpened.Close()
+
+	err = registry.DeleteKey(k, testKName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
+	if err == nil {
+		defer testKOpenedAgain.Close()
+		t.Fatalf("key %q should already been deleted", testKName)
+	}
+	if err != registry.ErrNotExist {
+		t.Fatalf(`unexpected error ("not exist" expected): %v`, err)
+	}
+}
+
+func equalStringSlice(a, b []string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	if a == nil {
+		return true
+	}
+	for i := range a {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+type ValueTest struct {
+	Type     uint32
+	Name     string
+	Value    interface{}
+	WillFail bool
+}
+
+var ValueTests = []ValueTest{
+	{Type: registry.SZ, Name: "String1", Value: ""},
+	{Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true},
+	{Type: registry.SZ, Name: "String3", Value: "Hello World"},
+	{Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true},
+	{Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""},
+	{Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true},
+	{Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"},
+	{Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true},
+	{Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"},
+	{Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"},
+	{Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."},
+	{Type: registry.BINARY, Name: "Binary1", Value: []byte{}},
+	{Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}},
+	{Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}},
+	{Type: registry.DWORD, Name: "Dword1", Value: uint64(0)},
+	{Type: registry.DWORD, Name: "Dword2", Value: uint64(1)},
+	{Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)},
+	{Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)},
+	{Type: registry.QWORD, Name: "Qword1", Value: uint64(0)},
+	{Type: registry.QWORD, Name: "Qword2", Value: uint64(1)},
+	{Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)},
+	{Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)},
+	{Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)},
+	{Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)},
+	{Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}},
+	{Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}},
+	{Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}},
+	{Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}},
+	{Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true},
+}
+
+func setValues(t *testing.T, k registry.Key) {
+	for _, test := range ValueTests {
+		var err error
+		switch test.Type {
+		case registry.SZ:
+			err = k.SetStringValue(test.Name, test.Value.(string))
+		case registry.EXPAND_SZ:
+			err = k.SetExpandStringValue(test.Name, test.Value.(string))
+		case registry.MULTI_SZ:
+			err = k.SetStringsValue(test.Name, test.Value.([]string))
+		case registry.BINARY:
+			err = k.SetBinaryValue(test.Name, test.Value.([]byte))
+		case registry.DWORD:
+			err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64)))
+		case registry.QWORD:
+			err = k.SetQWordValue(test.Name, test.Value.(uint64))
+		default:
+			t.Fatalf("unsupported type %d for %s value", test.Type, test.Name)
+		}
+		if test.WillFail {
+			if err == nil {
+				t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value)
+			}
+		} else {
+			if err != nil {
+				t.Fatal(err)
+			}
+		}
+	}
+}
+
+func enumerateValues(t *testing.T, k registry.Key) {
+	names, err := k.ReadValueNames(-1)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	haveNames := make(map[string]bool)
+	for _, n := range names {
+		haveNames[n] = false
+	}
+	for _, test := range ValueTests {
+		wantFound := !test.WillFail
+		_, haveFound := haveNames[test.Name]
+		if wantFound && !haveFound {
+			t.Errorf("value %s is not found while enumerating", test.Name)
+		}
+		if haveFound && !wantFound {
+			t.Errorf("value %s is found while enumerating, but expected to fail", test.Name)
+		}
+		if haveFound {
+			delete(haveNames, test.Name)
+		}
+	}
+	for n, v := range haveNames {
+		t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
+	}
+}
+
+func testErrNotExist(t *testing.T, name string, err error) {
+	if err == nil {
+		t.Errorf("%s value should not exist", name)
+		return
+	}
+	if err != registry.ErrNotExist {
+		t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err)
+		return
+	}
+}
+
+func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) {
+	if err == nil {
+		t.Errorf("GetXValue(%q) should not succeed", test.Name)
+		return
+	}
+	if err != registry.ErrUnexpectedType {
+		t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetStringValue(test.Name)
+	if err != nil {
+		t.Errorf("GetStringValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if got != test.Value {
+		t.Errorf("want %s value %q, got %q", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	if gottype == registry.EXPAND_SZ {
+		_, err = registry.ExpandString(got)
+		if err != nil {
+			t.Errorf("ExpandString(%s) failed: %v", got, err)
+			return
+		}
+	}
+}
+
+func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetIntegerValue(test.Name)
+	if err != nil {
+		t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if got != test.Value.(uint64) {
+		t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetBinaryValue(test.Name)
+	if err != nil {
+		t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if !bytes.Equal(got, test.Value.([]byte)) {
+		t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetStringsValue(test.Name)
+	if err != nil {
+		t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if !equalStringSlice(got, test.Value.([]string)) {
+		t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
+	if size <= 0 {
+		return
+	}
+	// read data with no buffer
+	gotsize, gottype, err := k.GetValue(test.Name, nil)
+	if err != nil {
+		t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
+		return
+	}
+	if gotsize != size {
+		t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	// read data with short buffer
+	gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1))
+	if err == nil {
+		t.Errorf("GetValue(%s, [%d]byte) should fail, but suceeded", test.Name, size-1)
+		return
+	}
+	if err != registry.ErrShortBuffer {
+		t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err)
+		return
+	}
+	if gotsize != size {
+		t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	// read full data
+	gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size))
+	if err != nil {
+		t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
+		return
+	}
+	if gotsize != size {
+		t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	// check GetValue returns ErrNotExist as required
+	_, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size))
+	if err == nil {
+		t.Errorf("GetValue(%q) should not succeed", test.Name)
+		return
+	}
+	if err != registry.ErrNotExist {
+		t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err)
+		return
+	}
+}
+
+func testValues(t *testing.T, k registry.Key) {
+	for _, test := range ValueTests {
+		switch test.Type {
+		case registry.SZ, registry.EXPAND_SZ:
+			if test.WillFail {
+				_, _, err := k.GetStringValue(test.Name)
+				testErrNotExist(t, test.Name, err)
+			} else {
+				testGetStringValue(t, k, test)
+				_, gottype, err := k.GetIntegerValue(test.Name)
+				testErrUnexpectedType(t, test, gottype, err)
+				// Size of utf16 string in bytes is not perfect,
+				// but correct for current test values.
+				// Size also includes terminating 0.
+				testGetValue(t, k, test, (len(test.Value.(string))+1)*2)
+			}
+			_, _, err := k.GetStringValue(test.Name + "_string_not_created")
+			testErrNotExist(t, test.Name+"_string_not_created", err)
+		case registry.DWORD, registry.QWORD:
+			testGetIntegerValue(t, k, test)
+			_, gottype, err := k.GetBinaryValue(test.Name)
+			testErrUnexpectedType(t, test, gottype, err)
+			_, _, err = k.GetIntegerValue(test.Name + "_int_not_created")
+			testErrNotExist(t, test.Name+"_int_not_created", err)
+			size := 8
+			if test.Type == registry.DWORD {
+				size = 4
+			}
+			testGetValue(t, k, test, size)
+		case registry.BINARY:
+			testGetBinaryValue(t, k, test)
+			_, gottype, err := k.GetStringsValue(test.Name)
+			testErrUnexpectedType(t, test, gottype, err)
+			_, _, err = k.GetBinaryValue(test.Name + "_byte_not_created")
+			testErrNotExist(t, test.Name+"_byte_not_created", err)
+			testGetValue(t, k, test, len(test.Value.([]byte)))
+		case registry.MULTI_SZ:
+			if test.WillFail {
+				_, _, err := k.GetStringsValue(test.Name)
+				testErrNotExist(t, test.Name, err)
+			} else {
+				testGetStringsValue(t, k, test)
+				_, gottype, err := k.GetStringValue(test.Name)
+				testErrUnexpectedType(t, test, gottype, err)
+				size := 0
+				for _, s := range test.Value.([]string) {
+					size += len(s) + 1 // nil terminated
+				}
+				size += 1 // extra nil at the end
+				size *= 2 // count bytes, not uint16
+				testGetValue(t, k, test, size)
+			}
+			_, _, err := k.GetStringsValue(test.Name + "_strings_not_created")
+			testErrNotExist(t, test.Name+"_strings_not_created", err)
+		default:
+			t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
+			continue
+		}
+	}
+}
+
+func testStat(t *testing.T, k registry.Key) {
+	subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	defer subk.Close()
+
+	defer registry.DeleteKey(k, "subkey")
+
+	ki, err := k.Stat()
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if ki.SubKeyCount != 1 {
+		t.Error("key must have 1 subkey")
+	}
+	if ki.MaxSubKeyLen != 6 {
+		t.Error("key max subkey name length must be 6")
+	}
+	if ki.ValueCount != 24 {
+		t.Errorf("key must have 24 values, but is %d", ki.ValueCount)
+	}
+	if ki.MaxValueNameLen != 12 {
+		t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen)
+	}
+	if ki.MaxValueLen != 38 {
+		t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen)
+	}
+}
+
+func deleteValues(t *testing.T, k registry.Key) {
+	for _, test := range ValueTests {
+		if test.WillFail {
+			continue
+		}
+		err := k.DeleteValue(test.Name)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+	}
+	names, err := k.ReadValueNames(-1)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if len(names) != 0 {
+		t.Errorf("some values remain after deletion: %v", names)
+	}
+}
+
+func TestValues(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("TestValues_")
+
+	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)
+
+	setValues(t, k)
+
+	enumerateValues(t, k)
+
+	testValues(t, k)
+
+	testStat(t, k)
+
+	deleteValues(t, k)
+}
+
+func walkKey(t *testing.T, k registry.Key, kname string) {
+	names, err := k.ReadValueNames(-1)
+	if err != nil {
+		t.Fatalf("reading value names of %s failed: %v", kname, err)
+	}
+	for _, name := range names {
+		_, valtype, err := k.GetValue(name, nil)
+		if err != nil {
+			t.Fatalf("reading value type of %s of %s failed: %v", name, kname, err)
+		}
+		switch valtype {
+		case registry.NONE:
+		case registry.SZ:
+			_, _, err := k.GetStringValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.EXPAND_SZ:
+			s, _, err := k.GetStringValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+			_, err = registry.ExpandString(s)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.DWORD, registry.QWORD:
+			_, _, err := k.GetIntegerValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.BINARY:
+			_, _, err := k.GetBinaryValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.MULTI_SZ:
+			_, _, err := k.GetStringsValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST:
+			// TODO: not implemented
+		default:
+			t.Fatalf("value type %d of %s of %s failed: %v", valtype, name, kname, err)
+		}
+	}
+
+	names, err = k.ReadSubKeyNames(-1)
+	if err != nil {
+		t.Fatalf("reading sub-keys of %s failed: %v", kname, err)
+	}
+	for _, name := range names {
+		func() {
+			subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+			if err != nil {
+				if err == syscall.ERROR_ACCESS_DENIED {
+					// ignore error, if we are not allowed to access this key
+					return
+				}
+				t.Fatalf("opening sub-keys %s of %s failed: %v", name, kname, err)
+			}
+			defer subk.Close()
+
+			walkKey(t, subk, kname+`\`+name)
+		}()
+	}
+}
+
+func TestWalkFullRegistry(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping long running test in short mode")
+	}
+	walkKey(t, registry.CLASSES_ROOT, "CLASSES_ROOT")
+	walkKey(t, registry.CURRENT_USER, "CURRENT_USER")
+	walkKey(t, registry.LOCAL_MACHINE, "LOCAL_MACHINE")
+	walkKey(t, registry.USERS, "USERS")
+	walkKey(t, registry.CURRENT_CONFIG, "CURRENT_CONFIG")
+}
+
+func TestExpandString(t *testing.T) {
+	got, err := registry.ExpandString("%PATH%")
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := os.Getenv("PATH")
+	if got != want {
+		t.Errorf("want %q string expanded, got %q", want, got)
+	}
+}
diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go
new file mode 100644
index 0000000..38e573f
--- /dev/null
+++ b/src/internal/syscall/windows/registry/syscall.go
@@ -0,0 +1,28 @@
+// 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
+
+import "syscall"
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
+
+const (
+	_REG_OPTION_NON_VOLATILE = 0
+
+	_REG_CREATED_NEW_KEY     = 1
+	_REG_OPENED_EXISTING_KEY = 2
+
+	_ERROR_NO_MORE_ITEMS syscall.Errno = 259
+)
+
+//sys	regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
+//sys	regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
+//sys	regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
+//sys	regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
+//sys	regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
+
+//sys	expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
diff --git a/src/internal/syscall/windows/registry/value.go b/src/internal/syscall/windows/registry/value.go
new file mode 100644
index 0000000..1c1771d
--- /dev/null
+++ b/src/internal/syscall/windows/registry/value.go
@@ -0,0 +1,316 @@
+// 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
+
+import (
+	"errors"
+	"io"
+	"syscall"
+	"unicode/utf16"
+	"unsafe"
+)
+
+const (
+	// Registry value types.
+	NONE                       = 0
+	SZ                         = 1
+	EXPAND_SZ                  = 2
+	BINARY                     = 3
+	DWORD                      = 4
+	DWORD_BIG_ENDIAN           = 5
+	LINK                       = 6
+	MULTI_SZ                   = 7
+	RESOURCE_LIST              = 8
+	FULL_RESOURCE_DESCRIPTOR   = 9
+	RESOURCE_REQUIREMENTS_LIST = 10
+	QWORD                      = 11
+)
+
+var (
+	// ErrShortBuffer is returned when the buffer was too short for the operation.
+	ErrShortBuffer = syscall.ERROR_MORE_DATA
+
+	// ErrNotExist is returned when a registry key or value does not exist.
+	ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
+
+	// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
+	ErrUnexpectedType = errors.New("unexpected key value type")
+)
+
+// GetValue retrieves the type and data for the specified value associated
+// with an open key k. It fills up buffer buf and returns the retrieved
+// byte count n. If buf is too small to fit the stored value it returns
+// ErrShortBuffer error along with the required buffer size n.
+// If no buffer is provided, it returns true and actual buffer size n.
+// If no buffer is provided, GetValue returns the value's type only.
+// If the value does not exist, the error returned is ErrNotExist.
+//
+// GetValue is a low level function. If value's type is known, use the appropriate
+// Get*Value function instead.
+func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
+	pname, err := syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return 0, 0, err
+	}
+	var pbuf *byte
+	if len(buf) > 0 {
+		pbuf = (*byte)(unsafe.Pointer(&buf[0]))
+	}
+	l := uint32(len(buf))
+	err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
+	if err != nil {
+		return int(l), valtype, err
+	}
+	return int(l), valtype, nil
+}
+
+func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
+	p, err := syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return nil, 0, err
+	}
+	var t uint32
+	n := uint32(len(buf))
+	for {
+		err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
+		if err == nil {
+			return buf[:n], t, nil
+		}
+		if err != syscall.ERROR_MORE_DATA {
+			return nil, 0, err
+		}
+		if n <= uint32(len(buf)) {
+			return nil, 0, err
+		}
+		buf = make([]byte, n)
+	}
+}
+
+// GetStringValue retrieves the string value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetStringValue returns ErrNotExist.
+// If value is not SZ or EXPAND_SZ, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 64))
+	if err2 != nil {
+		return "", typ, err2
+	}
+	switch typ {
+	case SZ, EXPAND_SZ:
+	default:
+		return "", typ, ErrUnexpectedType
+	}
+	if len(data) == 0 {
+		return "", typ, nil
+	}
+	u := (*[1 << 10]uint16)(unsafe.Pointer(&data[0]))[:]
+	return syscall.UTF16ToString(u), typ, nil
+}
+
+// ExpandString expands environment-variable strings and replaces
+// them with the values defined for the current user.
+// Use ExpandString to expand EXPAND_SZ strings.
+func ExpandString(value string) (string, error) {
+	if value == "" {
+		return "", nil
+	}
+	p, err := syscall.UTF16PtrFromString(value)
+	if err != nil {
+		return "", err
+	}
+	r := make([]uint16, 100)
+	for {
+		n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
+		if err != nil {
+			return "", err
+		}
+		if n <= uint32(len(r)) {
+			u := (*[1 << 10]uint16)(unsafe.Pointer(&r[0]))[:]
+			return syscall.UTF16ToString(u), nil
+		}
+		r = make([]uint16, n)
+	}
+}
+
+// GetStringsValue retrieves the []string value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetStringsValue returns ErrNotExist.
+// If value is not MULTI_SZ, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 64))
+	if err2 != nil {
+		return nil, typ, err2
+	}
+	if typ != MULTI_SZ {
+		return nil, typ, ErrUnexpectedType
+	}
+	val = make([]string, 0, 5)
+	p := (*[1 << 24]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
+	p = p[:len(p)-1] // remove terminating nil
+	from := 0
+	for i, c := range p {
+		if c == 0 {
+			val = append(val, string(utf16.Decode(p[from:i])))
+			from = i + 1
+		}
+	}
+	return val, typ, nil
+}
+
+// GetIntegerValue retrieves the integer value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetIntegerValue returns ErrNotExist.
+// If value is not DWORD or QWORD, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 8))
+	if err2 != nil {
+		return 0, typ, err2
+	}
+	switch typ {
+	case DWORD:
+		return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
+	case QWORD:
+		return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
+	default:
+		return 0, typ, ErrUnexpectedType
+	}
+}
+
+// GetBinaryValue retrieves the binary value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetBinaryValue returns ErrNotExist.
+// If value is not BINARY, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 64))
+	if err2 != nil {
+		return nil, typ, err2
+	}
+	if typ != BINARY {
+		return nil, typ, ErrUnexpectedType
+	}
+	return data, typ, nil
+}
+
+func (k Key) setValue(name string, valtype uint32, data []byte) error {
+	p, err := syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return err
+	}
+	if len(data) == 0 {
+		return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
+	}
+	return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
+}
+
+// SetDWordValue sets the data and type of a name value
+// under key k to value and DWORD.
+func (k Key) SetDWordValue(name string, value uint32) error {
+	return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
+}
+
+// SetQWordValue sets the data and type of a name value
+// under key k to value and QWORD.
+func (k Key) SetQWordValue(name string, value uint64) error {
+	return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
+}
+
+func (k Key) setStringValue(name string, valtype uint32, value string) error {
+	v, err := syscall.UTF16FromString(value)
+	if err != nil {
+		return err
+	}
+	buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+	return k.setValue(name, valtype, buf)
+}
+
+// SetStringValue sets the data and type of a name value
+// under key k to value and SZ. The value must not contain a zero byte.
+func (k Key) SetStringValue(name, value string) error {
+	return k.setStringValue(name, SZ, value)
+}
+
+// SetExpandStringValue sets the data and type of a name value
+// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
+func (k Key) SetExpandStringValue(name, value string) error {
+	return k.setStringValue(name, EXPAND_SZ, value)
+}
+
+// SetStringsValue sets the data and type of a name value
+// under key k to value and MULTI_SZ. The value strings
+// must not contain a zero byte.
+func (k Key) SetStringsValue(name string, value []string) error {
+	ss := ""
+	for _, s := range value {
+		for i := 0; i < len(s); i++ {
+			if s[i] == 0 {
+				return errors.New("string cannot have 0 inside")
+			}
+		}
+		ss += s + "\x00"
+	}
+	v := utf16.Encode([]rune(ss + "\x00"))
+	buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+	return k.setValue(name, MULTI_SZ, buf)
+}
+
+// SetBinaryValue sets the data and type of a name value
+// under key k to value and BINARY.
+func (k Key) SetBinaryValue(name string, value []byte) error {
+	return k.setValue(name, BINARY, value)
+}
+
+// DeleteValue removes a named value from the key k.
+func (k Key) DeleteValue(name string) error {
+	return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
+}
+
+// ReadValueNames returns the value names of key k.
+// The parameter n controls the number of returned names,
+// analogous to the way os.File.Readdirnames works.
+func (k Key) ReadValueNames(n int) ([]string, error) {
+	ki, err := k.Stat()
+	if err != nil {
+		return nil, err
+	}
+	names := make([]string, 0, ki.ValueCount)
+	buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
+loopItems:
+	for i := uint32(0); ; i++ {
+		if n > 0 {
+			if len(names) == n {
+				return names, nil
+			}
+		}
+		l := uint32(len(buf))
+		for {
+			err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
+			if err == nil {
+				break
+			}
+			if err == syscall.ERROR_MORE_DATA {
+				println(len(buf), l)
+				// Double buffer size and try again.
+				l = uint32(2 * len(buf))
+				buf = make([]uint16, l)
+				continue
+			}
+			if err == _ERROR_NO_MORE_ITEMS {
+				break loopItems
+			}
+			return names, err
+		}
+		names = append(names, syscall.UTF16ToString(buf[:l]))
+	}
+	if n > len(names) {
+		return names, io.EOF
+	}
+	return names, nil
+}
diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go
new file mode 100644
index 0000000..2b3de63
--- /dev/null
+++ b/src/internal/syscall/windows/registry/zsyscall_windows.go
@@ -0,0 +1,73 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package registry
+
+import "unsafe"
+import "syscall"
+
+var _ unsafe.Pointer
+
+var (
+	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
+	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+	procRegCreateKeyExW           = modadvapi32.NewProc("RegCreateKeyExW")
+	procRegDeleteKeyW             = modadvapi32.NewProc("RegDeleteKeyW")
+	procRegSetValueExW            = modadvapi32.NewProc("RegSetValueExW")
+	procRegEnumValueW             = modadvapi32.NewProc("RegEnumValueW")
+	procRegDeleteValueW           = modadvapi32.NewProc("RegDeleteValueW")
+	procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
+)
+
+func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
+	r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
+	r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
+	r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
+	r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
+	r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
+	r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
index 49bfeea..dc8a916 100644
--- a/src/internal/syscall/windows/syscall_windows.go
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -95,8 +95,8 @@
 )
 
 //sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
-
 //sys	GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
+//sys	MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
 
 const (
 	ComputerNameNetBIOS                   = 0
@@ -108,4 +108,23 @@
 	ComputerNamePhysicalDnsDomain         = 6
 	ComputerNamePhysicalDnsFullyQualified = 7
 	ComputerNameMax                       = 8
+
+	MOVEFILE_REPLACE_EXISTING      = 0x1
+	MOVEFILE_COPY_ALLOWED          = 0x2
+	MOVEFILE_DELAY_UNTIL_REBOOT    = 0x4
+	MOVEFILE_WRITE_THROUGH         = 0x8
+	MOVEFILE_CREATE_HARDLINK       = 0x10
+	MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20
 )
+
+func Rename(oldpath, newpath string) error {
+	from, err := syscall.UTF16PtrFromString(oldpath)
+	if err != nil {
+		return err
+	}
+	to, err := syscall.UTF16PtrFromString(newpath)
+	if err != nil {
+		return err
+	}
+	return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
+}
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index 50c7c51..c6f607a 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -13,6 +13,7 @@
 
 	procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
 	procGetComputerNameExW   = modkernel32.NewProc("GetComputerNameExW")
+	procMoveFileExW          = modkernel32.NewProc("MoveFileExW")
 )
 
 func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) {
@@ -34,3 +35,15 @@
 	}
 	return
 }
+
+func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags))
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index f1f709e..8d48bfd 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -235,6 +235,12 @@
 				EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
 				EvGoSysBlock:
 				lastG = 0
+			case EvGoSysExit:
+				if e.Args[1] != 0 {
+					// EvGoSysExit emission is delayed until the thread has a P.
+					// Give it the real timestamp.
+					e.Ts = int64(e.Args[1])
+				}
 			}
 			events = append(events, e)
 		}
@@ -344,7 +350,6 @@
 	type pdesc struct {
 		running bool
 		g       uint64
-		evGC    *Event
 		evScan  *Event
 		evSweep *Event
 	}
@@ -352,6 +357,7 @@
 	gs := make(map[uint64]gdesc)
 	ps := make(map[int]pdesc)
 	gs[0] = gdesc{state: gRunning}
+	var evGC *Event
 
 	checkRunning := func(p pdesc, g gdesc, ev *Event) error {
 		name := EventDescriptions[ev.Type].Name
@@ -383,16 +389,16 @@
 			}
 			p.running = false
 		case EvGCStart:
-			if p.evGC != nil {
+			if evGC != nil {
 				return fmt.Errorf("previous GC is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
 			}
-			p.evGC = ev
+			evGC = ev
 		case EvGCDone:
-			if p.evGC == nil {
+			if evGC == nil {
 				return fmt.Errorf("bogus GC end (offset %v, time %v)", ev.Off, ev.Ts)
 			}
-			p.evGC.Link = ev
-			p.evGC = nil
+			evGC.Link = ev
+			evGC = nil
 		case EvGCScanStart:
 			if p.evScan != nil {
 				return fmt.Errorf("previous scanning is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
@@ -423,7 +429,12 @@
 			g1.state = gWaiting
 			gs[ev.Args[0]] = g1
 		case EvGoInSyscall:
-			// this case is intentionally left blank
+			g1 := gs[ev.Args[0]]
+			if g1.state != gRunnable {
+				return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+			}
+			g1.state = gWaiting
+			gs[ev.Args[0]] = g1
 		case EvGoCreate:
 			if err := checkRunning(p, g, ev); err != nil {
 				return err
@@ -498,17 +509,18 @@
 			if err := checkRunning(p, g, ev); err != nil {
 				return err
 			}
-			g.state = gRunnable
+			g.state = gWaiting
 			g.evStart.Link = ev
 			g.evStart = nil
 			p.g = 0
 		case EvGoSysExit:
-			if g.state != gRunnable {
-				return fmt.Errorf("g %v is not runnable during syscall exit (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
+			if g.state != gWaiting {
+				return fmt.Errorf("g %v is not waiting during syscall exit (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
 			}
 			if g.ev != nil && g.ev.Type == EvGoSysCall {
 				g.ev.Link = ev
 			}
+			g.state = gRunnable
 			g.ev = ev
 		case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
 			EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet:
@@ -638,6 +650,18 @@
 	l[i], l[j] = l[j], l[i]
 }
 
+// Print dumps events to stdout. For debugging.
+func Print(events []*Event) {
+	for _, ev := range events {
+		desc := EventDescriptions[ev.Type]
+		fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
+		for i, a := range desc.Args {
+			fmt.Printf(" %v=%v", a, ev.Args[i])
+		}
+		fmt.Printf("\n")
+	}
+}
+
 // Event types in the trace.
 // Verbatim copy from src/runtime/trace.go.
 const (
@@ -670,7 +694,7 @@
 	EvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
 	EvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
 	EvGoSysCall      = 28 // syscall enter [timestamp, stack]
-	EvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
+	EvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, real timestamp]
 	EvGoSysBlock     = 30 // syscall blocks [timestamp]
 	EvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
 	EvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
@@ -715,7 +739,7 @@
 	EvGoBlockCond:    {"GoBlockCond", true, []string{}},
 	EvGoBlockNet:     {"GoBlockNet", true, []string{}},
 	EvGoSysCall:      {"GoSysCall", true, []string{}},
-	EvGoSysExit:      {"GoSysExit", false, []string{"g"}},
+	EvGoSysExit:      {"GoSysExit", false, []string{"g", "ts"}},
 	EvGoSysBlock:     {"GoSysBlock", false, []string{}},
 	EvGoWaiting:      {"GoWaiting", false, []string{"g"}},
 	EvGoInSyscall:    {"GoInSyscall", false, []string{"g"}},
diff --git a/src/io/io.go b/src/io/io.go
index 7507a84..290fc88 100644
--- a/src/io/io.go
+++ b/src/io/io.go
@@ -348,6 +348,23 @@
 // Otherwise, if dst implements the ReaderFrom interface,
 // the copy is implemented by calling dst.ReadFrom(src).
 func Copy(dst Writer, src Reader) (written int64, err error) {
+	return copyBuffer(dst, src, nil)
+}
+
+// CopyBuffer is identical to Copy except that it stages through the
+// provided buffer (if one is required) rather than allocating a
+// temporary one. If buf is nil, one is allocated; otherwise if it has
+// zero length, CopyBuffer panics.
+func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
+	if buf != nil && len(buf) == 0 {
+		panic("empty buffer in io.CopyBuffer")
+	}
+	return copyBuffer(dst, src, buf)
+}
+
+// copyBuffer is the actual implementation of Copy and CopyBuffer.
+// if buf is nil, one is allocated.
+func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
 	// If the reader has a WriteTo method, use it to do the copy.
 	// Avoids an allocation and a copy.
 	if wt, ok := src.(WriterTo); ok {
@@ -357,7 +374,9 @@
 	if rt, ok := dst.(ReaderFrom); ok {
 		return rt.ReadFrom(src)
 	}
-	buf := make([]byte, 32*1024)
+	if buf == nil {
+		buf = make([]byte, 32*1024)
+	}
 	for {
 		nr, er := src.Read(buf)
 		if nr > 0 {
diff --git a/src/io/io_test.go b/src/io/io_test.go
index 57db1fb..e892574 100644
--- a/src/io/io_test.go
+++ b/src/io/io_test.go
@@ -20,7 +20,7 @@
 	WriterTo   // conflicts with and hides bytes.Buffer's WriterTo.
 }
 
-// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN.
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN.
 
 func TestCopy(t *testing.T) {
 	rb := new(Buffer)
@@ -32,6 +32,26 @@
 	}
 }
 
+func TestCopyBuffer(t *testing.T) {
+	rb := new(Buffer)
+	wb := new(Buffer)
+	rb.WriteString("hello, world.")
+	CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest.
+	if wb.String() != "hello, world." {
+		t.Errorf("CopyBuffer did not work properly")
+	}
+}
+
+func TestCopyBufferNil(t *testing.T) {
+	rb := new(Buffer)
+	wb := new(Buffer)
+	rb.WriteString("hello, world.")
+	CopyBuffer(wb, rb, nil) // Should allocate a buffer.
+	if wb.String() != "hello, world." {
+		t.Errorf("CopyBuffer did not work properly")
+	}
+}
+
 func TestCopyReadFrom(t *testing.T) {
 	rb := new(Buffer)
 	wb := new(bytes.Buffer) // implements ReadFrom.
@@ -78,6 +98,34 @@
 	}
 }
 
+type zeroErrReader struct {
+	err error
+}
+
+func (r zeroErrReader) Read(p []byte) (int, error) {
+	return copy(p, []byte{0}), r.err
+}
+
+type errWriter struct {
+	err error
+}
+
+func (w errWriter) Write([]byte) (int, error) {
+	return 0, w.err
+}
+
+// In case a Read results in an error with non-zero bytes read, and
+// the subsequent Write also results in an error, the error from Write
+// is returned, as it is the one that prevented progressing further.
+func TestCopyReadErrWriteErr(t *testing.T) {
+	er, ew := errors.New("readError"), errors.New("writeError")
+	r, w := zeroErrReader{err: er}, errWriter{err: ew}
+	n, err := Copy(w, r)
+	if n != 0 || err != ew {
+		t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err)
+	}
+}
+
 func TestCopyN(t *testing.T) {
 	rb := new(Buffer)
 	wb := new(Buffer)
diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go
index 4a06e97..61d4a7a 100644
--- a/src/io/ioutil/tempfile.go
+++ b/src/io/ioutil/tempfile.go
@@ -55,7 +55,9 @@
 		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
 		if os.IsExist(err) {
 			if nconflict++; nconflict > 10 {
+				randmu.Lock()
 				rand = reseed()
+				randmu.Unlock()
 			}
 			continue
 		}
@@ -82,7 +84,9 @@
 		err = os.Mkdir(try, 0700)
 		if os.IsExist(err) {
 			if nconflict++; nconflict > 10 {
+				randmu.Lock()
 				rand = reseed()
+				randmu.Unlock()
 			}
 			continue
 		}
diff --git a/src/iostest.bash b/src/iostest.bash
index 13f5e0c..5e09894 100755
--- a/src/iostest.bash
+++ b/src/iostest.bash
@@ -20,25 +20,31 @@
 	echo "iostest.bash requires GOOS=darwin, got GOOS=$GOOS" 1>&2
 	exit 1
 fi
+if [ "$GOARCH" != "arm" ] && [ "$GOARCH" != "arm64" ]; then
+	echo "iostest.bash requires GOARCH=arm or GOARCH=arm64, got GOARCH=$GOARCH" 1>&2
+	exit 1
+fi
 if [ "$GOARCH" == "arm" ]; then
 	export GOARM=7
 fi
 
-# Reboot to make sure previous runs do not interfere with the current run.
-# It is reasonably easy for a bad program leave an iOS device in an
-# almost unusable state.
-idevicediagnostics restart
-# Initial sleep to make sure we are restarting before we start polling.
-sleep 30
-# Poll until the device has restarted.
-until idevicediagnostics diagnostics; do
-	# TODO(crawshaw): replace with a test app using go_darwin_arm_exec.
-	echo "waiting for idevice to come online"
-	sleep 10
-done
-# Diagnostics are reported during boot before the device can start an
-# app. Wait a little longer before trying to use the device.
-sleep 30
+if [ "$1" == "-restart" ]; then
+	# Reboot to make sure previous runs do not interfere with the current run.
+	# It is reasonably easy for a bad program leave an iOS device in an
+	# almost unusable state.
+	idevicediagnostics restart
+	# Initial sleep to make sure we are restarting before we start polling.
+	sleep 30
+	# Poll until the device has restarted.
+	until idevicediagnostics diagnostics; do
+		# TODO(crawshaw): replace with a test app using go_darwin_arm_exec.
+		echo "waiting for idevice to come online"
+		sleep 10
+	done
+	# Diagnostics are reported during boot before the device can start an
+	# app. Wait a little longer before trying to use the device.
+	sleep 30
+fi
 
 unset GOBIN
 export GOROOT=$(dirname $(pwd))
@@ -47,12 +53,17 @@
 export CC_FOR_TARGET=$GOROOT/misc/ios/clangwrap.sh
 
 # Run the build for the host bootstrap, so we can build go_darwin_arm_exec.
-# Also lets us fail early before the (slow) adb push if the build is broken.
+# Also lets us fail early before the (slow) ios-deploy if the build is broken.
 ./make.bash
 
 GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
 	-o ../bin/go_darwin_${GOARCH}_exec \
 	../misc/ios/go_darwin_arm_exec.go
 
+if [ "$GOIOS_DEV_ID" == "" ]; then
+	echo "detecting iOS development identity"
+	eval $(GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go run ../misc/ios/detect.go)
+fi
+
 # Run standard build and tests.
 ./all.bash --no-clean
diff --git a/src/log/log.go b/src/log/log.go
index 17646a1..4cfe550 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -32,11 +32,12 @@
 	//	2009/01/23 01:23:23 message
 	// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
 	//	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
-	Ldate         = 1 << iota     // the date: 2009/01/23
-	Ltime                         // the time: 01:23:23
+	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
+	Ltime                         // the time in the local time zone: 01:23:23
 	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
 	Llongfile                     // full file name and line number: /a/b/c/d.go:23
 	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
+	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
 	LstdFlags     = Ldate | Ltime // initial values for the standard logger
 )
 
@@ -88,6 +89,9 @@
 
 func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
 	*buf = append(*buf, l.prefix...)
+	if l.flag&LUTC != 0 {
+		t = t.UTC()
+	}
 	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
 		if l.flag&Ldate != 0 {
 			year, month, day := t.Date()
@@ -156,7 +160,7 @@
 	l.buf = l.buf[:0]
 	l.formatHeader(&l.buf, now, file, line)
 	l.buf = append(l.buf, s...)
-	if len(s) > 0 && s[len(s)-1] != '\n' {
+	if len(s) == 0 || s[len(s)-1] != '\n' {
 		l.buf = append(l.buf, '\n')
 	}
 	_, err := l.out.Write(l.buf)
diff --git a/src/log/log_test.go b/src/log/log_test.go
index 14e0b29..709de1e 100644
--- a/src/log/log_test.go
+++ b/src/log/log_test.go
@@ -8,16 +8,19 @@
 
 import (
 	"bytes"
+	"fmt"
 	"os"
 	"regexp"
+	"strings"
 	"testing"
+	"time"
 )
 
 const (
 	Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
 	Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
 	Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
-	Rline         = `(54|56):` // must update if the calls to l.Printf / l.Print below move
+	Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
 	Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
 	Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
 )
@@ -118,6 +121,44 @@
 	}
 }
 
+func TestUTCFlag(t *testing.T) {
+	var b bytes.Buffer
+	l := New(&b, "Test:", LstdFlags)
+	l.SetFlags(Ldate | Ltime | LUTC)
+	// Verify a log message looks right in the right time zone. Quantize to the second only.
+	now := time.Now().UTC()
+	l.Print("hello")
+	want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
+		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
+	got := b.String()
+	if got == want {
+		return
+	}
+	// It's possible we crossed a second boundary between getting now and logging,
+	// so add a second and try again. This should very nearly always work.
+	now.Add(time.Second)
+	want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
+		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute())
+	if got == want {
+		return
+	}
+	t.Errorf("got %q; want %q", got, want)
+}
+
+func TestEmptyPrintCreatesLine(t *testing.T) {
+	var b bytes.Buffer
+	l := New(&b, "Header:", LstdFlags)
+	l.Print()
+	l.Println("non-empty")
+	output := b.String()
+	if n := strings.Count(output, "Header"); n != 2 {
+		t.Errorf("expected 2 headers, got %d", n)
+	}
+	if n := strings.Count(output, "\n"); n != 2 {
+		t.Errorf("expected 2 lines, got %d", n)
+	}
+}
+
 func BenchmarkItoa(b *testing.B) {
 	dst := make([]byte, 0, 64)
 	for i := 0; i < b.N; i++ {
diff --git a/src/log/syslog/doc.go b/src/log/syslog/doc.go
new file mode 100644
index 0000000..54e76ed
--- /dev/null
+++ b/src/log/syslog/doc.go
@@ -0,0 +1,18 @@
+// Copyright 2012 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 syslog provides a simple interface to the system log
+// service. It can send messages to the syslog daemon using UNIX
+// domain sockets, UDP or TCP.
+//
+// Only one call to Dial is necessary. On write failures,
+// the syslog client will attempt to reconnect to the server
+// and write again.
+package syslog
+
+// BUG(brainman): This package is not implemented on Windows yet.
+
+// BUG(akumar): This package is not implemented on Plan 9 yet.
+
+// BUG(minux): This package is not implemented on NaCl (Native Client) yet.
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index 5e09599..4bf4476 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -4,13 +4,6 @@
 
 // +build !windows,!nacl,!plan9
 
-// Package syslog provides a simple interface to the system log
-// service. It can send messages to the syslog daemon using UNIX
-// domain sockets, UDP or TCP.
-//
-// Only one call to Dial is necessary. On write failures,
-// the syslog client will attempt to reconnect to the server
-// and write again.
 package syslog
 
 import (
diff --git a/src/log/syslog/syslog_plan9.go b/src/log/syslog/syslog_plan9.go
deleted file mode 100644
index 0c05f6f..0000000
--- a/src/log/syslog/syslog_plan9.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2012 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 syslog provides a simple interface to the system log service.
-package syslog
-
-// BUG(akumar): This package is not implemented on Plan 9 yet.
diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go
index 7f7d7fd..85aec53 100644
--- a/src/log/syslog/syslog_test.go
+++ b/src/log/syslog/syslog_test.go
@@ -121,8 +121,11 @@
 	msg := "Test 123"
 	transport := []string{"unix", "unixgram", "udp", "tcp"}
 
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		transport = []string{"udp", "tcp"}
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			transport = []string{"udp", "tcp"}
+		}
 	}
 
 	for _, tr := range transport {
@@ -147,8 +150,11 @@
 }
 
 func TestFlap(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		}
 	}
 
 	net := "unix"
@@ -315,8 +321,11 @@
 	const N = 10
 	const M = 100
 	net := "unix"
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		net = "tcp"
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			net = "tcp"
+		}
 	}
 	done := make(chan string, N*M)
 	addr, sock, srvWG := startServer(net, "", done)
diff --git a/src/log/syslog/syslog_windows.go b/src/log/syslog/syslog_windows.go
deleted file mode 100644
index 8d99e2e..0000000
--- a/src/log/syslog/syslog_windows.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2012 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 syslog provides a simple interface to the system log service.
-package syslog
-
-// BUG(brainman): This package is not implemented on Windows yet.
diff --git a/src/math/all_test.go b/src/math/all_test.go
index c07ac74..84061be 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -2977,15 +2977,56 @@
 	}
 }
 
+var Global float64
+
 func BenchmarkSqrt(b *testing.B) {
+	x, y := 0.0, 10.0
 	for i := 0; i < b.N; i++ {
-		Sqrt(10)
+		x += Sqrt(y)
 	}
+	Global = x
+}
+
+func BenchmarkSqrtIndirect(b *testing.B) {
+	x, y := 0.0, 10.0
+	f := Sqrt
+	for i := 0; i < b.N; i++ {
+		x += f(y)
+	}
+	Global = x
 }
 
 func BenchmarkSqrtGo(b *testing.B) {
+	x, y := 0.0, 10.0
 	for i := 0; i < b.N; i++ {
-		SqrtGo(10)
+		x += SqrtGo(y)
+	}
+	Global = x
+}
+
+func isPrime(i int) bool {
+	// Yes, this is a dumb way to write this code,
+	// but calling Sqrt repeatedly in this way demonstrates
+	// the benefit of using a direct SQRT instruction on systems
+	// that have one, whereas the obvious loop seems not to
+	// demonstrate such a benefit.
+	for j := 2; float64(j) <= Sqrt(float64(i)); j++ {
+		if i%j == 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func BenchmarkSqrtPrime(b *testing.B) {
+	any := false
+	for i := 0; i < b.N; i++ {
+		if isPrime(100003) {
+			any = true
+		}
+	}
+	if any {
+		Global = 1
 	}
 }
 
diff --git a/src/math/big/arith.go b/src/math/big/arith.go
index 328c85c..1ff6349 100644
--- a/src/math/big/arith.go
+++ b/src/math/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/math/big/arith_arm64.s b/src/math/big/arith_arm64.s
index 6e10e47..24a717c 100644
--- a/src/math/big/arith_arm64.s
+++ b/src/math/big/arith_arm64.s
@@ -9,38 +9,169 @@
 // This file provides fast assembly versions for the elementary
 // arithmetic operations on vectors implemented in arith.go.
 
+// TODO: Consider re-implementing using Advanced SIMD
+// once the assembler supports those instructions.
+
+// func mulWW(x, y Word) (z1, z0 Word)
 TEXT ·mulWW(SB),NOSPLIT,$0
-	B ·mulWW_g(SB)
+	MOVD	x+0(FP), R0
+	MOVD	y+8(FP), R1
+	MUL	R0, R1, R2
+	UMULH	R0, R1, R3
+	MOVD	R3, z1+16(FP)
+	MOVD	R2, z0+24(FP)
+	RET
 
+
+// func divWW(x1, x0, y Word) (q, r Word)
 TEXT ·divWW(SB),NOSPLIT,$0
-	B ·divWW_g(SB)
+	B	·divWW_g(SB) // ARM64 has no multiword division
 
+
+// func addVV(z, x, y []Word) (c Word)
 TEXT ·addVV(SB),NOSPLIT,$0
-	B ·addVV_g(SB)
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	ADDS	$0, R0 // clear carry flag
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	MOVD.P	8(R2), R5
+	ADCS	R4, R5
+	MOVD.P	R5, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	HS, R0 // extract carry flag
+	MOVD	R0, c+72(FP)
+	RET
 
+
+// func subVV(z, x, y []Word) (c Word)
 TEXT ·subVV(SB),NOSPLIT,$0
-	B ·subVV_g(SB)
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	CMP	R0, R0 // set carry flag
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	MOVD.P	8(R2), R5
+	SBCS	R5, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	LO, R0 // extract carry flag
+	MOVD	R0, c+72(FP)
+	RET
 
+
+// func addVW(z, x []Word, y Word) (c Word)
 TEXT ·addVW(SB),NOSPLIT,$0
-	B ·addVW_g(SB)
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	CBZ	R0, return_y
+	MOVD.P	8(R1), R4
+	ADDS	R2, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	ADCS	$0, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	HS, R0 // extract carry flag
+	MOVD	R0, c+56(FP)
+	RET
+return_y: // z is empty; copy y to c
+	MOVD	R2, c+56(FP)
+	RET
 
+
+// func subVW(z, x []Word, y Word) (c Word)
 TEXT ·subVW(SB),NOSPLIT,$0
-	B ·subVW_g(SB)
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	CBZ	R0, rety
+	MOVD.P	8(R1), R4
+	SUBS	R2, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	SBCS	$0, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	LO, R0 // extract carry flag
+	MOVD	R0, c+56(FP)
+	RET
+rety: // z is empty; copy y to c
+	MOVD	R2, c+56(FP)
+	RET
 
+
+// func shlVU(z, x []Word, s uint) (c Word)
 TEXT ·shlVU(SB),NOSPLIT,$0
 	B ·shlVU_g(SB)
 
+
+// func shrVU(z, x []Word, s uint) (c Word)
 TEXT ·shrVU(SB),NOSPLIT,$0
 	B ·shrVU_g(SB)
 
-TEXT ·mulAddVWW(SB),NOSPLIT,$0
-	B ·mulAddVWW_g(SB)
 
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+	MOVD	z+0(FP), R1
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R2
+	MOVD	y+48(FP), R3
+	MOVD	r+56(FP), R4
+loop:
+	CBZ	R0, done
+	MOVD.P	8(R2), R5
+	UMULH	R5, R3, R7
+	MUL	R5, R3, R6
+	ADDS	R4, R6
+	ADC	$0, R7
+	MOVD.P	R6, 8(R1)
+	MOVD	R7, R4
+	SUB	$1, R0
+	B	loop
+done:
+	MOVD	R4, c+64(FP)
+	RET
+
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
 TEXT ·addMulVVW(SB),NOSPLIT,$0
 	B ·addMulVVW_g(SB)
 
+
+// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
 TEXT ·divWVW(SB),NOSPLIT,$0
 	B ·divWVW_g(SB)
 
+
+// func bitLen(x Word) (n int)
 TEXT ·bitLen(SB),NOSPLIT,$0
-	B ·bitLen_g(SB)
+	MOVD	x+0(FP), R0
+	CLZ	R0, R0
+	MOVD	$64, R1
+	SUB	R0, R1, R0
+	MOVD	R0, n+8(FP)
+	RET
diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go
index cd92dd7..f46a494 100644
--- a/src/math/big/arith_test.go
+++ b/src/math/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/math/big/float.go b/src/math/big/float.go
index 2e536e0..d46c046 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -65,15 +65,19 @@
 	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.
+// NewFloat panics with ErrNaN if x is a NaN.
 func NewFloat(x float64) *Float {
 	if math.IsNaN(x) {
 		panic(ErrNaN{"NewFloat(NaN)"})
@@ -1400,8 +1404,9 @@
 // it is changed to the larger of x's or y's precision before the operation.
 // Rounding is performed according to z's precision and rounding mode; and
 // z's accuracy reports the result error relative to the exact (not rounded)
-// result.
-// BUG(gri) Float.Add panics if an operand is Inf.
+// result. Add panics with ErrNaN if x and y are infinities with opposite
+// signs. The value of z is undefined in that case.
+//
 // BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
 func (z *Float) Add(x, y *Float) *Float {
 	if debugFloat {
@@ -1413,46 +1418,59 @@
 		z.prec = umax32(x.prec, y.prec)
 	}
 
-	// special cases
-	if x.form != finite || y.form != finite {
-		if x.form > finite || y.form > finite {
-			// TODO(gri) handle Inf separately
-			panic("Inf operand")
-		}
-		if x.form == zero {
-			z.Set(y)
-			if z.form == zero {
-				z.neg = x.neg && y.neg // -0 + -0 == -0
+	if x.form == finite && y.form == finite {
+		// x + y (commom case)
+		z.neg = x.neg
+		if x.neg == y.neg {
+			// x + y == x + y
+			// (-x) + (-y) == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x + (-y) == x - y == -(y - x)
+			// (-x) + y == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
 			}
-			return z
 		}
-		// y == ±0
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg != y.neg {
+		// +Inf + -Inf
+		// -Inf + +Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"addition of infinities with opposite signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 + ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && y.neg // -0 + -0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf + y
+		// x + ±0
 		return z.Set(x)
 	}
 
-	// x, y != 0
-	z.neg = x.neg
-	if x.neg == y.neg {
-		// x + y == x + y
-		// (-x) + (-y) == -(x + y)
-		z.uadd(x, y)
-	} else {
-		// x + (-y) == x - y == -(y - x)
-		// (-x) + y == y - x == -(x - y)
-		if x.ucmp(y) > 0 {
-			z.usub(x, y)
-		} else {
-			z.neg = !z.neg
-			z.usub(y, x)
-		}
-	}
-
-	return z
+	// ±0 + y
+	// x + ±Inf
+	return z.Set(y)
 }
 
 // Sub sets z to the rounded difference x-y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
-// BUG(gri) Float.Sub panics if an operand is Inf.
+// Sub panics with ErrNaN if x and y are infinities with equal
+// signs. The value of z is undefined in that case.
 func (z *Float) Sub(x, y *Float) *Float {
 	if debugFloat {
 		x.validate()
@@ -1463,46 +1481,59 @@
 		z.prec = umax32(x.prec, y.prec)
 	}
 
-	// special cases
-	if x.form != finite || y.form != finite {
-		if x.form > finite || y.form > finite {
-			// TODO(gri) handle Inf separately
-			panic("Inf operand")
-		}
-		if x.form == zero {
-			z.Neg(y)
-			if z.form == zero {
-				z.neg = x.neg && !y.neg // -0 - 0 == -0
+	if x.form == finite && y.form == finite {
+		// x - y (common case)
+		z.neg = x.neg
+		if x.neg != y.neg {
+			// x - (-y) == x + y
+			// (-x) - y == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x - y == x - y == -(y - x)
+			// (-x) - (-y) == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
 			}
-			return z
 		}
-		// y == ±0
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg == y.neg {
+		// +Inf - +Inf
+		// -Inf - -Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"subtraction of infinities with equal signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 - ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && !y.neg // -0 - +0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf - y
+		// x - ±0
 		return z.Set(x)
 	}
 
-	// x, y != 0
-	z.neg = x.neg
-	if x.neg != y.neg {
-		// x - (-y) == x + y
-		// (-x) - y == -(x + y)
-		z.uadd(x, y)
-	} else {
-		// x - y == x - y == -(y - x)
-		// (-x) - (-y) == y - x == -(x - y)
-		if x.ucmp(y) > 0 {
-			z.usub(x, y)
-		} else {
-			z.neg = !z.neg
-			z.usub(y, x)
-		}
-	}
-
-	return z
+	// ±0 - y
+	// x - ±Inf
+	return z.Neg(y)
 }
 
 // Mul sets z to the rounded product x*y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
-// BUG(gri) Float.Mul panics if an operand is Inf.
+// Mul panics with ErrNaN if one operand is zero and the other
+// operand an infinity. The value of z is undefined in that case.
 func (z *Float) Mul(x, y *Float) *Float {
 	if debugFloat {
 		x.validate()
@@ -1515,28 +1546,39 @@
 
 	z.neg = x.neg != y.neg
 
-	// special cases
-	if x.form != finite || y.form != finite {
-		if x.form > finite || y.form > finite {
-			// TODO(gri) handle Inf separately
-			panic("Inf operand")
-		}
-		// x == ±0 || y == ±0
-		z.acc = Exact
-		z.form = zero
+	if x.form == finite && y.form == finite {
+		// x * y (common case)
+		z.umul(x, y)
 		return z
 	}
 
-	// x, y != 0
-	z.umul(x, y)
+	z.acc = Exact
+	if x.form == zero && y.form == inf || x.form == inf && y.form == zero {
+		// ±0 * ±Inf
+		// ±Inf * ±0
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"multiplication of zero with infinity"})
+	}
 
+	if x.form == inf || y.form == inf {
+		// ±Inf * y
+		// x * ±Inf
+		z.form = inf
+		return z
+	}
+
+	// ±0 * y
+	// x * ±0
+	z.form = zero
 	return z
 }
 
 // Quo sets z to the rounded quotient x/y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
-// Quo panics is both operands are 0.
-// BUG(gri) Float.Quo panics if an operand is Inf.
+// Quo panics with ErrNaN if both operands are zero or infinities.
+// The value of z is undefined in that case.
 func (z *Float) Quo(x, y *Float) *Float {
 	if debugFloat {
 		x.validate()
@@ -1549,29 +1591,32 @@
 
 	z.neg = x.neg != y.neg
 
-	// special cases
-	z.acc = Exact
-	if x.form != finite || y.form != finite {
-		if x.form > finite || y.form > finite {
-			// TODO(gri) handle Inf separately
-			panic("Inf operand")
-		}
-		// x == ±0 || y == ±0
-		if x.form == zero {
-			if y.form == zero {
-				panic("0/0")
-			}
-			z.form = zero
-			return z
-		}
-		// y == ±0
-		z.form = inf
+	if x.form == finite && y.form == finite {
+		// x / y (common case)
+		z.uquo(x, y)
 		return z
 	}
 
-	// x, y != 0
-	z.uquo(x, y)
+	z.acc = Exact
+	if x.form == zero && y.form == zero || x.form == inf && y.form == inf {
+		// ±0 / ±0
+		// ±Inf / ±Inf
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"division of zero by zero or infinity by infinity"})
+	}
 
+	if x.form == zero || y.form == inf {
+		// ±0 / y
+		// x / ±Inf
+		z.form = zero
+		return z
+	}
+
+	// x / ±0
+	// ±Inf / y
+	z.form = inf
 	return z
 }
 
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index b3f1a60..5b5a024 100644
--- a/src/math/big/float_test.go
+++ b/src/math/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 {
@@ -1438,7 +1441,7 @@
 
 // TestFloatArithmeticSpecialValues tests that Float operations produce the
 // correct results for combinations of zero (±0), finite (±1 and ±2.71828),
-// and non-finite (±Inf) operands.
+// and infinite (±Inf) operands.
 func TestFloatArithmeticSpecialValues(t *testing.T) {
 	zero := 0.0
 	args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
@@ -1456,38 +1459,53 @@
 				t.Errorf("Float(%g) == %g (%s)", x, got, acc)
 			}
 			for _, y := range args {
-				// At the moment an Inf operand always leads to a panic (known bug).
-				// TODO(gri) remove this once the bug is fixed.
-				if math.IsInf(x, 0) || math.IsInf(y, 0) {
-					continue
-				}
 				yy.SetFloat64(y)
-				var op string
-				var z float64
+				var (
+					op string
+					z  float64
+					f  func(z, x, y *Float) *Float
+				)
 				switch i {
 				case 0:
 					op = "+"
 					z = x + y
-					got.Add(xx, yy)
+					f = (*Float).Add
 				case 1:
 					op = "-"
 					z = x - y
-					got.Sub(xx, yy)
+					f = (*Float).Sub
 				case 2:
 					op = "*"
 					z = x * y
-					got.Mul(xx, yy)
+					f = (*Float).Mul
 				case 3:
-					if x == 0 && y == 0 {
-						// TODO(gri) check for ErrNaN
-						continue // 0/0 panics with ErrNaN
-					}
 					op = "/"
 					z = x / y
-					got.Quo(xx, yy)
+					f = (*Float).Quo
 				default:
 					panic("unreachable")
 				}
+				var errnan bool // set if execution of f panicked with ErrNaN
+				// protect execution of f
+				func() {
+					defer func() {
+						if p := recover(); p != nil {
+							_ = p.(ErrNaN) // re-panic if not ErrNaN
+							errnan = true
+						}
+					}()
+					f(got, xx, yy)
+				}()
+				if math.IsNaN(z) {
+					if !errnan {
+						t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got)
+					}
+					continue
+				}
+				if errnan {
+					t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want)
+					continue
+				}
 				want.SetFloat64(z)
 				if !alike(got, want) {
 					t.Errorf("%5g %s %5g = %5s; want %5s", x, op, y, got, want)
@@ -1614,7 +1632,7 @@
 }
 
 // TestFloatCmpSpecialValues tests that Cmp produces the correct results for
-// combinations of zero (±0), finite (±1 and ±2.71828), and non-finite (±Inf)
+// combinations of zero (±0), finite (±1 and ±2.71828), and infinite (±Inf)
 // operands.
 func TestFloatCmpSpecialValues(t *testing.T) {
 	zero := 0.0
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index 7dc9a28..b929d12 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -163,24 +163,54 @@
 	}
 	// exp10 != 0
 
-	// compute decimal exponent power
-	expabs := exp10
-	if expabs < 0 {
-		expabs = -expabs
-	}
-	powTen := nat(nil).expNN(natTen, nat(nil).setUint64(uint64(expabs)), nil)
-	fpowTen := new(Float).SetInt(new(Int).SetBits(powTen))
-
 	// apply 10**exp10
+	p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
 	if exp10 < 0 {
-		z.uquo(z, fpowTen)
+		z.uquo(z, p.pow10(-exp10))
 	} else {
-		z.umul(z, fpowTen)
+		z.umul(z, p.pow10(exp10))
 	}
 
 	return
 }
 
+// These powers of 10 can be represented exactly as a float64.
+var pow10tab = [...]float64{
+	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// pow10 sets z to 10**n and returns z.
+// n must not be negative.
+func (z *Float) pow10(n int64) *Float {
+	if n < 0 {
+		panic("pow10 called with negative argument")
+	}
+
+	const m = int64(len(pow10tab) - 1)
+	if n <= m {
+		return z.SetFloat64(pow10tab[n])
+	}
+	// n > m
+
+	z.SetFloat64(pow10tab[m])
+	n -= m
+
+	// use more bits for f than for z
+	// TODO(gri) what is the right number?
+	f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
+
+	for n > 0 {
+		if n&1 != 0 {
+			z.Mul(z, f)
+		}
+		f.Mul(f, f)
+		n >>= 1
+	}
+
+	return z
+}
+
 // Parse is like z.Scan(r, base), but instead of reading from an
 // io.ByteScanner, it parses the string s. An error is also returned
 // if the string contains invalid or trailing bytes not belonging to
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index e7920d0..96c01ee 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -330,6 +330,12 @@
 		{"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
 		{"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"},
+		{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
+		{"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"},
+
 		// TODO(gri) need tests for actual large Floats
 
 		{"0", 53, 'b', 0, "0"},
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 3410ec4..5e31253 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -7,7 +7,6 @@
 package big
 
 import (
-	"errors"
 	"fmt"
 	"io"
 	"math/rand"
@@ -584,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)
@@ -813,7 +930,7 @@
 	}
 	b := buf[0]
 	if b>>1 != intGobVersion {
-		return errors.New(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+		return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
 	}
 	z.neg = b&1 != 0
 	z.abs = z.abs.setBytes(buf[1:])
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index a972a72..c19e88a 100644
--- a/src/math/big/int_test.go
+++ b/src/math/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/math/big/nat.go b/src/math/big/nat.go
index 2a279d1..7157a54 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -888,6 +888,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))
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index 748796c..fb16f18 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -546,7 +546,7 @@
 	}
 	b := buf[0]
 	if b>>1 != ratGobVersion {
-		return errors.New(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+		return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
 	}
 	const j = 1 + 4
 	i := j + binary.BigEndian.Uint32(buf[j-4:j])
diff --git a/src/math/sqrt.go b/src/math/sqrt.go
index fdc8699..23cf299 100644
--- a/src/math/sqrt.go
+++ b/src/math/sqrt.go
@@ -91,6 +91,11 @@
 //	Sqrt(NaN) = NaN
 func Sqrt(x float64) float64
 
+// Note: Sqrt is implemented in assembly on some systems.
+// Others have assembly stubs that jump to func sqrt below.
+// On systems where Sqrt is a single instruction, the compiler
+// may turn a direct call into a direct use of that instruction instead.
+
 func sqrt(x float64) float64 {
 	// special cases
 	switch {
diff --git a/src/math/sqrt_arm64.s b/src/math/sqrt_arm64.s
new file mode 100644
index 0000000..9861446
--- /dev/null
+++ b/src/math/sqrt_arm64.s
@@ -0,0 +1,12 @@
+// 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"
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),NOSPLIT,$0
+	FMOVD	x+0(FP), F0
+	FSQRTD	F0, F0
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/stubs_arm64.s b/src/math/stubs_arm64.s
index 2ffd228..eea81e9 100644
--- a/src/math/stubs_arm64.s
+++ b/src/math/stubs_arm64.s
@@ -84,8 +84,5 @@
 TEXT ·Cos(SB),NOSPLIT,$0
 	B ·cos(SB)
 
-TEXT ·Sqrt(SB),NOSPLIT,$0
-	B ·sqrt(SB)
-
 TEXT ·Tan(SB),NOSPLIT,$0
 	B ·tan(SB)
diff --git a/src/mime/quotedprintable/reader.go b/src/mime/quotedprintable/reader.go
index a39a20e..3bd6833 100644
--- a/src/mime/quotedprintable/reader.go
+++ b/src/mime/quotedprintable/reader.go
@@ -13,19 +13,16 @@
 	"io"
 )
 
-// Deviations from RFC 2045:
-// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
-// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
-//    with other broken QP encoders & decoders.
-type reader struct {
+// Reader is a quoted-printable decoder.
+type Reader struct {
 	br   *bufio.Reader
 	rerr error  // last read error
 	line []byte // to be consumed before more of br
 }
 
 // NewReader returns a quoted-printable reader, decoding from r.
-func NewReader(r io.Reader) io.Reader {
-	return &reader{
+func NewReader(r io.Reader) *Reader {
+	return &Reader{
 		br: bufio.NewReader(r),
 	}
 }
@@ -43,7 +40,7 @@
 	return 0, fmt.Errorf("quotedprintable: invalid hex byte 0x%02x", b)
 }
 
-func (q *reader) readHexByte(v []byte) (b byte, err error) {
+func readHexByte(v []byte) (b byte, err error) {
 	if len(v) < 2 {
 		return 0, io.ErrUnexpectedEOF
 	}
@@ -71,43 +68,48 @@
 	softSuffix = []byte("=")
 )
 
-func (q *reader) Read(p []byte) (n int, err error) {
+// Read reads and decodes quoted-printable data from the underlying reader.
+func (r *Reader) Read(p []byte) (n int, err error) {
+	// Deviations from RFC 2045:
+	// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
+	// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
+	//    with other broken QP encoders & decoders.
 	for len(p) > 0 {
-		if len(q.line) == 0 {
-			if q.rerr != nil {
-				return n, q.rerr
+		if len(r.line) == 0 {
+			if r.rerr != nil {
+				return n, r.rerr
 			}
-			q.line, q.rerr = q.br.ReadSlice('\n')
+			r.line, r.rerr = r.br.ReadSlice('\n')
 
 			// Does the line end in CRLF instead of just LF?
-			hasLF := bytes.HasSuffix(q.line, lf)
-			hasCR := bytes.HasSuffix(q.line, crlf)
-			wholeLine := q.line
-			q.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
-			if bytes.HasSuffix(q.line, softSuffix) {
-				rightStripped := wholeLine[len(q.line):]
-				q.line = q.line[:len(q.line)-1]
+			hasLF := bytes.HasSuffix(r.line, lf)
+			hasCR := bytes.HasSuffix(r.line, crlf)
+			wholeLine := r.line
+			r.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
+			if bytes.HasSuffix(r.line, softSuffix) {
+				rightStripped := wholeLine[len(r.line):]
+				r.line = r.line[:len(r.line)-1]
 				if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
-					q.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped)
+					r.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped)
 				}
 			} else if hasLF {
 				if hasCR {
-					q.line = append(q.line, '\r', '\n')
+					r.line = append(r.line, '\r', '\n')
 				} else {
-					q.line = append(q.line, '\n')
+					r.line = append(r.line, '\n')
 				}
 			}
 			continue
 		}
-		b := q.line[0]
+		b := r.line[0]
 
 		switch {
 		case b == '=':
-			b, err = q.readHexByte(q.line[1:])
+			b, err = readHexByte(r.line[1:])
 			if err != nil {
 				return n, err
 			}
-			q.line = q.line[2:] // 2 of the 3; other 1 is done below
+			r.line = r.line[2:] // 2 of the 3; other 1 is done below
 		case b == '\t' || b == '\r' || b == '\n':
 			break
 		case b < ' ' || b > '~':
@@ -115,7 +117,7 @@
 		}
 		p[0] = b
 		p = p[1:]
-		q.line = q.line[1:]
+		r.line = r.line[1:]
 		n++
 	}
 	return n, nil
diff --git a/src/mime/type_windows.go b/src/mime/type_windows.go
index 60362b4..97b9aeb 100644
--- a/src/mime/type_windows.go
+++ b/src/mime/type_windows.go
@@ -5,8 +5,7 @@
 package mime
 
 import (
-	"syscall"
-	"unsafe"
+	"internal/syscall/windows/registry"
 )
 
 func init() {
@@ -14,49 +13,24 @@
 }
 
 func initMimeWindows() {
-	var root syscall.Handle
-	rootpathp, _ := syscall.UTF16PtrFromString(`\`)
-	if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp,
-		0, syscall.KEY_READ, &root) != nil {
+	names, err := registry.CLASSES_ROOT.ReadSubKeyNames(-1)
+	if err != nil {
 		return
 	}
-	defer syscall.RegCloseKey(root)
-	var count uint32
-	if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != nil {
-		return
-	}
-	contenttypep, _ := syscall.UTF16PtrFromString("Content Type")
-	var buf [1 << 10]uint16
-	for i := uint32(0); i < count; i++ {
-		n := uint32(len(buf))
-		if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != nil {
+	for _, name := range names {
+		if len(name) < 2 || name[0] != '.' { // looking for extensions only
 			continue
 		}
-		ext := syscall.UTF16ToString(buf[:])
-		if len(ext) < 2 || ext[0] != '.' { // looking for extensions only
+		k, err := registry.OpenKey(registry.CLASSES_ROOT, name, registry.READ)
+		if err != nil {
 			continue
 		}
-		var h syscall.Handle
-		extpathp, _ := syscall.UTF16PtrFromString(`\` + ext)
-		if syscall.RegOpenKeyEx(
-			syscall.HKEY_CLASSES_ROOT, extpathp,
-			0, syscall.KEY_READ, &h) != nil {
+		v, _, err := k.GetStringValue("Content Type")
+		k.Close()
+		if err != nil {
 			continue
 		}
-		var typ uint32
-		n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
-		if syscall.RegQueryValueEx(
-			h, contenttypep,
-			nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil {
-			syscall.RegCloseKey(h)
-			continue
-		}
-		syscall.RegCloseKey(h)
-		if typ != syscall.REG_SZ { // null terminated strings only
-			continue
-		}
-		mimeType := syscall.UTF16ToString(buf[:])
-		setExtensionType(ext, mimeType)
+		setExtensionType(name, v)
 	}
 }
 
diff --git a/src/nacltest.bash b/src/nacltest.bash
index eb1ac3d..049aad2 100755
--- a/src/nacltest.bash
+++ b/src/nacltest.bash
@@ -78,3 +78,5 @@
 # Run standard build and tests.
 export PATH=$(pwd)/../misc/nacl:$PATH
 GOOS=nacl GOARCH=$naclGOARCH ./all.bash
+
+rm -f syscall/fstest_nacl.go
diff --git a/src/net/cgo_android.go b/src/net/cgo_android.go
index 3819ce5..fe9925b 100644
--- a/src/net/cgo_android.go
+++ b/src/net/cgo_android.go
@@ -9,6 +9,4 @@
 //#include <netdb.h>
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
diff --git a/src/net/cgo_bsd.go b/src/net/cgo_bsd.go
index 388eab4..c5ec9dd 100644
--- a/src/net/cgo_bsd.go
+++ b/src/net/cgo_bsd.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.
 
-// +build !netgo
+// +build cgo,!netgo
 // +build darwin dragonfly freebsd
 
 package net
@@ -12,6 +12,4 @@
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
-}
+const cgoAddrInfoFlags = (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
diff --git a/src/net/cgo_linux.go b/src/net/cgo_linux.go
index 4ef2d0c..9a5f898 100644
--- a/src/net/cgo_linux.go
+++ b/src/net/cgo_linux.go
@@ -11,12 +11,10 @@
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	// NOTE(rsc): In theory there are approximately balanced
-	// arguments for and against including AI_ADDRCONFIG
-	// in the flags (it includes IPv4 results only on IPv4 systems,
-	// and similarly for IPv6), but in practice setting it causes
-	// getaddrinfo to return the wrong canonical name on Linux.
-	// So definitely leave it out.
-	return C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
-}
+// NOTE(rsc): In theory there are approximately balanced
+// arguments for and against including AI_ADDRCONFIG
+// in the flags (it includes IPv4 results only on IPv4 systems,
+// and similarly for IPv6), but in practice setting it causes
+// getaddrinfo to return the wrong canonical name on Linux.
+// So definitely leave it out.
+const cgoAddrInfoFlags = C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
diff --git a/src/net/cgo_netbsd.go b/src/net/cgo_netbsd.go
index 09c5ad2..1830913 100644
--- a/src/net/cgo_netbsd.go
+++ b/src/net/cgo_netbsd.go
@@ -11,6 +11,4 @@
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
diff --git a/src/net/cgo_openbsd.go b/src/net/cgo_openbsd.go
index 09c5ad2..1830913 100644
--- a/src/net/cgo_openbsd.go
+++ b/src/net/cgo_openbsd.go
@@ -11,6 +11,4 @@
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
diff --git a/src/net/cgo_solaris.go b/src/net/cgo_solaris.go
new file mode 100644
index 0000000..2d452b9
--- /dev/null
+++ b/src/net/cgo_solaris.go
@@ -0,0 +1,15 @@
+// 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 cgo,!netgo
+
+package net
+
+/*
+#cgo LDFLAGS: -lsocket -lnsl
+#include <netdb.h>
+*/
+import "C"
+
+const cgoAddrInfoFlags = C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index d2d40da..c4937ef 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -4,10 +4,14 @@
 
 // +build !cgo netgo
 
-// Stub cgo routines for systems that do not use cgo to do network lookups.
-
 package net
 
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return "<nil>" }
+func (eai addrinfoErrno) Temporary() bool { return false }
+func (eai addrinfoErrno) Timeout() bool   { return false }
+
 func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
 	return nil, nil, false
 }
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index eba5777..34588a3 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !netgo
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build cgo,!netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
@@ -23,24 +23,30 @@
 	"unsafe"
 )
 
-func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
-	ip, err, completed := cgoLookupIP(name)
-	for _, p := range ip {
-		addrs = append(addrs, p.String())
+// An addrinfoErrno represents a getaddrinfo, getnameinfo-specific
+// error number. It's a signed number and a zero value is a non-error
+// by convention.
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return C.GoString(C.gai_strerror(C.int(eai))) }
+func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN }
+func (eai addrinfoErrno) Timeout() bool   { return false }
+
+func cgoLookupHost(name string) (hosts []string, err error, completed bool) {
+	addrs, err, completed := cgoLookupIP(name)
+	for _, addr := range addrs {
+		hosts = append(hosts, addr.String())
 	}
 	return
 }
 
-func cgoLookupPort(net, service string) (port int, err error, completed bool) {
+func cgoLookupPort(network, service string) (port int, err error, completed bool) {
 	acquireThread()
 	defer releaseThread()
 
-	var res *C.struct_addrinfo
 	var hints C.struct_addrinfo
-
-	switch net {
-	case "":
-		// no hints
+	switch network {
+	case "": // no hints
 	case "tcp", "tcp4", "tcp6":
 		hints.ai_socktype = C.SOCK_STREAM
 		hints.ai_protocol = C.IPPROTO_TCP
@@ -48,10 +54,10 @@
 		hints.ai_socktype = C.SOCK_DGRAM
 		hints.ai_protocol = C.IPPROTO_UDP
 	default:
-		return 0, UnknownNetworkError(net), true
+		return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true
 	}
-	if len(net) >= 4 {
-		switch net[3] {
+	if len(network) >= 4 {
+		switch network[3] {
 		case '4':
 			hints.ai_family = C.AF_INET
 		case '6':
@@ -60,45 +66,52 @@
 	}
 
 	s := C.CString(service)
+	var res *C.struct_addrinfo
 	defer C.free(unsafe.Pointer(s))
-	if C.getaddrinfo(nil, s, &hints, &res) == 0 {
-		defer C.freeaddrinfo(res)
-		for r := res; r != nil; r = r.ai_next {
-			switch r.ai_family {
-			default:
-				continue
-			case C.AF_INET:
-				sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
-				p := (*[2]byte)(unsafe.Pointer(&sa.Port))
-				return int(p[0])<<8 | int(p[1]), nil, true
-			case C.AF_INET6:
-				sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
-				p := (*[2]byte)(unsafe.Pointer(&sa.Port))
-				return int(p[0])<<8 | int(p[1]), nil, true
+	gerrno, err := C.getaddrinfo(nil, s, &hints, &res)
+	if gerrno != 0 {
+		switch gerrno {
+		case C.EAI_SYSTEM:
+			if err == nil { // see golang.org/issue/6232
+				err = syscall.EMFILE
 			}
+		default:
+			err = addrinfoErrno(gerrno)
+		}
+		return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true
+	}
+	defer C.freeaddrinfo(res)
+
+	for r := res; r != nil; r = r.ai_next {
+		switch r.ai_family {
+		case C.AF_INET:
+			sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+			p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+			return int(p[0])<<8 | int(p[1]), nil, true
+		case C.AF_INET6:
+			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+			p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+			return int(p[0])<<8 | int(p[1]), nil, true
 		}
 	}
-	return 0, &AddrError{"unknown port", net + "/" + service}, true
+	return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true
 }
 
 func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
 	acquireThread()
 	defer releaseThread()
 
-	var res *C.struct_addrinfo
 	var hints C.struct_addrinfo
-
-	hints.ai_flags = cgoAddrInfoFlags()
+	hints.ai_flags = cgoAddrInfoFlags
 	hints.ai_socktype = C.SOCK_STREAM
 
 	h := C.CString(name)
 	defer C.free(unsafe.Pointer(h))
+	var res *C.struct_addrinfo
 	gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
 	if gerrno != 0 {
-		var str string
-		if gerrno == C.EAI_NONAME {
-			str = noSuchHost
-		} else if gerrno == C.EAI_SYSTEM {
+		switch gerrno {
+		case C.EAI_SYSTEM:
 			if err == nil {
 				// err should not be nil, but sometimes getaddrinfo returns
 				// gerrno == C.EAI_SYSTEM with err == nil on Linux.
@@ -109,13 +122,15 @@
 				// comes up again. golang.org/issue/6232.
 				err = syscall.EMFILE
 			}
-			str = err.Error()
-		} else {
-			str = C.GoString(C.gai_strerror(gerrno))
+		case C.EAI_NONAME:
+			err = errNoSuchHost
+		default:
+			err = addrinfoErrno(gerrno)
 		}
-		return nil, "", &DNSError{Err: str, Name: name}, true
+		return nil, "", &DNSError{Err: err.Error(), Name: name}, true
 	}
 	defer C.freeaddrinfo(res)
+
 	if res != nil {
 		cname = C.GoString(res.ai_canonname)
 		if cname == "" {
@@ -131,8 +146,6 @@
 			continue
 		}
 		switch r.ai_family {
-		default:
-			continue
 		case C.AF_INET:
 			sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
 			addr := IPAddr{IP: copyIP(sa.Addr[:])}
diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go
index 33566ce9..55ea86a 100644
--- a/src/net/cgo_unix_test.go
+++ b/src/net/cgo_unix_test.go
@@ -16,9 +16,9 @@
 		t.Errorf("cgoLookupIP must not be a placeholder")
 	}
 	if err != nil {
-		t.Errorf("cgoLookupIP failed: %v", err)
+		t.Error(err)
 	}
 	if _, err := goLookupIP(host); err != nil {
-		t.Errorf("goLookupIP failed: %v", err)
+		t.Error(err)
 	}
 }
diff --git a/src/net/cgo_windows.go b/src/net/cgo_windows.go
new file mode 100644
index 0000000..8968b75
--- /dev/null
+++ b/src/net/cgo_windows.go
@@ -0,0 +1,13 @@
+// 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 cgo,!netgo
+
+package net
+
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return "<nil>" }
+func (eai addrinfoErrno) Temporary() bool { return false }
+func (eai addrinfoErrno) Timeout() bool   { return false }
diff --git a/src/net/conf.go b/src/net/conf.go
new file mode 100644
index 0000000..ca7fa87
--- /dev/null
+++ b/src/net/conf.go
@@ -0,0 +1,234 @@
+// 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 netbsd openbsd solaris
+
+package net
+
+import (
+	"os"
+	"runtime"
+	"sync"
+	"syscall"
+)
+
+// conf represents a system's network configuration.
+type conf struct {
+	// forceCgoLookupHost forces CGO to always be used, if available.
+	forceCgoLookupHost bool
+
+	// machine has an /etc/mdns.allow file
+	hasMDNSAllow bool
+
+	goos string // the runtime.GOOS, to ease testing
+
+	nss    *nssConf
+	resolv *dnsConfig
+}
+
+var (
+	confOnce sync.Once // guards init of confVal via initConfVal
+	confVal  = &conf{goos: runtime.GOOS}
+)
+
+// systemConf returns the machine's network configuration.
+func systemConf() *conf {
+	confOnce.Do(initConfVal)
+	return confVal
+}
+
+func initConfVal() {
+	// Darwin pops up annoying dialog boxes if programs try to do
+	// their own DNS requests. So always use cgo instead, which
+	// avoids that.
+	if runtime.GOOS == "darwin" {
+		confVal.forceCgoLookupHost = true
+		return
+	}
+
+	// If any environment-specified resolver options are specified,
+	// force cgo. Note that LOCALDOMAIN can change behavior merely
+	// by being specified with the empty string.
+	_, localDomainDefined := syscall.Getenv("LOCALDOMAIN")
+	if os.Getenv("RES_OPTIONS") != "" || os.Getenv("HOSTALIASES") != "" ||
+		localDomainDefined {
+		confVal.forceCgoLookupHost = true
+		return
+	}
+
+	// OpenBSD apparently lets you override the location of resolv.conf
+	// with ASR_CONFIG. If we notice that, defer to libc.
+	if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
+		confVal.forceCgoLookupHost = true
+		return
+	}
+
+	if runtime.GOOS != "openbsd" {
+		confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
+	}
+
+	confVal.resolv = dnsReadConfig("/etc/resolv.conf")
+	if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) &&
+		!os.IsPermission(confVal.resolv.err) {
+		// If we can't read the resolv.conf file, assume it
+		// had something important in it and defer to cgo.
+		// libc's resolver might then fail too, but at least
+		// it wasn't our fault.
+		confVal.forceCgoLookupHost = true
+	}
+
+	if _, err := os.Stat("/etc/mdns.allow"); err == nil {
+		confVal.hasMDNSAllow = true
+	}
+}
+
+// hostLookupOrder determines which strategy to use to resolve hostname.
+func (c *conf) hostLookupOrder(hostname string) hostLookupOrder {
+	if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
+		return hostLookupCgo
+	}
+	if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 {
+		// Don't deal with special form hostnames with backslashes
+		// or '%'.
+		return hostLookupCgo
+	}
+
+	// OpenBSD is unique and doesn't use nsswitch.conf.
+	// It also doesn't support mDNS.
+	if c.goos == "openbsd" {
+		// OpenBSD's resolv.conf manpage says that a non-existent
+		// resolv.conf means "lookup" defaults to only "files",
+		// without DNS lookups.
+		if os.IsNotExist(c.resolv.err) {
+			return hostLookupFiles
+		}
+		lookup := c.resolv.lookup
+		if len(lookup) == 0 {
+			// http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5
+			// "If the lookup keyword is not used in the
+			// system's resolv.conf file then the assumed
+			// order is 'bind file'"
+			return hostLookupDNSFiles
+		}
+		if len(lookup) < 1 || len(lookup) > 2 {
+			return hostLookupCgo
+		}
+		switch lookup[0] {
+		case "bind":
+			if len(lookup) == 2 {
+				if lookup[1] == "file" {
+					return hostLookupDNSFiles
+				}
+				return hostLookupCgo
+			}
+			return hostLookupDNS
+		case "file":
+			if len(lookup) == 2 {
+				if lookup[1] == "bind" {
+					return hostLookupFilesDNS
+				}
+				return hostLookupCgo
+			}
+			return hostLookupFiles
+		default:
+			return hostLookupCgo
+		}
+	}
+
+	hasDot := byteIndex(hostname, '.') != -1
+
+	// Canonicalize the hostname by removing any trailing dot.
+	if stringsHasSuffix(hostname, ".") {
+		hostname = hostname[:len(hostname)-1]
+	}
+	if stringsHasSuffixFold(hostname, ".local") {
+		// Per RFC 6762, the ".local" TLD is special.  And
+		// because Go's native resolver doesn't do mDNS or
+		// similar local resolution mechanisms, assume that
+		// libc might (via Avahi, etc) and use cgo.
+		return hostLookupCgo
+	}
+
+	nss := c.nss
+	srcs := nss.sources["hosts"]
+	// If /etc/nsswitch.conf doesn't exist or doesn't specify any
+	// sources for "hosts", assume Go's DNS will work fine.
+	if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
+		if c.goos == "solaris" {
+			// illumos defaults to "nis [NOTFOUND=return] files"
+			return hostLookupCgo
+		}
+		if c.goos == "linux" {
+			// glibc says the default is "dns [!UNAVAIL=return] files"
+			// http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html.
+			return hostLookupDNSFiles
+		}
+		return hostLookupFilesDNS
+	}
+	if nss.err != nil {
+		// We failed to parse or open nsswitch.conf, so
+		// conservatively assume we should use cgo if it's
+		// available.
+		return hostLookupCgo
+	}
+
+	var mdnsSource, filesSource, dnsSource bool
+	var first string
+	for _, src := range srcs {
+		if src.source == "myhostname" {
+			if hasDot {
+				continue
+			}
+			return hostLookupCgo
+		}
+		if src.source == "files" || src.source == "dns" {
+			if !src.standardCriteria() {
+				return hostLookupCgo // non-standard; let libc deal with it.
+			}
+			if src.source == "files" {
+				filesSource = true
+			} else if src.source == "dns" {
+				dnsSource = true
+			}
+			if first == "" {
+				first = src.source
+			}
+			continue
+		}
+		if stringsHasPrefix(src.source, "mdns") {
+			// e.g. "mdns4", "mdns4_minimal"
+			// We already returned true before if it was *.local.
+			// libc wouldn't have found a hit on this anyway.
+			mdnsSource = true
+			continue
+		}
+		// Some source we don't know how to deal with.
+		return hostLookupCgo
+	}
+
+	// We don't parse mdns.allow files. They're rare. If one
+	// exists, it might list other TLDs (besides .local) or even
+	// '*', so just let libc deal with it.
+	if mdnsSource && c.hasMDNSAllow {
+		return hostLookupCgo
+	}
+
+	// Cases where Go can handle it without cgo and C thread
+	// overhead.
+	switch {
+	case filesSource && dnsSource:
+		if first == "files" {
+			return hostLookupFilesDNS
+		} else {
+			return hostLookupDNSFiles
+		}
+	case filesSource:
+		return hostLookupFiles
+	case dnsSource:
+		return hostLookupDNS
+	}
+
+	// Something weird. Let libc deal with it.
+	return hostLookupCgo
+}
diff --git a/src/net/conf_test.go b/src/net/conf_test.go
new file mode 100644
index 0000000..003c615
--- /dev/null
+++ b/src/net/conf_test.go
@@ -0,0 +1,297 @@
+// 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 netbsd openbsd solaris
+
+package net
+
+import (
+	"os"
+	"strings"
+	"testing"
+)
+
+type nssHostTest struct {
+	host string
+	want hostLookupOrder
+}
+
+func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) }
+
+// represents a dnsConfig returned by parsing a nonexistent resolv.conf
+var defaultResolvConf = &dnsConfig{
+	servers:  defaultNS,
+	ndots:    1,
+	timeout:  5,
+	attempts: 2,
+	err:      os.ErrNotExist,
+}
+
+func TestConfHostLookupOrder(t *testing.T) {
+	tests := []struct {
+		name      string
+		c         *conf
+		goos      string
+		hostTests []nssHostTest
+	}{
+		{
+			name: "force",
+			c: &conf{
+				forceCgoLookupHost: true,
+				nss:                nssStr("foo: bar"),
+				resolv:             defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"foo.local", hostLookupCgo},
+				{"google.com", hostLookupCgo},
+			},
+		},
+		{
+			name: "ubuntu_trusty_avahi",
+			c: &conf{
+				nss:    nssStr("hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"foo.local", hostLookupCgo},
+				{"foo.local.", hostLookupCgo},
+				{"foo.LOCAL", hostLookupCgo},
+				{"foo.LOCAL.", hostLookupCgo},
+				{"google.com", hostLookupFilesDNS},
+			},
+		},
+		{
+			name: "freebsdlinux_no_resolv_conf",
+			c: &conf{
+				goos:   "freebsd",
+				nss:    nssStr("foo: bar"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+		},
+		// On OpenBSD, no resolv.conf means no DNS.
+		{
+			name: "openbsd_no_resolv_conf",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+		},
+		{
+			name: "solaris_no_nsswitch",
+			c: &conf{
+				goos:   "solaris",
+				nss:    &nssConf{err: os.ErrNotExist},
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		{
+			name: "openbsd_lookup_bind_file",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"bind", "file"}},
+			},
+			hostTests: []nssHostTest{
+				{"google.com", hostLookupDNSFiles},
+				{"foo.local", hostLookupDNSFiles},
+			},
+		},
+		{
+			name: "openbsd_lookup_file_bind",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file", "bind"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+		},
+		{
+			name: "openbsd_lookup_bind",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"bind"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupDNS}},
+		},
+		{
+			name: "openbsd_lookup_file",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+		},
+		{
+			name: "openbsd_lookup_yp",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file", "bind", "yp"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		{
+			name: "openbsd_lookup_two",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file", "foo"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		{
+			name: "openbsd_lookup_empty",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: nil},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+		},
+		// glibc lacking an nsswitch.conf, per
+		// http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html
+		{
+			name: "linux_no_nsswitch.conf",
+			c: &conf{
+				goos:   "linux",
+				nss:    &nssConf{err: os.ErrNotExist},
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+		},
+		{
+			name: "files_mdns_dns",
+			c: &conf{
+				nss:    nssStr("hosts: files mdns dns"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "dns_special_hostnames",
+			c: &conf{
+				nss:    nssStr("hosts: dns"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNS},
+				{"x\\.com", hostLookupCgo},     // punt on weird glibc escape
+				{"foo.com%en0", hostLookupCgo}, // and IPv6 zones
+			},
+		},
+		{
+			name: "mdns_allow",
+			c: &conf{
+				nss:          nssStr("hosts: files mdns dns"),
+				resolv:       defaultResolvConf,
+				hasMDNSAllow: true,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupCgo},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "files_dns",
+			c: &conf{
+				nss:    nssStr("hosts: files dns"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"x", hostLookupFilesDNS},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "dns_files",
+			c: &conf{
+				nss:    nssStr("hosts: dns files"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNSFiles},
+				{"x", hostLookupDNSFiles},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "something_custom",
+			c: &conf{
+				nss:    nssStr("hosts: dns files something_custom"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupCgo},
+			},
+		},
+		{
+			name: "myhostname",
+			c: &conf{
+				nss:    nssStr("hosts: files dns myhostname"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"somehostname", hostLookupCgo},
+			},
+		},
+		{
+			name: "ubuntu14.04.02",
+			c: &conf{
+				nss:    nssStr("hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"somehostname", hostLookupCgo},
+			},
+		},
+		// Debian Squeeze is just "dns,files", but lists all
+		// the default criteria for dns, but then has a
+		// non-standard but redundant notfound=return for the
+		// files.
+		{
+			name: "debian_squeeze",
+			c: &conf{
+				nss:    nssStr("hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNSFiles},
+				{"somehostname", hostLookupDNSFiles},
+			},
+		},
+		{
+			name: "resolv.conf-unknown",
+			c: &conf{
+				nss:    nssStr("foo: bar"),
+				resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		// Android should always use cgo.
+		{
+			name: "android",
+			c: &conf{
+				goos:   "android",
+				nss:    nssStr(""),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupCgo},
+			},
+		},
+	}
+	for _, tt := range tests {
+		for _, ht := range tt.hostTests {
+			gotOrder := tt.c.hostLookupOrder(ht.host)
+			if gotOrder != ht.want {
+				t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want)
+			}
+		}
+	}
+
+}
diff --git a/src/net/conn_test.go b/src/net/conn_test.go
index 912c084..6995c11 100644
--- a/src/net/conn_test.go
+++ b/src/net/conn_test.go
@@ -8,106 +8,58 @@
 package net
 
 import (
-	"os"
 	"testing"
 	"time"
 )
 
-var connTests = []struct {
-	net  string
-	addr string
-}{
-	{"tcp", "127.0.0.1:0"},
-	{"unix", testUnixAddr()},
-	{"unixpacket", testUnixAddr()},
-}
-
 // someTimeout is used just to test that net.Conn implementations
 // don't explode when their SetFooDeadline methods are called.
 // It isn't actually used for testing timeouts.
 const someTimeout = 10 * time.Second
 
 func TestConnAndListener(t *testing.T) {
-	for _, tt := range connTests {
-		if !testableNetwork(tt.net) {
-			t.Logf("skipping %s test", tt.net)
+	for i, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
 			continue
 		}
 
-		ln, err := Listen(tt.net, tt.addr)
+		ls, err := newLocalServer(network)
 		if err != nil {
-			t.Fatalf("Listen failed: %v", err)
+			t.Fatal(err)
 		}
-		defer func(ln Listener, net, addr string) {
-			ln.Close()
-			switch net {
-			case "unix", "unixpacket":
-				os.Remove(addr)
-			}
-		}(ln, tt.net, tt.addr)
-		if ln.Addr().Network() != tt.net {
-			t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net)
+		defer ls.teardown()
+		ch := make(chan error, 1)
+		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+		if ls.Listener.Addr().Network() != network {
+			t.Fatalf("got %s; want %s", ls.Listener.Addr().Network(), network)
 		}
 
-		done := make(chan int)
-		go transponder(t, ln, done)
-
-		c, err := Dial(tt.net, ln.Addr().String())
+		c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
-		if c.LocalAddr().Network() != tt.net || c.LocalAddr().Network() != tt.net {
-			t.Fatalf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), tt.net, tt.net)
+		if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+			t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
 		}
 		c.SetDeadline(time.Now().Add(someTimeout))
 		c.SetReadDeadline(time.Now().Add(someTimeout))
 		c.SetWriteDeadline(time.Now().Add(someTimeout))
 
-		if _, err := c.Write([]byte("CONN TEST")); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+		if _, err := c.Write([]byte("CONN AND LISTENER TEST")); err != nil {
+			t.Fatal(err)
 		}
 		rb := make([]byte, 128)
 		if _, err := c.Read(rb); err != nil {
-			t.Fatalf("Conn.Read failed: %v", err)
+			t.Fatal(err)
 		}
 
-		<-done
-	}
-}
-
-func transponder(t *testing.T, ln Listener, done chan<- int) {
-	defer func() { done <- 1 }()
-
-	switch ln := ln.(type) {
-	case *TCPListener:
-		ln.SetDeadline(time.Now().Add(someTimeout))
-	case *UnixListener:
-		ln.SetDeadline(time.Now().Add(someTimeout))
-	}
-	c, err := ln.Accept()
-	if err != nil {
-		t.Errorf("Listener.Accept failed: %v", err)
-		return
-	}
-	defer c.Close()
-	network := ln.Addr().Network()
-	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
-		t.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
-		return
-	}
-	c.SetDeadline(time.Now().Add(someTimeout))
-	c.SetReadDeadline(time.Now().Add(someTimeout))
-	c.SetWriteDeadline(time.Now().Add(someTimeout))
-
-	b := make([]byte, 128)
-	n, err := c.Read(b)
-	if err != nil {
-		t.Errorf("Conn.Read failed: %v", err)
-		return
-	}
-	if _, err := c.Write(b[:n]); err != nil {
-		t.Errorf("Conn.Write failed: %v", err)
-		return
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
+		}
 	}
 }
diff --git a/src/net/dial.go b/src/net/dial.go
index 0424ed2..4f0c6cb 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -95,7 +95,7 @@
 	return "", 0, UnknownNetworkError(net)
 }
 
-func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
+func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) {
 	afnet, _, err := parseNetwork(net)
 	if err != nil {
 		return nil, err
@@ -105,9 +105,13 @@
 	}
 	switch afnet {
 	case "unix", "unixgram", "unixpacket":
-		return ResolveUnixAddr(afnet, addr)
+		addr, err := ResolveUnixAddr(afnet, addr)
+		if err != nil {
+			return nil, err
+		}
+		return addrList{addr}, nil
 	}
-	return resolveInternetAddr(afnet, addr, deadline)
+	return internetAddrList(afnet, addr, deadline)
 }
 
 // Dial connects to the address on the named network.
@@ -155,33 +159,35 @@
 // See func Dial for a description of the network and address
 // parameters.
 func (d *Dialer) Dial(network, address string) (Conn, error) {
-	ra, err := resolveAddr("dial", network, address, d.deadline())
+	addrs, err := resolveAddrList("dial", network, address, d.deadline())
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
+		return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
 	}
 	var dialer func(deadline time.Time) (Conn, error)
-	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
-		dialer = func(deadline time.Time) (Conn, error) {
-			return dialMulti(network, address, d.LocalAddr, ras, deadline)
-		}
-	} else {
-		dialer = func(deadline time.Time) (Conn, error) {
-			return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
+	if d.DualStack && network == "tcp" {
+		primaries, fallbacks := addrs.partition(isIPv4)
+		if len(fallbacks) > 0 {
+			dialer = func(deadline time.Time) (Conn, error) {
+				return dialMulti(network, address, d.LocalAddr, addrList{primaries[0], fallbacks[0]}, deadline)
+			}
 		}
 	}
-	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
+	if dialer == nil {
+		dialer = func(deadline time.Time) (Conn, error) {
+			return dialSingle(network, address, d.LocalAddr, addrs.first(isIPv4), deadline)
+		}
+	}
+	c, err := dial(network, addrs.first(isIPv4), dialer, d.deadline())
 	if d.KeepAlive > 0 && err == nil {
 		if tc, ok := c.(*TCPConn); ok {
-			tc.SetKeepAlive(true)
-			tc.SetKeepAlivePeriod(d.KeepAlive)
+			setKeepAlive(tc.fd, true)
+			setKeepAlivePeriod(tc.fd, d.KeepAlive)
 			testHookSetKeepAlive()
 		}
 	}
 	return c, err
 }
 
-var testHookSetKeepAlive = func() {} // changed by dial_test.go
-
 // dialMulti attempts to establish connections to each destination of
 // the list of addresses. It will return the first established
 // connection and close the other connections. Otherwise it returns
@@ -208,7 +214,7 @@
 				// unnecessary resource starvation.
 				c.Close()
 			}
-		}(ra.toAddr())
+		}(ra)
 	}
 	defer close(sig)
 	lastErr := errTimeout
@@ -229,7 +235,7 @@
 // the destination address.
 func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
 	if la != nil && la.Network() != ra.Network() {
-		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
+		return nil, &OpError{Op: "dial", Net: net, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
 	}
 	switch ra := ra.(type) {
 	case *TCPAddr:
@@ -245,7 +251,7 @@
 		la, _ := la.(*UnixAddr)
 		c, err = dialUnix(net, la, ra, deadline)
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
+		return nil, &OpError{Op: "dial", Net: net, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
 	}
 	if err != nil {
 		return nil, err // c is non-nil interface containing nil pointer
@@ -258,18 +264,18 @@
 // "tcp6", "unix" or "unixpacket".
 // See Dial for the syntax of laddr.
 func Listen(net, laddr string) (Listener, error) {
-	la, err := resolveAddr("listen", net, laddr, noDeadline)
+	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 	}
 	var l Listener
-	switch la := la.toAddr().(type) {
+	switch la := addrs.first(isIPv4).(type) {
 	case *TCPAddr:
 		l, err = ListenTCP(net, la)
 	case *UnixAddr:
 		l, err = ListenUnix(net, la)
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 	}
 	if err != nil {
 		return nil, err // l is non-nil interface containing nil pointer
@@ -282,12 +288,12 @@
 // "udp6", "ip", "ip4", "ip6" or "unixgram".
 // See Dial for the syntax of laddr.
 func ListenPacket(net, laddr string) (PacketConn, error) {
-	la, err := resolveAddr("listen", net, laddr, noDeadline)
+	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 	}
 	var l PacketConn
-	switch la := la.toAddr().(type) {
+	switch la := addrs.first(isIPv4).(type) {
 	case *UDPAddr:
 		l, err = ListenUDP(net, la)
 	case *IPAddr:
@@ -295,7 +301,7 @@
 	case *UnixAddr:
 		l, err = ListenUnixgram(net, la)
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 	}
 	if err != nil {
 		return nil, err // l is non-nil interface containing nil pointer
diff --git a/src/net/dial_gen.go b/src/net/dial_gen.go
index ada6233..a628f71 100644
--- a/src/net/dial_gen.go
+++ b/src/net/dial_gen.go
@@ -6,23 +6,19 @@
 
 package net
 
-import (
-	"time"
-)
-
-var testingIssue5349 bool // used during tests
+import "time"
 
 // dialChannel is the simple pure-Go implementation of dial, still
 // used on operating systems where the deadline hasn't been pushed
 // down into the pollserver. (Plan 9 and some old versions of Windows)
 func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
-	var timeout time.Duration
-	if !deadline.IsZero() {
-		timeout = deadline.Sub(time.Now())
-	}
-	if timeout <= 0 {
+	if deadline.IsZero() {
 		return dialer(noDeadline)
 	}
+	timeout := deadline.Sub(time.Now())
+	if timeout <= 0 {
+		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
+	}
 	t := time.NewTimer(timeout)
 	defer t.Stop()
 	type racer struct {
@@ -31,15 +27,13 @@
 	}
 	ch := make(chan racer, 1)
 	go func() {
-		if testingIssue5349 {
-			time.Sleep(time.Millisecond)
-		}
+		testHookDialChannel()
 		c, err := dialer(noDeadline)
 		ch <- racer{c, err}
 	}()
 	select {
 	case <-t.C:
-		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errTimeout}
+		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
 	case racer := <-ch:
 		return racer.Conn, racer.error
 	}
diff --git a/src/net/dial_gen_test.go b/src/net/dial_gen_test.go
deleted file mode 100644
index c857acd..0000000
--- a/src/net/dial_gen_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 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 plan9
-
-package net
-
-func init() {
-	testingIssue5349 = true
-}
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 42898d6..f5141bc 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -5,111 +5,49 @@
 package net
 
 import (
-	"bytes"
-	"flag"
-	"fmt"
-	"io"
-	"os"
-	"os/exec"
-	"reflect"
-	"regexp"
+	"net/internal/socktest"
 	"runtime"
-	"strconv"
 	"sync"
 	"testing"
 	"time"
 )
 
-func newLocalListener(t *testing.T) Listener {
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		ln, err = Listen("tcp6", "[::1]:0")
+var prohibitionaryDialArgTests = []struct {
+	network string
+	address string
+}{
+	{"tcp6", "127.0.0.1"},
+	{"tcp6", "::ffff:127.0.0.1"},
+}
+
+func TestProhibitionaryDialArg(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4map {
+		t.Skip("mapping ipv4 address inside ipv6 address not supported")
+	}
+
+	ln, err := Listen("tcp", "[::]:0")
 	if err != nil {
 		t.Fatal(err)
 	}
-	return ln
-}
-
-func TestDialTimeout(t *testing.T) {
-	origBacklog := listenerBacklog
-	defer func() {
-		listenerBacklog = origBacklog
-	}()
-	listenerBacklog = 1
-
-	ln := newLocalListener(t)
 	defer ln.Close()
 
-	errc := make(chan error)
-
-	numConns := listenerBacklog + 100
-
-	// TODO(bradfitz): It's hard to test this in a portable
-	// way. This is unfortunate, but works for now.
-	switch runtime.GOOS {
-	case "linux":
-		// The kernel will start accepting TCP connections before userspace
-		// gets a chance to not accept them, so fire off a bunch to fill up
-		// the kernel's backlog.  Then we test we get a failure after that.
-		for i := 0; i < numConns; i++ {
-			go func() {
-				_, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
-				errc <- err
-			}()
-		}
-	case "darwin", "plan9", "windows":
-		// At least OS X 10.7 seems to accept any number of
-		// connections, ignoring listen's backlog, so resort
-		// to connecting to a hopefully-dead 127/8 address.
-		// Same for windows.
-		//
-		// Use an IANA reserved port (49151) instead of 80, because
-		// on our 386 builder, this Dial succeeds, connecting
-		// to an IIS web server somewhere.  The data center
-		// or VM or firewall must be stealing the TCP connection.
-		//
-		// IANA Service Name and Transport Protocol Port Number Registry
-		// <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
-		go func() {
-			c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
-			if err == nil {
-				err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
-				c.Close()
-			}
-			errc <- err
-		}()
-	default:
-		// TODO(bradfitz):
-		// OpenBSD may have a reject route to 127/8 except 127.0.0.1/32
-		// by default. FreeBSD likely works, but is untested.
-		// TODO(rsc):
-		// The timeout never happens on Windows.  Why?  Issue 3016.
-		t.Skipf("skipping test on %q; untested.", runtime.GOOS)
+	_, port, err := SplitHostPort(ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 
-	connected := 0
-	for {
-		select {
-		case <-time.After(15 * time.Second):
-			t.Fatal("too slow")
-		case err := <-errc:
-			if err == nil {
-				connected++
-				if connected == numConns {
-					t.Fatal("all connections connected; expected some to time out")
-				}
-			} else {
-				terr, ok := err.(timeout)
-				if !ok {
-					t.Fatalf("got error %q; want error with timeout interface", err)
-				}
-				if !terr.Timeout() {
-					t.Fatalf("got error %q; not a timeout", err)
-				}
-				// Pass. We saw a timeout error.
-				return
-			}
+	for i, tt := range prohibitionaryDialArgTests {
+		c, err := Dial(tt.network, JoinHostPort(tt.address, port))
+		if err == nil {
+			c.Close()
+			t.Errorf("#%d: %v", i, err)
 		}
 	}
 }
@@ -117,7 +55,7 @@
 func TestSelfConnect(t *testing.T) {
 	if runtime.GOOS == "windows" {
 		// TODO(brainman): do not know why it hangs.
-		t.Skip("skipping known-broken test on windows")
+		t.Skip("known-broken test on windows")
 	}
 
 	// Test that Dial does not honor self-connects.
@@ -160,303 +98,144 @@
 	}
 }
 
-var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
-
-type DialErrorTest struct {
-	Net     string
-	Raddr   string
-	Pattern string
-}
-
-var dialErrorTests = []DialErrorTest{
-	{
-		"datakit", "mh/astro/r70",
-		"dial datakit mh/astro/r70: unknown network datakit",
-	},
-	{
-		"tcp", "127.0.0.1:☺",
-		"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
-	},
-	{
-		"tcp", "no-such-name.google.com.:80",
-		"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
-	},
-	{
-		"tcp", "no-such-name.no-such-top-level-domain.:80",
-		"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
-	},
-	{
-		"tcp", "no-such-name:80",
-		`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
-	},
-	{
-		"tcp", "mh/astro/r70:http",
-		"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
-	},
-	{
-		"unix", "/etc/file-not-found",
-		"dial unix /etc/file-not-found: no such file or directory",
-	},
-	{
-		"unix", "/etc/",
-		"dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
-	},
-	{
-		"unixpacket", "/etc/file-not-found",
-		"dial unixpacket /etc/file-not-found: no such file or directory",
-	},
-	{
-		"unixpacket", "/etc/",
-		"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
-	},
-}
-
-var duplicateErrorPattern = `dial (.*) dial (.*)`
-
-func TestDialError(t *testing.T) {
-	if !*runErrorTest {
-		t.Logf("test disabled; use -run_error_test to enable")
-		return
-	}
-	for i, tt := range dialErrorTests {
-		c, err := Dial(tt.Net, tt.Raddr)
-		if c != nil {
-			c.Close()
-		}
-		if err == nil {
-			t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
-			continue
-		}
-		s := err.Error()
-		match, _ := regexp.MatchString(tt.Pattern, s)
-		if !match {
-			t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
-		}
-		match, _ = regexp.MatchString(duplicateErrorPattern, s)
-		if match {
-			t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
-		}
-	}
-}
-
-var invalidDialAndListenArgTests = []struct {
-	net  string
-	addr string
-	err  error
-}{
-	{"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}},
-	{"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}},
-	{"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}},
-}
-
-func TestInvalidDialAndListenArgs(t *testing.T) {
-	for _, tt := range invalidDialAndListenArgTests {
-		var err error
-		switch tt.err.(*OpError).Op {
-		case "dial":
-			_, err = Dial(tt.net, tt.addr)
-		case "listen":
-			_, err = Listen(tt.net, tt.addr)
-		}
-		if !reflect.DeepEqual(tt.err, err) {
-			t.Fatalf("got %#v; expected %#v", err, tt.err)
-		}
-	}
-}
-
 func TestDialTimeoutFDLeak(t *testing.T) {
-	if runtime.GOOS != "linux" {
-		// TODO(bradfitz): test on other platforms
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
+	const T = 100 * time.Millisecond
 
-	type connErr struct {
-		conn Conn
-		err  error
-	}
-	dials := listenerBacklog + 100
-	// used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
-	maxGoodConnect := listenerBacklog + runtime.NumCPU()*10
-	resc := make(chan connErr)
-	for i := 0; i < dials; i++ {
-		go func() {
-			conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond)
-			resc <- connErr{conn, err}
-		}()
-	}
-
-	var firstErr string
-	var ngood int
-	var toClose []io.Closer
-	for i := 0; i < dials; i++ {
-		ce := <-resc
-		if ce.err == nil {
-			ngood++
-			if ngood > maxGoodConnect {
-				t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect)
-			}
-			toClose = append(toClose, ce.conn)
-			continue
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		origTestHookDialChannel := testHookDialChannel
+		testHookDialChannel = func() { time.Sleep(2 * T) }
+		defer func() { testHookDialChannel = origTestHookDialChannel }()
+		if runtime.GOOS == "plan9" {
+			break
 		}
-		err := ce.err
-		if firstErr == "" {
-			firstErr = err.Error()
-		} else if err.Error() != firstErr {
-			t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err)
-		}
-	}
-	for _, c := range toClose {
-		c.Close()
-	}
-	for i := 0; i < 100; i++ {
-		if got := numFD(); got < dials {
-			// Test passes.
-			return
-		}
-		time.Sleep(10 * time.Millisecond)
-	}
-	if got := numFD(); got >= dials {
-		t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials)
-	}
-}
-
-func numTCP() (ntcp, nopen, nclose int, err error) {
-	lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
-	if err != nil {
-		return 0, 0, 0, err
-	}
-	ntcp += bytes.Count(lsof, []byte("TCP"))
-	for _, state := range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} {
-		nopen += bytes.Count(lsof, []byte(state))
-	}
-	for _, state := range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} {
-		nclose += bytes.Count(lsof, []byte(state))
-	}
-	return ntcp, nopen, nclose, nil
-}
-
-func TestDialMultiFDLeak(t *testing.T) {
-	t.Skip("flaky test - golang.org/issue/8764")
-
-	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("neither ipv4 nor ipv6 is supported")
+		fallthrough
+	default:
+		sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+			time.Sleep(2 * T)
+			return nil, errTimeout
+		})
+		defer sw.Set(socktest.FilterConnect, nil)
 	}
 
-	halfDeadServer := func(dss *dualStackServer, ln Listener) {
-		for {
-			if c, err := ln.Accept(); err != nil {
-				return
-			} else {
-				// It just keeps established
-				// connections like a half-dead server
-				// does.
-				dss.putConn(c)
-			}
-		}
-	}
-	dss, err := newDualStackServer([]streamListener{
-		{net: "tcp4", addr: "127.0.0.1"},
-		{net: "tcp6", addr: "[::1]"},
-	})
-	if err != nil {
-		t.Fatalf("newDualStackServer failed: %v", err)
-	}
-	defer dss.teardown()
-	if err := dss.buildup(halfDeadServer); err != nil {
-		t.Fatalf("dualStackServer.buildup failed: %v", err)
-	}
-
-	_, before, _, err := numTCP()
-	if err != nil {
-		t.Skipf("skipping test; error finding or running lsof: %v", err)
-	}
-
+	before := sw.Sockets()
+	const N = 100
 	var wg sync.WaitGroup
-	portnum, _, _ := dtoi(dss.port, 0)
-	ras := addrList{
-		// Losers that will fail to connect, see RFC 6890.
-		&TCPAddr{IP: IPv4(198, 18, 0, 254), Port: portnum},
-		&TCPAddr{IP: ParseIP("2001:2::254"), Port: portnum},
-
-		// Winner candidates of this race.
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
-		&TCPAddr{IP: IPv6loopback, Port: portnum},
-
-		// Losers that will have established connections.
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
-		&TCPAddr{IP: IPv6loopback, Port: portnum},
-	}
-	const T1 = 10 * time.Millisecond
-	const T2 = 2 * T1
-	const N = 10
+	wg.Add(N)
 	for i := 0; i < N; i++ {
-		wg.Add(1)
 		go func() {
 			defer wg.Done()
-			if c, err := dialMulti("tcp", "fast failover test", nil, ras, time.Now().Add(T1)); err == nil {
+			// This dial never starts to send any SYN
+			// segment because of above socket filter and
+			// test hook.
+			c, err := DialTimeout("tcp", "127.0.0.1:0", T)
+			if err == nil {
+				t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
 				c.Close()
 			}
 		}()
 	}
 	wg.Wait()
-	time.Sleep(T2)
-
-	ntcp, after, nclose, err := numTCP()
-	if err != nil {
-		t.Skipf("skipping test; error finding or running lsof: %v", err)
-	}
-	t.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp, after, nclose)
-
-	if after != before {
-		t.Fatalf("got %v open sessions; expected %v", after, before)
+	after := sw.Sockets()
+	if len(after) != len(before) {
+		t.Errorf("got %d; want %d", len(after), len(before))
 	}
 }
 
-func numFD() int {
-	if runtime.GOOS == "linux" {
-		f, err := os.Open("/proc/self/fd")
-		if err != nil {
-			panic(err)
-		}
-		defer f.Close()
-		names, err := f.Readdirnames(0)
-		if err != nil {
-			panic(err)
-		}
-		return len(names)
+func TestDialerDualStackFDLeak(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	case "windows":
+		t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
 	}
-	// All tests using this should be skipped anyway, but:
-	panic("numFDs not implemented on " + runtime.GOOS)
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+	handler := func(dss *dualStackServer, ln Listener) {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			c.Close()
+		}
+	}
+	dss, err := newDualStackServer([]streamListener{
+		{network: "tcp4", address: "127.0.0.1"},
+		{network: "tcp6", address: "::1"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer dss.teardown()
+	if err := dss.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	before := sw.Sockets()
+	const T = 100 * time.Millisecond
+	const N = 10
+	var wg sync.WaitGroup
+	wg.Add(N)
+	d := &Dialer{DualStack: true, Timeout: T}
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			c.Close()
+		}()
+	}
+	wg.Wait()
+	time.Sleep(2 * T) // wait for the dial racers to stop
+	after := sw.Sockets()
+	if len(after) != len(before) {
+		t.Errorf("got %d; want %d", len(after), len(before))
+	}
 }
 
-func TestDialer(t *testing.T) {
-	ln, err := Listen("tcp4", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
-	defer ln.Close()
+func TestDialerLocalAddr(t *testing.T) {
 	ch := make(chan error, 1)
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
-			ch <- fmt.Errorf("Accept failed: %v", err)
+			ch <- err
 			return
 		}
 		defer c.Close()
 		ch <- nil
-	}()
-
-	laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
 	}
-	d := &Dialer{LocalAddr: laddr}
-	c, err := d.Dial("tcp4", ln.Addr().String())
+	ls, err := newLocalServer("tcp")
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	laddr.Port = 0
+	d := &Dialer{LocalAddr: laddr}
+	c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.Read(make([]byte, 1))
@@ -466,61 +245,15 @@
 	}
 }
 
-func TestDialDualStackLocalhost(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+func TestDialerDualStack(t *testing.T) {
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	if ips, err := LookupIP("localhost"); err != nil {
-		t.Fatalf("LookupIP failed: %v", err)
-	} else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 {
-		t.Skip("localhost doesn't have a pair of different address family IP addresses")
-	}
-
-	touchAndByeServer := func(dss *dualStackServer, ln Listener) {
-		for {
-			if c, err := ln.Accept(); err != nil {
-				return
-			} else {
-				c.Close()
-			}
-		}
-	}
-	dss, err := newDualStackServer([]streamListener{
-		{net: "tcp4", addr: "127.0.0.1"},
-		{net: "tcp6", addr: "[::1]"},
-	})
-	if err != nil {
-		t.Fatalf("newDualStackServer failed: %v", err)
-	}
-	defer dss.teardown()
-	if err := dss.buildup(touchAndByeServer); err != nil {
-		t.Fatalf("dualStackServer.buildup failed: %v", err)
-	}
-
-	d := &Dialer{DualStack: true}
-	for range dss.lns {
-		if c, err := d.Dial("tcp", "localhost:"+dss.port); err != nil {
-			t.Errorf("Dial failed: %v", err)
-		} else {
-			if addr := c.LocalAddr().(*TCPAddr); addr.IP.To4() != nil {
-				dss.teardownNetwork("tcp4")
-			} else if addr.IP.To16() != nil && addr.IP.To4() == nil {
-				dss.teardownNetwork("tcp6")
-			}
-			c.Close()
-		}
-	}
-}
-
-func TestDialerKeepAlive(t *testing.T) {
-	ln := newLocalListener(t)
-	defer ln.Close()
-	defer func() {
-		testHookSetKeepAlive = func() {}
-	}()
-	go func() {
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+	handler := func(dss *dualStackServer, ln Listener) {
 		for {
 			c, err := ln.Accept()
 			if err != nil {
@@ -528,7 +261,58 @@
 			}
 			c.Close()
 		}
-	}()
+	}
+	dss, err := newDualStackServer([]streamListener{
+		{network: "tcp4", address: "127.0.0.1"},
+		{network: "tcp6", address: "::1"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer dss.teardown()
+	if err := dss.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	const T = 100 * time.Millisecond
+	d := &Dialer{DualStack: true, Timeout: T}
+	for range dss.lns {
+		c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		switch addr := c.LocalAddr().(*TCPAddr); {
+		case addr.IP.To4() != nil:
+			dss.teardownNetwork("tcp4")
+		case addr.IP.To16() != nil && addr.IP.To4() == nil:
+			dss.teardownNetwork("tcp6")
+		}
+		c.Close()
+	}
+	time.Sleep(2 * T) // wait for the dial racers to stop
+}
+
+func TestDialerKeepAlive(t *testing.T) {
+	handler := func(ls *localServer, ln Listener) {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			c.Close()
+		}
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+	defer func() { testHookSetKeepAlive = func() {} }()
+
 	for _, keepAlive := range []bool{false, true} {
 		got := false
 		testHookSetKeepAlive = func() { got = true }
@@ -536,7 +320,7 @@
 		if keepAlive {
 			d.KeepAlive = 30 * time.Second
 		}
-		c, err := d.Dial("tcp", ln.Addr().String())
+		c, err := d.Dial("tcp", ls.Listener.Addr().String())
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/net/dialgoogle_test.go b/src/net/dialgoogle_test.go
deleted file mode 100644
index df5895a..0000000
--- a/src/net/dialgoogle_test.go
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
-	"flag"
-	"fmt"
-	"io"
-	"strings"
-	"syscall"
-	"testing"
-)
-
-// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
-var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
-
-func TestResolveGoogle(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
-		addr, err := ResolveTCPAddr(network, "www.google.com:http")
-		if err != nil {
-			if (network == "tcp" || network == "tcp4") && !supportsIPv4 {
-				t.Logf("ipv4 is not supported: %v", err)
-			} else if network == "tcp6" && !supportsIPv6 {
-				t.Logf("ipv6 is not supported: %v", err)
-			} else {
-				t.Errorf("ResolveTCPAddr failed: %v", err)
-			}
-			continue
-		}
-		if (network == "tcp" || network == "tcp4") && addr.IP.To4() == nil {
-			t.Errorf("got %v; expected an IPv4 address on %v", addr, network)
-		} else if network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil) {
-			t.Errorf("got %v; expected an IPv6 address on %v", addr, network)
-		}
-	}
-}
-
-func TestDialGoogle(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	d := &Dialer{DualStack: true}
-	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
-		if network == "tcp" && !supportsIPv4 && !supportsIPv6 {
-			t.Logf("skipping test; both ipv4 and ipv6 are not supported")
-			continue
-		} else if network == "tcp4" && !supportsIPv4 {
-			t.Logf("skipping test; ipv4 is not supported")
-			continue
-		} else if network == "tcp6" && !supportsIPv6 {
-			t.Logf("skipping test; ipv6 is not supported")
-			continue
-		} else if network == "tcp6" && !*testIPv6 {
-			t.Logf("test disabled; use -ipv6 to enable")
-			continue
-		}
-		if c, err := d.Dial(network, "www.google.com:http"); err != nil {
-			t.Errorf("Dial failed: %v", err)
-		} else {
-			c.Close()
-		}
-	}
-}
-
-// fd is already connected to the destination, port 80.
-// Run an HTTP request to fetch the appropriate page.
-func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
-	req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
-	n, err := fd.Write(req)
-
-	buf := make([]byte, 1000)
-	n, err = io.ReadFull(fd, buf)
-
-	if n < 1000 {
-		t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err)
-		return
-	}
-}
-
-func doDial(t *testing.T, network, addr string) {
-	fd, err := Dial(network, addr)
-	if err != nil {
-		t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
-		return
-	}
-	fetchGoogle(t, fd, network, addr)
-	fd.Close()
-}
-
-var googleaddrsipv4 = []string{
-	"%d.%d.%d.%d:80",
-	"www.google.com:80",
-	"%d.%d.%d.%d:http",
-	"www.google.com:http",
-	"%03d.%03d.%03d.%03d:0080",
-	"[::ffff:%d.%d.%d.%d]:80",
-	"[::ffff:%02x%02x:%02x%02x]:80",
-	"[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
-	"[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
-	"[0:0:0:0::ffff:%d.%d.%d.%d]:80",
-}
-
-func TestDialGoogleIPv4(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	// Insert an actual IPv4 address for google.com
-	// into the table.
-	addrs, err := LookupIP("www.google.com")
-	if err != nil {
-		t.Fatalf("lookup www.google.com: %v", err)
-	}
-	var ip IP
-	for _, addr := range addrs {
-		if x := addr.To4(); x != nil {
-			ip = x
-			break
-		}
-	}
-	if ip == nil {
-		t.Fatalf("no IPv4 addresses for www.google.com")
-	}
-
-	for i, s := range googleaddrsipv4 {
-		if strings.Contains(s, "%") {
-			googleaddrsipv4[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3])
-		}
-	}
-
-	for i := 0; i < len(googleaddrsipv4); i++ {
-		addr := googleaddrsipv4[i]
-		if addr == "" {
-			continue
-		}
-		t.Logf("-- %s --", addr)
-		doDial(t, "tcp", addr)
-		if addr[0] != '[' {
-			doDial(t, "tcp4", addr)
-			if supportsIPv6 {
-				// make sure syscall.SocketDisableIPv6 flag works.
-				syscall.SocketDisableIPv6 = true
-				doDial(t, "tcp", addr)
-				doDial(t, "tcp4", addr)
-				syscall.SocketDisableIPv6 = false
-			}
-		}
-	}
-}
-
-var googleaddrsipv6 = []string{
-	"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80",
-	"ipv6.google.com:80",
-	"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http",
-	"ipv6.google.com:http",
-}
-
-func TestDialGoogleIPv6(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-	// Only run tcp6 if the kernel will take it.
-	if !supportsIPv6 {
-		t.Skip("skipping test; ipv6 is not supported")
-	}
-	if !*testIPv6 {
-		t.Skip("test disabled; use -ipv6 to enable")
-	}
-
-	// Insert an actual IPv6 address for ipv6.google.com
-	// into the table.
-	addrs, err := LookupIP("ipv6.google.com")
-	if err != nil {
-		t.Fatalf("lookup ipv6.google.com: %v", err)
-	}
-	var ip IP
-	for _, addr := range addrs {
-		if x := addr.To16(); x != nil {
-			ip = x
-			break
-		}
-	}
-	if ip == nil {
-		t.Fatalf("no IPv6 addresses for ipv6.google.com")
-	}
-
-	for i, s := range googleaddrsipv6 {
-		if strings.Contains(s, "%") {
-			googleaddrsipv6[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15])
-		}
-	}
-
-	for i := 0; i < len(googleaddrsipv6); i++ {
-		addr := googleaddrsipv6[i]
-		if addr == "" {
-			continue
-		}
-		t.Logf("-- %s --", addr)
-		doDial(t, "tcp", addr)
-		doDial(t, "tcp6", addr)
-	}
-}
diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go
index 099ea45..e5d0ae0 100644
--- a/src/net/dnsclient.go
+++ b/src/net/dnsclient.go
@@ -9,31 +9,6 @@
 	"sort"
 )
 
-// DNSError represents a DNS lookup error.
-type DNSError struct {
-	Err       string // description of the error
-	Name      string // name looked for
-	Server    string // server used
-	IsTimeout bool
-}
-
-func (e *DNSError) Error() string {
-	if e == nil {
-		return "<nil>"
-	}
-	s := "lookup " + e.Name
-	if e.Server != "" {
-		s += " on " + e.Server
-	}
-	s += ": " + e.Err
-	return s
-}
-
-func (e *DNSError) Timeout() bool   { return e.IsTimeout }
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
-
-const noSuchHost = "no such host"
-
 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
 // to parse the IP address.
@@ -43,8 +18,7 @@
 		return "", &DNSError{Err: "unrecognized address", Name: addr}
 	}
 	if ip.To4() != nil {
-		return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." +
-			uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
+		return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
 	}
 	// Must be IPv6
 	buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
@@ -67,7 +41,7 @@
 	addrs = make([]dnsRR, 0, len(dns.answer))
 
 	if dns.rcode == dnsRcodeNameError && dns.recursion_available {
-		return "", nil, &DNSError{Err: noSuchHost, Name: name}
+		return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name}
 	}
 	if dns.rcode != dnsRcodeSuccess {
 		// None of the error codes make sense
@@ -106,7 +80,7 @@
 			}
 		}
 		if len(addrs) == 0 {
-			return "", nil, &DNSError{Err: noSuchHost, Name: name, Server: server}
+			return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
 		}
 		return name, addrs, nil
 	}
@@ -194,13 +168,10 @@
 type byPriorityWeight []*SRV
 
 func (s byPriorityWeight) Len() int { return len(s) }
-
-func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
 func (s byPriorityWeight) Less(i, j int) bool {
-	return s[i].Priority < s[j].Priority ||
-		(s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
+	return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
 }
+func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
 // shuffleByWeight shuffles SRV records by weight using the algorithm
 // described in RFC 2782.
@@ -248,11 +219,9 @@
 // byPref implements sort.Interface to sort MX records by preference
 type byPref []*MX
 
-func (s byPref) Len() int { return len(s) }
-
+func (s byPref) Len() int           { return len(s) }
 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
-
-func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s byPref) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 
 // sort reorders MX records as specified in RFC 5321.
 func (s byPref) sort() {
diff --git a/src/net/dnsclient_test.go b/src/net/dnsclient_test.go
index 435eb35..3ab2b83 100644
--- a/src/net/dnsclient_test.go
+++ b/src/net/dnsclient_test.go
@@ -47,7 +47,7 @@
 	checkDistribution(t, data, margin)
 }
 
-func TestUniformity(t *testing.T) {
+func TestDNSSRVUniformity(t *testing.T) {
 	testUniformity(t, 2, 0.05)
 	testUniformity(t, 3, 0.10)
 	testUniformity(t, 10, 0.20)
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 30c7ada..5a4411f 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -20,6 +20,7 @@
 	"io"
 	"math/rand"
 	"os"
+	"strconv"
 	"sync"
 	"time"
 )
@@ -185,7 +186,7 @@
 				continue
 			}
 			cname, addrs, err := answer(name, server, msg, qtype)
-			if err == nil || err.(*DNSError).Err == noSuchHost {
+			if err == nil || err.(*DNSError).Err == errNoSuchHost.Error() {
 				return cname, addrs, err
 			}
 			lastErr = err
@@ -215,10 +216,10 @@
 
 var cfg struct {
 	ch        chan struct{}
-	mu        sync.RWMutex // protects dnsConfig and dnserr
+	mu        sync.RWMutex // protects dnsConfig
 	dnsConfig *dnsConfig
-	dnserr    error
 }
+
 var onceLoadConfig sync.Once
 
 // Assume dns config file is /etc/resolv.conf here
@@ -229,12 +230,12 @@
 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 {
-		cfg.dnserr = err
-	} else {
+	if fi, err := os.Stat(resolvConfPath); err == nil {
 		mtime = fi.ModTime()
-		cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
 	}
+
+	cfg.dnsConfig = dnsReadConfig(resolvConfPath)
+
 	go func() {
 		for {
 			time.Sleep(reloadTime)
@@ -257,19 +258,16 @@
 			}
 			mtime = m
 			// In case of error, we keep the previous config
-			ncfg, err := dnsReadConfig(resolvConfPath)
-			if err != nil || len(ncfg.servers) == 0 {
-				continue
+			if ncfg := dnsReadConfig(resolvConfPath); ncfg.err == nil {
+				cfg.mu.Lock()
+				cfg.dnsConfig = ncfg
+				cfg.mu.Unlock()
 			}
-			cfg.mu.Lock()
-			cfg.dnsConfig = ncfg
-			cfg.dnserr = nil
-			cfg.mu.Unlock()
 		}
 	}()
 }
 
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
+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}
 	}
@@ -283,10 +281,6 @@
 	cfg.mu.RLock()
 	defer cfg.mu.RUnlock()
 
-	if cfg.dnserr != nil || cfg.dnsConfig == nil {
-		err = cfg.dnserr
-		return
-	}
 	// If name is rooted (trailing dot) or has enough dots,
 	// try it by itself first.
 	rooted := len(name) > 0 && name[len(name)-1] == '.'
@@ -296,7 +290,7 @@
 			rname += "."
 		}
 		// Can try as ordinary name.
-		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+		cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
 		if rooted || err == nil {
 			return
 		}
@@ -308,7 +302,7 @@
 		if rname[len(rname)-1] != '.' {
 			rname += "."
 		}
-		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+		cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
 		if err == nil {
 			return
 		}
@@ -317,7 +311,7 @@
 	// 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, addrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
+		cname, rrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
 		if err == nil {
 			return
 		}
@@ -332,6 +326,35 @@
 	return
 }
 
+// hostLookupOrder specifies the order of LookupHost lookup strategies.
+// It is basically a simplified representation of nsswitch.conf.
+// "files" means /etc/hosts.
+type hostLookupOrder int
+
+const (
+	// hostLookupCgo means defer to cgo.
+	hostLookupCgo      hostLookupOrder = iota
+	hostLookupFilesDNS                 // files first
+	hostLookupDNSFiles                 // dns first
+	hostLookupFiles                    // only files
+	hostLookupDNS                      // only DNS
+)
+
+var lookupOrderName = map[hostLookupOrder]string{
+	hostLookupCgo:      "cgo",
+	hostLookupFilesDNS: "files,dns",
+	hostLookupDNSFiles: "dns,files",
+	hostLookupFiles:    "files",
+	hostLookupDNS:      "dns",
+}
+
+func (o hostLookupOrder) String() string {
+	if s, ok := lookupOrderName[o]; ok {
+		return s
+	}
+	return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
+}
+
 // goLookupHost is the native Go implementation of LookupHost.
 // Used only if cgoLookupHost refuses to handle the request
 // (that is, only if cgoLookupHost is the stub in cgo_stub.go).
@@ -339,12 +362,18 @@
 // depending on our lookup code, so that Go and C get the same
 // answers.
 func goLookupHost(name string) (addrs []string, err error) {
-	// Use entries from /etc/hosts if they match.
-	addrs = lookupStaticHost(name)
-	if len(addrs) > 0 {
-		return
+	return goLookupHostOrder(name, hostLookupFilesDNS)
+}
+
+func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
+	if order == hostLookupFilesDNS || order == hostLookupFiles {
+		// Use entries from /etc/hosts if they match.
+		addrs = lookupStaticHost(name)
+		if len(addrs) > 0 || order == hostLookupFiles {
+			return
+		}
 	}
-	ips, err := goLookupIP(name)
+	ips, err := goLookupIPOrder(name, order)
 	if err != nil {
 		return
 	}
@@ -355,25 +384,30 @@
 	return
 }
 
+// lookup entries from /etc/hosts
+func goLookupIPFiles(name string) (addrs []IPAddr) {
+	for _, haddr := range lookupStaticHost(name) {
+		haddr, zone := splitHostZone(haddr)
+		if ip := ParseIP(haddr); ip != nil {
+			addr := IPAddr{IP: ip, Zone: zone}
+			addrs = append(addrs, addr)
+		}
+	}
+	return
+}
+
 // goLookupIP is the native Go implementation of LookupIP.
 // Used only if cgoLookupIP refuses to handle the request
 // (that is, only if cgoLookupIP is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
 func goLookupIP(name string) (addrs []IPAddr, err error) {
-	// Use entries from /etc/hosts if possible.
-	haddrs := lookupStaticHost(name)
-	if len(haddrs) > 0 {
-		for _, haddr := range haddrs {
-			haddr, zone := splitHostZone(haddr)
-			if ip := ParseIP(haddr); ip != nil {
-				addr := IPAddr{IP: ip, Zone: zone}
-				addrs = append(addrs, addr)
-			}
-		}
-		if len(addrs) > 0 {
-			return
+	return goLookupIPOrder(name, hostLookupFilesDNS)
+}
+
+func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
+	if order == hostLookupFilesDNS || order == hostLookupFiles {
+		addrs = goLookupIPFiles(name)
+		if len(addrs) > 0 || order == hostLookupFiles {
+			return addrs, nil
 		}
 	}
 	type racer struct {
@@ -409,8 +443,13 @@
 			}
 		}
 	}
-	if len(addrs) == 0 && lastErr != nil {
-		return nil, lastErr
+	if len(addrs) == 0 {
+		if lastErr != nil {
+			return nil, lastErr
+		}
+		if order == hostLookupDNSFiles {
+			addrs = goLookupIPFiles(name)
+		}
 	}
 	return addrs, nil
 }
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 2934634..1b88e77 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -31,7 +31,7 @@
 
 func TestDNSTransportFallback(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range dnsTransportFallbackTests {
@@ -73,7 +73,7 @@
 
 func TestSpecialDomainName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	server := "8.8.8.8:53"
@@ -101,9 +101,9 @@
 }
 
 func newResolvConfTest(t *testing.T) *resolvConfTest {
-	dir, err := ioutil.TempDir("", "resolvConfTest")
+	dir, err := ioutil.TempDir("", "go-resolvconftest")
 	if err != nil {
-		t.Fatalf("could not create temp dir: %v", err)
+		t.Fatal(err)
 	}
 
 	// Disable the default loadConfig
@@ -150,7 +150,7 @@
 	cfg.mu.RLock()
 	defer cfg.mu.RUnlock()
 	if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) {
-		r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want)
+		r.Fatalf("unexpected dns server loaded, got %v want %v", got, want)
 	}
 }
 
@@ -165,52 +165,60 @@
 
 func TestReloadResolvConfFail(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	r := newResolvConfTest(t)
 	defer r.Close()
 
-	// resolv.conf.tmp does not exist yet
 	r.Start()
-	if _, err := goLookupIP("golang.org"); err == nil {
-		t.Fatal("goLookupIP(missing) succeeded")
-	}
-
 	r.SetConf("nameserver 8.8.8.8")
+
 	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(missing; good) failed: %v", err)
+		t.Fatal(err)
 	}
 
-	// Using a bad resolv.conf while we had a good
-	// one before should not update the config
+	// Using an empty resolv.conf should use localhost as servers
 	r.SetConf("")
-	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err)
+
+	if len(cfg.dnsConfig.servers) != len(defaultNS) {
+		t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
+	}
+
+	for i := range cfg.dnsConfig.servers {
+		if cfg.dnsConfig.servers[i] != defaultNS[i] {
+			t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
+		}
 	}
 }
 
 func TestReloadResolvConfChange(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	r := newResolvConfTest(t)
 	defer r.Close()
 
-	r.SetConf("nameserver 8.8.8.8")
 	r.Start()
+	r.SetConf("nameserver 8.8.8.8")
 
 	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(good) failed: %v", err)
+		t.Fatal(err)
 	}
 	r.WantServers([]string{"8.8.8.8"})
 
-	// Using a bad resolv.conf when we had a good one
-	// before should not update the config
+	// Using an empty resolv.conf should use localhost as servers
 	r.SetConf("")
-	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(good; bad) failed: %v", err)
+
+	if len(cfg.dnsConfig.servers) != len(defaultNS) {
+		t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
+	}
+
+	for i := range cfg.dnsConfig.servers {
+		if cfg.dnsConfig.servers[i] != defaultNS[i] {
+			t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
+		}
 	}
 
 	// A new good config should get picked up
@@ -219,8 +227,7 @@
 }
 
 func BenchmarkGoLookupIP(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
@@ -228,8 +235,7 @@
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		goLookupIP("some.nonexistent")
@@ -237,13 +243,10 @@
 }
 
 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	onceLoadConfig.Do(loadDefaultConfig)
-	if cfg.dnserr != nil || cfg.dnsConfig == nil {
-		b.Fatalf("loadConfig failed: %v", cfg.dnserr)
-	}
+
 	// This looks ugly but it's safe as long as benchmarks are run
 	// sequentially in package testing.
 	orig := cfg.dnsConfig
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 66ab7c4..6073fdb 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -8,30 +8,41 @@
 
 package net
 
+var defaultNS = []string{"127.0.0.1", "::1"}
+
 type dnsConfig struct {
-	servers  []string // servers to use
-	search   []string // suffixes to append to local name
-	ndots    int      // number of dots in name to trigger absolute lookup
-	timeout  int      // seconds before giving up on packet
-	attempts int      // lost packets before giving up on server
-	rotate   bool     // round robin among servers
+	servers    []string // servers to use
+	search     []string // suffixes to append to local name
+	ndots      int      // number of dots in name to trigger absolute lookup
+	timeout    int      // seconds before giving up on packet
+	attempts   int      // lost packets before giving up on server
+	rotate     bool     // round robin among servers
+	unknownOpt bool     // anything unknown was encountered
+	lookup     []string // OpenBSD top-level database "lookup" order
+	err        error    // any error that occurs during open of resolv.conf
 }
 
 // See resolv.conf(5) on a Linux machine.
 // TODO(rsc): Supposed to call uname() and chop the beginning
 // of the host name to get the default search domain.
-func dnsReadConfig(filename string) (*dnsConfig, error) {
-	file, err := open(filename)
-	if err != nil {
-		return nil, &DNSConfigError{err}
-	}
-	defer file.close()
+func dnsReadConfig(filename string) *dnsConfig {
 	conf := &dnsConfig{
 		ndots:    1,
 		timeout:  5,
 		attempts: 2,
 	}
+	file, err := open(filename)
+	if err != nil {
+		conf.servers = defaultNS
+		conf.err = err
+		return conf
+	}
+	defer file.close()
 	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+		if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
+			// comment.
+			continue
+		}
 		f := getFields(line)
 		if len(f) < 1 {
 			continue
@@ -61,8 +72,7 @@
 			}
 
 		case "options": // magic options
-			for i := 1; i < len(f); i++ {
-				s := f[i]
+			for _, s := range f[1:] {
 				switch {
 				case hasPrefix(s, "ndots:"):
 					n, _, _ := dtoi(s, 6)
@@ -84,11 +94,25 @@
 					conf.attempts = n
 				case s == "rotate":
 					conf.rotate = true
+				default:
+					conf.unknownOpt = true
 				}
 			}
+
+		case "lookup":
+			// OpenBSD option:
+			// http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5
+			// "the legal space-separated values are: bind, file, yp"
+			conf.lookup = f[1:]
+
+		default:
+			conf.unknownOpt = true
 		}
 	}
-	return conf, nil
+	if len(conf.servers) == 0 {
+		conf.servers = defaultNS
+	}
+	return conf
 }
 
 func hasPrefix(s, prefix string) bool {
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index 94fb0c3..c8eed61 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -7,28 +7,30 @@
 package net
 
 import (
+	"os"
 	"reflect"
 	"testing"
 )
 
 var dnsReadConfigTests = []struct {
 	name string
-	conf dnsConfig
+	want *dnsConfig
 }{
 	{
 		name: "testdata/resolv.conf",
-		conf: dnsConfig{
-			servers:  []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
-			search:   []string{"localdomain"},
-			ndots:    5,
-			timeout:  10,
-			attempts: 3,
-			rotate:   true,
+		want: &dnsConfig{
+			servers:    []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
+			search:     []string{"localdomain"},
+			ndots:      5,
+			timeout:    10,
+			attempts:   3,
+			rotate:     true,
+			unknownOpt: true, // the "options attempts 3" line
 		},
 	},
 	{
 		name: "testdata/domain-resolv.conf",
-		conf: dnsConfig{
+		want: &dnsConfig{
 			servers:  []string{"8.8.8.8"},
 			search:   []string{"localdomain"},
 			ndots:    1,
@@ -38,7 +40,7 @@
 	},
 	{
 		name: "testdata/search-resolv.conf",
-		conf: dnsConfig{
+		want: &dnsConfig{
 			servers:  []string{"8.8.8.8"},
 			search:   []string{"test", "invalid"},
 			ndots:    1,
@@ -48,22 +50,51 @@
 	},
 	{
 		name: "testdata/empty-resolv.conf",
-		conf: dnsConfig{
+		want: &dnsConfig{
+			servers:  defaultNS,
 			ndots:    1,
 			timeout:  5,
 			attempts: 2,
 		},
 	},
+	{
+		name: "testdata/openbsd-resolv.conf",
+		want: &dnsConfig{
+			ndots:    1,
+			timeout:  5,
+			attempts: 2,
+			lookup:   []string{"file", "bind"},
+			servers:  []string{"169.254.169.254", "10.240.0.1"},
+			search:   []string{"c.symbolic-datum-552.internal."},
+		},
+	},
 }
 
 func TestDNSReadConfig(t *testing.T) {
 	for _, tt := range dnsReadConfigTests {
-		conf, err := dnsReadConfig(tt.name)
-		if err != nil {
-			t.Fatal(err)
+		conf := dnsReadConfig(tt.name)
+		if conf.err != nil {
+			t.Fatal(conf.err)
 		}
-		if !reflect.DeepEqual(conf, &tt.conf) {
-			t.Errorf("got %v; want %v", conf, &tt.conf)
+		if !reflect.DeepEqual(conf, tt.want) {
+			t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
 		}
 	}
 }
+
+func TestDNSReadMissingFile(t *testing.T) {
+	conf := dnsReadConfig("a-nonexistent-file")
+	if !os.IsNotExist(conf.err) {
+		t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist)
+	}
+	conf.err = nil
+	want := &dnsConfig{
+		servers:  defaultNS,
+		ndots:    1,
+		timeout:  5,
+		attempts: 2,
+	}
+	if !reflect.DeepEqual(conf, want) {
+		t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
+	}
+}
diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go
index 161afb2..6ecaa94 100644
--- a/src/net/dnsmsg.go
+++ b/src/net/dnsmsg.go
@@ -306,7 +306,23 @@
 }
 
 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
+	if !rr.Hdr.Walk(f) {
+		return false
+	}
+	var n uint16 = 0
+	for n < rr.Hdr.Rdlength {
+		var txt string
+		if !f(&txt, "Txt", "") {
+			return false
+		}
+		// more bytes than rr.Hdr.Rdlength said there woudld be
+		if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
+			return false
+		}
+		n += uint16(len(txt)) + 1
+		rr.Txt += txt
+	}
+	return true
 }
 
 type dnsRR_SRV struct {
diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go
index 159a03e..1078d77 100644
--- a/src/net/dnsmsg_test.go
+++ b/src/net/dnsmsg_test.go
@@ -66,7 +66,7 @@
 	msg := new(dnsMsg)
 	ok := msg.Unpack(data)
 	if !ok {
-		t.Fatalf("unpacking packet failed")
+		t.Fatal("unpacking packet failed")
 	}
 	msg.String() // exercise this code path
 	if g, e := len(msg.answer), 5; g != e {
@@ -96,6 +96,93 @@
 	}
 }
 
+func TestDNSParseTXTReply(t *testing.T) {
+	expectedTxt1 := "v=spf1 redirect=_spf.google.com"
+	expectedTxt2 := "v=spf1 ip4:69.63.179.25 ip4:69.63.178.128/25 ip4:69.63.184.0/25 " +
+		"ip4:66.220.144.128/25 ip4:66.220.155.0/24 " +
+		"ip4:69.171.232.0/25 ip4:66.220.157.0/25 " +
+		"ip4:69.171.244.0/24 mx -all"
+
+	replies := []string{dnsTXTReply1, dnsTXTReply2}
+	expectedTxts := []string{expectedTxt1, expectedTxt2}
+
+	for i := range replies {
+		data, err := hex.DecodeString(replies[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := new(dnsMsg)
+		ok := msg.Unpack(data)
+		if !ok {
+			t.Errorf("test %d: unpacking packet failed", i)
+			continue
+		}
+
+		if len(msg.answer) != 1 {
+			t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
+			continue
+		}
+
+		rr := msg.answer[0]
+		rrTXT, ok := rr.(*dnsRR_TXT)
+		if !ok {
+			t.Errorf("test %d: answer[0] = %T; want *dnsRR_TXT", i, rr)
+			continue
+		}
+
+		if rrTXT.Txt != expectedTxts[i] {
+			t.Errorf("test %d: Txt = %s; want %s", i, rrTXT.Txt, expectedTxts[i])
+		}
+	}
+}
+
+func TestDNSParseTXTCorruptDataLengthReply(t *testing.T) {
+	replies := []string{dnsTXTCorruptDataLengthReply1, dnsTXTCorruptDataLengthReply2}
+
+	for i := range replies {
+		data, err := hex.DecodeString(replies[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := new(dnsMsg)
+		ok := msg.Unpack(data)
+		if ok {
+			t.Errorf("test %d: expected to fail on unpacking corrupt packet", i)
+		}
+	}
+}
+
+func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) {
+	replies := []string{dnsTXTCorruptTXTLengthReply1, dnsTXTCorruptTXTLengthReply2}
+
+	for i := range replies {
+		data, err := hex.DecodeString(replies[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := new(dnsMsg)
+		ok := msg.Unpack(data)
+		// Unpacking should succeed, but we should just get the header.
+		if !ok {
+			t.Errorf("test %d: unpacking packet failed", i)
+			continue
+		}
+
+		if len(msg.answer) != 1 {
+			t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
+			continue
+		}
+
+		rr := msg.answer[0]
+		if _, justHeader := rr.(*dnsRR_Header); !justHeader {
+			t.Errorf("test %d: rr = %T; expected *dnsRR_Header", i, rr)
+		}
+	}
+}
+
 // Valid DNS SRV reply
 const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
 	"6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
@@ -117,3 +204,63 @@
 	"6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" +
 	"72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" +
 	"6d70702d73657276657231016c06676f6f676c6503636f6d00"
+
+// TXT reply with one <character-string>
+const dnsTXTReply1 = "b3458180000100010004000505676d61696c03636f6d0000100001c00c001000010000012c00" +
+	"201f763d737066312072656469726563743d5f7370662e676f6f676c652e636f6dc00" +
+	"c0002000100025d4c000d036e733406676f6f676c65c012c00c0002000100025d4c00" +
+	"06036e7331c057c00c0002000100025d4c0006036e7333c057c00c0002000100025d4" +
+	"c0006036e7332c057c06c00010001000248b50004d8ef200ac09000010001000248b5" +
+	"0004d8ef220ac07e00010001000248b50004d8ef240ac05300010001000248b50004d" +
+	"8ef260a0000291000000000000000"
+
+// TXT reply with more than one <character-string>.
+// See https://tools.ietf.org/html/rfc1035#section-3.3.14
+const dnsTXTReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// DataLength field should be sum of all TXT fields. In this case it's less.
+const dnsTXTCorruptDataLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000967f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// Same as above but DataLength is more than sum of TXT fields.
+const dnsTXTCorruptDataLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1001227f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// TXT Length field is less than actual length.
+const dnsTXTCorruptTXTLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520691470343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// TXT Length field is more than actual length.
+const dnsTXTCorruptTXTLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520693370343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index 4fecf8d..cc660c9 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -9,12 +9,12 @@
 	"testing"
 )
 
-type testCase struct {
+type dnsNameTest struct {
 	name   string
 	result bool
 }
 
-var tests = []testCase{
+var dnsNameTests = []dnsNameTest{
 	// RFC2181, section 11.
 	{"_xmpp-server._tcp.google.com", true},
 	{"foo.com", true},
@@ -30,7 +30,7 @@
 	{"b.com.", true},
 }
 
-func getTestCases(ch chan<- testCase) {
+func emitDNSNameTest(ch chan<- dnsNameTest) {
 	defer close(ch)
 	var char59 = ""
 	var char63 = ""
@@ -41,38 +41,36 @@
 	char63 = char59 + "aaaa"
 	char64 = char63 + "a"
 
-	for _, tc := range tests {
+	for _, tc := range dnsNameTests {
 		ch <- tc
 	}
 
-	ch <- testCase{char63 + ".com", true}
-	ch <- testCase{char64 + ".com", false}
+	ch <- dnsNameTest{char63 + ".com", true}
+	ch <- dnsNameTest{char64 + ".com", false}
 	// 255 char name is fine:
-	ch <- testCase{char59 + "." + char63 + "." + char63 + "." +
+	ch <- dnsNameTest{char59 + "." + char63 + "." + char63 + "." +
 		char63 + ".com",
 		true}
 	// 256 char name is bad:
-	ch <- testCase{char59 + "a." + char63 + "." + char63 + "." +
+	ch <- dnsNameTest{char59 + "a." + char63 + "." + char63 + "." +
 		char63 + ".com",
 		false}
 }
 
-func TestDNSNames(t *testing.T) {
-	ch := make(chan testCase)
-	go getTestCases(ch)
+func TestDNSName(t *testing.T) {
+	ch := make(chan dnsNameTest)
+	go emitDNSNameTest(ch)
 	for tc := range ch {
 		if isDomainName(tc.name) != tc.result {
-			t.Errorf("isDomainName(%v) failed: Should be %v",
-				tc.name, tc.result)
+			t.Errorf("isDomainName(%q) = %v; want %v", tc.name, !tc.result, tc.result)
 		}
 	}
 }
 
-func BenchmarkDNSNames(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+func BenchmarkDNSName(b *testing.B) {
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
-	benchmarks := append(tests, []testCase{
+	benchmarks := append(dnsNameTests, []dnsNameTest{
 		{strings.Repeat("a", 63), true},
 		{strings.Repeat("a", 64), false},
 	}...)
diff --git a/src/net/error_plan9_test.go b/src/net/error_plan9_test.go
new file mode 100644
index 0000000..495ea96
--- /dev/null
+++ b/src/net/error_plan9_test.go
@@ -0,0 +1,17 @@
+// 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 "syscall"
+
+var (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EPLAN9
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(syscall.ErrorString)
+	return ok
+}
diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go
new file mode 100644
index 0000000..a642e29
--- /dev/null
+++ b/src/net/error_posix_test.go
@@ -0,0 +1,19 @@
+// 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 !plan9
+
+package net
+
+import "syscall"
+
+var (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EOPNOTSUPP
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(syscall.Errno)
+	return ok
+}
diff --git a/src/net/error_test.go b/src/net/error_test.go
new file mode 100644
index 0000000..c65d3f9
--- /dev/null
+++ b/src/net/error_test.go
@@ -0,0 +1,587 @@
+// 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"
+	"io"
+	"io/ioutil"
+	"net/internal/socktest"
+	"os"
+	"runtime"
+	"testing"
+	"time"
+)
+
+func (e *OpError) isValid() error {
+	if e.Op == "" {
+		return fmt.Errorf("OpError.Op is empty: %v", e)
+	}
+	if e.Net == "" {
+		return fmt.Errorf("OpError.Net is empty: %v", e)
+	}
+	for _, addr := range []Addr{e.Source, e.Addr} {
+		if addr != nil {
+			switch addr.(type) {
+			case *TCPAddr, *UDPAddr, *IPAddr, *IPNet, *UnixAddr, *pipeAddr, fileAddr:
+			default:
+				return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
+			}
+		}
+	}
+	if e.Err == nil {
+		return fmt.Errorf("OpError.Err is empty: %v", e)
+	}
+	return nil
+}
+
+// parseDialError parses nestedErr and reports whether it is a valid
+// error value from Dial, Listen functions.
+// It returns nil when nestedErr is valid.
+func parseDialError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
+		return nil
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errMissingAddress:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+var dialErrorTests = []struct {
+	network, address string
+}{
+	{"foo", ""},
+	{"bar", "baz"},
+	{"datakit", "mh/astro/r70"},
+	{"tcp", ""},
+	{"tcp", "127.0.0.1:☺"},
+	{"tcp", "no-such-name:80"},
+	{"tcp", "mh/astro/r70:http"},
+
+	{"tcp", "127.0.0.1:0"},
+	{"udp", "127.0.0.1:0"},
+	{"ip:icmp", "127.0.0.1"},
+
+	{"unix", "/path/to/somewhere"},
+	{"unixgram", "/path/to/somewhere"},
+	{"unixpacket", "/path/to/somewhere"},
+}
+
+func TestDialError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+		return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true}
+	}
+	sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		return nil, errOpNotSupported
+	})
+	defer sw.Set(socktest.FilterConnect, nil)
+
+	d := Dialer{Timeout: someTimeout}
+	for i, tt := range dialErrorTests {
+		c, err := d.Dial(tt.network, tt.address)
+		if err == nil {
+			t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr())
+			c.Close()
+			continue
+		}
+		if c != nil {
+			t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("#%d: %v", i, err)
+			continue
+		}
+	}
+}
+
+var listenErrorTests = []struct {
+	network, address string
+}{
+	{"foo", ""},
+	{"bar", "baz"},
+	{"datakit", "mh/astro/r70"},
+	{"tcp", "127.0.0.1:☺"},
+	{"tcp", "no-such-name:80"},
+	{"tcp", "mh/astro/r70:http"},
+
+	{"tcp", "127.0.0.1:0"},
+
+	{"unix", "/path/to/somewhere"},
+	{"unixpacket", "/path/to/somewhere"},
+}
+
+func TestListenError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
+	}
+	sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		return nil, errOpNotSupported
+	})
+	defer sw.Set(socktest.FilterListen, nil)
+
+	for i, tt := range listenErrorTests {
+		ln, err := Listen(tt.network, tt.address)
+		if err == nil {
+			t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr())
+			ln.Close()
+			continue
+		}
+		if ln != nil {
+			t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("#%d: %v", i, err)
+			continue
+		}
+	}
+}
+
+var listenPacketErrorTests = []struct {
+	network, address string
+}{
+	{"foo", ""},
+	{"bar", "baz"},
+	{"datakit", "mh/astro/r70"},
+	{"udp", "127.0.0.1:☺"},
+	{"udp", "no-such-name:80"},
+	{"udp", "mh/astro/r70:http"},
+}
+
+func TestListenPacketError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
+	}
+
+	for i, tt := range listenPacketErrorTests {
+		c, err := ListenPacket(tt.network, tt.address)
+		if err == nil {
+			t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr())
+			c.Close()
+			continue
+		}
+		if c != nil {
+			t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c)
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("#%d: %v", i, err)
+			continue
+		}
+	}
+}
+
+// parseReadError parses nestedErr and reports whether it is a valid
+// error value from Read functions.
+// It returns nil when nestedErr is valid.
+func parseReadError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	if nestedErr == io.EOF {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errTimeout:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+// parseWriteError parses nestedErr and reports whether it is a valid
+// error value from Write functions.
+// It returns nil when nestedErr is valid.
+func parseWriteError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
+		return nil
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+// parseCloseError parses nestedErr and reports whether it is a valid
+// error value from Close functions.
+// It returns nil when nestedErr is valid.
+func parseCloseError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	case *os.PathError: // for Plan 9
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+func TestCloseError(t *testing.T) {
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	for i := 0; i < 3; i++ {
+		err = c.(*TCPConn).CloseRead()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		err = c.(*TCPConn).CloseWrite()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		err = c.Close()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+		err = ln.Close()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+
+	pc, err := ListenPacket("udp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer pc.Close()
+
+	for i := 0; i < 3; i++ {
+		err = pc.Close()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+}
+
+// parseAcceptError parses nestedErr and reports whether it is a valid
+// error value from Accept functions.
+// It returns nil when nestedErr is valid.
+func parseAcceptError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errTimeout:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+func TestAcceptError(t *testing.T) {
+	handler := func(ls *localServer, ln Listener) {
+		for {
+			ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
+			c, err := ln.Accept()
+			if perr := parseAcceptError(err); perr != nil {
+				t.Error(perr)
+			}
+			if err != nil {
+				if c != nil {
+					t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c)
+				}
+				if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) {
+					return
+				}
+				continue
+			}
+			c.Close()
+		}
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := ls.buildup(handler); err != nil {
+		ls.teardown()
+		t.Fatal(err)
+	}
+
+	time.Sleep(100 * time.Millisecond)
+	ls.teardown()
+}
+
+// parseCommonError parses nestedErr and reports whether it is a valid
+// error value from miscellaneous functions.
+// It returns nil when nestedErr is valid.
+func parseCommonError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	case *os.LinkError:
+		nestedErr = err.Err
+		goto third
+	case *os.PathError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+func TestFileError(t *testing.T) {
+	switch runtime.GOOS {
+	case "windows":
+		t.Skip("not supported on %s", runtime.GOOS)
+	}
+
+	f, err := ioutil.TempFile("", "go-nettest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(f.Name())
+	defer f.Close()
+
+	c, err := FileConn(f)
+	if err != nil {
+		if c != nil {
+			t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c)
+		}
+		if perr := parseCommonError(err); perr != nil {
+			t.Error(perr)
+		}
+	} else {
+		c.Close()
+		t.Error("should fail")
+	}
+	ln, err := FileListener(f)
+	if err != nil {
+		if ln != nil {
+			t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln)
+		}
+		if perr := parseCommonError(err); perr != nil {
+			t.Error(perr)
+		}
+	} else {
+		ln.Close()
+		t.Error("should fail")
+	}
+	pc, err := FilePacketConn(f)
+	if err != nil {
+		if pc != nil {
+			t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc)
+		}
+		if perr := parseCommonError(err); perr != nil {
+			t.Error(perr)
+		}
+	} else {
+		pc.Close()
+		t.Error("should fail")
+	}
+
+	ln, err = newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for i := 0; i < 3; i++ {
+		f, err := ln.(*TCPListener).File()
+		if err != nil {
+			if perr := parseCommonError(err); perr != nil {
+				t.Error(perr)
+			}
+		} else {
+			f.Close()
+		}
+		ln.Close()
+	}
+}
diff --git a/src/net/external_test.go b/src/net/external_test.go
new file mode 100644
index 0000000..20611ff
--- /dev/null
+++ b/src/net/external_test.go
@@ -0,0 +1,196 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"fmt"
+	"io"
+	"strings"
+	"testing"
+)
+
+func TestResolveGoogle(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 && !supportsIPv6 {
+		t.Skip("ipv4 and ipv6 are not supported")
+	}
+
+	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)
+			}
+			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)
+		case network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil):
+			t.Errorf("got %v; want an ipv6 address on %s", addr, network)
+		}
+	}
+}
+
+var dialGoogleTests = []struct {
+	dial               func(string, string) (Conn, error)
+	unreachableNetwork string
+	networks           []string
+	addrs              []string
+}{
+	{
+		dial:     (&Dialer{DualStack: true}).Dial,
+		networks: []string{"tcp", "tcp4", "tcp6"},
+		addrs:    []string{"www.google.com:http"},
+	},
+	{
+		dial:               Dial,
+		unreachableNetwork: "tcp6",
+		networks:           []string{"tcp", "tcp4"},
+	},
+	{
+		dial:               Dial,
+		unreachableNetwork: "tcp4",
+		networks:           []string{"tcp", "tcp6"},
+	},
+}
+
+func TestDialGoogle(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 && !supportsIPv6 {
+		t.Skip("ipv4 and ipv6 are not supported")
+	}
+
+	var err error
+	dialGoogleTests[1].addrs, dialGoogleTests[2].addrs, err = googleLiteralAddrs()
+	if err != nil {
+		t.Error(err)
+	}
+	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 {
+					t.Error(err)
+				}
+			}
+			enableSocketConnect()
+		}
+	}
+}
+
+var (
+	literalAddrs4 = [...]string{
+		"%d.%d.%d.%d:80",
+		"www.google.com:80",
+		"%d.%d.%d.%d:http",
+		"www.google.com:http",
+		"%03d.%03d.%03d.%03d:0080",
+		"[::ffff:%d.%d.%d.%d]:80",
+		"[::ffff:%02x%02x:%02x%02x]:80",
+		"[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
+		"[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
+		"[0:0:0:0::ffff:%d.%d.%d.%d]:80",
+	}
+	literalAddrs6 = [...]string{
+		"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80",
+		"ipv6.google.com:80",
+		"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http",
+		"ipv6.google.com:http",
+	}
+)
+
+func googleLiteralAddrs() (lits4, lits6 []string, err error) {
+	ips, err := LookupIP("www.google.com")
+	if err != nil {
+		return nil, nil, err
+	}
+	if len(ips) == 0 {
+		return nil, nil, nil
+	}
+	var ip4, ip6 IP
+	for _, ip := range ips {
+		if ip4 == nil && ip.To4() != nil {
+			ip4 = ip.To4()
+		}
+		if ip6 == nil && ip.To16() != nil && ip.To4() == nil {
+			ip6 = ip.To16()
+		}
+		if ip4 != nil && ip6 != nil {
+			break
+		}
+	}
+	if ip4 != nil {
+		for i, lit4 := range literalAddrs4 {
+			if strings.Contains(lit4, "%") {
+				literalAddrs4[i] = fmt.Sprintf(lit4, ip4[0], ip4[1], ip4[2], ip4[3])
+			}
+		}
+		lits4 = literalAddrs4[:]
+	}
+	if ip6 != nil {
+		for i, lit6 := range literalAddrs6 {
+			if strings.Contains(lit6, "%") {
+				literalAddrs6[i] = fmt.Sprintf(lit6, ip6[0], ip6[1], ip6[2], ip6[3], ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15])
+			}
+		}
+		lits6 = literalAddrs6[:]
+	}
+	return
+}
+
+func fetchGoogle(dial func(string, string) (Conn, error), network, address string) error {
+	c, err := dial(network, address)
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+	req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+	if _, err := c.Write(req); err != nil {
+		return err
+	}
+	b := make([]byte, 1000)
+	n, err := io.ReadFull(c, b)
+	if err != nil {
+		return err
+	}
+	if n < 1000 {
+		return fmt.Errorf("short read from %s:%s->%s", network, c.RemoteAddr(), c.LocalAddr())
+	}
+	return nil
+}
diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go
index ddadb6e..32766f5 100644
--- a/src/net/fd_plan9.go
+++ b/src/net/fd_plan9.go
@@ -11,13 +11,13 @@
 	"time"
 )
 
-// Network file descritor.
+// Network file descriptor.
 type netFD struct {
 	// locking/lifetime of sysfd + serialize access to Read and Write methods
 	fdmu fdMutex
 
 	// immutable until Close
-	proto        string
+	net          string
 	n            string
 	dir          string
 	ctl, data    *os.File
@@ -38,8 +38,8 @@
 	return dialChannel(net, ra, dialer, deadline)
 }
 
-func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
-	return &netFD{proto: proto, n: name, dir: netdir + "/" + proto + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
+	return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
 }
 
 func (fd *netFD) init() error {
@@ -55,7 +55,7 @@
 	if fd.raddr != nil {
 		rs = fd.raddr.String()
 	}
-	return fd.proto + ":" + ls + "->" + rs
+	return fd.net + ":" + ls + "->" + rs
 }
 
 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
@@ -132,7 +132,7 @@
 	}
 	defer fd.readUnlock()
 	n, err = fd.data.Read(b)
-	if fd.proto == "udp" && err == io.EOF {
+	if fd.net == "udp" && err == io.EOF {
 		n = 0
 		err = nil
 	}
@@ -202,7 +202,7 @@
 	dfd, err := syscall.Dup(int(f.Fd()), -1)
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return nil, &OpError{"dup", s, fd.laddr, err}
+		return nil, os.NewSyscallError("dup", err)
 	}
 	return os.NewFile(uintptr(dfd), s), nil
 }
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 9e19761..64e94fe 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -93,7 +93,7 @@
 		}
 		fallthrough
 	default:
-		return err
+		return os.NewSyscallError("connect", err)
 	}
 	if err := fd.init(); err != nil {
 		return err
@@ -116,14 +116,14 @@
 		}
 		nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
 		if err != nil {
-			return err
+			return os.NewSyscallError("getsockopt", err)
 		}
 		switch err := syscall.Errno(nerr); err {
 		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 		case syscall.Errno(0), syscall.EISCONN:
 			return nil
 		default:
-			return err
+			return os.NewSyscallError("getsockopt", err)
 		}
 	}
 }
@@ -205,11 +205,7 @@
 		return err
 	}
 	defer fd.decref()
-	err := syscall.Shutdown(fd.sysfd, how)
-	if err != nil {
-		return &OpError{"shutdown", fd.net, fd.laddr, err}
-	}
-	return nil
+	return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
 }
 
 func (fd *netFD) closeRead() error {
@@ -226,7 +222,7 @@
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, &OpError{"read", fd.net, fd.raddr, err}
+		return 0, err
 	}
 	for {
 		n, err = syscall.Read(int(fd.sysfd), p)
@@ -241,8 +237,8 @@
 		err = fd.eofError(n, err)
 		break
 	}
-	if err != nil && err != io.EOF {
-		err = &OpError{"read", fd.net, fd.raddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("read", err)
 	}
 	return
 }
@@ -253,7 +249,7 @@
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+		return 0, nil, err
 	}
 	for {
 		n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
@@ -268,8 +264,8 @@
 		err = fd.eofError(n, err)
 		break
 	}
-	if err != nil && err != io.EOF {
-		err = &OpError{"read", fd.net, fd.laddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("recvfrom", err)
 	}
 	return
 }
@@ -280,7 +276,7 @@
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+		return 0, 0, 0, nil, err
 	}
 	for {
 		n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
@@ -295,8 +291,8 @@
 		err = fd.eofError(n, err)
 		break
 	}
-	if err != nil && err != io.EOF {
-		err = &OpError{"read", fd.net, fd.laddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("recvmsg", err)
 	}
 	return
 }
@@ -307,7 +303,7 @@
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, &OpError{"write", fd.net, fd.raddr, err}
+		return 0, err
 	}
 	for {
 		var n int
@@ -324,7 +320,6 @@
 			}
 		}
 		if err != nil {
-			n = 0
 			break
 		}
 		if n == 0 {
@@ -332,8 +327,8 @@
 			break
 		}
 	}
-	if err != nil {
-		err = &OpError{"write", fd.net, fd.raddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("write", err)
 	}
 	return nn, err
 }
@@ -344,7 +339,7 @@
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, &OpError{"write", fd.net, fd.raddr, err}
+		return 0, err
 	}
 	for {
 		err = syscall.Sendto(fd.sysfd, p, 0, sa)
@@ -357,8 +352,9 @@
 	}
 	if err == nil {
 		n = len(p)
-	} else {
-		err = &OpError{"write", fd.net, fd.raddr, err}
+	}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("sendto", err)
 	}
 	return
 }
@@ -369,7 +365,7 @@
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
+		return 0, 0, err
 	}
 	for {
 		n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
@@ -382,8 +378,9 @@
 	}
 	if err == nil {
 		oobn = len(oob)
-	} else {
-		err = &OpError{"write", fd.net, fd.raddr, err}
+	}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("sendmsg", err)
 	}
 	return
 }
@@ -397,21 +394,28 @@
 	var s int
 	var rsa syscall.Sockaddr
 	if err = fd.pd.PrepareRead(); err != nil {
-		return nil, &OpError{"accept", fd.net, fd.laddr, err}
+		return nil, err
 	}
 	for {
 		s, rsa, err = accept(fd.sysfd)
 		if err != nil {
-			if err == syscall.EAGAIN {
+			nerr, ok := err.(*os.SyscallError)
+			if !ok {
+				return nil, err
+			}
+			switch nerr.Err {
+			case syscall.EAGAIN:
 				if err = fd.pd.WaitRead(); err == nil {
 					continue
 				}
-			} else if err == syscall.ECONNABORTED {
-				// This means that a socket on the listen queue was closed
-				// before we Accept()ed it; it's a silly error, so try again.
+			case syscall.ECONNABORTED:
+				// This means that a socket on the
+				// listen queue was closed before we
+				// Accept()ed it; it's a silly error,
+				// so try again.
 				continue
 			}
-			return nil, &OpError{"accept", fd.net, fd.laddr, err}
+			return nil, err
 		}
 		break
 	}
@@ -457,7 +461,7 @@
 			// from now on.
 			atomic.StoreInt32(&tryDupCloexec, 0)
 		default:
-			return -1, e1
+			return -1, os.NewSyscallError("fcntl", e1)
 		}
 	}
 	return dupCloseOnExecOld(fd)
@@ -470,7 +474,7 @@
 	defer syscall.ForkLock.RUnlock()
 	newfd, err = syscall.Dup(fd)
 	if err != nil {
-		return -1, err
+		return -1, os.NewSyscallError("dup", err)
 	}
 	syscall.CloseOnExec(newfd)
 	return
@@ -479,7 +483,7 @@
 func (fd *netFD) dup() (f *os.File, err error) {
 	ns, err := dupCloseOnExec(fd.sysfd)
 	if err != nil {
-		return nil, &OpError{"dup", fd.net, fd.laddr, err}
+		return nil, err
 	}
 
 	// We want blocking mode for the new fd, hence the double negative.
@@ -487,7 +491,7 @@
 	// I/O will block the thread instead of letting us use the epoll server.
 	// Everything will still work, just with more threads.
 	if err = syscall.SetNonblock(ns, false); err != nil {
-		return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
+		return nil, os.NewSyscallError("setnonblock", err)
 	}
 
 	return os.NewFile(uintptr(ns), fd.name()), nil
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index d685883..205daff 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -5,7 +5,6 @@
 package net
 
 import (
-	"errors"
 	"os"
 	"runtime"
 	"sync"
@@ -39,7 +38,7 @@
 	var d syscall.WSAData
 	e := syscall.WSAStartup(uint32(0x202), &d)
 	if e != nil {
-		initErr = os.NewSyscallError("WSAStartup", e)
+		initErr = os.NewSyscallError("wsastartup", e)
 	}
 	canCancelIO = syscall.LoadCancelIoEx() == nil
 	if syscall.LoadGetAddrInfo() == nil {
@@ -154,7 +153,7 @@
 	// Notify runtime netpoll about starting IO.
 	err := fd.pd.Prepare(int(o.mode))
 	if err != nil {
-		return 0, &OpError{name, fd.net, fd.laddr, err}
+		return 0, err
 	}
 	// Start IO.
 	if canCancelIO {
@@ -177,7 +176,7 @@
 		// IO started, and we have to wait for its completion.
 		err = nil
 	default:
-		return 0, &OpError{name, fd.net, fd.laddr, err}
+		return 0, err
 	}
 	// Wait for our request to complete.
 	err = fd.pd.Wait(int(o.mode))
@@ -185,7 +184,7 @@
 		// All is good. Extract our IO results and return.
 		if o.errno != 0 {
 			err = syscall.Errno(o.errno)
-			return 0, &OpError{name, fd.net, fd.laddr, err}
+			return 0, err
 		}
 		return int(o.qty), nil
 	}
@@ -216,7 +215,7 @@
 		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
 			err = netpollErr
 		}
-		return 0, &OpError{name, fd.net, fd.laddr, err}
+		return 0, err
 	}
 	// We issued cancellation request. But, it seems, IO operation succeeded
 	// before cancellation request run. We need to treat IO operation as
@@ -298,7 +297,7 @@
 		size := uint32(unsafe.Sizeof(flag))
 		err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
 		if err != nil {
-			return os.NewSyscallError("WSAIoctl", err)
+			return os.NewSyscallError("wsaioctl", err)
 		}
 	}
 	fd.rop.mode = 'r'
@@ -332,7 +331,7 @@
 		defer fd.setWriteDeadline(noDeadline)
 	}
 	if !canUseConnectEx(fd.net) {
-		return connectFunc(fd.sysfd, ra)
+		return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra))
 	}
 	// ConnectEx windows API requires an unconnected, previously bound socket.
 	if la == nil {
@@ -345,7 +344,7 @@
 			panic("unexpected type in connect")
 		}
 		if err := syscall.Bind(fd.sysfd, la); err != nil {
-			return err
+			return os.NewSyscallError("bind", err)
 		}
 	}
 	// Call ConnectEx API.
@@ -355,10 +354,13 @@
 		return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
 	})
 	if err != nil {
+		if _, ok := err.(syscall.Errno); ok {
+			err = os.NewSyscallError("connectex", err)
+		}
 		return err
 	}
 	// Refresh socket properties.
-	return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
+	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
 }
 
 func (fd *netFD) destroy() {
@@ -438,11 +440,7 @@
 		return err
 	}
 	defer fd.decref()
-	err := syscall.Shutdown(fd.sysfd, how)
-	if err != nil {
-		return &OpError{"shutdown", fd.net, fd.laddr, err}
-	}
-	return nil
+	return syscall.Shutdown(fd.sysfd, how)
 }
 
 func (fd *netFD) closeRead() error {
@@ -467,10 +465,13 @@
 		raceAcquire(unsafe.Pointer(&ioSync))
 	}
 	err = fd.eofError(n, err)
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsarecv", err)
+	}
 	return n, err
 }
 
-func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
 	if len(buf) == 0 {
 		return 0, nil, nil
 	}
@@ -480,7 +481,7 @@
 	defer fd.readUnlock()
 	o := &fd.rop
 	o.InitBuf(buf)
-	n, err = rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
+	n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
 		if o.rsa == nil {
 			o.rsa = new(syscall.RawSockaddrAny)
 		}
@@ -488,11 +489,14 @@
 		return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
 	})
 	err = fd.eofError(n, err)
-	if err != nil {
-		return 0, nil, err
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsarecvfrom", err)
 	}
-	sa, _ = o.rsa.Sockaddr()
-	return
+	if err != nil {
+		return n, nil, err
+	}
+	sa, _ := o.rsa.Sockaddr()
+	return n, sa, nil
 }
 
 func (fd *netFD) Write(buf []byte) (int, error) {
@@ -505,9 +509,13 @@
 	}
 	o := &fd.wop
 	o.InitBuf(buf)
-	return wsrv.ExecIO(o, "WSASend", func(o *operation) error {
+	n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
 		return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
 	})
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsasend", err)
+	}
+	return n, err
 }
 
 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
@@ -521,23 +529,27 @@
 	o := &fd.wop
 	o.InitBuf(buf)
 	o.sa = sa
-	return wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
+	n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
 		return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
 	})
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsasendto", err)
+	}
+	return n, err
 }
 
 func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) {
 	// Get new socket.
 	s, err := sysSocket(fd.family, fd.sotype, 0)
 	if err != nil {
-		return nil, &OpError{"socket", fd.net, fd.laddr, err}
+		return nil, err
 	}
 
 	// Associate our new socket with IOCP.
 	netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
 	if err != nil {
 		closeFunc(s)
-		return nil, &OpError{"accept", fd.net, fd.laddr, err}
+		return nil, err
 	}
 	if err := netfd.init(); err != nil {
 		fd.Close()
@@ -552,6 +564,9 @@
 	})
 	if err != nil {
 		netfd.Close()
+		if _, ok := err.(syscall.Errno); ok {
+			err = os.NewSyscallError("acceptex", err)
+		}
 		return nil, err
 	}
 
@@ -559,7 +574,7 @@
 	err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
 	if err != nil {
 		netfd.Close()
-		return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err}
+		return nil, os.NewSyscallError("setsockopt", err)
 	}
 
 	return netfd, nil
@@ -585,11 +600,11 @@
 		// before AcceptEx could complete. These errors relate to new
 		// connection, not to AcceptEx, so ignore broken connection and
 		// try AcceptEx again for more connections.
-		operr, ok := err.(*OpError)
+		nerr, ok := err.(*os.SyscallError)
 		if !ok {
 			return nil, err
 		}
-		errno, ok := operr.Err.(syscall.Errno)
+		errno, ok := nerr.Err.(syscall.Errno)
 		if !ok {
 			return nil, err
 		}
@@ -617,15 +632,13 @@
 
 func (fd *netFD) dup() (*os.File, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
 
-var errNoSupport = errors.New("address family not supported")
-
 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
-	return 0, 0, 0, nil, errNoSupport
+	return 0, 0, 0, nil, syscall.EWINDOWS
 }
 
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
-	return 0, 0, errNoSupport
+	return 0, 0, syscall.EWINDOWS
 }
diff --git a/src/net/file.go b/src/net/file.go
new file mode 100644
index 0000000..1aad477
--- /dev/null
+++ b/src/net/file.go
@@ -0,0 +1,48 @@
+// 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 "os"
+
+type fileAddr string
+
+func (fileAddr) Network() string  { return "file+net" }
+func (f fileAddr) String() string { return string(f) }
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.
+// 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 FileConn(f *os.File) (c Conn, err error) {
+	c, err = fileConn(f)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.
+// It is the caller's responsibility to close ln when finished.
+// Closing ln does not affect f, and closing f does not affect ln.
+func FileListener(f *os.File) (ln Listener, err error) {
+	ln, err = fileListener(f)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.
+// 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 FilePacketConn(f *os.File) (c PacketConn, err error) {
+	c, err = filePacketConn(f)
+	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_plan9.go b/src/net/file_plan9.go
index 068f088..892775a 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -86,7 +86,7 @@
 	return newFD(comp[1], name, ctl, nil, laddr, nil)
 }
 
-func newFileConn(f *os.File) (c Conn, err error) {
+func fileConn(f *os.File) (Conn, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -109,7 +109,7 @@
 	return nil, syscall.EPLAN9
 }
 
-func newFileListener(f *os.File) (l Listener, err error) {
+func fileListener(f *os.File) (Listener, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -132,26 +132,6 @@
 	return &TCPListener{fd}, nil
 }
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  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 FileConn(f *os.File) (c Conn, err error) {
-	return newFileConn(f)
-}
-
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
-	return newFileListener(f)
-}
-
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  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 FilePacketConn(f *os.File) (c PacketConn, err error) {
+func filePacketConn(f *os.File) (PacketConn, error) {
 	return nil, syscall.EPLAN9
 }
diff --git a/src/net/file_stub.go b/src/net/file_stub.go
index 4281072e..0f7460c 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_stub.go
@@ -11,28 +11,6 @@
 	"syscall"
 )
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  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 FileConn(f *os.File) (c Conn, err error) {
-	return nil, syscall.ENOPROTOOPT
-
-}
-
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
-	return nil, syscall.ENOPROTOOPT
-
-}
-
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  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 FilePacketConn(f *os.File) (c PacketConn, err 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 }
diff --git a/src/net/file_test.go b/src/net/file_test.go
index 609efb2..f358f70 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -29,26 +29,26 @@
 func testFileListener(t *testing.T, net, laddr string) {
 	l, err := Listen(net, laddr)
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	defer l.Close()
 	lf := l.(listenerFile)
 	f, err := lf.File()
 	if err != nil {
-		t.Fatalf("File failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := FileListener(f)
 	if err != nil {
-		t.Fatalf("FileListener failed: %v", err)
+		t.Fatal(err)
 	}
 	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
-		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
+		t.Fatalf("got %#v; want%#v", l.Addr(), c.Addr())
 	}
 	if err := c.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 	if err := f.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
@@ -84,12 +84,12 @@
 func TestFileListener(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	for _, tt := range fileListenerTests {
 		if !testableListenArgs(tt.net, tt.laddr, "") {
-			t.Logf("skipping %s test", tt.net+":"+tt.laddr+"->")
+			t.Logf("skipping %s test", tt.net+" "+tt.laddr)
 			continue
 		}
 		testFileListener(t, tt.net, tt.laddr)
@@ -99,47 +99,47 @@
 func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
 	f, err := pcf.File()
 	if err != nil {
-		t.Fatalf("File failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := FilePacketConn(f)
 	if err != nil {
-		t.Fatalf("FilePacketConn failed: %v", err)
+		t.Fatal(err)
 	}
 	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
-		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
+		t.Fatalf("got %#v; want %#v", pcf.LocalAddr(), c.LocalAddr())
 	}
 	if listen {
 		if _, err := c.WriteTo([]byte{}, c.LocalAddr()); err != nil {
-			t.Fatalf("WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 	}
 	if err := c.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 	if err := f.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
 func testFilePacketConnListen(t *testing.T, net, laddr string) {
 	l, err := ListenPacket(net, laddr)
 	if err != nil {
-		t.Fatalf("ListenPacket failed: %v", err)
+		t.Fatal(err)
 	}
 	testFilePacketConn(t, l.(packetConnFile), true)
 	if err := l.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
 func testFilePacketConnDial(t *testing.T, net, raddr string) {
 	c, err := Dial(net, raddr)
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
 	}
 	testFilePacketConn(t, c.(packetConnFile), false)
 	if err := c.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
@@ -156,7 +156,8 @@
 
 	{net: "udp6", addr: "[::1]:0"},
 
-	{net: "ip4:icmp", addr: "127.0.0.1"},
+	// TODO(mikioh,bradfitz): renable once 10730 is fixed
+	// {net: "ip4:icmp", addr: "127.0.0.1"},
 
 	{net: "unixgram", addr: "@gotest3/net"},
 }
@@ -164,12 +165,12 @@
 func TestFilePacketConn(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	for _, tt := range filePacketConnTests {
 		if !testableListenArgs(tt.net, tt.addr, "") {
-			t.Logf("skipping %s test", tt.net+":"+tt.addr+"->")
+			t.Logf("skipping %s test", tt.net+" "+tt.addr)
 			continue
 		}
 		if os.Getuid() != 0 && tt.net == "ip4:icmp" {
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index 8d806a1..147ca1e 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -14,12 +14,12 @@
 func newFileFD(f *os.File) (*netFD, error) {
 	fd, err := dupCloseOnExec(int(f.Fd()))
 	if err != nil {
-		return nil, os.NewSyscallError("dup", err)
+		return nil, err
 	}
 
 	if err = syscall.SetNonblock(fd, true); err != nil {
 		closeFunc(fd)
-		return nil, err
+		return nil, os.NewSyscallError("setnonblock", err)
 	}
 
 	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
@@ -32,9 +32,6 @@
 	toAddr := sockaddrToTCP
 	lsa, _ := syscall.Getsockname(fd)
 	switch lsa.(type) {
-	default:
-		closeFunc(fd)
-		return nil, syscall.EINVAL
 	case *syscall.SockaddrInet4:
 		family = syscall.AF_INET
 		if sotype == syscall.SOCK_DGRAM {
@@ -57,6 +54,9 @@
 		} else if sotype == syscall.SOCK_SEQPACKET {
 			toAddr = sockaddrToUnixpacket
 		}
+	default:
+		closeFunc(fd)
+		return nil, syscall.EPROTONOSUPPORT
 	}
 	laddr := toAddr(lsa)
 	rsa, _ := syscall.Getpeername(fd)
@@ -75,11 +75,7 @@
 	return netfd, nil
 }
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  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 FileConn(f *os.File) (c Conn, err error) {
+func fileConn(f *os.File) (Conn, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -98,11 +94,7 @@
 	return nil, syscall.EINVAL
 }
 
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
+func fileListener(f *os.File) (Listener, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -117,11 +109,7 @@
 	return nil, syscall.EINVAL
 }
 
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  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 FilePacketConn(f *os.File) (c PacketConn, err error) {
+func filePacketConn(f *os.File) (PacketConn, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
diff --git a/src/net/file_windows.go b/src/net/file_windows.go
index ca2b9b2..241fa17 100644
--- a/src/net/file_windows.go
+++ b/src/net/file_windows.go
@@ -9,29 +9,17 @@
 	"syscall"
 )
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  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 FileConn(f *os.File) (c Conn, err error) {
+func fileConn(f *os.File) (Conn, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
 
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
+func fileListener(f *os.File) (Listener, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
 
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  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 FilePacketConn(f *os.File) (c PacketConn, err error) {
+func filePacketConn(f *os.File) (PacketConn, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
diff --git a/src/net/hook.go b/src/net/hook.go
new file mode 100644
index 0000000..32ba15e
--- /dev/null
+++ b/src/net/hook.go
@@ -0,0 +1,10 @@
+// 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
+
+var (
+	testHookLookupIP     = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { return fn(host) }
+	testHookSetKeepAlive = func() {}
+)
diff --git a/src/net/hook_plan9.go b/src/net/hook_plan9.go
new file mode 100644
index 0000000..e053348
--- /dev/null
+++ b/src/net/hook_plan9.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.
+
+package net
+
+import "time"
+
+var testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
index 626d07f..361ca59 100644
--- a/src/net/hook_unix.go
+++ b/src/net/hook_unix.go
@@ -9,10 +9,13 @@
 import "syscall"
 
 var (
+	testHookDialChannel = func() {} // see golang.org/issue/5349
+
 	// Placeholders for socket system calls.
 	socketFunc        func(int, int, int) (int, error)         = syscall.Socket
 	closeFunc         func(int) error                          = syscall.Close
 	connectFunc       func(int, syscall.Sockaddr) error        = syscall.Connect
+	listenFunc        func(int, int) error                     = syscall.Listen
 	acceptFunc        func(int) (int, syscall.Sockaddr, error) = syscall.Accept
 	getsockoptIntFunc func(int, int, int) (int, error)         = syscall.GetsockoptInt
 )
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
index 2a6e5bf..126b0eb 100644
--- a/src/net/hook_windows.go
+++ b/src/net/hook_windows.go
@@ -4,12 +4,18 @@
 
 package net
 
-import "syscall"
+import (
+	"syscall"
+	"time"
+)
 
 var (
+	testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
+
 	// Placeholders for socket system calls.
 	socketFunc    func(int, int, int) (syscall.Handle, error)                                               = syscall.Socket
 	closeFunc     func(syscall.Handle) error                                                                = syscall.Closesocket
 	connectFunc   func(syscall.Handle, syscall.Sockaddr) error                                              = syscall.Connect
 	connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
+	listenFunc    func(syscall.Handle, int) error                                                           = syscall.Listen
 )
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index 5bb663b..352ecb9 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -39,14 +39,12 @@
 		tt := hosttests[i]
 		ips := lookupStaticHost(tt.host)
 		if len(ips) != len(tt.ips) {
-			t.Errorf("# of hosts = %v; want %v",
-				len(ips), len(tt.ips))
+			t.Errorf("# of hosts = %v; want %v", len(ips), len(tt.ips))
 			continue
 		}
 		for k, v := range ips {
 			if tt.ips[k].String() != v {
-				t.Errorf("lookupStaticHost(%q) = %v; want %v",
-					tt.host, v, tt.ips[k])
+				t.Errorf("lookupStaticHost(%q) = %v; want %v", tt.host, v, tt.ips[k])
 			}
 		}
 	}
diff --git a/src/net/http/cgi/matryoshka_test.go b/src/net/http/cgi/matryoshka_test.go
index bf28c56..c89c6d5 100644
--- a/src/net/http/cgi/matryoshka_test.go
+++ b/src/net/http/cgi/matryoshka_test.go
@@ -21,10 +21,13 @@
 	"time"
 )
 
+// iOS cannot fork, so we skip some tests
+var iOS = runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
+
 // This test is a CGI host (testing host.go) that runs its own binary
 // as a child process testing the other half of CGI (child.go).
 func TestHostingOurselves(t *testing.T) {
-	if runtime.GOOS == "nacl" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm") {
+	if runtime.GOOS == "nacl" || iOS {
 		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
 	}
 
@@ -93,7 +96,7 @@
 // If there's an error copying the child's output to the parent, test
 // that we kill the child.
 func TestKillChildAfterCopyError(t *testing.T) {
-	if runtime.GOOS == "nacl" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm") {
+	if runtime.GOOS == "nacl" || iOS {
 		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
 	}
 
@@ -140,7 +143,7 @@
 // Test that a child handler writing only headers works.
 // golang.org/issue/7196
 func TestChildOnlyHeaders(t *testing.T) {
-	if runtime.GOOS == "nacl" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm") {
+	if runtime.GOOS == "nacl" || iOS {
 		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
 	}
 
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 7341871..1c5e191 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -257,8 +257,9 @@
 	return false
 }
 
-// Get issues a GET to the specified URL.  If the response is one of the following
-// redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
+// Get issues a GET to the specified URL. If the response is one of
+// the following redirect codes, Get follows the redirect, up to a
+// maximum of 10 redirects:
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -273,11 +274,14 @@
 // Caller should close resp.Body when done reading from it.
 //
 // Get is a wrapper around DefaultClient.Get.
+//
+// To make a request with custom headers, use NewRequest and
+// DefaultClient.Do.
 func Get(url string) (resp *Response, err error) {
 	return DefaultClient.Get(url)
 }
 
-// Get issues a GET to the specified URL.  If the response is one of the
+// Get issues a GET to the specified URL. If the response is one of the
 // following redirect codes, Get follows the redirect after calling the
 // Client's CheckRedirect function.
 //
@@ -292,6 +296,8 @@
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
+//
+// To make a request with custom headers, use NewRequest and Client.Do.
 func (c *Client) Get(url string) (resp *Response, err error) {
 	req, err := NewRequest("GET", url, nil)
 	if err != nil {
@@ -390,7 +396,7 @@
 			}
 			resp.Body.Close()
 			if urlStr = resp.Header.Get("Location"); urlStr == "" {
-				err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
+				err = fmt.Errorf("%d response missing Location header", resp.StatusCode)
 				break
 			}
 			base = req.URL
@@ -438,7 +444,12 @@
 //
 // Caller should close resp.Body when done reading from it.
 //
-// Post is a wrapper around DefaultClient.Post
+// If the provided body is an io.Closer, it is closed after the
+// request.
+//
+// Post is a wrapper around DefaultClient.Post.
+//
+// To set custom headers, use NewRequest and DefaultClient.Do.
 func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	return DefaultClient.Post(url, bodyType, body)
 }
@@ -447,8 +458,10 @@
 //
 // Caller should close resp.Body when done reading from it.
 //
-// If the provided body is also an io.Closer, it is closed after the
+// If the provided body is an io.Closer, it is closed after the
 // request.
+//
+// To set custom headers, use NewRequest and Client.Do.
 func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	req, err := NewRequest("POST", url, body)
 	if err != nil {
@@ -461,16 +474,22 @@
 // PostForm issues a POST to the specified URL, with data's keys and
 // values URL-encoded as the request body.
 //
+// The Content-Type header is set to application/x-www-form-urlencoded.
+// To set other headers, use NewRequest and DefaultClient.Do.
+//
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
 //
-// PostForm is a wrapper around DefaultClient.PostForm
+// PostForm is a wrapper around DefaultClient.PostForm.
 func PostForm(url string, data url.Values) (resp *Response, err error) {
 	return DefaultClient.PostForm(url, data)
 }
 
 // PostForm issues a POST to the specified URL,
-// with data's keys and values urlencoded as the request body.
+// with data's keys and values URL-encoded as the request body.
+//
+// The Content-Type header is set to application/x-www-form-urlencoded.
+// To set other headers, use NewRequest and DefaultClient.Do.
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 18645ff..dc499a9 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -334,6 +334,7 @@
 })
 
 func TestClientSendsCookieFromJar(t *testing.T) {
+	defer afterTest(t)
 	tr := &recordingTransport{}
 	client := &Client{Transport: tr}
 	client.Jar = &TestJar{perURL: make(map[string][]*Cookie)}
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index 87b6c07..0457be5 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -10,9 +10,17 @@
 import (
 	"net"
 	"net/url"
+	"sync"
 	"time"
 )
 
+func init() {
+	// We only want to pay for this cost during testing.
+	// When not under test, these values are always nil
+	// and never assigned to.
+	testHookMu = new(sync.Mutex)
+}
+
 func NewLoggingConn(baseName string, c net.Conn) net.Conn {
 	return newLoggingConn(baseName, c)
 }
@@ -78,6 +86,20 @@
 	})
 }
 
+func SetInstallConnClosedHook(f func()) {
+	testHookPersistConnClosedGotRes = f
+}
+
+func SetEnterRoundTripHook(f func()) {
+	testHookEnterRoundTrip = f
+}
+
+func SetReadLoopBeforeNextReadHook(f func()) {
+	testHookMu.Lock()
+	defer testHookMu.Unlock()
+	testHookReadLoopBeforeNextRead = f
+}
+
 func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
 	f := func() <-chan time.Time {
 		return ch
@@ -106,3 +128,5 @@
 var ExportServerNewConn = (*Server).newConn
 
 var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
+
+var ExportErrRequestCanceled = errRequestCanceled
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index 4e69da8..7572023 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -358,16 +358,16 @@
 
 	f, err := fs.Open(name)
 	if err != nil {
-		// TODO expose actual error?
-		NotFound(w, r)
+		msg, code := toHTTPError(err)
+		Error(w, msg, code)
 		return
 	}
 	defer f.Close()
 
 	d, err1 := f.Stat()
 	if err1 != nil {
-		// TODO expose actual error?
-		NotFound(w, r)
+		msg, code := toHTTPError(err)
+		Error(w, msg, code)
 		return
 	}
 
@@ -417,6 +417,22 @@
 	serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
 }
 
+// toHTTPError returns a non-specific HTTP error message and status code
+// for a given non-nil error value. It's important that toHTTPError does not
+// actually return err.Error(), since msg and httpStatus are returned to users,
+// and historically Go's ServeContent always returned just "404 Not Found" for
+// all errors. We don't want to start leaking information in error messages.
+func toHTTPError(err error) (msg string, httpStatus int) {
+	if os.IsNotExist(err) {
+		return "404 page not found", StatusNotFound
+	}
+	if os.IsPermission(err) {
+		return "403 Forbidden", StatusForbidden
+	}
+	// Default:
+	return "500 Internal Server Error", StatusInternalServerError
+}
+
 // localRedirect gives a Moved Permanently response.
 // It does not convert relative paths to absolute paths like Redirect does.
 func localRedirect(w ResponseWriter, r *Request, newPath string) {
@@ -427,7 +443,13 @@
 	w.WriteHeader(StatusMovedPermanently)
 }
 
-// ServeFile replies to the request with the contents of the named file or directory.
+// ServeFile replies to the request with the contents of the named
+// file or directory.
+//
+// As a special case, ServeFile redirects any request where r.URL.Path
+// ends in "/index.html" to the same path, without the final
+// "index.html". To avoid such redirects either modify the path or
+// use ServeContent.
 func ServeFile(w ResponseWriter, r *Request, name string) {
 	dir, file := filepath.Split(name)
 	serveFile(w, r, Dir(dir), file, false)
@@ -444,6 +466,10 @@
 // use http.Dir:
 //
 //     http.Handle("/", http.FileServer(http.Dir("/tmp")))
+//
+// As a special case, the returned file server redirects any request
+// ending in "/index.html" to the same path, without the final
+// "index.html".
 func FileServer(root FileSystem) Handler {
 	return &fileHandler{root}
 }
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index a8cfe5f..794dabc 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -497,6 +497,7 @@
 	modtime  time.Time
 	ents     []*fakeFileInfo
 	contents string
+	err      error
 }
 
 func (f *fakeFileInfo) Name() string       { return f.basename }
@@ -549,6 +550,9 @@
 	if !ok {
 		return nil, os.ErrNotExist
 	}
+	if f.err != nil {
+		return nil, f.err
+	}
 	return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
 }
 
@@ -803,6 +807,31 @@
 	}
 }
 
+func TestServeContentErrorMessages(t *testing.T) {
+	defer afterTest(t)
+	fs := fakeFS{
+		"/500": &fakeFileInfo{
+			err: errors.New("random error"),
+		},
+		"/403": &fakeFileInfo{
+			err: &os.PathError{Err: os.ErrPermission},
+		},
+	}
+	ts := httptest.NewServer(FileServer(fs))
+	defer ts.Close()
+	for _, code := range []int{403, 404, 500} {
+		res, err := DefaultClient.Get(fmt.Sprintf("%s/%d", ts.URL, code))
+		if err != nil {
+			t.Errorf("Error fetching /%d: %v", code, err)
+			continue
+		}
+		if res.StatusCode != code {
+			t.Errorf("For /%d, status code = %d; want %d", code, res.StatusCode, code)
+		}
+		res.Body.Close()
+	}
+}
+
 // verifies that sendfile is being used on Linux
 func TestLinuxSendfile(t *testing.T) {
 	defer afterTest(t)
diff --git a/src/net/http/lex.go b/src/net/http/lex.go
index cb33318..50b14f8 100644
--- a/src/net/http/lex.go
+++ b/src/net/http/lex.go
@@ -4,6 +4,11 @@
 
 package http
 
+import (
+	"strings"
+	"unicode/utf8"
+)
+
 // This file deals with lexical matters of HTTP
 
 var isTokenTable = [127]bool{
@@ -94,3 +99,71 @@
 func isNotToken(r rune) bool {
 	return !isToken(r)
 }
+
+// headerValuesContainsToken reports whether any string in values
+// contains the provided token, ASCII case-insensitively.
+func headerValuesContainsToken(values []string, token string) bool {
+	for _, v := range values {
+		if headerValueContainsToken(v, token) {
+			return true
+		}
+	}
+	return false
+}
+
+// isOWS reports whether b is an optional whitespace byte, as defined
+// by RFC 7230 section 3.2.3.
+func isOWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// trimOWS returns x with all optional whitespace removes from the
+// beginning and end.
+func trimOWS(x string) string {
+	// TODO: consider using strings.Trim(x, " \t") instead,
+	// if and when it's fast enough. See issue 10292.
+	// But this ASCII-only code will probably always beat UTF-8
+	// aware code.
+	for len(x) > 0 && isOWS(x[0]) {
+		x = x[1:]
+	}
+	for len(x) > 0 && isOWS(x[len(x)-1]) {
+		x = x[:len(x)-1]
+	}
+	return x
+}
+
+// headerValueContainsToken reports whether v (assumed to be a
+// 0#element, in the ABNF extension described in RFC 7230 section 7)
+// contains token amongst its comma-separated tokens, ASCII
+// case-insensitively.
+func headerValueContainsToken(v string, token string) bool {
+	v = trimOWS(v)
+	if comma := strings.IndexByte(v, ','); comma != -1 {
+		return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
+	}
+	return tokenEqual(v, token)
+}
+
+// lowerASCII returns the ASCII lowercase version of b.
+func lowerASCII(b byte) byte {
+	if 'A' <= b && b <= 'Z' {
+		return b + ('a' - 'A')
+	}
+	return b
+}
+
+// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
+func tokenEqual(t1, t2 string) bool {
+	if len(t1) != len(t2) {
+		return false
+	}
+	for i, b := range t1 {
+		if b >= utf8.RuneSelf {
+			// No UTF-8 or non-ASCII allowed in tokens.
+			return false
+		}
+		if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/net/http/lex_test.go b/src/net/http/lex_test.go
index 6d9d294..986fda1 100644
--- a/src/net/http/lex_test.go
+++ b/src/net/http/lex_test.go
@@ -29,3 +29,73 @@
 		}
 	}
 }
+
+func TestHeaderValuesContainsToken(t *testing.T) {
+	tests := []struct {
+		vals  []string
+		token string
+		want  bool
+	}{
+		{
+			vals:  []string{"foo"},
+			token: "foo",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar", "foo"},
+			token: "foo",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo"},
+			token: "bar",
+			want:  false,
+		},
+		{
+			vals:  []string{" foo "},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo,bar"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar,foo,bar"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar , foo"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo ,bar "},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar, foo ,bar"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar , foo"},
+			token: "FOO",
+			want:  true,
+		},
+	}
+	for _, tt := range tests {
+		got := headerValuesContainsToken(tt.vals, tt.token)
+		if got != tt.want {
+			t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want)
+		}
+	}
+}
diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go
index c7407df..12eea6f 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -56,17 +56,21 @@
 		// not counting goroutines for leakage in -short mode
 		return false
 	}
-	gs := interestingGoroutines()
 
-	n := 0
-	stackCount := make(map[string]int)
-	for _, g := range gs {
-		stackCount[g]++
-		n++
-	}
-
-	if n == 0 {
-		return false
+	var stackCount map[string]int
+	for i := 0; i < 5; i++ {
+		n := 0
+		stackCount = make(map[string]int)
+		gs := interestingGoroutines()
+		for _, g := range gs {
+			stackCount[g]++
+			n++
+		}
+		if n == 0 {
+			return false
+		}
+		// Wait for goroutines to schedule and die off:
+		time.Sleep(100 * time.Millisecond)
 	}
 	fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
 	for stack, count := range stackCount {
diff --git a/src/net/http/npn_test.go b/src/net/http/npn_test.go
index 98b8930..e2e911d 100644
--- a/src/net/http/npn_test.go
+++ b/src/net/http/npn_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"bufio"
+	"bytes"
 	"crypto/tls"
 	"fmt"
 	"io"
@@ -17,6 +18,7 @@
 )
 
 func TestNextProtoUpgrade(t *testing.T) {
+	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		fmt.Fprintf(w, "path=%s,proto=", r.URL.Path)
 		if r.TLS != nil {
@@ -38,12 +40,12 @@
 	ts.StartTLS()
 	defer ts.Close()
 
-	tr := newTLSTransport(t, ts)
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
-
 	// Normal request, without NPN.
 	{
+		tr := newTLSTransport(t, ts)
+		defer tr.CloseIdleConnections()
+		c := &Client{Transport: tr}
+
 		res, err := c.Get(ts.URL)
 		if err != nil {
 			t.Fatal(err)
@@ -60,11 +62,17 @@
 	// Request to an advertised but unhandled NPN protocol.
 	// Server will hang up.
 	{
-		tr.CloseIdleConnections()
+		tr := newTLSTransport(t, ts)
 		tr.TLSClientConfig.NextProtos = []string{"unhandled-proto"}
-		_, err := c.Get(ts.URL)
+		defer tr.CloseIdleConnections()
+		c := &Client{Transport: tr}
+
+		res, err := c.Get(ts.URL)
 		if err == nil {
-			t.Errorf("expected error on unhandled-proto request")
+			defer res.Body.Close()
+			var buf bytes.Buffer
+			res.Write(&buf)
+			t.Errorf("expected error on unhandled-proto request; got: %s", buf.Bytes())
 		}
 	}
 
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 639a579..43d9de3 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -169,8 +169,9 @@
 	// The HTTP client ignores Form and uses Body instead.
 	Form url.Values
 
-	// PostForm contains the parsed form data from POST or PUT
-	// body parameters.
+	// PostForm contains the parsed form data from POST, PATCH,
+	// or PUT body parameters.
+	//
 	// This field is only available after ParseForm is called.
 	// The HTTP client ignores PostForm and uses Body instead.
 	PostForm url.Values
@@ -361,12 +362,15 @@
 
 // extraHeaders may be nil
 func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
-	host := req.Host
+	// According to RFC 6874, an HTTP client, proxy, or other
+	// intermediary must remove any IPv6 zone identifier attached
+	// to an outgoing URI.
+	host := removeZone(req.Host)
 	if host == "" {
 		if req.URL == nil {
 			return errors.New("http: Request.Write on Request with no Host or URL set")
 		}
-		host = req.URL.Host
+		host = removeZone(req.URL.Host)
 	}
 
 	ruri := req.URL.RequestURI()
@@ -453,6 +457,23 @@
 	return nil
 }
 
+// removeZone removes IPv6 zone identifer from host.
+// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
+func removeZone(host string) string {
+	if !strings.HasPrefix(host, "[") {
+		return host
+	}
+	i := strings.LastIndex(host, "]")
+	if i < 0 {
+		return host
+	}
+	j := strings.LastIndex(host[:i], "%")
+	if j < 0 {
+		return host
+	}
+	return host[:j] + host[i:]
+}
+
 // ParseHTTPVersion parses a HTTP version string.
 // "HTTP/1.0" returns (1, 0, true).
 func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
@@ -486,6 +507,13 @@
 // If the provided body is also an io.Closer, the returned
 // Request.Body is set to body and will be closed by the Client
 // methods Do, Post, and PostForm, and Transport.RoundTrip.
+//
+// NewRequest returns a Request suitable for use with Client.Do or
+// Transport.RoundTrip.
+// To create a request for use with testing a Server Handler use either
+// ReadRequest or manually update the Request fields. See the Request
+// type's documentation for the difference between inbound and outbound
+// request fields.
 func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
 	u, err := url.Parse(urlStr)
 	if err != nil {
@@ -585,7 +613,7 @@
 	textprotoReaderPool.Put(r)
 }
 
-// ReadRequest reads and parses a request from b.
+// ReadRequest reads and parses an incoming request from b.
 func ReadRequest(b *bufio.Reader) (req *Request, err error) {
 
 	tp := newTextprotoReader(b)
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 671841f..a518b00 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -178,6 +178,7 @@
 }
 
 func TestRedirect(t *testing.T) {
+	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		switch r.URL.Path {
 		case "/":
@@ -326,13 +327,31 @@
 	}
 }
 
+var newRequestHostTests = []struct {
+	in, out string
+}{
+	{"http://www.example.com/", "www.example.com"},
+	{"http://www.example.com:8080/", "www.example.com:8080"},
+
+	{"http://192.168.0.1/", "192.168.0.1"},
+	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
+
+	{"http://[fe80::1]/", "[fe80::1]"},
+	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
+	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
+	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
+}
+
 func TestNewRequestHost(t *testing.T) {
-	req, err := NewRequest("GET", "http://localhost:1234/", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if req.Host != "localhost:1234" {
-		t.Errorf("Host = %q; want localhost:1234", req.Host)
+	for i, tt := range newRequestHostTests {
+		req, err := NewRequest("GET", tt.in, nil)
+		if err != nil {
+			t.Errorf("#%v: %v", i, err)
+			continue
+		}
+		if req.Host != tt.out {
+			t.Errorf("got %q; want %q", req.Host, tt.out)
+		}
 	}
 }
 
diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go
index 7a6bd58..e9a5f5f 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -455,6 +455,37 @@
 			"ALL-CAPS: x\r\n" +
 			"\r\n",
 	},
+
+	// Request with host header field; IPv6 address with zone identifier
+	{
+		Req: Request{
+			Method: "GET",
+			URL: &url.URL{
+				Host: "[fe80::1%en0]",
+			},
+		},
+
+		WantWrite: "GET / HTTP/1.1\r\n" +
+			"Host: [fe80::1]\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
+			"\r\n",
+	},
+
+	// Request with optional host header field; IPv6 address with zone identifier
+	{
+		Req: Request{
+			Method: "GET",
+			URL: &url.URL{
+				Host: "www.example.com",
+			},
+			Host: "[fe80::1%en0]:8080",
+		},
+
+		WantWrite: "GET / HTTP/1.1\r\n" +
+			"Host: [fe80::1]:8080\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
+			"\r\n",
+	},
 }
 
 func TestRequestWrite(t *testing.T) {
diff --git a/src/net/http/response.go b/src/net/http/response.go
index cfe695c..4afecda 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -189,8 +189,10 @@
 		r.ProtoMajor == major && r.ProtoMinor >= minor
 }
 
-// Writes the response (header, body and trailer) in wire format. This method
-// consults the following fields of the response:
+// Write writes r to w in the HTTP/1.n server response format,
+// including the status line, headers, body, and optional trailer.
+//
+// This method consults the following fields of the response r:
 //
 //  StatusCode
 //  ProtoMajor
@@ -202,7 +204,7 @@
 //  ContentLength
 //  Header, values for non-canonical keys will have unpredictable behavior
 //
-// Body is closed after it is sent.
+// The Response Body is closed after it is sent.
 func (r *Response) Write(w io.Writer) error {
 	// Status line
 	text := r.Status
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index 06e940d..421cf55f 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -405,6 +405,57 @@
 
 		"foobar",
 	},
+
+	// Both keep-alive and close, on the same Connection line. (Issue 8840)
+	{
+		"HTTP/1.1 200 OK\r\n" +
+			"Content-Length: 256\r\n" +
+			"Connection: keep-alive, close\r\n" +
+			"\r\n",
+
+		Response{
+			Status:     "200 OK",
+			StatusCode: 200,
+			Proto:      "HTTP/1.1",
+			ProtoMajor: 1,
+			ProtoMinor: 1,
+			Request:    dummyReq("HEAD"),
+			Header: Header{
+				"Content-Length": {"256"},
+			},
+			TransferEncoding: nil,
+			Close:            true,
+			ContentLength:    256,
+		},
+
+		"",
+	},
+
+	// Both keep-alive and close, on different Connection lines. (Issue 8840)
+	{
+		"HTTP/1.1 200 OK\r\n" +
+			"Content-Length: 256\r\n" +
+			"Connection: keep-alive\r\n" +
+			"Connection: close\r\n" +
+			"\r\n",
+
+		Response{
+			Status:     "200 OK",
+			StatusCode: 200,
+			Proto:      "HTTP/1.1",
+			ProtoMajor: 1,
+			ProtoMinor: 1,
+			Request:    dummyReq("HEAD"),
+			Header: Header{
+				"Content-Length": {"256"},
+			},
+			TransferEncoding: nil,
+			Close:            true,
+			ContentLength:    256,
+		},
+
+		"",
+	},
 }
 
 func TestReadResponse(t *testing.T) {
diff --git a/src/net/http/responsewrite_test.go b/src/net/http/responsewrite_test.go
index 585b13b..5b8d47a 100644
--- a/src/net/http/responsewrite_test.go
+++ b/src/net/http/responsewrite_test.go
@@ -207,6 +207,21 @@
 			},
 			"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
 		},
+
+		// When a response to a POST has Content-Length: -1, make sure we don't
+		// write the Content-Length as -1.
+		{
+			Response{
+				StatusCode:    StatusOK,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       &Request{Method: "POST"},
+				Header:        Header{},
+				ContentLength: -1,
+				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
+			},
+			"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef",
+		},
 	}
 
 	for i := range respWriteTests {
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index c21b57b..6cbe24b 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -146,6 +146,7 @@
 }
 
 func TestConsumingBodyOnNextConn(t *testing.T) {
+	defer afterTest(t)
 	conn := new(testConn)
 	for i := 0; i < 2; i++ {
 		conn.readBuf.Write([]byte(
@@ -1451,19 +1452,23 @@
 	}
 }
 
-func TestNoDate(t *testing.T) {
+func TestServerNoDate(t *testing.T)        { testServerNoHeader(t, "Date") }
+func TestServerNoContentType(t *testing.T) { testServerNoHeader(t, "Content-Type") }
+
+func testServerNoHeader(t *testing.T, header string) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		w.Header()["Date"] = nil
+		w.Header()[header] = nil
+		io.WriteString(w, "<html>foo</html>") // non-empty
 	}))
 	defer ts.Close()
 	res, err := Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
 	}
-	_, present := res.Header["Date"]
-	if present {
-		t.Fatalf("Expected no Date header; got %v", res.Header["Date"])
+	res.Body.Close()
+	if got, ok := res.Header[header]; ok {
+		t.Fatalf("Expected no %s header; got %q", header, got)
 	}
 }
 
@@ -2762,6 +2767,43 @@
 	}
 }
 
+// Issue 9987: shouldn't add automatic Content-Length (or
+// Content-Type) if a Transfer-Encoding was set by the handler.
+func TestNoContentLengthIfTransferEncoding(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Transfer-Encoding", "foo")
+		io.WriteString(w, "<html>")
+	}))
+	defer ts.Close()
+	c, err := net.Dial("tcp", ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
+	}
+	defer c.Close()
+	if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
+		t.Fatal(err)
+	}
+	bs := bufio.NewScanner(c)
+	var got bytes.Buffer
+	for bs.Scan() {
+		if strings.TrimSpace(bs.Text()) == "" {
+			break
+		}
+		got.WriteString(bs.Text())
+		got.WriteByte('\n')
+	}
+	if err := bs.Err(); err != nil {
+		t.Fatal(err)
+	}
+	if strings.Contains(got.String(), "Content-Length") {
+		t.Errorf("Unexpected Content-Length in response headers: %s", got.String())
+	}
+	if strings.Contains(got.String(), "Content-Type") {
+		t.Errorf("Unexpected Content-Type in response headers: %s", got.String())
+	}
+}
+
 func BenchmarkClientServer(b *testing.B) {
 	b.ReportAllocs()
 	b.StopTimer()
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 565c87d..dbd6292 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -61,6 +61,7 @@
 	// WriteHeader (or Write) has no effect unless the modified
 	// headers were declared as trailers by setting the
 	// "Trailer" header before the call to WriteHeader.
+	// To suppress implicit response headers, set their value to nil.
 	Header() Header
 
 	// Write writes the data to the connection as part of an HTTP reply.
@@ -780,6 +781,9 @@
 		foreachHeaderElement(v, cw.res.declareTrailer)
 	}
 
+	te := header.get("Transfer-Encoding")
+	hasTE := te != ""
+
 	// If the handler is done but never sent a Content-Length
 	// response header and this is our first (and last) write, set
 	// it, even to zero. This helps HTTP/1.0 clients keep their
@@ -792,7 +796,9 @@
 	// write non-zero bytes.  If it's actually 0 bytes and the
 	// handler never looked at the Request.Method, we just don't
 	// send a Content-Length header.
-	if w.handlerDone && !trailers && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+	// Further, we don't send an automatic Content-Length if they
+	// set a Transfer-Encoding, because they're generally incompatible.
+	if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
 		w.contentLength = int64(len(p))
 		setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
 	}
@@ -844,7 +850,7 @@
 	if bodyAllowedForStatus(code) {
 		// If no content type, apply sniffing algorithm to body.
 		_, haveType := header["Content-Type"]
-		if !haveType {
+		if !haveType && !hasTE {
 			setHeader.contentType = DetectContentType(p)
 		}
 	} else {
@@ -857,8 +863,6 @@
 		setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now())
 	}
 
-	te := header.get("Transfer-Encoding")
-	hasTE := te != ""
 	if hasCL && hasTE && te != "identity" {
 		// TODO: return an error if WriteHeader gets a return parameter
 		// For now just ignore the Content-Length.
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index c39d6cf..5640344 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -138,6 +138,9 @@
 	if t.ContentLength > 0 {
 		return true
 	}
+	if t.ContentLength < 0 {
+		return false
+	}
 	// Many servers expect a Content-Length for these methods
 	if t.Method == "POST" || t.Method == "PUT" {
 		return true
@@ -505,14 +508,13 @@
 	if major < 1 {
 		return true
 	} else if major == 1 && minor == 0 {
-		if !strings.Contains(strings.ToLower(header.get("Connection")), "keep-alive") {
+		vv := header["Connection"]
+		if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") {
 			return true
 		}
 		return false
 	} else {
-		// TODO: Should split on commas, toss surrounding white space,
-		// and check each field.
-		if strings.ToLower(header.get("Connection")) == "close" {
+		if headerValuesContainsToken(header["Connection"], "close") {
 			if removeCloseHeader {
 				header.Del("Connection")
 			}
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index b18e445..5de5d944 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -279,6 +279,7 @@
 func (t *Transport) CancelRequest(req *Request) {
 	t.reqMu.Lock()
 	cancel := t.reqCanceler[req]
+	delete(t.reqCanceler, req)
 	t.reqMu.Unlock()
 	if cancel != nil {
 		cancel()
@@ -474,6 +475,25 @@
 	}
 }
 
+// replaceReqCanceler replaces an existing cancel function. If there is no cancel function
+// for the request, we don't set the function and return false.
+// Since CancelRequest will clear the canceler, we can use the return value to detect if
+// the request was canceled since the last setReqCancel call.
+func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
+	t.reqMu.Lock()
+	defer t.reqMu.Unlock()
+	_, ok := t.reqCanceler[r]
+	if !ok {
+		return false
+	}
+	if fn != nil {
+		t.reqCanceler[r] = fn
+	} else {
+		delete(t.reqCanceler, r)
+	}
+	return true
+}
+
 func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
 	if t.Dial != nil {
 		return t.Dial(network, addr)
@@ -490,6 +510,10 @@
 // is ready to write requests to.
 func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
 	if pc := t.getIdleConn(cm); pc != nil {
+		// set request canceler to some non-nil function so we
+		// can detect whether it was cleared between now and when
+		// we enter roundTrip
+		t.setReqCanceler(req, func() {})
 		return pc, nil
 	}
 
@@ -805,6 +829,7 @@
 	numExpectedResponses int
 	closed               bool // whether conn has been closed
 	broken               bool // an error has happened on this connection; marked broken so it's not reused.
+	canceled             bool // whether this conn was broken due a CancelRequest
 	// mutateHeaderFunc is an optional func to modify extra
 	// headers on each outbound request before it's written. (the
 	// original Request given to RoundTrip is not modified)
@@ -819,8 +844,18 @@
 	return b
 }
 
+// isCanceled reports whether this connection was closed due to CancelRequest.
+func (pc *persistConn) isCanceled() bool {
+	pc.lk.Lock()
+	defer pc.lk.Unlock()
+	return pc.canceled
+}
+
 func (pc *persistConn) cancelRequest() {
-	pc.conn.Close()
+	pc.lk.Lock()
+	defer pc.lk.Unlock()
+	pc.canceled = true
+	pc.closeLocked()
 }
 
 var remoteSideClosedFunc func(error) bool // or nil to use default
@@ -836,8 +871,18 @@
 }
 
 func (pc *persistConn) readLoop() {
-	alive := true
+	// eofc is used to block http.Handler goroutines reading from Response.Body
+	// at EOF until this goroutines has (potentially) added the connection
+	// back to the idle pool.
+	eofc := make(chan struct{})
+	defer close(eofc) // unblock reader on errors
 
+	// Read this once, before loop starts. (to avoid races in tests)
+	testHookMu.Lock()
+	testHookReadLoopBeforeNextRead := testHookReadLoopBeforeNextRead
+	testHookMu.Unlock()
+
+	alive := true
 	for alive {
 		pb, err := pc.br.Peek(1)
 
@@ -895,49 +940,70 @@
 			alive = false
 		}
 
-		var waitForBodyRead chan bool
+		var waitForBodyRead chan bool // channel is nil when there's no body
 		if hasBody {
 			waitForBodyRead = make(chan bool, 2)
 			resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
-				// Sending false here sets alive to
-				// false and closes the connection
-				// below.
 				waitForBodyRead <- false
 				return nil
 			}
-			resp.Body.(*bodyEOFSignal).fn = func(err error) {
-				waitForBodyRead <- alive &&
-					err == nil &&
-					!pc.sawEOF &&
-					pc.wroteRequest() &&
-					pc.t.putIdleConn(pc)
+			resp.Body.(*bodyEOFSignal).fn = func(err error) error {
+				isEOF := err == io.EOF
+				waitForBodyRead <- isEOF
+				if isEOF {
+					<-eofc // see comment at top
+				} else if err != nil && pc.isCanceled() {
+					return errRequestCanceled
+				}
+				return err
 			}
 		}
 
-		if alive && !hasBody {
-			alive = !pc.sawEOF &&
+		pc.lk.Lock()
+		pc.numExpectedResponses--
+		pc.lk.Unlock()
+
+		// The connection might be going away when we put the
+		// idleConn below. When that happens, we close the response channel to signal
+		// to roundTrip that the connection is gone. roundTrip waits for
+		// both closing and a response in a select, so it might choose
+		// the close channel, rather than the response.
+		// We send the response first so that roundTrip can check
+		// if there is a pending one with a non-blocking select
+		// on the response channel before erroring out.
+		rc.ch <- responseAndError{resp, err}
+
+		if hasBody {
+			// To avoid a race, wait for the just-returned
+			// response body to be fully consumed before peek on
+			// the underlying bufio reader.
+			select {
+			case bodyEOF := <-waitForBodyRead:
+				pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool
+				alive = alive &&
+					bodyEOF &&
+					!pc.sawEOF &&
+					pc.wroteRequest() &&
+					pc.t.putIdleConn(pc)
+				if bodyEOF {
+					eofc <- struct{}{}
+				}
+			case <-pc.closech:
+				alive = false
+			}
+		} else {
+			pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool
+			alive = alive &&
+				!pc.sawEOF &&
 				pc.wroteRequest() &&
 				pc.t.putIdleConn(pc)
 		}
 
-		rc.ch <- responseAndError{resp, err}
-
-		// Wait for the just-returned response body to be fully consumed
-		// before we race and peek on the underlying bufio reader.
-		if waitForBodyRead != nil {
-			select {
-			case alive = <-waitForBodyRead:
-			case <-pc.closech:
-				alive = false
-			}
-		}
-
-		pc.t.setReqCanceler(rc.req, nil)
-
-		if !alive {
-			pc.close()
+		if hook := testHookReadLoopBeforeNextRead; hook != nil {
+			hook()
 		}
 	}
+	pc.close()
 }
 
 func (pc *persistConn) writeLoop() {
@@ -1027,9 +1093,24 @@
 
 var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
 var errClosed error = &httpError{err: "net/http: transport closed before response was received"}
+var errRequestCanceled = errors.New("net/http: request canceled")
+
+// nil except for tests
+var (
+	testHookPersistConnClosedGotRes func()
+	testHookEnterRoundTrip          func()
+	testHookMu                      sync.Locker = fakeLocker{} // guards following
+	testHookReadLoopBeforeNextRead  func()
+)
 
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
-	pc.t.setReqCanceler(req.Request, pc.cancelRequest)
+	if hook := testHookEnterRoundTrip; hook != nil {
+		hook()
+	}
+	if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) {
+		pc.t.putIdleConn(pc)
+		return nil, errRequestCanceled
+	}
 	pc.lk.Lock()
 	pc.numExpectedResponses++
 	headerFn := pc.mutateHeaderFunc
@@ -1078,8 +1159,6 @@
 	pc.reqch <- requestAndChan{req.Request, resc, requestedGzip}
 
 	var re responseAndError
-	var pconnDeadCh = pc.closech
-	var failTicker <-chan time.Time
 	var respHeaderTimer <-chan time.Time
 WaitResponse:
 	for {
@@ -1095,23 +1174,25 @@
 				defer timer.Stop() // prevent leaks
 				respHeaderTimer = timer.C
 			}
-		case <-pconnDeadCh:
+		case <-pc.closech:
 			// The persist connection is dead. This shouldn't
 			// usually happen (only with Connection: close responses
 			// with no response bodies), but if it does happen it
 			// means either a) the remote server hung up on us
 			// prematurely, or b) the readLoop sent us a response &
 			// closed its closech at roughly the same time, and we
-			// selected this case first, in which case a response
-			// might still be coming soon.
-			//
-			// We can't avoid the select race in b) by using a unbuffered
-			// resc channel instead, because then goroutines can
-			// leak if we exit due to other errors.
-			pconnDeadCh = nil                               // avoid spinning
-			failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
-		case <-failTicker:
-			re = responseAndError{err: errClosed}
+			// selected this case first. If we got a response, readLoop makes sure
+			// to send it before it puts the conn and closes the channel.
+			// That way, we can fetch the response, if there is one,
+			// with a non-blocking receive.
+			select {
+			case re = <-resc:
+				if fn := testHookPersistConnClosedGotRes; fn != nil {
+					fn()
+				}
+			default:
+				re = responseAndError{err: errClosed}
+			}
 			break WaitResponse
 		case <-respHeaderTimer:
 			pc.close()
@@ -1122,10 +1203,6 @@
 		}
 	}
 
-	pc.lk.Lock()
-	pc.numExpectedResponses--
-	pc.lk.Unlock()
-
 	if re.err != nil {
 		pc.t.setReqCanceler(req.Request, nil)
 	}
@@ -1173,16 +1250,18 @@
 
 // bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
 // once, right before its final (error-producing) Read or Close call
-// returns. If earlyCloseFn is non-nil and Close is called before
-// io.EOF is seen, earlyCloseFn is called instead of fn, and its
-// return value is the return value from Close.
+// returns. fn should return the new error to return from Read or Close.
+//
+// If earlyCloseFn is non-nil and Close is called before io.EOF is
+// seen, earlyCloseFn is called instead of fn, and its return value is
+// the return value from Close.
 type bodyEOFSignal struct {
 	body         io.ReadCloser
-	mu           sync.Mutex   // guards following 4 fields
-	closed       bool         // whether Close has been called
-	rerr         error        // sticky Read error
-	fn           func(error)  // error will be nil on Read io.EOF
-	earlyCloseFn func() error // optional alt Close func used if io.EOF not seen
+	mu           sync.Mutex        // guards following 4 fields
+	closed       bool              // whether Close has been called
+	rerr         error             // sticky Read error
+	fn           func(error) error // err will be nil on Read io.EOF
+	earlyCloseFn func() error      // optional alt Close func used if io.EOF not seen
 }
 
 func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
@@ -1203,7 +1282,7 @@
 		if es.rerr == nil {
 			es.rerr = err
 		}
-		es.condfn(err)
+		err = es.condfn(err)
 	}
 	return
 }
@@ -1219,20 +1298,17 @@
 		return es.earlyCloseFn()
 	}
 	err := es.body.Close()
-	es.condfn(err)
-	return err
+	return es.condfn(err)
 }
 
 // caller must hold es.mu.
-func (es *bodyEOFSignal) condfn(err error) {
+func (es *bodyEOFSignal) condfn(err error) error {
 	if es.fn == nil {
-		return
+		return err
 	}
-	if err == io.EOF {
-		err = nil
-	}
-	es.fn(err)
+	err = es.fn(err)
 	es.fn = nil
+	return err
 }
 
 // gzipReader wraps a response body so it can lazily
@@ -1279,3 +1355,11 @@
 	}
 	return
 }
+
+// fakeLocker is a sync.Locker which does nothing. It's used to guard
+// test-only fields when not under test, to avoid runtime atomic
+// overhead.
+type fakeLocker struct{}
+
+func (fakeLocker) Lock()   {}
+func (fakeLocker) Unlock() {}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 504a6a7..ace5889 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -505,12 +505,17 @@
 
 	tr := &Transport{DisableKeepAlives: false}
 	c := &Client{Transport: tr}
+	defer tr.CloseIdleConnections()
 
 	// Do a bunch of traffic from different goroutines. Send to activityc
 	// after each request completes, regardless of whether it failed.
+	// If these are too high, OS X exhausts its emphemeral ports
+	// and hangs waiting for them to transition TCP states. That's
+	// not what we want to test.  TODO(bradfitz): use an io.Pipe
+	// dialer for this test instead?
 	const (
-		numClients    = 50
-		reqsPerClient = 250
+		numClients    = 20
+		reqsPerClient = 25
 	)
 	activityc := make(chan bool)
 	for i := 0; i < numClients; i++ {
@@ -1371,8 +1376,8 @@
 	body, err := ioutil.ReadAll(res.Body)
 	d := time.Since(t0)
 
-	if err == nil {
-		t.Error("expected an error reading the body")
+	if err != ExportErrRequestCanceled {
+		t.Errorf("Body.Read error = %v; want errRequestCanceled", err)
 	}
 	if string(body) != "Hello" {
 		t.Errorf("Body = %q; want Hello", body)
@@ -1382,7 +1387,7 @@
 	}
 	// Verify no outstanding requests after readLoop/writeLoop
 	// goroutines shut down.
-	for tries := 3; tries > 0; tries-- {
+	for tries := 5; tries > 0; tries-- {
 		n := tr.NumPendingRequestsForTesting()
 		if n == 0 {
 			break
@@ -1431,6 +1436,7 @@
 
 	eventLog.Printf("canceling")
 	tr.CancelRequest(req)
+	tr.CancelRequest(req) // used to panic on second call
 
 	select {
 	case <-gotres:
@@ -1821,6 +1827,11 @@
 	}))
 	defer ts.Close()
 
+	const nReqs = 5
+	didRead := make(chan bool, nReqs)
+	SetReadLoopBeforeNextReadHook(func() { didRead <- true })
+	defer SetReadLoopBeforeNextReadHook(nil)
+
 	tr := &Transport{
 		Dial: func(netw, addr string) (net.Conn, error) {
 			return net.Dial(netw, ts.Listener.Addr().String())
@@ -1833,12 +1844,28 @@
 	// First, without keep-alives.
 	for _, disableKeep := range []bool{true, false} {
 		tr.DisableKeepAlives = disableKeep
-		for i := 0; i < 5; i++ {
+		for i := 0; i < nReqs; i++ {
 			_, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i))
 			if err != nil {
 				t.Fatal(err)
 			}
+			// Note: no res.Body.Close is needed here, since the
+			// response Content-Length is zero. Perhaps the test
+			// should be more explicit and use a HEAD, but tests
+			// elsewhere guarantee that zero byte responses generate
+			// a "Content-Length: 0" instead of chunking.
 		}
+
+		// At this point, each of the 5 Transport.readLoop goroutines
+		// are scheduling noting that there are no response bodies (see
+		// earlier comment), and are then calling putIdleConn, which
+		// decrements this count. Usually that happens quickly, which is
+		// why this test has seemed to work for ages. But it's still
+		// racey: we have wait for them to finish first. See Issue 10427
+		for i := 0; i < nReqs; i++ {
+			<-didRead
+		}
+
 		if got := tr.IdleConnChMapSizeForTesting(); got != 0 {
 			t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got)
 		}
@@ -2086,6 +2113,38 @@
 	}
 }
 
+// Tests that we don't leak Transport persistConn.readLoop goroutines
+// when a server hangs up immediately after saying it would keep-alive.
+func TestTransportIssue10457(t *testing.T) {
+	defer afterTest(t) // used to fail in goroutine leak check
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		// Send a response with no body, keep-alive
+		// (implicit), and then lie and immediately close the
+		// connection. This forces the Transport's readLoop to
+		// immediately Peek an io.EOF and get to the point
+		// that used to hang.
+		conn, _, _ := w.(Hijacker).Hijack()
+		conn.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n")) // keep-alive
+		conn.Close()
+	}))
+	defer ts.Close()
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	cl := &Client{Transport: tr}
+	res, err := cl.Get(ts.URL)
+	if err != nil {
+		t.Fatalf("Get: %v", err)
+	}
+	defer res.Body.Close()
+
+	// Just a sanity check that we at least get the response. The real
+	// test here is that the "defer afterTest" above doesn't find any
+	// leaked goroutines.
+	if got, want := res.Header.Get("Foo"), "Bar"; got != want {
+		t.Errorf("Foo header = %q; want %q", got, want)
+	}
+}
+
 type errorReader struct {
 	err error
 }
@@ -2275,6 +2334,119 @@
 	res.Body.Close()
 }
 
+// Previously, we used to handle a logical race within RoundTrip by waiting for 100ms
+// in the case of an error. Changing the order of the channel operations got rid of this
+// race.
+//
+// In order to test that the channel op reordering works, we install a hook into the
+// roundTrip function which gets called if we saw the connection go away and
+// we subsequently received a response.
+func TestTransportResponseCloseRace(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+	}))
+	defer ts.Close()
+	sawRace := false
+	SetInstallConnClosedHook(func() {
+		sawRace = true
+	})
+	defer SetInstallConnClosedHook(nil)
+	tr := &Transport{
+		DisableKeepAlives: true,
+	}
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// selects are not deterministic, so do this a bunch
+	// and see if we handle the logical race at least once.
+	for i := 0; i < 10000; i++ {
+		resp, err := tr.RoundTrip(req)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+			continue
+		}
+		resp.Body.Close()
+		if sawRace {
+			break
+		}
+	}
+	if !sawRace {
+		t.Errorf("didn't see response/connection going away race")
+	}
+}
+
+// Test for issue 10474
+func TestTransportResponseCancelRace(t *testing.T) {
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		// important that this response has a body.
+		var b [1024]byte
+		w.Write(b[:])
+	}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res, err := tr.RoundTrip(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// If we do an early close, Transport just throws the connection away and
+	// doesn't reuse it. In order to trigger the bug, it has to reuse the connection
+	// so read the body
+	if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+		t.Fatal(err)
+	}
+
+	req2, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tr.CancelRequest(req)
+	res, err = tr.RoundTrip(req2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+}
+
+func TestTransportDialCancelRace(t *testing.T) {
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	SetEnterRoundTripHook(func() {
+		tr.CancelRequest(req)
+	})
+	defer SetEnterRoundTripHook(nil)
+	res, err := tr.RoundTrip(req)
+	if err != ExportErrRequestCanceled {
+		t.Errorf("expected canceled request error; got %v", err)
+		if err == nil {
+			res.Body.Close()
+		}
+	}
+}
+
 func wantBody(res *http.Response, err error, want string) error {
 	if err != nil {
 		return err
diff --git a/src/net/interface.go b/src/net/interface.go
index 2e9f1eb..9c7b5da 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -62,41 +62,61 @@
 // Addrs returns interface addresses for a specific interface.
 func (ifi *Interface) Addrs() ([]Addr, error) {
 	if ifi == nil {
-		return nil, errInvalidInterface
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
 	}
-	return interfaceAddrTable(ifi)
+	ifat, err := interfaceAddrTable(ifi)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifat, err
 }
 
 // MulticastAddrs returns multicast, joined group addresses for
 // a specific interface.
 func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
 	if ifi == nil {
-		return nil, errInvalidInterface
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
 	}
-	return interfaceMulticastAddrTable(ifi)
+	ifat, err := interfaceMulticastAddrTable(ifi)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifat, err
 }
 
 // Interfaces returns a list of the system's network interfaces.
 func Interfaces() ([]Interface, error) {
-	return interfaceTable(0)
+	ift, err := interfaceTable(0)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ift, err
 }
 
 // InterfaceAddrs returns a list of the system's network interface
 // addresses.
 func InterfaceAddrs() ([]Addr, error) {
-	return interfaceAddrTable(nil)
+	ifat, err := interfaceAddrTable(nil)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifat, err
 }
 
 // InterfaceByIndex returns the interface specified by index.
 func InterfaceByIndex(index int) (*Interface, error) {
 	if index <= 0 {
-		return nil, errInvalidInterfaceIndex
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
 	}
 	ift, err := interfaceTable(index)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
-	return interfaceByIndex(ift, index)
+	ifi, err := interfaceByIndex(ift, index)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifi, err
 }
 
 func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
@@ -111,16 +131,16 @@
 // InterfaceByName returns the interface specified by name.
 func InterfaceByName(name string) (*Interface, error) {
 	if name == "" {
-		return nil, errInvalidInterfaceName
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
 	}
 	ift, err := interfaceTable(0)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
 	for _, ifi := range ift {
 		if name == ifi.Name {
 			return &ifi, nil
 		}
 	}
-	return nil, errNoSuchInterface
+	return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
 }
diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go
index 2f66e4f..208f37f 100644
--- a/src/net/interface_bsd.go
+++ b/src/net/interface_bsd.go
@@ -18,11 +18,11 @@
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	return parseInterfaceTable(ifindex, msgs)
 }
@@ -51,7 +51,7 @@
 func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
 	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
 	sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
@@ -104,11 +104,11 @@
 	}
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	var ift []Interface
 	if index == 0 {
@@ -145,7 +145,7 @@
 func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
 	ifa := &IPNet{}
 	switch sa := sas[syscall.RTAX_NETMASK].(type) {
diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go
index 475b861..b7a3338 100644
--- a/src/net/interface_darwin.go
+++ b/src/net/interface_darwin.go
@@ -14,11 +14,11 @@
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	var ifmat []Addr
 	for _, m := range msgs {
@@ -41,7 +41,7 @@
 func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
 	switch sa := sas[syscall.RTAX_IFA].(type) {
 	case *syscall.SockaddrInet4:
diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go
index 13bf438..c42d90b 100644
--- a/src/net/interface_freebsd.go
+++ b/src/net/interface_freebsd.go
@@ -14,11 +14,11 @@
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	var ifmat []Addr
 	for _, m := range msgs {
@@ -41,7 +41,7 @@
 func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
 	switch sa := sas[syscall.RTAX_IFA].(type) {
 	case *syscall.SockaddrInet4:
diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go
index 1115d0f..6551a35 100644
--- a/src/net/interface_linux.go
+++ b/src/net/interface_linux.go
@@ -16,11 +16,11 @@
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink rib", err)
+		return nil, os.NewSyscallError("netlinkrib", err)
 	}
 	msgs, err := syscall.ParseNetlinkMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink message", err)
+		return nil, os.NewSyscallError("parsenetlinkmessage", err)
 	}
 	var ift []Interface
 loop:
@@ -33,7 +33,7 @@
 			if ifindex == 0 || ifindex == int(ifim.Index) {
 				attrs, err := syscall.ParseNetlinkRouteAttr(&m)
 				if err != nil {
-					return nil, os.NewSyscallError("netlink routeattr", err)
+					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
 				}
 				ift = append(ift, *newLink(ifim, attrs))
 				if ifindex == int(ifim.Index) {
@@ -120,11 +120,11 @@
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink rib", err)
+		return nil, os.NewSyscallError("netlinkrib", err)
 	}
 	msgs, err := syscall.ParseNetlinkMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink message", err)
+		return nil, os.NewSyscallError("parsenetlinkmessage", err)
 	}
 	var ift []Interface
 	if ifi == nil {
@@ -160,7 +160,7 @@
 				}
 				attrs, err := syscall.ParseNetlinkRouteAttr(&m)
 				if err != nil {
-					return nil, os.NewSyscallError("netlink routeattr", err)
+					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
 				}
 				ifa := newAddr(ifi, ifam, attrs)
 				if ifa != nil {
@@ -238,8 +238,8 @@
 					b[i/2], _ = xtoi2(f[0][i:i+2], 0)
 				}
 				i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
-				ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
-				ifmat = append(ifmat, ifma.toAddr())
+				ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
+				ifmat = append(ifmat, ifma)
 			}
 		}
 	}
@@ -263,8 +263,8 @@
 			for i := 0; i+1 < len(f[2]); i += 2 {
 				b[i/2], _ = xtoi2(f[2][i:i+2], 0)
 			}
-			ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
-			ifmat = append(ifmat, ifma.toAddr())
+			ifma := &IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+			ifmat = append(ifmat, ifma)
 		}
 	}
 	return ifmat
diff --git a/src/net/interface_linux_test.go b/src/net/interface_linux_test.go
index d8800bd..059bde1 100644
--- a/src/net/interface_linux_test.go
+++ b/src/net/interface_linux_test.go
@@ -78,7 +78,7 @@
 func TestParseProcNet(t *testing.T) {
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("parseProcNetIGMP or parseProtNetIGMP6 panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
@@ -88,7 +88,7 @@
 		ifmat4 = append(ifmat4, ifmat...)
 	}
 	if len(ifmat4) != numOfTestIPv4MCAddrs {
-		t.Fatalf("parseProcNetIGMP returns %v addresses, expected %v", len(ifmat4), numOfTestIPv4MCAddrs)
+		t.Fatalf("got %d; want %d", len(ifmat4), numOfTestIPv4MCAddrs)
 	}
 
 	var ifmat6 []Addr
@@ -97,6 +97,6 @@
 		ifmat6 = append(ifmat6, ifmat...)
 	}
 	if len(ifmat6) != numOfTestIPv6MCAddrs {
-		t.Fatalf("parseProcNetIGMP6 returns %v addresses, expected %v", len(ifmat6), numOfTestIPv6MCAddrs)
+		t.Fatalf("got %d; want %d", len(ifmat6), numOfTestIPv6MCAddrs)
 	}
 }
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 666f11a..0e5c2e3 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -229,8 +229,7 @@
 }
 
 func BenchmarkInterfaces(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		if _, err := Interfaces(); err != nil {
@@ -240,8 +239,7 @@
 }
 
 func BenchmarkInterfaceByIndex(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -255,8 +253,7 @@
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -270,8 +267,7 @@
 }
 
 func BenchmarkInterfaceAddrs(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceAddrs(); err != nil {
@@ -281,8 +277,7 @@
 }
 
 func BenchmarkInterfacesAndAddrs(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -296,8 +291,7 @@
 }
 
 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	ifi := loopbackInterface()
 	if ifi == nil {
diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go
index 01f609f..84bf06c 100644
--- a/src/net/interface_unix_test.go
+++ b/src/net/interface_unix_test.go
@@ -42,14 +42,13 @@
 
 func TestPointToPointInterface(t *testing.T) {
 	if testing.Short() {
-		t.Skip("skipping test in short mode")
+		t.Skip("avoid external network")
 	}
-	switch {
-	case runtime.GOOS == "darwin":
-		t.Skipf("skipping read test on %q", runtime.GOOS)
+	if runtime.GOOS == "darwin" {
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	if os.Getuid() != 0 {
-		t.Skip("skipping test; must be root")
+		t.Skip("must be root")
 	}
 
 	local, remote := "169.254.0.1", "169.254.0.254"
@@ -60,21 +59,21 @@
 			t.Skipf("test requries external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
-			t.Fatalf("testInterface.setup failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift, err := Interfaces()
 		if err != nil {
 			ti.teardown()
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		for _, ifi := range ift {
 			if ti.name == ifi.Name {
 				ifat, err := ifi.Addrs()
 				if err != nil {
 					ti.teardown()
-					t.Fatalf("Interface.Addrs failed: %v", err)
+					t.Fatal(err)
 				}
 				for _, ifa := range ifat {
 					if ip.Equal(ifa.(*IPNet).IP) {
@@ -85,7 +84,7 @@
 			}
 		}
 		if err := ti.teardown(); err != nil {
-			t.Fatalf("testInterface.teardown failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
@@ -94,30 +93,30 @@
 
 func TestInterfaceArrivalAndDeparture(t *testing.T) {
 	if testing.Short() {
-		t.Skip("skipping test in short mode")
+		t.Skip("avoid external network")
 	}
 	if os.Getuid() != 0 {
-		t.Skip("skipping test; must be root")
+		t.Skip("must be root")
 	}
 
 	for i := 0; i < 3; i++ {
 		ift1, err := Interfaces()
 		if err != nil {
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		ti := &testInterface{}
 		if err := ti.setBroadcast(5682 + i); err != nil {
 			t.Skipf("test requires external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
-			t.Fatalf("testInterface.setup failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift2, err := Interfaces()
 		if err != nil {
 			ti.teardown()
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		if len(ift2) <= len(ift1) {
 			for _, ifi := range ift1 {
@@ -130,13 +129,13 @@
 			t.Fatalf("got %v; want gt %v", len(ift2), len(ift1))
 		}
 		if err := ti.teardown(); err != nil {
-			t.Fatalf("testInterface.teardown failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift3, err := Interfaces()
 		if err != nil {
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		if len(ift3) >= len(ift2) {
 			for _, ifi := range ift2 {
diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go
index 438dc87..e25c1ed 100644
--- a/src/net/interface_windows.go
+++ b/src/net/interface_windows.go
@@ -27,7 +27,7 @@
 			break
 		}
 		if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
-			return nil, os.NewSyscallError("GetAdaptersAddresses", err)
+			return nil, os.NewSyscallError("getadaptersaddresses", err)
 		}
 	}
 	return &addrs[0], nil
@@ -36,16 +36,16 @@
 func getInterfaceInfos() ([]syscall.InterfaceInfo, error) {
 	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
 	if err != nil {
-		return nil, os.NewSyscallError("Socket", err)
+		return nil, err
 	}
-	defer syscall.Closesocket(s)
+	defer closeFunc(s)
 
 	iia := [20]syscall.InterfaceInfo{}
 	ret := uint32(0)
 	size := uint32(unsafe.Sizeof(iia))
 	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
 	if err != nil {
-		return nil, os.NewSyscallError("WSAIoctl", err)
+		return nil, os.NewSyscallError("wsaioctl", err)
 	}
 	iilen := ret / uint32(unsafe.Sizeof(iia[0]))
 	return iia[:iilen-1], nil
@@ -217,11 +217,11 @@
 					case *syscall.SockaddrInet4:
 						ifa := &IPAddr{IP: make(IP, IPv4len)}
 						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa.toAddr())
+						ifat = append(ifat, ifa)
 					case *syscall.SockaddrInet6:
 						ifa := &IPAddr{IP: make(IP, IPv6len)}
 						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa.toAddr())
+						ifat = append(ifat, ifa)
 					}
 				}
 			}
diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go
index 5398191..5e558a2 100644
--- a/src/net/internal/socktest/switch.go
+++ b/src/net/internal/socktest/switch.go
@@ -5,7 +5,10 @@
 // Package socktest provides utilities for socket testing.
 package socktest
 
-import "sync"
+import (
+	"fmt"
+	"sync"
+)
 
 func switchInit(sw *Switch) {
 	sw.fltab = make(map[FilterType]Filter)
@@ -70,7 +73,11 @@
 type Status struct {
 	Cookie    Cookie
 	Err       error // error status of socket system call
-	SocketErr int   // error status of socket by SO_ERROR
+	SocketErr error // error status of socket by SO_ERROR
+}
+
+func (so Status) String() string {
+	return fmt.Sprintf("(%s, %s, %s): syscallerr=%v, socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
 }
 
 // A Stat represents a per-cookie socket statistics.
@@ -80,9 +87,20 @@
 	Protocol int // protocol number
 
 	Opened    uint64 // number of sockets opened
-	Accepted  uint64 // number of sockets accepted
 	Connected uint64 // number of sockets connected
+	Listened  uint64 // number of sockets listened
+	Accepted  uint64 // number of sockets accepted
 	Closed    uint64 // number of sockets closed
+
+	OpenFailed    uint64 // number of sockets open failed
+	ConnectFailed uint64 // number of sockets connect failed
+	ListenFailed  uint64 // number of sockets listen failed
+	AcceptFailed  uint64 // number of sockets accept failed
+	CloseFailed   uint64 // number of sockets close failed
+}
+
+func (st Stat) String() string {
+	return fmt.Sprintf("(%s, %s, %s): opened=%d, connected=%d, listened=%d, accepted=%d, closed=%d, openfailed=%d, connectfailed=%d, listenfailed=%d, acceptfailed=%d, closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
 }
 
 type stats map[Cookie]*Stat
@@ -101,8 +119,9 @@
 
 const (
 	FilterSocket        FilterType = iota // for Socket
-	FilterAccept                          // for Accept or Accept4
 	FilterConnect                         // for Connect or ConnectEx
+	FilterListen                          // for Listen
+	FilterAccept                          // for Accept or Accept4
 	FilterGetsockoptInt                   // for GetsockoptInt
 	FilterClose                           // for Close or Closesocket
 )
diff --git a/src/net/internal/socktest/switch_posix.go b/src/net/internal/socktest/switch_posix.go
new file mode 100644
index 0000000..863edef
--- /dev/null
+++ b/src/net/internal/socktest/switch_posix.go
@@ -0,0 +1,58 @@
+// 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 !plan9
+
+package socktest
+
+import (
+	"fmt"
+	"syscall"
+)
+
+func familyString(family int) string {
+	switch family {
+	case syscall.AF_INET:
+		return "inet4"
+	case syscall.AF_INET6:
+		return "inet6"
+	case syscall.AF_UNIX:
+		return "local"
+	default:
+		return fmt.Sprintf("%d", family)
+	}
+}
+
+func typeString(sotype int) string {
+	var s string
+	switch sotype & 0xff {
+	case syscall.SOCK_STREAM:
+		s = "stream"
+	case syscall.SOCK_DGRAM:
+		s = "datagram"
+	case syscall.SOCK_RAW:
+		s = "raw"
+	case syscall.SOCK_SEQPACKET:
+		s = "seqpacket"
+	default:
+		s = fmt.Sprintf("%d", sotype&0xff)
+	}
+	if flags := uint(sotype) & ^uint(0xff); flags != 0 {
+		s += fmt.Sprintf("|%#x", flags)
+	}
+	return s
+}
+
+func protocolString(proto int) string {
+	switch proto {
+	case 0:
+		return "default"
+	case syscall.IPPROTO_TCP:
+		return "tcp"
+	case syscall.IPPROTO_UDP:
+		return "udp"
+	default:
+		return fmt.Sprintf("%d", proto)
+	}
+}
diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go
index be97628..28ce72c 100644
--- a/src/net/internal/socktest/switch_stub.go
+++ b/src/net/internal/socktest/switch_stub.go
@@ -8,3 +8,9 @@
 
 // Sockets maps a socket descriptor to the status of socket.
 type Sockets map[int]Status
+
+func familyString(family int) string { return "<nil>" }
+
+func typeString(sotype int) string { return "<nil>" }
+
+func protocolString(proto int) string { return "<nil>" }
diff --git a/src/net/internal/socktest/sys_cloexec.go b/src/net/internal/socktest/sys_cloexec.go
index 61cb6ae..340ff07 100644
--- a/src/net/internal/socktest/sys_cloexec.go
+++ b/src/net/internal/socktest/sys_cloexec.go
@@ -30,12 +30,13 @@
 		return -1, nil, err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).AcceptFailed++
 		return -1, nil, so.Err
 	}
-	sw.smu.Lock()
 	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
 	sw.stats.getLocked(nso.Cookie).Accepted++
-	sw.smu.Unlock()
 	return ns, sa, nil
 }
diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go
index b128c01..4089f8c 100644
--- a/src/net/internal/socktest/sys_unix.go
+++ b/src/net/internal/socktest/sys_unix.go
@@ -27,13 +27,14 @@
 		return -1, err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).OpenFailed++
 		return -1, so.Err
 	}
-	sw.smu.Lock()
 	nso := sw.addLocked(s, family, sotype, proto)
 	sw.stats.getLocked(nso.Cookie).Opened++
-	sw.smu.Unlock()
 	return s, nil
 }
 
@@ -56,13 +57,14 @@
 		return err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).CloseFailed++
 		return so.Err
 	}
-	sw.smu.Lock()
 	delete(sw.sotab, s)
 	sw.stats.getLocked(so.Cookie).Closed++
-	sw.smu.Unlock()
 	return nil
 }
 
@@ -85,12 +87,42 @@
 		return err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ConnectFailed++
 		return so.Err
 	}
-	sw.smu.Lock()
 	sw.stats.getLocked(so.Cookie).Connected++
-	sw.smu.Unlock()
+	return nil
+}
+
+// Listen wraps syscall.Listen.
+func (sw *Switch) Listen(s, backlog int) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Listen(s, backlog)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterListen]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Listen(s, backlog)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ListenFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Listened++
 	return nil
 }
 
@@ -116,13 +148,14 @@
 		return -1, nil, err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).AcceptFailed++
 		return -1, nil, so.Err
 	}
-	sw.smu.Lock()
 	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
 	sw.stats.getLocked(nso.Cookie).Accepted++
-	sw.smu.Unlock()
 	return ns, sa, nil
 }
 
@@ -140,7 +173,8 @@
 	if err != nil {
 		return -1, err
 	}
-	so.SocketErr, so.Err = syscall.GetsockoptInt(s, level, opt)
+	soerr, so.Err = syscall.GetsockoptInt(s, level, opt)
+	so.SocketErr = syscall.Errno(soerr)
 	if err = af.apply(so); err != nil {
 		return -1, err
 	}
@@ -148,10 +182,10 @@
 	if so.Err != nil {
 		return -1, so.Err
 	}
-	if opt == syscall.SO_ERROR && (so.SocketErr == 0 || syscall.Errno(so.SocketErr) == syscall.EISCONN) {
+	if opt == syscall.SO_ERROR && (so.SocketErr == syscall.Errno(0) || so.SocketErr == syscall.EISCONN) {
 		sw.smu.Lock()
 		sw.stats.getLocked(so.Cookie).Connected++
 		sw.smu.Unlock()
 	}
-	return so.SocketErr, nil
+	return soerr, nil
 }
diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go
index 30bac45..907e01b 100644
--- a/src/net/internal/socktest/sys_windows.go
+++ b/src/net/internal/socktest/sys_windows.go
@@ -25,13 +25,14 @@
 		return syscall.InvalidHandle, err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).OpenFailed++
 		return syscall.InvalidHandle, so.Err
 	}
-	sw.smu.Lock()
 	nso := sw.addLocked(s, family, sotype, proto)
 	sw.stats.getLocked(nso.Cookie).Opened++
-	sw.smu.Unlock()
 	return s, nil
 }
 
@@ -54,13 +55,14 @@
 		return err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).CloseFailed++
 		return so.Err
 	}
-	sw.smu.Lock()
 	delete(sw.sotab, s)
 	sw.stats.getLocked(so.Cookie).Closed++
-	sw.smu.Unlock()
 	return nil
 }
 
@@ -83,12 +85,13 @@
 		return err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ConnectFailed++
 		return so.Err
 	}
-	sw.smu.Lock()
 	sw.stats.getLocked(so.Cookie).Connected++
-	sw.smu.Unlock()
 	return nil
 }
 
@@ -111,11 +114,41 @@
 		return err
 	}
 
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
 	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ConnectFailed++
 		return so.Err
 	}
-	sw.smu.Lock()
 	sw.stats.getLocked(so.Cookie).Connected++
-	sw.smu.Unlock()
+	return nil
+}
+
+// Listen wraps syscall.Listen.
+func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Listen(s, backlog)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterListen]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Listen(s, backlog)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ListenFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Listened++
 	return nil
 }
diff --git a/src/net/ip.go b/src/net/ip.go
index a554165..a7f4564 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -12,8 +12,6 @@
 
 package net
 
-import "errors"
-
 // IP address lengths (bytes).
 const (
 	IPv4len = 4
@@ -331,7 +329,7 @@
 		return []byte(""), nil
 	}
 	if len(ip) != IPv4len && len(ip) != IPv6len {
-		return nil, errors.New("invalid IP address")
+		return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()}
 	}
 	return []byte(ip.String()), nil
 }
@@ -346,7 +344,7 @@
 	s := string(text)
 	x := ParseIP(s)
 	if x == nil {
-		return &ParseError{"IP address", s}
+		return &ParseError{Type: "IP address", Text: s}
 	}
 	*ip = x
 	return nil
@@ -633,16 +631,6 @@
 	return ip, zone
 }
 
-// A ParseError represents a malformed text string and the type of string that was expected.
-type ParseError struct {
-	Type string
-	Text string
-}
-
-func (e *ParseError) Error() string {
-	return "invalid " + e.Type + ": " + e.Text
-}
-
 // ParseIP parses s as an IP address, returning the result.
 // The string s can be in dotted decimal ("74.125.19.99")
 // or IPv6 ("2001:4860:0:2001::68") form.
@@ -671,7 +659,7 @@
 func ParseCIDR(s string) (IP, *IPNet, error) {
 	i := byteIndex(s, '/')
 	if i < 0 {
-		return nil, nil, &ParseError{"CIDR address", s}
+		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
 	}
 	addr, mask := s[:i], s[i+1:]
 	iplen := IPv4len
@@ -682,7 +670,7 @@
 	}
 	n, i, ok := dtoi(mask, 0)
 	if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
-		return nil, nil, &ParseError{"CIDR address", s}
+		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
 	}
 	m := CIDRMask(n, 8*iplen)
 	return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index e6f4e65..24f67ca 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -53,8 +53,7 @@
 }
 
 func BenchmarkParseIP(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		for _, tt := range parseIPTests {
@@ -111,8 +110,7 @@
 }
 
 func BenchmarkIPString(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipStringTests {
@@ -164,8 +162,7 @@
 }
 
 func BenchmarkIPMaskString(b *testing.B) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipMaskStringTests {
@@ -197,10 +194,10 @@
 	{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
 	{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
 	{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
-	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}},
-	{"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}},
-	{"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
-	{"", nil, nil, &ParseError{"CIDR address", ""}},
+	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
+	{"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
+	{"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
+	{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
 }
 
 func TestParseCIDR(t *testing.T) {
diff --git a/src/net/ipraw_test.go b/src/net/ipraw_test.go
index f93b9ef..7221f78 100644
--- a/src/net/ipraw_test.go
+++ b/src/net/ipraw_test.go
@@ -5,7 +5,6 @@
 package net
 
 import (
-	"fmt"
 	"reflect"
 	"testing"
 )
@@ -17,7 +16,7 @@
 //	golang.org/x/net/icmp
 
 type resolveIPAddrTest struct {
-	net           string
+	network       string
 	litAddrOrName string
 	addr          *IPAddr
 	err           error
@@ -44,34 +43,30 @@
 	{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
 }
 
-func init() {
-	if ifi := loopbackInterface(); ifi != nil {
-		index := fmt.Sprintf("%v", ifi.Index)
-		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
-			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
-			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
-		}...)
-	}
-	if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
-		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
-			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
-			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
-			{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil},
-		}...)
-	}
-}
-
 func TestResolveIPAddr(t *testing.T) {
 	if !testableNetwork("ip+nopriv") {
 		t.Skip("ip+nopriv test")
 	}
 
-	for _, tt := range resolveIPAddrTests {
-		addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+
+	for i, tt := range resolveIPAddrTests {
+		addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName)
 		if err != tt.err {
-			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddrOrName, err)
+			t.Errorf("#%d: %v", i, err)
 		} else if !reflect.DeepEqual(addr, tt.addr) {
-			t.Fatalf("got %#v; expected %#v", addr, tt.addr)
+			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
+		}
+		if err != nil {
+			continue
+		}
+		rtaddr, err := ResolveIPAddr(addr.Network(), addr.String())
+		if err != nil {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(rtaddr, addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
 		}
 	}
 }
@@ -93,11 +88,11 @@
 		}
 		c, err := ListenIP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatalf("ListenIP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
 		if la := c.LocalAddr(); la == nil {
-			t.Fatal("IPConn.LocalAddr failed")
+			t.Fatal("should not fail")
 		}
 	}
 }
@@ -110,10 +105,10 @@
 	raddr := &IPAddr{IP: IPv4(127, 0, 0, 1).To4()}
 	c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr)
 	if err != nil {
-		t.Fatalf("DialIP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	if !reflect.DeepEqual(raddr, c.RemoteAddr()) {
-		t.Fatalf("got %#v, expected %#v", c.RemoteAddr(), raddr)
+		t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr)
 	}
 }
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index 1e53ab2..782561a 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -30,13 +30,6 @@
 	return a.IP.IsUnspecified()
 }
 
-func (a *IPAddr) toAddr() Addr {
-	if a == nil {
-		return nil
-	}
-	return a
-}
-
 // ResolveIPAddr parses addr as an IP address of the form "host" or
 // "ipv6-host%zone" and resolves the domain name on the network net,
 // which must be "ip", "ip4" or "ip6".
@@ -53,9 +46,9 @@
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	a, err := resolveInternetAddr(afnet, addr, noDeadline)
+	addrs, err := internetAddrList(afnet, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return a.toAddr().(*IPAddr), nil
+	return addrs.first(isIPv4).(*IPAddr), nil
 }
diff --git a/src/net/iprawsock_plan9.go b/src/net/iprawsock_plan9.go
index e62d116..0796290 100644
--- a/src/net/iprawsock_plan9.go
+++ b/src/net/iprawsock_plan9.go
@@ -23,12 +23,12 @@
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
 func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -36,7 +36,7 @@
 // bytes copied into b, the number of bytes copied into oob, the flags
 // that were set on the packet and the source address of the packet.
 func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
-	return 0, 0, 0, nil, syscall.EPLAN9
+	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // WriteToIP writes an IP packet to addr via c, copying the payload
@@ -47,19 +47,19 @@
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // WriteTo implements the PacketConn WriteTo method.
 func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // WriteMsgIP writes a packet to addr via c, copying the payload from
 // b and the associated out-of-band data from oob.  It returns the
 // number of payload and out-of-band bytes written.
 func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
-	return 0, 0, syscall.EPLAN9
+	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // DialIP connects to the remote address raddr on the network protocol
@@ -70,7 +70,7 @@
 }
 
 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: syscall.EPLAN9}
 }
 
 // ListenIP listens for incoming IP packets addressed to the local
@@ -78,5 +78,5 @@
 // methods can be used to receive and send IP packets with per-packet
 // addressing.
 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: syscall.EPLAN9}
 }
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index 94db068..1102823 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -80,6 +80,9 @@
 	case *syscall.SockaddrInet6:
 		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return n, addr, err
 }
 
@@ -104,7 +107,10 @@
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromIP(b)
-	return n, addr.toAddr(), err
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -123,6 +129,9 @@
 	case *syscall.SockaddrInet6:
 		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return
 }
 
@@ -138,16 +147,20 @@
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
 	}
-	return c.fd.writeTo(b, sa)
+	n, err := c.fd.writeTo(b, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return n, err
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -157,7 +170,7 @@
 	}
 	a, ok := addr.(*IPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToIP(b, a)
 }
@@ -170,16 +183,21 @@
 		return 0, 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
 	}
-	sa, err := addr.sockaddr(c.fd.family)
+	var sa syscall.Sockaddr
+	sa, err = addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
 	}
-	return c.fd.writeMsg(b, oob, sa)
+	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return
 }
 
 // DialIP connects to the remote address raddr on the network protocol
@@ -192,19 +210,19 @@
 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
 	net, proto, err := parseNetwork(netProto)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: err}
 	}
 	switch net {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: UnknownNetworkError(netProto)}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: UnknownNetworkError(netProto)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: errMissingAddress}
 	}
 	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: err}
 	}
 	return newIPConn(fd), nil
 }
@@ -216,16 +234,16 @@
 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
 	net, proto, err := parseNetwork(netProto)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: nil, Addr: laddr, Err: err}
 	}
 	switch net {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: UnknownNetworkError(netProto)}
+		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: UnknownNetworkError(netProto)}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: err}
 	}
 	return newIPConn(fd), nil
 }
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index 98d2dbf..6e75c33 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -26,93 +26,70 @@
 	supportsIPv4map bool
 )
 
-func init() {
-	sysInit()
-	supportsIPv4 = probeIPv4Stack()
-	supportsIPv6, supportsIPv4map = probeIPv6Stack()
-}
-
-// A netaddr represents a network endpoint address or a list of
-// network endpoint addresses.
-type netaddr interface {
-	// toAddr returns the address represented in Addr interface.
-	// It returns a nil interface when the address is nil.
-	toAddr() Addr
-}
-
 // An addrList represents a list of network endpoint addresses.
-type addrList []netaddr
+type addrList []Addr
 
-func (al addrList) toAddr() Addr {
-	switch len(al) {
-	case 0:
-		return nil
-	case 1:
-		return al[0].toAddr()
-	default:
-		// For now, we'll roughly pick first one without
-		// considering dealing with any preferences such as
-		// DNS TTL, transport path quality, network routing
-		// information.
-		return al[0].toAddr()
+// isIPv4 returns true if the Addr contains an IPv4 address.
+func isIPv4(addr Addr) bool {
+	switch addr := addr.(type) {
+	case *TCPAddr:
+		return addr.IP.To4() != nil
+	case *UDPAddr:
+		return addr.IP.To4() != nil
+	case *IPAddr:
+		return addr.IP.To4() != nil
 	}
+	return false
+}
+
+// first returns the first address which satisfies strategy, or if
+// none do, then the first address of any kind.
+func (addrs addrList) first(strategy func(Addr) bool) Addr {
+	for _, addr := range addrs {
+		if strategy(addr) {
+			return addr
+		}
+	}
+	return addrs[0]
+}
+
+// partition divides an address list into two categories, using a
+// strategy function to assign a boolean label to each address.
+// The first address, and any with a matching label, are returned as
+// primaries, while addresses with the opposite label are returned
+// as fallbacks. For non-empty inputs, primaries is guaranteed to be
+// non-empty.
+func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks addrList) {
+	var primaryLabel bool
+	for i, addr := range addrs {
+		label := strategy(addr)
+		if i == 0 || label == primaryLabel {
+			primaryLabel = label
+			primaries = append(primaries, addr)
+		} else {
+			fallbacks = append(fallbacks, addr)
+		}
+	}
+	return
 }
 
 var errNoSuitableAddress = errors.New("no suitable address found")
 
-// firstFavoriteAddr returns an address or a list of addresses that
-// implement the netaddr interface. Known filters are nil, ipv4only
-// and ipv6only. It returns any address when filter is nil. The result
-// contains at least one address when error is nil.
-func firstFavoriteAddr(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) netaddr) (netaddr, error) {
-	if filter != nil {
-		return firstSupportedAddr(filter, ips, inetaddr)
-	}
-	var (
-		ipv4, ipv6, swap bool
-		list             addrList
-	)
+// filterAddrList applies a filter to a list of IP addresses,
+// yielding a list of Addr objects. Known filters are nil, ipv4only,
+// and ipv6only. It returns every address when the filter is nil.
+// The result contains at least one address when error is nil.
+func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) {
+	var addrs addrList
 	for _, ip := range ips {
-		// We'll take any IP address, but since the dialing
-		// code does not yet try multiple addresses
-		// effectively, prefer to use an IPv4 address if
-		// possible. This is especially relevant if localhost
-		// resolves to [ipv6-localhost, ipv4-localhost]. Too
-		// much code assumes localhost == ipv4-localhost.
-		if ipv4only(ip) && !ipv4 {
-			list = append(list, inetaddr(ip))
-			ipv4 = true
-			if ipv6 {
-				swap = true
-			}
-		} else if ipv6only(ip) && !ipv6 {
-			list = append(list, inetaddr(ip))
-			ipv6 = true
-		}
-		if ipv4 && ipv6 {
-			if swap {
-				list[0], list[1] = list[1], list[0]
-			}
-			break
+		if filter == nil || filter(ip) {
+			addrs = append(addrs, inetaddr(ip))
 		}
 	}
-	switch len(list) {
-	case 0:
+	if len(addrs) == 0 {
 		return nil, errNoSuitableAddress
-	case 1:
-		return list[0], nil
-	default:
-		return list, nil
 	}
-}
-
-func firstSupportedAddr(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) netaddr) (netaddr, error) {
-	for _, ip := range ips {
-		if filter(ip) {
-			return inetaddr(ip), nil
-		}
-	}
-	return nil, errNoSuitableAddress
+	return addrs, nil
 }
 
 // ipv4only reports whether the kernel supports IPv4 addressing mode
@@ -145,7 +122,7 @@
 		// Expect the first ']' just before the last ':'.
 		end := byteIndex(hostport, ']')
 		if end < 0 {
-			err = &AddrError{"missing ']' in address", hostport}
+			err = &AddrError{Err: "missing ']' in address", Addr: hostport}
 			return
 		}
 		switch end + 1 {
@@ -174,11 +151,11 @@
 		}
 	}
 	if byteIndex(hostport[j:], '[') >= 0 {
-		err = &AddrError{"unexpected '[' in address", hostport}
+		err = &AddrError{Err: "unexpected '[' in address", Addr: hostport}
 		return
 	}
 	if byteIndex(hostport[k:], ']') >= 0 {
-		err = &AddrError{"unexpected ']' in address", hostport}
+		err = &AddrError{Err: "unexpected ']' in address", Addr: hostport}
 		return
 	}
 
@@ -186,15 +163,15 @@
 	return
 
 missingPort:
-	err = &AddrError{"missing port in address", hostport}
+	err = &AddrError{Err: "missing port in address", Addr: hostport}
 	return
 
 tooManyColons:
-	err = &AddrError{"too many colons in address", hostport}
+	err = &AddrError{Err: "too many colons in address", Addr: hostport}
 	return
 
 missingBrackets:
-	err = &AddrError{"missing brackets in address", hostport}
+	err = &AddrError{Err: "missing brackets in address", Addr: hostport}
 	return
 }
 
@@ -220,13 +197,11 @@
 	return host + ":" + port
 }
 
-// resolveInternetAddr resolves addr that is either a literal IP
-// address or a DNS name and returns an internet protocol family
-// address. It returns a list that contains a pair of different
-// address family addresses when addr is a DNS name and the name has
-// multiple address family records. The result contains at least one
-// address when error is nil.
-func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
+// internetAddrList resolves addr, which may be a literal IP
+// address or a DNS name, and returns a list of internet protocol
+// family addresses. The result contains at least one address when
+// error is nil.
+func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
 	var (
 		err        error
 		host, port string
@@ -249,7 +224,7 @@
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	inetaddr := func(ip IPAddr) netaddr {
+	inetaddr := func(ip IPAddr) Addr {
 		switch net {
 		case "tcp", "tcp4", "tcp6":
 			return &TCPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}
@@ -262,16 +237,16 @@
 		}
 	}
 	if host == "" {
-		return inetaddr(IPAddr{}), nil
+		return addrList{inetaddr(IPAddr{})}, nil
 	}
 	// Try as a literal IP address.
 	var ip IP
 	if ip = parseIPv4(host); ip != nil {
-		return inetaddr(IPAddr{IP: ip}), nil
+		return addrList{inetaddr(IPAddr{IP: ip})}, nil
 	}
 	var zone string
 	if ip, zone = parseIPv6(host, true); ip != nil {
-		return inetaddr(IPAddr{IP: ip, Zone: zone}), nil
+		return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil
 	}
 	// Try as a DNS name.
 	ips, err := lookupIPDeadline(host, deadline)
@@ -285,7 +260,7 @@
 	if net != "" && net[len(net)-1] == '6' {
 		filter = ipv6only
 	}
-	return firstFavoriteAddr(filter, ips, inetaddr)
+	return filterAddrList(filter, ips, inetaddr)
 }
 
 func zoneToString(zone int) string {
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index 94ceea3..72d640d 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.go
@@ -7,7 +7,6 @@
 package net
 
 import (
-	"errors"
 	"os"
 	"syscall"
 )
@@ -60,15 +59,15 @@
 	if i >= 0 {
 		addr = ParseIP(s[:i])
 		if addr == nil {
-			return nil, 0, errors.New("parsing IP failed")
+			return nil, 0, &ParseError{Type: "IP address", Text: s}
 		}
 	}
 	p, _, ok := dtoi(s[i+1:], 0)
 	if !ok {
-		return nil, 0, errors.New("parsing port failed")
+		return nil, 0, &ParseError{Type: "port", Text: s}
 	}
 	if p < 0 || p > 0xFFFF {
-		return nil, 0, &AddrError{"invalid port", string(p)}
+		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
 	}
 	return addr, p, nil
 }
@@ -95,7 +94,7 @@
 	case "udp":
 		addr = &UDPAddr{IP: ip, Port: port}
 	default:
-		return nil, errors.New("unknown protocol " + proto)
+		return nil, UnknownNetworkError(proto)
 	}
 	return addr, nil
 }
@@ -152,23 +151,23 @@
 	defer func() { netErr(err) }()
 	f, dest, proto, name, err := startPlan9(net, raddr)
 	if err != nil {
-		return nil, &OpError{"dial", net, raddr, err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	_, err = f.WriteString("connect " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"dial", f.Name(), raddr, err}
+		return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
 	}
 	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"dial", net, raddr, err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{"dial", proto, raddr, err}
+		return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
 	}
 	return newFD(proto, name, f, data, laddr, raddr)
 }
@@ -177,52 +176,52 @@
 	defer func() { netErr(err) }()
 	f, dest, proto, name, err := startPlan9(net, laddr)
 	if err != nil {
-		return nil, &OpError{"listen", net, laddr, err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	_, err = f.WriteString("announce " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"announce", proto, laddr, err}
+		return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "listen", Net: net, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return newFD(proto, name, f, nil, laddr, nil)
 }
 
-func (l *netFD) netFD() (*netFD, error) {
-	return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
+func (fd *netFD) netFD() (*netFD, error) {
+	return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
 }
 
-func (l *netFD) acceptPlan9() (fd *netFD, err error) {
+func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
 	defer func() { netErr(err) }()
-	if err := l.readLock(); err != nil {
+	if err := fd.readLock(); err != nil {
 		return nil, err
 	}
-	defer l.readUnlock()
-	f, err := os.Open(l.dir + "/listen")
+	defer fd.readUnlock()
+	f, err := os.Open(fd.dir + "/listen")
 	if err != nil {
-		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
 	}
 	var buf [16]byte
 	n, err := f.Read(buf[:])
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
 	}
 	name := string(buf[:n])
-	data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
+	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"accept", l.proto, l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
 	}
-	raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
+	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{"accept", l.proto, l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
 	}
-	return newFD(l.proto, name, f, data, l.laddr, raddr)
+	return newFD(fd.net, name, f, data, fd.laddr, raddr)
 }
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index 7597a92..56b9872 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -144,7 +144,7 @@
 			ip = IPv4zero
 		}
 		if ip = ip.To4(); ip == nil {
-			return nil, InvalidAddrError("non-IPv4 address")
+			return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
 		}
 		sa := new(syscall.SockaddrInet4)
 		for i := 0; i < IPv4len; i++ {
@@ -163,7 +163,7 @@
 			ip = IPv6zero
 		}
 		if ip = ip.To16(); ip == nil {
-			return nil, InvalidAddrError("non-IPv6 address")
+			return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
 		}
 		sa := new(syscall.SockaddrInet6)
 		for i := 0; i < IPv6len; i++ {
@@ -173,5 +173,5 @@
 		sa.ZoneId = uint32(zoneToInt(zone))
 		return sa, nil
 	}
-	return nil, InvalidAddrError("unexpected socket family")
+	return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
 }
diff --git a/src/net/ipsock_test.go b/src/net/ipsock_test.go
index 754ccbb..b36557a 100644
--- a/src/net/ipsock_test.go
+++ b/src/net/ipsock_test.go
@@ -9,14 +9,16 @@
 	"testing"
 )
 
-var testInetaddr = func(ip IPAddr) netaddr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
+var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
 
-var firstFavoriteAddrTests = []struct {
-	filter   func(IPAddr) bool
-	ips      []IPAddr
-	inetaddr func(IPAddr) netaddr
-	addr     netaddr
-	err      error
+var addrListTests = []struct {
+	filter    func(IPAddr) bool
+	ips       []IPAddr
+	inetaddr  func(IPAddr) Addr
+	first     Addr
+	primaries addrList
+	fallbacks addrList
+	err       error
 }{
 	{
 		nil,
@@ -25,10 +27,9 @@
 			{IP: IPv6loopback},
 		},
 		testInetaddr,
-		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-		},
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
 		nil,
 	},
 	{
@@ -38,10 +39,9 @@
 			{IP: IPv4(127, 0, 0, 1)},
 		},
 		testInetaddr,
-		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-		},
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
 		nil,
 	},
 	{
@@ -52,6 +52,11 @@
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{
+			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+		},
+		nil,
 		nil,
 	},
 	{
@@ -62,6 +67,11 @@
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
+		addrList{
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+		},
+		nil,
 		nil,
 	},
 	{
@@ -73,9 +83,14 @@
 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
 		},
 		testInetaddr,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+		},
+		addrList{
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
 		},
 		nil,
 	},
@@ -88,9 +103,14 @@
 			{IP: IPv4(192, 168, 0, 1)},
 		},
 		testInetaddr,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+		},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
 		},
 		nil,
 	},
@@ -103,9 +123,14 @@
 			{IP: ParseIP("fe80::1"), Zone: "eth0"},
 		},
 		testInetaddr,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+		},
+		addrList{
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
 		},
 		nil,
 	},
@@ -118,9 +143,14 @@
 			{IP: IPv4(192, 168, 0, 1)},
 		},
 		testInetaddr,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+		},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
 		},
 		nil,
 	},
@@ -133,6 +163,8 @@
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		nil,
 		nil,
 	},
 	{
@@ -143,6 +175,8 @@
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		nil,
 		nil,
 	},
 
@@ -154,6 +188,8 @@
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		nil,
 		nil,
 	},
 	{
@@ -164,30 +200,83 @@
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		nil,
 		nil,
 	},
 
-	{nil, nil, testInetaddr, nil, errNoSuitableAddress},
+	{nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
 
-	{ipv4only, nil, testInetaddr, nil, errNoSuitableAddress},
-	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, errNoSuitableAddress},
+	{ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
 
-	{ipv6only, nil, testInetaddr, nil, errNoSuitableAddress},
-	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, errNoSuitableAddress},
+	{ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
 }
 
-func TestFirstFavoriteAddr(t *testing.T) {
+func TestAddrList(t *testing.T) {
 	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("ipv4 or ipv6 is not supported")
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	for i, tt := range firstFavoriteAddrTests {
-		addr, err := firstFavoriteAddr(tt.filter, tt.ips, tt.inetaddr)
+	for i, tt := range addrListTests {
+		addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr)
 		if err != tt.err {
-			t.Errorf("#%v: got %v; expected %v", i, err, tt.err)
+			t.Errorf("#%v: got %v; want %v", i, err, tt.err)
 		}
-		if !reflect.DeepEqual(addr, tt.addr) {
-			t.Errorf("#%v: got %v; expected %v", i, addr, tt.addr)
+		if tt.err != nil {
+			if len(addrs) != 0 {
+				t.Errorf("#%v: got %v; want 0", i, len(addrs))
+			}
+			continue
+		}
+		first := addrs.first(isIPv4)
+		if !reflect.DeepEqual(first, tt.first) {
+			t.Errorf("#%v: got %v; want %v", i, first, tt.first)
+		}
+		primaries, fallbacks := addrs.partition(isIPv4)
+		if !reflect.DeepEqual(primaries, tt.primaries) {
+			t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
+		}
+		if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
+			t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
+		}
+		expectedLen := len(primaries) + len(fallbacks)
+		if len(addrs) != expectedLen {
+			t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen)
+		}
+	}
+}
+
+func TestAddrListPartition(t *testing.T) {
+	addrs := addrList{
+		&IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"},
+		&IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"},
+		&IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"},
+	}
+	cases := []struct {
+		lastByte  byte
+		primaries addrList
+		fallbacks addrList
+	}{
+		{0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}},
+		{1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}},
+		{2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}},
+		{3, addrList{addrs[0], addrs[1], addrs[2]}, nil},
+	}
+	for i, tt := range cases {
+		// Inverting the function's output should not affect the outcome.
+		for _, invert := range []bool{false, true} {
+			primaries, fallbacks := addrs.partition(func(a Addr) bool {
+				ip := a.(*IPAddr).IP
+				return (ip[len(ip)-1] == tt.lastByte) != invert
+			})
+			if !reflect.DeepEqual(primaries, tt.primaries) {
+				t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
+			}
+			if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
+				t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
+			}
 		}
 	}
 }
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
new file mode 100644
index 0000000..8f43c84
--- /dev/null
+++ b/src/net/listen_test.go
@@ -0,0 +1,687 @@
+// Copyright 2011 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 !plan9
+
+package net
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+func (ln *TCPListener) port() string {
+	_, port, err := SplitHostPort(ln.Addr().String())
+	if err != nil {
+		return ""
+	}
+	return port
+}
+
+func (c *UDPConn) port() string {
+	_, port, err := SplitHostPort(c.LocalAddr().String())
+	if err != nil {
+		return ""
+	}
+	return port
+}
+
+var tcpListenerTests = []struct {
+	network string
+	address string
+}{
+	{"tcp", ""},
+	{"tcp", "0.0.0.0"},
+	{"tcp", "::ffff:0.0.0.0"},
+	{"tcp", "::"},
+
+	{"tcp", "127.0.0.1"},
+	{"tcp", "::ffff:127.0.0.1"},
+	{"tcp", "::1"},
+
+	{"tcp4", ""},
+	{"tcp4", "0.0.0.0"},
+	{"tcp4", "::ffff:0.0.0.0"},
+
+	{"tcp4", "127.0.0.1"},
+	{"tcp4", "::ffff:127.0.0.1"},
+
+	{"tcp6", ""},
+	{"tcp6", "::"},
+
+	{"tcp6", "::1"},
+}
+
+// TestTCPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestTCPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	for _, tt := range tcpListenerTests {
+		if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") {
+			t.Logf("skipping %s test", tt.network+" "+tt.address)
+			continue
+		}
+
+		ln1, err := Listen(tt.network, JoinHostPort(tt.address, "0"))
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := checkFirstListener(tt.network, ln1); err != nil {
+			ln1.Close()
+			t.Fatal(err)
+		}
+		ln2, err := Listen(tt.network, JoinHostPort(tt.address, ln1.(*TCPListener).port()))
+		if err == nil {
+			ln2.Close()
+		}
+		if err := checkSecondListener(tt.network, tt.address, err); err != nil {
+			ln1.Close()
+			t.Fatal(err)
+		}
+		ln1.Close()
+	}
+}
+
+var udpListenerTests = []struct {
+	network string
+	address string
+}{
+	{"udp", ""},
+	{"udp", "0.0.0.0"},
+	{"udp", "::ffff:0.0.0.0"},
+	{"udp", "::"},
+
+	{"udp", "127.0.0.1"},
+	{"udp", "::ffff:127.0.0.1"},
+	{"udp", "::1"},
+
+	{"udp4", ""},
+	{"udp4", "0.0.0.0"},
+	{"udp4", "::ffff:0.0.0.0"},
+
+	{"udp4", "127.0.0.1"},
+	{"udp4", "::ffff:127.0.0.1"},
+
+	{"udp6", ""},
+	{"udp6", "::"},
+
+	{"udp6", "::1"},
+}
+
+// TestUDPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestUDPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	for _, tt := range udpListenerTests {
+		if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") {
+			t.Logf("skipping %s test", tt.network+" "+tt.address)
+			continue
+		}
+
+		c1, err := ListenPacket(tt.network, JoinHostPort(tt.address, "0"))
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := checkFirstListener(tt.network, c1); err != nil {
+			c1.Close()
+			t.Fatal(err)
+		}
+		c2, err := ListenPacket(tt.network, JoinHostPort(tt.address, c1.(*UDPConn).port()))
+		if err == nil {
+			c2.Close()
+		}
+		if err := checkSecondListener(tt.network, tt.address, err); err != nil {
+			c1.Close()
+			t.Fatal(err)
+		}
+		c1.Close()
+	}
+}
+
+var dualStackTCPListenerTests = []struct {
+	network1, address1 string // first listener
+	network2, address2 string // second listener
+	xerr               error  // expected error value, nil or other
+}{
+	// Test cases and expected results for the attemping 2nd listen on the same port
+	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
+	// ------------------------------------------------------------------------------------
+	// "tcp"  ""                 "tcp"  ""                    -        -       -       -
+	// "tcp"  ""                 "tcp"  "0.0.0.0"             -        -       -       -
+	// "tcp"  "0.0.0.0"          "tcp"  ""                    -        -       -       -
+	// ------------------------------------------------------------------------------------
+	// "tcp"  ""                 "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  ""                    -        -       -       ok
+	// "tcp"  "0.0.0.0"          "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  "0.0.0.0"             -        -       -       ok
+	// "tcp"  "[::ffff:0.0.0.0]" "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  "[::ffff:0.0.0.0]"    -        -       -       ok
+	// ------------------------------------------------------------------------------------
+	// "tcp4" ""                 "tcp6" ""                    ok       ok      ok      ok
+	// "tcp6" ""                 "tcp4" ""                    ok       ok      ok      ok
+	// "tcp4" "0.0.0.0"          "tcp6" "[::]"                ok       ok      ok      ok
+	// "tcp6" "[::]"             "tcp4" "0.0.0.0"             ok       ok      ok      ok
+	// ------------------------------------------------------------------------------------
+	// "tcp"  "127.0.0.1"        "tcp"  "[::1]"               ok       ok      ok      ok
+	// "tcp"  "[::1]"            "tcp"  "127.0.0.1"           ok       ok      ok      ok
+	// "tcp4" "127.0.0.1"        "tcp6" "[::1]"               ok       ok      ok      ok
+	// "tcp6" "[::1]"            "tcp4" "127.0.0.1"           ok       ok      ok      ok
+	//
+	// Platform default configurations:
+	// darwin, kernel version 11.3.0
+	//	net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+	// freebsd, kernel version 8.2
+	//	net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
+	// linux, kernel version 3.0.0
+	//	net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+	// openbsd, kernel version 5.0
+	//	net.inet6.ip6.v6only=1 (overriding is prohibited)
+
+	{"tcp", "", "tcp", "", syscall.EADDRINUSE},
+	{"tcp", "", "tcp", "0.0.0.0", syscall.EADDRINUSE},
+	{"tcp", "0.0.0.0", "tcp", "", syscall.EADDRINUSE},
+
+	{"tcp", "", "tcp", "::", syscall.EADDRINUSE},
+	{"tcp", "::", "tcp", "", syscall.EADDRINUSE},
+	{"tcp", "0.0.0.0", "tcp", "::", syscall.EADDRINUSE},
+	{"tcp", "::", "tcp", "0.0.0.0", syscall.EADDRINUSE},
+	{"tcp", "::ffff:0.0.0.0", "tcp", "::", syscall.EADDRINUSE},
+	{"tcp", "::", "tcp", "::ffff:0.0.0.0", syscall.EADDRINUSE},
+
+	{"tcp4", "", "tcp6", "", nil},
+	{"tcp6", "", "tcp4", "", nil},
+	{"tcp4", "0.0.0.0", "tcp6", "::", nil},
+	{"tcp6", "::", "tcp4", "0.0.0.0", nil},
+
+	{"tcp", "127.0.0.1", "tcp", "::1", nil},
+	{"tcp", "::1", "tcp", "127.0.0.1", nil},
+	{"tcp4", "127.0.0.1", "tcp6", "::1", nil},
+	{"tcp6", "::1", "tcp4", "127.0.0.1", nil},
+}
+
+// TestDualStackTCPListener tests both single and double listen
+// to a test listener with various address families, different
+// 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)
+	}
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	for _, tt := range dualStackTCPListenerTests {
+		if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") {
+			t.Logf("skipping %s test", tt.network1+" "+tt.address1)
+			continue
+		}
+
+		if runtime.GOOS == "openbsd" && differentWildcardAddr(tt.address1, tt.address2) {
+			tt.xerr = nil
+		}
+		var firstErr, secondErr error
+		for i := 0; i < 5; i++ {
+			lns, err := newDualStackListener()
+			if err != nil {
+				t.Fatal(err)
+			}
+			port := lns[0].port()
+			for _, ln := range lns {
+				ln.Close()
+			}
+			var ln1 Listener
+			ln1, firstErr = Listen(tt.network1, JoinHostPort(tt.address1, port))
+			if firstErr != nil {
+				continue
+			}
+			if err := checkFirstListener(tt.network1, ln1); err != nil {
+				ln1.Close()
+				t.Fatal(err)
+			}
+			ln2, err := Listen(tt.network2, JoinHostPort(tt.address2, ln1.(*TCPListener).port()))
+			if err == nil {
+				ln2.Close()
+			}
+			if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil {
+				ln1.Close()
+				continue
+			}
+			ln1.Close()
+			break
+		}
+		if firstErr != nil {
+			t.Error(firstErr)
+		}
+		if secondErr != nil {
+			t.Error(secondErr)
+		}
+	}
+}
+
+var dualStackUDPListenerTests = []struct {
+	network1, address1 string // first listener
+	network2, address2 string // second listener
+	xerr               error  // expected error value, nil or other
+}{
+	{"udp", "", "udp", "", syscall.EADDRINUSE},
+	{"udp", "", "udp", "0.0.0.0", syscall.EADDRINUSE},
+	{"udp", "0.0.0.0", "udp", "", syscall.EADDRINUSE},
+
+	{"udp", "", "udp", "::", syscall.EADDRINUSE},
+	{"udp", "::", "udp", "", syscall.EADDRINUSE},
+	{"udp", "0.0.0.0", "udp", "::", syscall.EADDRINUSE},
+	{"udp", "::", "udp", "0.0.0.0", syscall.EADDRINUSE},
+	{"udp", "::ffff:0.0.0.0", "udp", "::", syscall.EADDRINUSE},
+	{"udp", "::", "udp", "::ffff:0.0.0.0", syscall.EADDRINUSE},
+
+	{"udp4", "", "udp6", "", nil},
+	{"udp6", "", "udp4", "", nil},
+	{"udp4", "0.0.0.0", "udp6", "::", nil},
+	{"udp6", "::", "udp4", "0.0.0.0", nil},
+
+	{"udp", "127.0.0.1", "udp", "::1", nil},
+	{"udp", "::1", "udp", "127.0.0.1", nil},
+	{"udp4", "127.0.0.1", "udp6", "::1", nil},
+	{"udp6", "::1", "udp4", "127.0.0.1", nil},
+}
+
+// TestDualStackUDPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackUDPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	for _, tt := range dualStackUDPListenerTests {
+		if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") {
+			t.Logf("skipping %s test", tt.network1+" "+tt.address1)
+			continue
+		}
+
+		if runtime.GOOS == "openbsd" && differentWildcardAddr(tt.address1, tt.address2) {
+			tt.xerr = nil
+		}
+		var firstErr, secondErr error
+		for i := 0; i < 5; i++ {
+			cs, err := newDualStackPacketListener()
+			if err != nil {
+				t.Fatal(err)
+			}
+			port := cs[0].port()
+			for _, c := range cs {
+				c.Close()
+			}
+			var c1 PacketConn
+			c1, firstErr = ListenPacket(tt.network1, JoinHostPort(tt.address1, port))
+			if firstErr != nil {
+				continue
+			}
+			if err := checkFirstListener(tt.network1, c1); err != nil {
+				c1.Close()
+				t.Fatal(err)
+			}
+			c2, err := ListenPacket(tt.network2, JoinHostPort(tt.address2, c1.(*UDPConn).port()))
+			if err == nil {
+				c2.Close()
+			}
+			if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil {
+				c1.Close()
+				continue
+			}
+			c1.Close()
+			break
+		}
+		if firstErr != nil {
+			t.Error(firstErr)
+		}
+		if secondErr != nil {
+			t.Error(secondErr)
+		}
+	}
+}
+
+func differentWildcardAddr(i, j string) bool {
+	if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
+		return false
+	}
+	if i == "[::]" && j == "[::]" {
+		return false
+	}
+	return true
+}
+
+func checkFirstListener(network string, ln interface{}) error {
+	switch network {
+	case "tcp":
+		fd := ln.(*TCPListener).fd
+		if err := checkDualStackAddrFamily(fd); err != nil {
+			return err
+		}
+	case "tcp4":
+		fd := ln.(*TCPListener).fd
+		if fd.family != syscall.AF_INET {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET)
+		}
+	case "tcp6":
+		fd := ln.(*TCPListener).fd
+		if fd.family != syscall.AF_INET6 {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6)
+		}
+	case "udp":
+		fd := ln.(*UDPConn).fd
+		if err := checkDualStackAddrFamily(fd); err != nil {
+			return err
+		}
+	case "udp4":
+		fd := ln.(*UDPConn).fd
+		if fd.family != syscall.AF_INET {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET)
+		}
+	case "udp6":
+		fd := ln.(*UDPConn).fd
+		if fd.family != syscall.AF_INET6 {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6)
+		}
+	default:
+		return UnknownNetworkError(network)
+	}
+	return nil
+}
+
+func checkSecondListener(network, address string, err error) error {
+	switch network {
+	case "tcp", "tcp4", "tcp6":
+		if err == nil {
+			return fmt.Errorf("%s should fail", network+" "+address)
+		}
+	case "udp", "udp4", "udp6":
+		if err == nil {
+			return fmt.Errorf("%s should fail", network+" "+address)
+		}
+	default:
+		return UnknownNetworkError(network)
+	}
+	return nil
+}
+
+func checkDualStackSecondListener(network, address string, err, xerr error) error {
+	switch network {
+	case "tcp", "tcp4", "tcp6":
+		if xerr == nil && err != nil || xerr != nil && err == nil {
+			return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr)
+		}
+	case "udp", "udp4", "udp6":
+		if xerr == nil && err != nil || xerr != nil && err == nil {
+			return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr)
+		}
+	default:
+		return UnknownNetworkError(network)
+	}
+	return nil
+}
+
+func checkDualStackAddrFamily(fd *netFD) error {
+	switch a := fd.laddr.(type) {
+	case *TCPAddr:
+		// If a node under test supports both IPv6 capability
+		// and IPv6 IPv4-mapping capability, we can assume
+		// that the node listens on a wildcard address with an
+		// AF_INET6 socket.
+		if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+			if fd.family != syscall.AF_INET6 {
+				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6)
+			}
+		} else {
+			if fd.family != a.family() {
+				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family())
+			}
+		}
+	case *UDPAddr:
+		// If a node under test supports both IPv6 capability
+		// and IPv6 IPv4-mapping capability, we can assume
+		// that the node listens on a wildcard address with an
+		// AF_INET6 socket.
+		if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+			if fd.family != syscall.AF_INET6 {
+				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6)
+			}
+		} else {
+			if fd.family != a.family() {
+				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family())
+			}
+		}
+	default:
+		return fmt.Errorf("unexpected protocol address type: %T", a)
+	}
+	return nil
+}
+
+func TestWildWildcardListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+
+	defer func() {
+		if p := recover(); p != nil {
+			t.Fatalf("panicked: %v", p)
+		}
+	}()
+
+	if ln, err := Listen("tcp", ""); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenPacket("udp", ""); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenTCP("tcp", nil); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenUDP("udp", nil); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenIP("ip:icmp", nil); err == nil {
+		ln.Close()
+	}
+}
+
+var ipv4MulticastListenerTests = []struct {
+	net   string
+	gaddr *UDPAddr // see RFC 4727
+}{
+	{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+
+	{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+}
+
+// TestIPv4MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv4MulticastListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "android", "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	case "solaris":
+		t.Skipf("not supported on solaris, see golang.org/issue/7399")
+	}
+
+	closer := func(cs []*UDPConn) {
+		for _, c := range cs {
+			if c != nil {
+				c.Close()
+			}
+		}
+	}
+
+	for _, ifi := range []*Interface{loopbackInterface(), nil} {
+		// Note that multicast interface assignment by system
+		// is not recommended because it usually relies on
+		// routing stuff for finding out an appropriate
+		// nexthop containing both network and link layer
+		// adjacencies.
+		if ifi == nil && !*testExternal {
+			continue
+		}
+		for _, tt := range ipv4MulticastListenerTests {
+			var err error
+			cs := make([]*UDPConn, 2)
+			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			closer(cs)
+		}
+	}
+}
+
+var ipv6MulticastListenerTests = []struct {
+	net   string
+	gaddr *UDPAddr // see RFC 4727
+}{
+	{"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+
+	{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+}
+
+// TestIPv6MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv6MulticastListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	case "solaris":
+		t.Skipf("not supported on solaris, see issue 7399")
+	}
+	if !supportsIPv6 {
+		t.Skip("ipv6 is not supported")
+	}
+	if os.Getuid() != 0 {
+		t.Skip("must be root")
+	}
+
+	closer := func(cs []*UDPConn) {
+		for _, c := range cs {
+			if c != nil {
+				c.Close()
+			}
+		}
+	}
+
+	for _, ifi := range []*Interface{loopbackInterface(), nil} {
+		// Note that multicast interface assignment by system
+		// is not recommended because it usually relies on
+		// routing stuff for finding out an appropriate
+		// nexthop containing both network and link layer
+		// adjacencies.
+		if ifi == nil && (!*testExternal || !*testIPv6) {
+			continue
+		}
+		for _, tt := range ipv6MulticastListenerTests {
+			var err error
+			cs := make([]*UDPConn, 2)
+			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			closer(cs)
+		}
+	}
+}
+
+func checkMulticastListener(c *UDPConn, ip IP) error {
+	if ok, err := multicastRIBContains(ip); err != nil {
+		return err
+	} else if !ok {
+		return fmt.Errorf("%s not found in multicast rib", ip.String())
+	}
+	la := c.LocalAddr()
+	if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
+		return fmt.Errorf("got %v; want a proper address with non-zero port number", la)
+	}
+	return nil
+}
+
+func multicastRIBContains(ip IP) (bool, error) {
+	switch runtime.GOOS {
+	case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows":
+		return true, nil // not implemented yet
+	case "linux":
+		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+			return true, nil // not implemented yet
+		}
+	}
+	ift, err := Interfaces()
+	if err != nil {
+		return false, err
+	}
+	for _, ifi := range ift {
+		ifmat, err := ifi.MulticastAddrs()
+		if err != nil {
+			return false, err
+		}
+		for _, ifma := range ifmat {
+			if ifma.(*IPAddr).IP.Equal(ip) {
+				return true, nil
+			}
+		}
+	}
+	return false, nil
+}
diff --git a/src/net/lookup.go b/src/net/lookup.go
index 65abc81..e2becc5 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -4,7 +4,10 @@
 
 package net
 
-import "time"
+import (
+	"internal/singleflight"
+	"time"
+)
 
 // protocols contains minimal mappings between internet protocol
 // names and numbers for platforms that don't have a complete list of
@@ -39,14 +42,14 @@
 	return
 }
 
-var lookupGroup singleflight
+var lookupGroup singleflight.Group
 
 // lookupIPMerge wraps lookupIP, but makes sure that for any given
 // host, only one lookup is in-flight at a time. The returned memory
 // is always owned by the caller.
 func lookupIPMerge(host string) (addrs []IPAddr, err error) {
 	addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
-		return lookupIP(host)
+		return testHookLookupIP(lookupIP, host)
 	})
 	return lookupIPReturn(addrsi, err, shared)
 }
@@ -84,7 +87,7 @@
 	defer t.Stop()
 
 	ch := lookupGroup.DoChan(host, func() (interface{}, error) {
-		return lookupIP(host)
+		return testHookLookupIP(lookupIP, host)
 	})
 
 	select {
@@ -98,7 +101,7 @@
 		return nil, errTimeout
 
 	case r := <-ch:
-		return lookupIPReturn(r.v, r.err, r.shared)
+		return lookupIPReturn(r.Val, r.Err, r.Shared)
 	}
 }
 
@@ -129,22 +132,22 @@
 }
 
 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err error) {
+func LookupMX(name string) (mxs []*MX, err error) {
 	return lookupMX(name)
 }
 
 // LookupNS returns the DNS NS records for the given domain name.
-func LookupNS(name string) (ns []*NS, err error) {
+func LookupNS(name string) (nss []*NS, err error) {
 	return lookupNS(name)
 }
 
 // LookupTXT returns the DNS TXT records for the given domain name.
-func LookupTXT(name string) (txt []string, err error) {
+func LookupTXT(name string) (txts []string, err error) {
 	return lookupTXT(name)
 }
 
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
-func LookupAddr(addr string) (name []string, err error) {
+func LookupAddr(addr string) (names []string, err error) {
 	return lookupAddr(addr)
 }
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index 73abbad..c627464 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -101,19 +101,18 @@
 	if err != nil {
 		return 0, err
 	}
-	unknownProtoError := errors.New("unknown IP protocol specified: " + name)
 	if len(lines) == 0 {
-		return 0, unknownProtoError
+		return 0, UnknownNetworkError(name)
 	}
 	f := getFields(lines[0])
 	if len(f) < 2 {
-		return 0, unknownProtoError
+		return 0, UnknownNetworkError(name)
 	}
 	s := f[1]
 	if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
 		return n, nil
 	}
-	return 0, unknownProtoError
+	return 0, UnknownNetworkError(name)
 }
 
 func lookupHost(host string) (addrs []string, err error) {
@@ -173,7 +172,7 @@
 	if err != nil {
 		return
 	}
-	unknownPortError := &AddrError{"unknown port", network + "/" + service}
+	unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
 	if len(lines) == 0 {
 		return 0, unknownPortError
 	}
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 430adfd..1f36184 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -2,20 +2,26 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO It would be nice to use a mock DNS server, to eliminate
-// external dependencies.
-
 package net
 
 import (
-	"flag"
 	"fmt"
 	"strings"
 	"testing"
 	"time"
 )
 
-var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
+func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+	switch host {
+	case "localhost":
+		return []IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
+		}, nil
+	default:
+		return fn(host)
+	}
+}
 
 var lookupGoogleSRVTests = []struct {
 	service, proto, name string
@@ -33,7 +39,7 @@
 
 func TestLookupGoogleSRV(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range lookupGoogleSRVTests {
@@ -57,7 +63,7 @@
 
 func TestLookupGmailMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	mxs, err := LookupMX("gmail.com")
@@ -76,7 +82,7 @@
 
 func TestLookupGmailNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	nss, err := LookupNS("gmail.com")
@@ -95,7 +101,7 @@
 
 func TestLookupGmailTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	txts, err := LookupTXT("gmail.com")
@@ -124,7 +130,7 @@
 
 func TestLookupGooglePublicDNSAddr(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range lookupGooglePublicDNSAddrs {
@@ -145,7 +151,7 @@
 
 func TestLookupIANACNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	cname, err := LookupCNAME("www.iana.org")
@@ -159,7 +165,7 @@
 
 func TestLookupGoogleHost(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	addrs, err := LookupHost("google.com")
@@ -178,7 +184,7 @@
 
 func TestLookupGoogleIP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	ips, err := LookupIP("google.com")
@@ -232,8 +238,6 @@
 	}
 }
 
-var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding")
-
 func TestLookupIPDeadline(t *testing.T) {
 	if !*testDNSFlood {
 		t.Skip("test disabled; use -dnsflood to enable")
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index 473adf8..6484414 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -6,10 +6,7 @@
 
 package net
 
-import (
-	"errors"
-	"sync"
-)
+import "sync"
 
 var onceReadProtocols sync.Once
 
@@ -43,126 +40,129 @@
 
 // lookupProtocol looks up IP protocol name in /etc/protocols and
 // returns correspondent protocol number.
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(name string) (int, error) {
 	onceReadProtocols.Do(readProtocols)
 	proto, found := protocols[name]
 	if !found {
-		return 0, errors.New("unknown IP protocol specified: " + name)
+		return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
 	}
-	return
+	return proto, nil
 }
 
 func lookupHost(host string) (addrs []string, err error) {
-	addrs, err, ok := cgoLookupHost(host)
-	if !ok {
-		addrs, err = goLookupHost(host)
+	order := systemConf().hostLookupOrder(host)
+	if order == hostLookupCgo {
+		if addrs, err, ok := cgoLookupHost(host); ok {
+			return addrs, err
+		}
+		// cgo not available (or netgo); fall back to Go's DNS resolver
+		order = hostLookupFilesDNS
 	}
-	return
+	return goLookupHostOrder(host, order)
 }
 
 func lookupIP(host string) (addrs []IPAddr, err error) {
-	addrs, err, ok := cgoLookupIP(host)
-	if !ok {
-		addrs, err = goLookupIP(host)
+	order := systemConf().hostLookupOrder(host)
+	if order == hostLookupCgo {
+		if addrs, err, ok := cgoLookupIP(host); ok {
+			return addrs, err
+		}
+		// cgo not available (or netgo); fall back to Go's DNS resolver
+		order = hostLookupFilesDNS
 	}
-	return
+	return goLookupIPOrder(host, order)
 }
 
-func lookupPort(network, service string) (port int, err error) {
+func lookupPort(network, service string) (int, error) {
 	port, err, ok := cgoLookupPort(network, service)
 	if !ok {
 		port, err = goLookupPort(network, service)
 	}
-	return
+	return port, err
 }
 
-func lookupCNAME(name string) (cname string, err error) {
+func lookupCNAME(name string) (string, error) {
 	cname, err, ok := cgoLookupCNAME(name)
 	if !ok {
 		cname, err = goLookupCNAME(name)
 	}
-	return
+	return cname, err
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	var target string
 	if service == "" && proto == "" {
 		target = name
 	} else {
 		target = "_" + service + "._" + proto + "." + name
 	}
-	var records []dnsRR
-	cname, records, err = lookup(target, dnsTypeSRV)
+	cname, rrs, err := lookup(target, dnsTypeSRV)
 	if err != nil {
-		return
+		return "", nil, err
 	}
-	addrs = make([]*SRV, len(records))
-	for i, rr := range records {
-		r := rr.(*dnsRR_SRV)
-		addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+	srvs := make([]*SRV, len(rrs))
+	for i, rr := range rrs {
+		rr := rr.(*dnsRR_SRV)
+		srvs[i] = &SRV{Target: rr.Target, Port: rr.Port, Priority: rr.Priority, Weight: rr.Weight}
 	}
-	byPriorityWeight(addrs).sort()
-	return
+	byPriorityWeight(srvs).sort()
+	return cname, srvs, nil
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
-	_, records, err := lookup(name, dnsTypeMX)
+func lookupMX(name string) ([]*MX, error) {
+	_, rrs, err := lookup(name, dnsTypeMX)
 	if err != nil {
-		return
+		return nil, err
 	}
-	mx = make([]*MX, len(records))
-	for i, rr := range records {
-		r := rr.(*dnsRR_MX)
-		mx[i] = &MX{r.Mx, r.Pref}
+	mxs := make([]*MX, len(rrs))
+	for i, rr := range rrs {
+		rr := rr.(*dnsRR_MX)
+		mxs[i] = &MX{Host: rr.Mx, Pref: rr.Pref}
 	}
-	byPref(mx).sort()
-	return
+	byPref(mxs).sort()
+	return mxs, nil
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
-	_, records, err := lookup(name, dnsTypeNS)
+func lookupNS(name string) ([]*NS, error) {
+	_, rrs, err := lookup(name, dnsTypeNS)
 	if err != nil {
-		return
+		return nil, err
 	}
-	ns = make([]*NS, len(records))
-	for i, r := range records {
-		r := r.(*dnsRR_NS)
-		ns[i] = &NS{r.Ns}
+	nss := make([]*NS, len(rrs))
+	for i, rr := range rrs {
+		nss[i] = &NS{Host: rr.(*dnsRR_NS).Ns}
 	}
-	return
+	return nss, nil
 }
 
-func lookupTXT(name string) (txt []string, err error) {
-	_, records, err := lookup(name, dnsTypeTXT)
+func lookupTXT(name string) ([]string, error) {
+	_, rrs, err := lookup(name, dnsTypeTXT)
 	if err != nil {
-		return
+		return nil, err
 	}
-	txt = make([]string, len(records))
-	for i, r := range records {
-		txt[i] = r.(*dnsRR_TXT).Txt
+	txts := make([]string, len(rrs))
+	for i, rr := range rrs {
+		txts[i] = rr.(*dnsRR_TXT).Txt
 	}
-	return
+	return txts, nil
 }
 
-func lookupAddr(addr string) (name []string, err error) {
-	name = lookupStaticAddr(addr)
-	if len(name) > 0 {
-		return
+func lookupAddr(addr string) ([]string, error) {
+	names := lookupStaticAddr(addr)
+	if len(names) > 0 {
+		return names, nil
 	}
-	var arpa string
-	arpa, err = reverseaddr(addr)
+	arpa, err := reverseaddr(addr)
 	if err != nil {
-		return
+		return nil, err
 	}
-	var records []dnsRR
-	_, records, err = lookup(arpa, dnsTypePTR)
+	_, rrs, err := lookup(arpa, dnsTypePTR)
 	if err != nil {
-		return
+		return nil, err
 	}
-	name = make([]string, len(records))
-	for i := range records {
-		r := records[i].(*dnsRR_PTR)
-		name[i] = r.Ptr
+	ptrs := make([]string, len(rrs))
+	for i, rr := range rrs {
+		ptrs[i] = rr.(*dnsRR_PTR).Ptr
 	}
-	return
+	return ptrs, nil
 }
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 6a8d918..1b6d392 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -19,13 +19,13 @@
 func getprotobyname(name string) (proto int, err error) {
 	p, err := syscall.GetProtoByName(name)
 	if err != nil {
-		return 0, os.NewSyscallError("GetProtoByName", err)
+		return 0, os.NewSyscallError("getorotobyname", err)
 	}
 	return int(p.Proto), nil
 }
 
 // lookupProtocol looks up IP protocol name and returns correspondent protocol number.
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(name string) (int, error) {
 	// GetProtoByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -46,27 +46,28 @@
 		if proto, ok := protocols[name]; ok {
 			return proto, nil
 		}
+		r.err = &DNSError{Err: r.err.Error(), Name: name}
 	}
 	return r.proto, r.err
 }
 
-func lookupHost(name string) (addrs []string, err error) {
+func lookupHost(name string) ([]string, error) {
 	ips, err := LookupIP(name)
 	if err != nil {
-		return
+		return nil, err
 	}
-	addrs = make([]string, 0, len(ips))
+	addrs := make([]string, 0, len(ips))
 	for _, ip := range ips {
 		addrs = append(addrs, ip.String())
 	}
-	return
+	return addrs, nil
 }
 
 func gethostbyname(name string) (addrs []IPAddr, err error) {
 	// caller already acquired thread
 	h, err := syscall.GetHostByName(name)
 	if err != nil {
-		return nil, os.NewSyscallError("GetHostByName", err)
+		return nil, os.NewSyscallError("gethostbyname", err)
 	}
 	switch h.AddrType {
 	case syscall.AF_INET:
@@ -77,12 +78,12 @@
 		}
 		addrs = addrs[0:i]
 	default: // TODO(vcc): Implement non IPv4 address lookups.
-		return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+		return nil, syscall.EWINDOWS
 	}
 	return addrs, nil
 }
 
-func oldLookupIP(name string) (addrs []IPAddr, err error) {
+func oldLookupIP(name string) ([]IPAddr, error) {
 	// GetHostByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -99,10 +100,13 @@
 		ch <- result{addrs: addrs, err: err}
 	}()
 	r := <-ch
-	return addrs, r.err
+	if r.err != nil {
+		r.err = &DNSError{Err: r.err.Error(), Name: name}
+	}
+	return r.addrs, r.err
 }
 
-func newLookupIP(name string) (addrs []IPAddr, err error) {
+func newLookupIP(name string) ([]IPAddr, error) {
 	acquireThread()
 	defer releaseThread()
 	hints := syscall.AddrinfoW{
@@ -113,10 +117,10 @@
 	var result *syscall.AddrinfoW
 	e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
 	if e != nil {
-		return nil, os.NewSyscallError("GetAddrInfoW", e)
+		return nil, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}
 	}
 	defer syscall.FreeAddrInfoW(result)
-	addrs = make([]IPAddr, 0, 5)
+	addrs := make([]IPAddr, 0, 5)
 	for ; result != nil; result = result.Next {
 		addr := unsafe.Pointer(result.Addr)
 		switch result.Family {
@@ -128,13 +132,13 @@
 			zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
 			addrs = append(addrs, IPAddr{IP: IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]}, Zone: zone})
 		default:
-			return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+			return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
 		}
 	}
 	return addrs, nil
 }
 
-func getservbyname(network, service string) (port int, err error) {
+func getservbyname(network, service string) (int, error) {
 	acquireThread()
 	defer releaseThread()
 	switch network {
@@ -145,12 +149,12 @@
 	}
 	s, err := syscall.GetServByName(service, network)
 	if err != nil {
-		return 0, os.NewSyscallError("GetServByName", err)
+		return 0, os.NewSyscallError("getservbyname", err)
 	}
 	return int(syscall.Ntohs(s.Port)), nil
 }
 
-func oldLookupPort(network, service string) (port int, err error) {
+func oldLookupPort(network, service string) (int, error) {
 	// GetServByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -167,10 +171,13 @@
 		ch <- result{port: port, err: err}
 	}()
 	r := <-ch
+	if r.err != nil {
+		r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service}
+	}
 	return r.port, r.err
 }
 
-func newLookupPort(network, service string) (port int, err error) {
+func newLookupPort(network, service string) (int, error) {
 	acquireThread()
 	defer releaseThread()
 	var stype int32
@@ -188,11 +195,11 @@
 	var result *syscall.AddrinfoW
 	e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
 	if e != nil {
-		return 0, os.NewSyscallError("GetAddrInfoW", e)
+		return 0, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: network + "/" + service}
 	}
 	defer syscall.FreeAddrInfoW(result)
 	if result == nil {
-		return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
+		return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
 	}
 	addr := unsafe.Pointer(result.Addr)
 	switch result.Family {
@@ -203,10 +210,10 @@
 		a := (*syscall.RawSockaddrInet6)(addr)
 		return int(syscall.Ntohs(a.Port)), nil
 	}
-	return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
+	return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
 }
 
-func lookupCNAME(name string) (cname string, err error) {
+func lookupCNAME(name string) (string, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -220,16 +227,16 @@
 		return name, nil
 	}
 	if e != nil {
-		return "", os.NewSyscallError("LookupCNAME", e)
+		return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
 	resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
-	cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
-	return
+	cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
+	return cname, nil
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	acquireThread()
 	defer releaseThread()
 	var target string
@@ -241,78 +248,78 @@
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
 	if e != nil {
-		return "", nil, os.NewSyscallError("LookupSRV", e)
+		return "", nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: target}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	addrs = make([]*SRV, 0, 10)
+	srvs := make([]*SRV, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
 		v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
-		addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
+		srvs = append(srvs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
 	}
-	byPriorityWeight(addrs).sort()
-	return name, addrs, nil
+	byPriorityWeight(srvs).sort()
+	return name, srvs, nil
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
+func lookupMX(name string) ([]*MX, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupMX", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	mx = make([]*MX, 0, 10)
+	mxs := make([]*MX, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
 		v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
-		mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+		mxs = append(mxs, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
 	}
-	byPref(mx).sort()
-	return mx, nil
+	byPref(mxs).sort()
+	return mxs, nil
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
+func lookupNS(name string) ([]*NS, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupNS", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	ns = make([]*NS, 0, 10)
+	nss := make([]*NS, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
 		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-		ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
+		nss = append(nss, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
 	}
-	return ns, nil
+	return nss, nil
 }
 
-func lookupTXT(name string) (txt []string, err error) {
+func lookupTXT(name string) ([]string, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupTXT", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	txt = make([]string, 0, 10)
+	txts := make([]string, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) {
 		d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0]))
 		for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] {
 			s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:])
-			txt = append(txt, s)
+			txts = append(txts, s)
 		}
 	}
-	return
+	return txts, nil
 }
 
-func lookupAddr(addr string) (name []string, err error) {
+func lookupAddr(addr string) ([]string, error) {
 	acquireThread()
 	defer releaseThread()
 	arpa, err := reverseaddr(addr)
@@ -322,16 +329,16 @@
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupAddr", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: addr}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	name = make([]string, 0, 10)
+	ptrs := make([]string, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
 		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-		name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+		ptrs = append(ptrs, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
 	}
-	return name, nil
+	return ptrs, nil
 }
 
 const dnsSectionMask = 0x0003
diff --git a/src/net/lookup_windows_test.go b/src/net/lookup_windows_test.go
index 7495b5b..3f64d8c 100644
--- a/src/net/lookup_windows_test.go
+++ b/src/net/lookup_windows_test.go
@@ -26,12 +26,13 @@
 
 func TestLookupMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		mx, err := LookupMX(server)
 		if err != nil {
-			t.Errorf("failed %s: %s", server, err)
+			t.Error(err)
 			continue
 		}
 		if len(mx) == 0 {
@@ -52,8 +53,9 @@
 
 func TestLookupCNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		cname, err := LookupCNAME(server)
 		if err != nil {
@@ -76,8 +78,9 @@
 
 func TestLookupNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		ns, err := LookupNS(server)
 		if err != nil {
@@ -103,8 +106,9 @@
 
 func TestLookupTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		txt, err := LookupTXT(server)
 		if err != nil {
diff --git a/src/net/mac.go b/src/net/mac.go
index d616b1f..8594a91 100644
--- a/src/net/mac.go
+++ b/src/net/mac.go
@@ -2,12 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// MAC address manipulations
-
 package net
 
-import "errors"
-
 const hexDigit = "0123456789abcdef"
 
 // A HardwareAddr represents a physical hardware address.
@@ -82,5 +78,5 @@
 	return hw, nil
 
 error:
-	return nil, errors.New("invalid MAC address: " + s)
+	return nil, &AddrError{Err: "invalid MAC address", Addr: s}
 }
diff --git a/src/net/mac_test.go b/src/net/mac_test.go
index 8f9dc66..0af0c01 100644
--- a/src/net/mac_test.go
+++ b/src/net/mac_test.go
@@ -10,7 +10,7 @@
 	"testing"
 )
 
-var mactests = []struct {
+var parseMACTests = []struct {
 	in  string
 	out HardwareAddr
 	err string
@@ -36,19 +36,18 @@
 	{"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
 }
 
-func match(err error, s string) bool {
-	if s == "" {
-		return err == nil
+func TestParseMAC(t *testing.T) {
+	match := func(err error, s string) bool {
+		if s == "" {
+			return err == nil
+		}
+		return err != nil && strings.Contains(err.Error(), s)
 	}
-	return err != nil && strings.Contains(err.Error(), s)
-}
 
-func TestMACParseString(t *testing.T) {
-	for i, tt := range mactests {
+	for i, tt := range parseMACTests {
 		out, err := ParseMAC(tt.in)
 		if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
-			t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
-				tt.err)
+			t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out, tt.err)
 		}
 		if tt.err == "" {
 			// Verify that serialization works too, and that it round-trips.
diff --git a/src/net/main_plan9_test.go b/src/net/main_plan9_test.go
index bbd47aa..94501cad 100644
--- a/src/net/main_plan9_test.go
+++ b/src/net/main_plan9_test.go
@@ -9,3 +9,7 @@
 func uninstallTestHooks() {}
 
 func forceCloseSockets() {}
+
+func enableSocketConnect() {}
+
+func disableSocketConnect(network string) {}
diff --git a/src/net/main_posix_test.go b/src/net/main_posix_test.go
new file mode 100644
index 0000000..ead311c
--- /dev/null
+++ b/src/net/main_posix_test.go
@@ -0,0 +1,50 @@
+// 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 !plan9
+
+package net
+
+import (
+	"net/internal/socktest"
+	"strings"
+	"syscall"
+)
+
+func enableSocketConnect() {
+	sw.Set(socktest.FilterConnect, nil)
+}
+
+func disableSocketConnect(network string) {
+	ss := strings.Split(network, ":")
+	sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		switch ss[0] {
+		case "tcp4":
+			if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_STREAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "udp4":
+			if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_DGRAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "ip4":
+			if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_RAW {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "tcp6":
+			if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_STREAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "udp6":
+			if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_DGRAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "ip6":
+			if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_RAW {
+				return nil, syscall.EHOSTUNREACH
+			}
+		}
+		return nil, nil
+	})
+}
diff --git a/src/net/main_test.go b/src/net/main_test.go
index bc0f92e..a56b9cd 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -5,32 +5,93 @@
 package net
 
 import (
+	"flag"
 	"fmt"
 	"net/internal/socktest"
 	"os"
 	"runtime"
 	"sort"
 	"strings"
+	"sync"
 	"testing"
 )
 
-var sw socktest.Switch
+var (
+	sw socktest.Switch
+
+	// uninstallTestHooks runs just before a run of benchmarks.
+	testHookUninstaller sync.Once
+)
+
+var (
+	testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
+
+	testExternal = flag.Bool("external", true, "allow use of external networks during long test")
+
+	// If external IPv4 connectivity exists, we can try dialing
+	// non-node/interface local scope IPv4 addresses.
+	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.
+	testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists")
+)
 
 func TestMain(m *testing.M) {
+	setupTestData()
 	installTestHooks()
 
 	st := m.Run()
 
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 	if !testing.Short() {
 		printLeakedGoroutines()
 		printLeakedSockets()
 		printSocketStats()
 	}
 	forceCloseSockets()
-	uninstallTestHooks()
 	os.Exit(st)
 }
 
+func setupTestData() {
+	if supportsIPv4 {
+		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
+			{"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
+			{"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
+		}...)
+		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
+			{"udp", "localhost:1", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
+			{"udp4", "localhost:2", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
+		}...)
+		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+		}...)
+	}
+
+	if supportsIPv6 {
+		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil})
+		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil})
+		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil})
+	}
+
+	if ifi := loopbackInterface(); 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},
+			{"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
+		}...)
+		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
+			{"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil},
+			{"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
+		}...)
+		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
+			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
+		}...)
+	}
+}
+
 func printLeakedGoroutines() {
 	gss := leakedGoroutines()
 	if len(gss) == 0 {
@@ -43,8 +104,8 @@
 	fmt.Fprintf(os.Stderr, "\n")
 }
 
-// leakedGoroutines returns a list of remaining goroutins used in test
-// cases.
+// leakedGoroutines returns a list of remaining goroutines used in
+// test cases.
 func leakedGoroutines() []string {
 	var gss []string
 	b := make([]byte, 2<<20)
@@ -71,7 +132,7 @@
 	}
 	fmt.Fprintf(os.Stderr, "Leaked sockets:\n")
 	for s, so := range sos {
-		fmt.Fprintf(os.Stderr, "%v: %+v\n", s, so)
+		fmt.Fprintf(os.Stderr, "%v: %v\n", s, so)
 	}
 	fmt.Fprintf(os.Stderr, "\n")
 }
@@ -83,7 +144,7 @@
 	}
 	fmt.Fprintf(os.Stderr, "Socket statistical information:\n")
 	for _, st := range sts {
-		fmt.Fprintf(os.Stderr, "%+v\n", st)
+		fmt.Fprintf(os.Stderr, "%v\n", st)
 	}
 	fmt.Fprintf(os.Stderr, "\n")
 }
diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go
index 637ac3d..bfb4cd0 100644
--- a/src/net/main_unix_test.go
+++ b/src/net/main_unix_test.go
@@ -11,6 +11,7 @@
 	origSocket        = socketFunc
 	origClose         = closeFunc
 	origConnect       = connectFunc
+	origListen        = listenFunc
 	origAccept        = acceptFunc
 	origGetsockoptInt = getsockoptIntFunc
 
@@ -22,6 +23,7 @@
 	socketFunc = sw.Socket
 	closeFunc = sw.Close
 	connectFunc = sw.Connect
+	listenFunc = sw.Listen
 	acceptFunc = sw.Accept
 	getsockoptIntFunc = sw.GetsockoptInt
 
@@ -34,6 +36,7 @@
 	socketFunc = origSocket
 	closeFunc = origClose
 	connectFunc = origConnect
+	listenFunc = origListen
 	acceptFunc = origAccept
 	getsockoptIntFunc = origGetsockoptInt
 
diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go
index 03c3796..2d82974 100644
--- a/src/net/main_windows_test.go
+++ b/src/net/main_windows_test.go
@@ -10,6 +10,7 @@
 	origClosesocket = closeFunc
 	origConnect     = connectFunc
 	origConnectEx   = connectExFunc
+	origListen      = listenFunc
 )
 
 func installTestHooks() {
@@ -17,6 +18,7 @@
 	closeFunc = sw.Closesocket
 	connectFunc = sw.Connect
 	connectExFunc = sw.ConnectEx
+	listenFunc = sw.Listen
 }
 
 func uninstallTestHooks() {
@@ -24,6 +26,7 @@
 	closeFunc = origClosesocket
 	connectFunc = origConnect
 	connectExFunc = origConnectEx
+	listenFunc = origListen
 }
 
 func forceCloseSockets() {
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index 68ded5d..62bcfa4 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -4,11 +4,123 @@
 
 package net
 
-import "sync"
+import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"sync"
+	"testing"
+	"time"
+)
+
+// testUnixAddr uses ioutil.TempFile to get a name that is unique.
+// It also uses /tmp directory in case it is prohibited to create UNIX
+// sockets in TMPDIR.
+func testUnixAddr() string {
+	f, err := ioutil.TempFile("", "go-nettest")
+	if err != nil {
+		panic(err)
+	}
+	addr := f.Name()
+	f.Close()
+	os.Remove(addr)
+	return addr
+}
+
+func newLocalListener(network string) (Listener, error) {
+	switch network {
+	case "tcp", "tcp4", "tcp6":
+		if supportsIPv4 {
+			return Listen("tcp4", "127.0.0.1:0")
+		}
+		if supportsIPv6 {
+			return Listen("tcp6", "[::1]:0")
+		}
+	case "unix", "unixpacket":
+		return Listen(network, testUnixAddr())
+	}
+	return nil, fmt.Errorf("%s is not supported", network)
+}
+
+func newDualStackListener() (lns []*TCPListener, err error) {
+	var args = []struct {
+		network string
+		TCPAddr
+	}{
+		{"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}},
+		{"tcp6", TCPAddr{IP: IPv6loopback}},
+	}
+	for i := 0; i < 64; i++ {
+		var port int
+		var lns []*TCPListener
+		for _, arg := range args {
+			arg.TCPAddr.Port = port
+			ln, err := ListenTCP(arg.network, &arg.TCPAddr)
+			if err != nil {
+				continue
+			}
+			port = ln.Addr().(*TCPAddr).Port
+			lns = append(lns, ln)
+		}
+		if len(lns) != len(args) {
+			for _, ln := range lns {
+				ln.Close()
+			}
+			continue
+		}
+		return lns, nil
+	}
+	return nil, errors.New("no dualstack port available")
+}
+
+type localServer struct {
+	lnmu sync.RWMutex
+	Listener
+	done chan bool // signal that indicates server stopped
+}
+
+func (ls *localServer) buildup(handler func(*localServer, Listener)) error {
+	go func() {
+		handler(ls, ls.Listener)
+		close(ls.done)
+	}()
+	return nil
+}
+
+func (ls *localServer) teardown() error {
+	ls.lnmu.Lock()
+	if ls.Listener != nil {
+		network := ls.Listener.Addr().Network()
+		address := ls.Listener.Addr().String()
+		ls.Listener.Close()
+		<-ls.done
+		ls.Listener = nil
+		switch network {
+		case "unix", "unixpacket":
+			os.Remove(address)
+		}
+	}
+	ls.lnmu.Unlock()
+	return nil
+}
+
+func newLocalServer(network string) (*localServer, error) {
+	ln, err := newLocalListener(network)
+	if err != nil {
+		return nil, err
+	}
+	return &localServer{Listener: ln, done: make(chan bool)}, nil
+}
 
 type streamListener struct {
-	net, addr string
-	ln        Listener
+	network, address string
+	Listener
+	done chan bool // signal that indicates server stopped
+}
+
+func (sl *streamListener) newLocalServer() (*localServer, error) {
+	return &localServer{Listener: sl.Listener, done: make(chan bool)}, nil
 }
 
 type dualStackServer struct {
@@ -20,9 +132,12 @@
 	cs  []Conn // established connections at the passive open side
 }
 
-func (dss *dualStackServer) buildup(server func(*dualStackServer, Listener)) error {
+func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error {
 	for i := range dss.lns {
-		go server(dss, dss.lns[i].ln)
+		go func(i int) {
+			handler(dss, dss.lns[i].Listener)
+			close(dss.lns[i].done)
+		}(i)
 	}
 	return nil
 }
@@ -34,12 +149,13 @@
 	return nil
 }
 
-func (dss *dualStackServer) teardownNetwork(net string) error {
+func (dss *dualStackServer) teardownNetwork(network string) error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
-		if net == dss.lns[i].net && dss.lns[i].ln != nil {
-			dss.lns[i].ln.Close()
-			dss.lns[i].ln = nil
+		if network == dss.lns[i].network && dss.lns[i].Listener != nil {
+			dss.lns[i].Listener.Close()
+			<-dss.lns[i].done
+			dss.lns[i].Listener = nil
 		}
 	}
 	dss.lnmu.Unlock()
@@ -49,15 +165,18 @@
 func (dss *dualStackServer) teardown() error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
-		if dss.lns[i].ln != nil {
-			dss.lns[i].ln.Close()
+		if dss.lns[i].Listener != nil {
+			dss.lns[i].Listener.Close()
+			<-dss.lns[i].done
 		}
 	}
+	dss.lns = dss.lns[:0]
 	dss.lnmu.Unlock()
 	dss.cmu.Lock()
 	for _, c := range dss.cs {
 		c.Close()
 	}
+	dss.cs = dss.cs[:0]
 	dss.cmu.Unlock()
 	return nil
 }
@@ -65,18 +184,333 @@
 func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
 	dss := &dualStackServer{lns: lns, port: "0"}
 	for i := range dss.lns {
-		ln, err := Listen(dss.lns[i].net, dss.lns[i].addr+":"+dss.port)
+		ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
 		if err != nil {
-			dss.teardown()
+			for _, ln := range dss.lns {
+				ln.Listener.Close()
+			}
 			return nil, err
 		}
-		dss.lns[i].ln = ln
+		dss.lns[i].Listener = ln
+		dss.lns[i].done = make(chan bool)
 		if dss.port == "0" {
 			if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil {
-				dss.teardown()
+				for _, ln := range dss.lns {
+					ln.Listener.Close()
+				}
 				return nil, err
 			}
 		}
 	}
 	return dss, nil
 }
+
+func transponder(ln Listener, ch chan<- error) {
+	defer close(ch)
+
+	switch ln := ln.(type) {
+	case *TCPListener:
+		ln.SetDeadline(time.Now().Add(someTimeout))
+	case *UnixListener:
+		ln.SetDeadline(time.Now().Add(someTimeout))
+	}
+	c, err := ln.Accept()
+	if err != nil {
+		if perr := parseAcceptError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	defer c.Close()
+
+	network := ln.Addr().Network()
+	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+		ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
+		return
+	}
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	b := make([]byte, 256)
+	n, err := c.Read(b)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if _, err := c.Write(b[:n]); err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+}
+
+func transceiver(c Conn, wb []byte, ch chan<- error) {
+	defer close(ch)
+
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	n, err := c.Write(wb)
+	if err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
+	}
+	rb := make([]byte, len(wb))
+	n, err = c.Read(rb)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("read %d; want %d", n, len(wb))
+	}
+}
+
+func timeoutReceiver(c Conn, d, min, max time.Duration, ch chan<- error) {
+	var err error
+	defer func() { ch <- err }()
+
+	t0 := time.Now()
+	if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
+		return
+	}
+	b := make([]byte, 256)
+	var n int
+	n, err = c.Read(b)
+	t1 := time.Now()
+	if n != 0 || err == nil || !err.(Error).Timeout() {
+		err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
+		return
+	}
+	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
+		err = fmt.Errorf("Read took %s; expected %s", dt, d)
+		return
+	}
+}
+
+func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
+	var err error
+	defer func() { ch <- err }()
+
+	t0 := time.Now()
+	if err = c.SetWriteDeadline(time.Now().Add(d)); err != nil {
+		return
+	}
+	var n int
+	for {
+		n, err = c.Write([]byte("TIMEOUT TRANSMITTER"))
+		if err != nil {
+			break
+		}
+	}
+	t1 := time.Now()
+	if err == nil || !err.(Error).Timeout() {
+		err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err)
+		return
+	}
+	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
+		err = fmt.Errorf("Write took %s; expected %s", dt, d)
+		return
+	}
+}
+
+func newLocalPacketListener(network string) (PacketConn, error) {
+	switch network {
+	case "udp", "udp4", "udp6":
+		if supportsIPv4 {
+			return ListenPacket("udp4", "127.0.0.1:0")
+		}
+		if supportsIPv6 {
+			return ListenPacket("udp6", "[::1]:0")
+		}
+	case "unixgram":
+		return ListenPacket(network, testUnixAddr())
+	}
+	return nil, fmt.Errorf("%s is not supported", network)
+}
+
+func newDualStackPacketListener() (cs []*UDPConn, err error) {
+	var args = []struct {
+		network string
+		UDPAddr
+	}{
+		{"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}},
+		{"udp6", UDPAddr{IP: IPv6loopback}},
+	}
+	for i := 0; i < 64; i++ {
+		var port int
+		var cs []*UDPConn
+		for _, arg := range args {
+			arg.UDPAddr.Port = port
+			c, err := ListenUDP(arg.network, &arg.UDPAddr)
+			if err != nil {
+				continue
+			}
+			port = c.LocalAddr().(*UDPAddr).Port
+			cs = append(cs, c)
+		}
+		if len(cs) != len(args) {
+			for _, c := range cs {
+				c.Close()
+			}
+			continue
+		}
+		return cs, nil
+	}
+	return nil, errors.New("no dualstack port available")
+}
+
+type localPacketServer struct {
+	pcmu sync.RWMutex
+	PacketConn
+	done chan bool // signal that indicates server stopped
+}
+
+func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error {
+	go func() {
+		handler(ls, ls.PacketConn)
+		close(ls.done)
+	}()
+	return nil
+}
+
+func (ls *localPacketServer) teardown() error {
+	ls.pcmu.Lock()
+	if ls.PacketConn != nil {
+		network := ls.PacketConn.LocalAddr().Network()
+		address := ls.PacketConn.LocalAddr().String()
+		ls.PacketConn.Close()
+		<-ls.done
+		ls.PacketConn = nil
+		switch network {
+		case "unixgram":
+			os.Remove(address)
+		}
+	}
+	ls.pcmu.Unlock()
+	return nil
+}
+
+func newLocalPacketServer(network string) (*localPacketServer, error) {
+	c, err := newLocalPacketListener(network)
+	if err != nil {
+		return nil, err
+	}
+	return &localPacketServer{PacketConn: c, done: make(chan bool)}, nil
+}
+
+type packetListener struct {
+	PacketConn
+}
+
+func (pl *packetListener) newLocalServer() (*localPacketServer, error) {
+	return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}, nil
+}
+
+func packetTransponder(c PacketConn, ch chan<- error) {
+	defer close(ch)
+
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	b := make([]byte, 256)
+	n, peer, err := c.ReadFrom(b)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if peer == nil { // for connected-mode sockets
+		switch c.LocalAddr().Network() {
+		case "udp":
+			peer, err = ResolveUDPAddr("udp", string(b[:n]))
+		case "unixgram":
+			peer, err = ResolveUnixAddr("unixgram", string(b[:n]))
+		}
+		if err != nil {
+			ch <- err
+			return
+		}
+	}
+	if _, err := c.WriteTo(b[:n], peer); err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+}
+
+func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) {
+	defer close(ch)
+
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	n, err := c.WriteTo(wb, dst)
+	if err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
+	}
+	rb := make([]byte, len(wb))
+	n, _, err = c.ReadFrom(rb)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("read %d; want %d", n, len(wb))
+	}
+}
+
+func timeoutPacketReceiver(c PacketConn, d, min, max time.Duration, ch chan<- error) {
+	var err error
+	defer func() { ch <- err }()
+
+	t0 := time.Now()
+	if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
+		return
+	}
+	b := make([]byte, 256)
+	var n int
+	n, _, err = c.ReadFrom(b)
+	t1 := time.Now()
+	if n != 0 || err == nil || !err.(Error).Timeout() {
+		err = fmt.Errorf("ReadFrom did not return (0, timeout): (%d, %v)", n, err)
+		return
+	}
+	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
+		err = fmt.Errorf("ReadFrom took %s; expected %s", dt, d)
+		return
+	}
+}
diff --git a/src/net/multicast_test.go b/src/net/multicast_test.go
deleted file mode 100644
index 5f253f4..0000000
--- a/src/net/multicast_test.go
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2011 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"
-	"runtime"
-	"testing"
-)
-
-var ipv4MulticastListenerTests = []struct {
-	net   string
-	gaddr *UDPAddr // see RFC 4727
-}{
-	{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
-
-	{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
-}
-
-// TestIPv4MulticastListener tests both single and double listen to a
-// test listener with same address family, same group address and same
-// port.
-func TestIPv4MulticastListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl", "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	case "solaris":
-		t.Skipf("skipping test on solaris, see issue 7399")
-	}
-
-	closer := func(cs []*UDPConn) {
-		for _, c := range cs {
-			if c != nil {
-				c.Close()
-			}
-		}
-	}
-
-	for _, ifi := range []*Interface{loopbackInterface(), nil} {
-		// Note that multicast interface assignment by system
-		// is not recommended because it usually relies on
-		// routing stuff for finding out an appropriate
-		// nexthop containing both network and link layer
-		// adjacencies.
-		if ifi == nil && !*testExternal {
-			continue
-		}
-		for _, tt := range ipv4MulticastListenerTests {
-			var err error
-			cs := make([]*UDPConn, 2)
-			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				closer(cs)
-				t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			closer(cs)
-		}
-	}
-}
-
-var ipv6MulticastListenerTests = []struct {
-	net   string
-	gaddr *UDPAddr // see RFC 4727
-}{
-	{"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
-
-	{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
-}
-
-// TestIPv6MulticastListener tests both single and double listen to a
-// test listener with same address family, same group address and same
-// port.
-func TestIPv6MulticastListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	case "solaris":
-		t.Skipf("skipping test on solaris, see issue 7399")
-	}
-	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-	if os.Getuid() != 0 {
-		t.Skip("skipping test; must be root")
-	}
-
-	closer := func(cs []*UDPConn) {
-		for _, c := range cs {
-			if c != nil {
-				c.Close()
-			}
-		}
-	}
-
-	for _, ifi := range []*Interface{loopbackInterface(), nil} {
-		// Note that multicast interface assignment by system
-		// is not recommended because it usually relies on
-		// routing stuff for finding out an appropriate
-		// nexthop containing both network and link layer
-		// adjacencies.
-		if ifi == nil && (!*testExternal || !*testIPv6) {
-			continue
-		}
-		for _, tt := range ipv6MulticastListenerTests {
-			var err error
-			cs := make([]*UDPConn, 2)
-			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				closer(cs)
-				t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			closer(cs)
-		}
-	}
-}
-
-func checkMulticastListener(c *UDPConn, ip IP) error {
-	if ok, err := multicastRIBContains(ip); err != nil {
-		return err
-	} else if !ok {
-		return fmt.Errorf("%q not found in multicast RIB", ip.String())
-	}
-	la := c.LocalAddr()
-	if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
-		return fmt.Errorf("got %v; expected a proper address with non-zero port number", la)
-	}
-	return nil
-}
-
-func multicastRIBContains(ip IP) (bool, error) {
-	switch runtime.GOOS {
-	case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows":
-		return true, nil // not implemented yet
-	case "linux":
-		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
-			return true, nil // not implemented yet
-		}
-	}
-	ift, err := Interfaces()
-	if err != nil {
-		return false, err
-	}
-	for _, ifi := range ift {
-		ifmat, err := ifi.MulticastAddrs()
-		if err != nil {
-			return false, err
-		}
-		for _, ifma := range ifmat {
-			if ifma.(*IPAddr).IP.Equal(ip) {
-				return true, nil
-			}
-		}
-	}
-	return false, nil
-}
diff --git a/src/net/net.go b/src/net/net.go
index 339c972..fbeac81 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -46,6 +46,12 @@
 	"time"
 )
 
+func init() {
+	sysInit()
+	supportsIPv4 = probeIPv4Stack()
+	supportsIPv6, supportsIPv4map = probeIPv6Stack()
+}
+
 // Addr represents a network end point address.
 type Addr interface {
 	Network() string // name of the network
@@ -115,7 +121,11 @@
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	return c.fd.Read(b)
+	n, err := c.fd.Read(b)
+	if err != nil && err != io.EOF {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // Write implements the Conn Write method.
@@ -123,7 +133,11 @@
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	return c.fd.Write(b)
+	n, err := c.fd.Write(b)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // Close closes the connection.
@@ -131,7 +145,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.Close()
+	err := c.fd.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // LocalAddr returns the local network address.
@@ -159,7 +177,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.setDeadline(t)
+	if err := c.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetReadDeadline implements the Conn SetReadDeadline method.
@@ -167,7 +188,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.setReadDeadline(t)
+	if err := c.fd.setReadDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetWriteDeadline implements the Conn SetWriteDeadline method.
@@ -175,7 +199,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.setWriteDeadline(t)
+	if err := c.fd.setWriteDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetReadBuffer sets the size of the operating system's
@@ -184,7 +211,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setReadBuffer(c.fd, bytes)
+	if err := setReadBuffer(c.fd, bytes); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetWriteBuffer sets the size of the operating system's
@@ -193,7 +223,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setWriteBuffer(c.fd, bytes)
+	if err := setWriteBuffer(c.fd, bytes); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File sets the underlying os.File to blocking mode and returns a copy.
@@ -203,13 +236,12 @@
 // The returned os.File's file descriptor is different from the connection's.
 // Attempting to change properties of the original using this duplicate
 // may or may not have the desired effect.
-func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
-
-// An Error represents a network error.
-type Error interface {
-	error
-	Timeout() bool   // Is the error a timeout?
-	Temporary() bool // Is the error temporary?
+func (c *conn) File() (f *os.File, err error) {
+	f, err = c.fd.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return
 }
 
 // PacketConn is a generic packet-oriented network connection.
@@ -275,6 +307,13 @@
 	Addr() Addr
 }
 
+// An Error represents a network error.
+type Error interface {
+	error
+	Timeout() bool   // Is the error a timeout?
+	Temporary() bool // Is the error temporary?
+}
+
 // Various errors contained in OpError.
 var (
 	// For connection setup and write operations.
@@ -298,7 +337,17 @@
 	// such as "tcp" or "udp6".
 	Net string
 
-	// Addr is the network address on which this error occurred.
+	// For operations involving a remote network connection, like
+	// Dial, Read, or Write, Source is the corresponding local
+	// network address.
+	Source Addr
+
+	// Addr is the network address for which this error occurred.
+	// For local operations, like Listen or SetDeadline, Addr is
+	// the address of the local endpoint being manipulated.
+	// For operations involving a remote network connection, like
+	// Dial, Read, or Write, Addr is the remote address of that
+	// connection.
 	Addr Addr
 
 	// Err is the error that occurred during the operation.
@@ -313,22 +362,21 @@
 	if e.Net != "" {
 		s += " " + e.Net
 	}
+	if e.Source != nil {
+		s += " " + e.Source.String()
+	}
 	if e.Addr != nil {
-		s += " " + e.Addr.String()
+		if e.Source != nil {
+			s += "->"
+		} else {
+			s += " "
+		}
+		s += e.Addr.String()
 	}
 	s += ": " + e.Err.Error()
 	return s
 }
 
-type temporary interface {
-	Temporary() bool
-}
-
-func (e *OpError) Temporary() bool {
-	t, ok := e.Err.(temporary)
-	return ok && t.Temporary()
-}
-
 var noDeadline = time.Time{}
 
 type timeout interface {
@@ -336,16 +384,45 @@
 }
 
 func (e *OpError) Timeout() bool {
+	if ne, ok := e.Err.(*os.SyscallError); ok {
+		t, ok := ne.Err.(timeout)
+		return ok && t.Timeout()
+	}
 	t, ok := e.Err.(timeout)
 	return ok && t.Timeout()
 }
 
+type temporary interface {
+	Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+	if ne, ok := e.Err.(*os.SyscallError); ok {
+		t, ok := ne.Err.(temporary)
+		return ok && t.Temporary()
+	}
+	t, ok := e.Err.(temporary)
+	return ok && t.Temporary()
+}
+
 type timeoutError struct{}
 
 func (e *timeoutError) Error() string   { return "i/o timeout" }
 func (e *timeoutError) Timeout() bool   { return true }
 func (e *timeoutError) Temporary() bool { return true }
 
+// A ParseError is the error type of literal network address parsers.
+type ParseError struct {
+	// Type is the type of string that was expected, such as
+	// "IP address", "CIDR address".
+	Type string
+
+	// Text is the malformed text string.
+	Text string
+}
+
+func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
+
 type AddrError struct {
 	Err  string
 	Addr string
@@ -362,19 +439,14 @@
 	return s
 }
 
-func (e *AddrError) Temporary() bool {
-	return false
-}
-
-func (e *AddrError) Timeout() bool {
-	return false
-}
+func (e *AddrError) Timeout() bool   { return false }
+func (e *AddrError) Temporary() bool { return false }
 
 type UnknownNetworkError string
 
 func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
-func (e UnknownNetworkError) Temporary() bool { return false }
 func (e UnknownNetworkError) Timeout() bool   { return false }
+func (e UnknownNetworkError) Temporary() bool { return false }
 
 type InvalidAddrError string
 
@@ -383,17 +455,50 @@
 func (e InvalidAddrError) Temporary() bool { return false }
 
 // DNSConfigError represents an error reading the machine's DNS configuration.
+// (No longer used; kept for compatibility.)
 type DNSConfigError struct {
 	Err error
 }
 
-func (e *DNSConfigError) Error() string {
-	return "error reading DNS config: " + e.Err.Error()
-}
-
+func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
 func (e *DNSConfigError) Timeout() bool   { return false }
 func (e *DNSConfigError) Temporary() bool { return false }
 
+// Various errors contained in DNSError.
+var (
+	errNoSuchHost = errors.New("no such host")
+)
+
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+	Err       string // description of the error
+	Name      string // name looked for
+	Server    string // server used
+	IsTimeout bool   // if true, timed out; not all timeouts set this
+}
+
+func (e *DNSError) Error() string {
+	if e == nil {
+		return "<nil>"
+	}
+	s := "lookup " + e.Name
+	if e.Server != "" {
+		s += " on " + e.Server
+	}
+	s += ": " + e.Err
+	return s
+}
+
+// Timeout reports whether the DNS lookup is known to have timed out.
+// This is not always known; a DNS lookup may fail due to a timeout
+// and return a DNSError for which Timeout returns false.
+func (e *DNSError) Timeout() bool { return e.IsTimeout }
+
+// Temporary reports whether the DNS error is known to be temporary.
+// This is not always known; a DNS lookup may fail due to a temporary
+// error and return a DNSError for which Temporary returns false.
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
 type writerOnly struct {
 	io.Writer
 }
@@ -413,10 +518,6 @@
 
 var threadLimit = make(chan struct{}, 500)
 
-// Using send for acquire is fine here because we are not using this
-// to protect any memory. All we care about is the number of goroutines
-// making calls at a time.
-
 func acquireThread() {
 	threadLimit <- struct{}{}
 }
diff --git a/src/net/net_test.go b/src/net/net_test.go
index 5a88363..3907ce4 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -6,258 +6,251 @@
 
 import (
 	"io"
-	"io/ioutil"
 	"os"
 	"runtime"
 	"testing"
-	"time"
 )
 
-func TestShutdown(t *testing.T) {
-	if runtime.GOOS == "plan9" {
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		if ln, err = Listen("tcp6", "[::1]:0"); err != nil {
-			t.Fatalf("ListenTCP on :0: %v", err)
-		}
+func TestCloseRead(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	go func() {
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
+
+		ln, err := newLocalListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(ln.Addr().String())
+		}
 		defer ln.Close()
-		c, err := ln.Accept()
+
+		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
 		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
+			t.Fatal(err)
 		}
-		var buf [10]byte
-		n, err := c.Read(buf[:])
-		if n != 0 || err != io.EOF {
-			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
-			return
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(c.LocalAddr().String())
 		}
-		c.Write([]byte("response"))
-		c.Close()
-	}()
+		defer c.Close()
 
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-
-	err = c.(*TCPConn).CloseWrite()
-	if err != nil {
-		t.Fatalf("CloseWrite: %v", err)
-	}
-	var buf [10]byte
-	n, err := c.Read(buf[:])
-	if err != nil {
-		t.Fatalf("client Read: %d, %v", n, err)
-	}
-	got := string(buf[:n])
-	if got != "response" {
-		t.Errorf("read = %q, want \"response\"", got)
+		switch c := c.(type) {
+		case *TCPConn:
+			err = c.CloseRead()
+		case *UnixConn:
+			err = c.CloseRead()
+		}
+		if err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, err := c.Read(b[:])
+		if n != 0 || err == nil {
+			t.Fatalf("got (%d, %v); want (0, error)", n, err)
+		}
 	}
 }
 
-func TestShutdownUnix(t *testing.T) {
-	if !testableNetwork("unix") {
-		t.Skip("unix test")
+func TestCloseWrite(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	f, err := ioutil.TempFile("", "go_net_unixtest")
-	if err != nil {
-		t.Fatalf("TempFile: %s", err)
-	}
-	f.Close()
-	tmpname := f.Name()
-	os.Remove(tmpname)
-	ln, err := Listen("unix", tmpname)
-	if err != nil {
-		t.Fatalf("ListenUnix on %s: %s", tmpname, err)
-	}
-	defer func() {
-		ln.Close()
-		os.Remove(tmpname)
-	}()
-
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Errorf("Accept: %v", err)
+			t.Error(err)
 			return
 		}
-		var buf [10]byte
-		n, err := c.Read(buf[:])
+		defer c.Close()
+
+		var b [1]byte
+		n, err := c.Read(b[:])
 		if n != 0 || err != io.EOF {
-			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+			t.Errorf("got (%d, %v); want (0, io.EOF)", n, err)
 			return
 		}
-		c.Write([]byte("response"))
-		c.Close()
-	}()
+		switch c := c.(type) {
+		case *TCPConn:
+			err = c.CloseWrite()
+		case *UnixConn:
+			err = c.CloseWrite()
+		}
+		if err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Error(err)
+			return
+		}
+		n, err = c.Write(b[:])
+		if err == nil {
+			t.Errorf("got (%d, %v); want (any, error)", n, err)
+			return
+		}
+	}
 
-	c, err := Dial("unix", tmpname)
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
 
-	err = c.(*UnixConn).CloseWrite()
-	if err != nil {
-		t.Fatalf("CloseWrite: %v", err)
-	}
-	var buf [10]byte
-	n, err := c.Read(buf[:])
-	if err != nil {
-		t.Fatalf("client Read: %d, %v", n, err)
-	}
-	got := string(buf[:n])
-	if got != "response" {
-		t.Errorf("read = %q, want \"response\"", got)
+		ls, err := newLocalServer(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+
+		c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
+
+		switch c := c.(type) {
+		case *TCPConn:
+			err = c.CloseWrite()
+		case *UnixConn:
+			err = c.CloseWrite()
+		}
+		if err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, err := c.Read(b[:])
+		if n != 0 || err != io.EOF {
+			t.Fatalf("got (%d, %v); want (0, io.EOF)", n, err)
+		}
+		n, err = c.Write(b[:])
+		if err == nil {
+			t.Fatalf("got (%d, %v); want (any, error)", n, err)
+		}
 	}
 }
 
-func TestTCPListenClose(t *testing.T) {
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
+func TestConnClose(t *testing.T) {
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
 
-	done := make(chan bool, 1)
-	go func() {
-		time.Sleep(100 * time.Millisecond)
-		ln.Close()
-	}()
-	go func() {
+		ln, err := newLocalListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(ln.Addr().String())
+		}
+		defer ln.Close()
+
+		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
+
+		if err := c.Close(); err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, err := c.Read(b[:])
+		if n != 0 || err == nil {
+			t.Fatalf("got (%d, %v); want (0, error)", n, err)
+		}
+	}
+}
+
+func TestListenerClose(t *testing.T) {
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
+
+		ln, err := newLocalListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(ln.Addr().String())
+		}
+		defer ln.Close()
+
+		if err := ln.Close(); err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
 		c, err := ln.Accept()
 		if err == nil {
 			c.Close()
-			t.Error("Accept succeeded")
-		} else {
-			t.Logf("Accept timeout error: %s (any error is fine)", err)
+			t.Fatal("should fail")
 		}
-		done <- true
-	}()
-	select {
-	case <-done:
-	case <-time.After(2 * time.Second):
-		t.Fatal("timeout waiting for TCP close")
 	}
 }
 
-func TestUDPListenClose(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	ln, err := ListenPacket("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
-
-	buf := make([]byte, 1000)
-	done := make(chan bool, 1)
-	go func() {
-		time.Sleep(100 * time.Millisecond)
-		ln.Close()
-	}()
-	go func() {
-		_, _, err = ln.ReadFrom(buf)
-		if err == nil {
-			t.Error("ReadFrom succeeded")
-		} else {
-			t.Logf("ReadFrom timeout error: %s (any error is fine)", err)
+func TestPacketConnClose(t *testing.T) {
+	for _, network := range []string{"udp", "unixgram"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
 		}
-		done <- true
-	}()
-	select {
-	case <-done:
-	case <-time.After(2 * time.Second):
-		t.Fatal("timeout waiting for UDP close")
-	}
-}
 
-func TestTCPClose(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	l, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer l.Close()
-
-	read := func(r io.Reader) error {
-		var m [1]byte
-		_, err := r.Read(m[:])
-		return err
-	}
-
-	go func() {
-		c, err := Dial("tcp", l.Addr().String())
+		c, err := newLocalPacketListener(network)
 		if err != nil {
-			t.Errorf("Dial: %v", err)
-			return
+			t.Fatal(err)
 		}
+		switch network {
+		case "unixgram":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
 
-		go read(c)
-
-		time.Sleep(10 * time.Millisecond)
-		c.Close()
-	}()
-
-	c, err := l.Accept()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	for err == nil {
-		err = read(c)
-	}
-	if err != nil && err != io.EOF {
-		t.Fatal(err)
-	}
-}
-
-func TestErrorNil(t *testing.T) {
-	c, err := Dial("tcp", "127.0.0.1:65535")
-	if err == nil {
-		t.Fatal("Dial 127.0.0.1:65535 succeeded")
-	}
-	if c != nil {
-		t.Fatalf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
-	}
-
-	// Make Listen fail by relistening on the same address.
-	l, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen 127.0.0.1:0: %v", err)
-	}
-	defer l.Close()
-	l1, err := Listen("tcp", l.Addr().String())
-	if err == nil {
-		t.Fatalf("second Listen %v: %v", l.Addr(), err)
-	}
-	if l1 != nil {
-		t.Fatalf("Listen returned non-nil interface %T(%v) with err != nil", l1, l1)
-	}
-
-	// Make ListenPacket fail by relistening on the same address.
-	lp, err := ListenPacket("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen 127.0.0.1:0: %v", err)
-	}
-	defer lp.Close()
-	lp1, err := ListenPacket("udp", lp.LocalAddr().String())
-	if err == nil {
-		t.Fatalf("second Listen %v: %v", lp.LocalAddr(), err)
-	}
-	if lp1 != nil {
-		t.Fatalf("ListenPacket returned non-nil interface %T(%v) with err != nil", lp1, lp1)
+		if err := c.Close(); err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, _, err := c.ReadFrom(b[:])
+		if n != 0 || err == nil {
+			t.Fatalf("got (%d, %v); want (0, error)", n, err)
+		}
 	}
 }
diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go
index 750a430..21b4796 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -16,8 +16,6 @@
 )
 
 func TestAcceptIgnoreSomeErrors(t *testing.T) {
-	t.Skip("skipping temporarily, see issue 8662")
-
 	recv := func(ln Listener) (string, error) {
 		c, err := ln.Accept()
 		if err != nil {
@@ -64,7 +62,7 @@
 		// In child process.
 		c, err := Dial("tcp", envaddr)
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		fmt.Printf("sleeping\n")
 		time.Sleep(time.Minute) // process will be killed here
@@ -73,7 +71,7 @@
 
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 
diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go
index 9fb2a56..1d950d6 100644
--- a/src/net/netgo_unix_test.go
+++ b/src/net/netgo_unix_test.go
@@ -16,9 +16,9 @@
 		t.Errorf("cgoLookupIP must be a placeholder")
 	}
 	if err != nil {
-		t.Errorf("cgoLookupIP failed: %v", err)
+		t.Error(err)
 	}
 	if _, err := goLookupIP(host); err != nil {
-		t.Errorf("goLookupIP failed: %v", err)
+		t.Error(err)
 	}
 }
diff --git a/src/net/nss.go b/src/net/nss.go
new file mode 100644
index 0000000..08c3e6a
--- /dev/null
+++ b/src/net/nss.go
@@ -0,0 +1,159 @@
+// 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 netbsd openbsd solaris
+
+package net
+
+import (
+	"errors"
+	"io"
+	"os"
+)
+
+// nssConf represents the state of the machine's /etc/nsswitch.conf file.
+type nssConf struct {
+	err     error                  // any error encountered opening or parsing the file
+	sources map[string][]nssSource // keyed by database (e.g. "hosts")
+}
+
+type nssSource struct {
+	source   string // e.g. "compat", "files", "mdns4_minimal"
+	criteria []nssCriterion
+}
+
+// standardCriteria reports all specified criteria have the default
+// status actions.
+func (s nssSource) standardCriteria() bool {
+	for i, crit := range s.criteria {
+		if !crit.standardStatusAction(i == len(s.criteria)-1) {
+			return false
+		}
+	}
+	return true
+}
+
+// nssCriterion is the parsed structure of one of the criteria in brackets
+// after an NSS source name.
+type nssCriterion struct {
+	negate bool   // if "!" was present
+	status string // e.g. "success", "unavail" (lowercase)
+	action string // e.g. "return", "continue" (lowercase)
+}
+
+// standardStatusAction reports whether c is equivalent to not
+// specifying the criterion at all. last is whether this criteria is the
+// last in the list.
+func (c nssCriterion) standardStatusAction(last bool) bool {
+	if c.negate {
+		return false
+	}
+	var def string
+	switch c.status {
+	case "success":
+		def = "return"
+	case "notfound", "unavail", "tryagain":
+		def = "continue"
+	default:
+		// Unknown status
+		return false
+	}
+	if last && c.action == "return" {
+		return true
+	}
+	return c.action == def
+}
+
+func parseNSSConfFile(file string) *nssConf {
+	f, err := os.Open(file)
+	if err != nil {
+		return &nssConf{err: err}
+	}
+	defer f.Close()
+	return parseNSSConf(f)
+}
+
+func parseNSSConf(r io.Reader) *nssConf {
+	slurp, err := readFull(r)
+	if err != nil {
+		return &nssConf{err: err}
+	}
+	conf := new(nssConf)
+	conf.err = foreachLine(slurp, func(line []byte) error {
+		line = trimSpace(removeComment(line))
+		if len(line) == 0 {
+			return nil
+		}
+		colon := bytesIndexByte(line, ':')
+		if colon == -1 {
+			return errors.New("no colon on line")
+		}
+		db := string(trimSpace(line[:colon]))
+		srcs := line[colon+1:]
+		for {
+			srcs = trimSpace(srcs)
+			if len(srcs) == 0 {
+				break
+			}
+			sp := bytesIndexByte(srcs, ' ')
+			var src string
+			if sp == -1 {
+				src = string(srcs)
+				srcs = nil // done
+			} else {
+				src = string(srcs[:sp])
+				srcs = trimSpace(srcs[sp+1:])
+			}
+			var criteria []nssCriterion
+			// See if there's a criteria block in brackets.
+			if len(srcs) > 0 && srcs[0] == '[' {
+				bclose := bytesIndexByte(srcs, ']')
+				if bclose == -1 {
+					return errors.New("unclosed criterion bracket")
+				}
+				var err error
+				criteria, err = parseCriteria(srcs[1:bclose])
+				if err != nil {
+					return errors.New("invalid criteria: " + string(srcs[1:bclose]))
+				}
+				srcs = srcs[bclose+1:]
+			}
+			if conf.sources == nil {
+				conf.sources = make(map[string][]nssSource)
+			}
+			conf.sources[db] = append(conf.sources[db], nssSource{
+				source:   src,
+				criteria: criteria,
+			})
+		}
+		return nil
+	})
+	return conf
+}
+
+// parses "foo=bar !foo=bar"
+func parseCriteria(x []byte) (c []nssCriterion, err error) {
+	err = foreachField(x, func(f []byte) error {
+		not := false
+		if len(f) > 0 && f[0] == '!' {
+			not = true
+			f = f[1:]
+		}
+		if len(f) < 3 {
+			return errors.New("criterion too short")
+		}
+		eq := bytesIndexByte(f, '=')
+		if eq == -1 {
+			return errors.New("criterion lacks equal sign")
+		}
+		lowerASCIIBytes(f)
+		c = append(c, nssCriterion{
+			negate: not,
+			status: string(f[:eq]),
+			action: string(f[eq+1:]),
+		})
+		return nil
+	})
+	return
+}
diff --git a/src/net/nss_test.go b/src/net/nss_test.go
new file mode 100644
index 0000000..371deb5
--- /dev/null
+++ b/src/net/nss_test.go
@@ -0,0 +1,169 @@
+// 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 netbsd openbsd solaris
+
+package net
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+const ubuntuTrustyAvahi = `# /etc/nsswitch.conf
+#
+# Example configuration of GNU Name Service Switch functionality.
+# If you have the libc-doc-reference' and nfo' packages installed, try:
+# nfo libc "Name Service Switch"' for information about this file.
+
+passwd:         compat
+group:          compat
+shadow:         compat
+
+hosts:          files mdns4_minimal [NOTFOUND=return] dns mdns4
+networks:       files
+
+protocols:      db files
+services:       db files
+ethers:         db files
+rpc:            db files
+
+netgroup:       nis
+`
+
+func TestParseNSSConf(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		want *nssConf
+	}{
+		{
+			name: "no_newline",
+			in:   "foo: a b",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "newline",
+			in:   "foo: a b\n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "whitespace",
+			in:   "   foo:a    b    \n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "comment1",
+			in:   "   foo:a    b#c\n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "comment2",
+			in:   "   foo:a    b #c \n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "crit",
+			in:   "   foo:a    b [!a=b    X=Y ] c#d \n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {
+						{source: "a"},
+						{
+							source: "b",
+							criteria: []nssCriterion{
+								{
+									negate: true,
+									status: "a",
+									action: "b",
+								},
+								{
+									status: "x",
+									action: "y",
+								},
+							},
+						},
+						{source: "c"},
+					},
+				},
+			},
+		},
+
+		// Ubuntu Trusty w/ avahi-daemon, libavahi-* etc installed.
+		{
+			name: "ubuntu_trusty_avahi",
+			in:   ubuntuTrustyAvahi,
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"passwd": {{source: "compat"}},
+					"group":  {{source: "compat"}},
+					"shadow": {{source: "compat"}},
+					"hosts": {
+						{source: "files"},
+						{
+							source: "mdns4_minimal",
+							criteria: []nssCriterion{
+								{
+									negate: false,
+									status: "notfound",
+									action: "return",
+								},
+							},
+						},
+						{source: "dns"},
+						{source: "mdns4"},
+					},
+					"networks": {{source: "files"}},
+					"protocols": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"services": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"ethers": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"rpc": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"netgroup": {
+						{source: "nis"},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		gotConf := parseNSSConf(strings.NewReader(tt.in))
+		if !reflect.DeepEqual(gotConf, tt.want) {
+			t.Errorf("%s: mismatch\n got %#v\nwant %#v", tt.name, gotConf, tt.want)
+		}
+	}
+}
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index 31e050f..7f3ea8a 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -54,7 +54,7 @@
 
 		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
+			t.Fatal(err)
 		}
 		defer closer(c1, tt.net, tt.addr1, tt.addr2)
 		c1.LocalAddr()
@@ -64,7 +64,7 @@
 
 		c2, err := ListenPacket(tt.net, tt.addr2)
 		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
+			t.Fatal(err)
 		}
 		defer closer(c2, tt.net, tt.addr1, tt.addr2)
 		c2.LocalAddr()
@@ -74,17 +74,17 @@
 		rb2 := make([]byte, 128)
 
 		if _, err := c1.WriteTo(wb, c2.LocalAddr()); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 		if _, _, err := c2.ReadFrom(rb2); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			t.Fatal(err)
 		}
 		if _, err := c2.WriteTo(wb, c1.LocalAddr()); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 		rb1 := make([]byte, 128)
 		if _, _, err := c1.ReadFrom(rb1); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			t.Fatal(err)
 		}
 	}
 }
@@ -109,7 +109,7 @@
 
 		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
+			t.Fatal(err)
 		}
 		defer closer(c1, tt.net, tt.addr1, tt.addr2)
 		c1.LocalAddr()
@@ -119,7 +119,7 @@
 
 		c2, err := Dial(tt.net, c1.LocalAddr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c2.Close()
 		c2.LocalAddr()
@@ -129,11 +129,11 @@
 		c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
 
 		if _, err := c2.Write(wb); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 		rb1 := make([]byte, 128)
 		if _, _, err := c1.ReadFrom(rb1); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			t.Fatal(err)
 		}
 		var dst Addr
 		switch tt.net {
@@ -143,11 +143,11 @@
 			dst = c2.LocalAddr()
 		}
 		if _, err := c1.WriteTo(wb, dst); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 		rb2 := make([]byte, 128)
 		if _, err := c2.Read(rb2); err != nil {
-			t.Fatalf("Conn.Read failed: %v", err)
+			t.Fatal(err)
 		}
 	}
 }
diff --git a/src/net/parse.go b/src/net/parse.go
index ad901ff..5b834e6 100644
--- a/src/net/parse.go
+++ b/src/net/parse.go
@@ -232,3 +232,132 @@
 	}
 	return i
 }
+
+// lowerASCIIBytes makes x ASCII lowercase in-place.
+func lowerASCIIBytes(x []byte) {
+	for i, b := range x {
+		if 'A' <= b && b <= 'Z' {
+			x[i] += 'a' - 'A'
+		}
+	}
+}
+
+// lowerASCII returns the ASCII lowercase version of b.
+func lowerASCII(b byte) byte {
+	if 'A' <= b && b <= 'Z' {
+		return b + ('a' - 'A')
+	}
+	return b
+}
+
+// trimSpace returns x without any leading or trailing ASCII whitespace.
+func trimSpace(x []byte) []byte {
+	for len(x) > 0 && isSpace(x[0]) {
+		x = x[1:]
+	}
+	for len(x) > 0 && isSpace(x[len(x)-1]) {
+		x = x[:len(x)-1]
+	}
+	return x
+}
+
+// isSpace reports whether b is an ASCII space character.
+func isSpace(b byte) bool {
+	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
+
+// removeComment returns line, removing any '#' byte and any following
+// bytes.
+func removeComment(line []byte) []byte {
+	if i := bytesIndexByte(line, '#'); i != -1 {
+		return line[:i]
+	}
+	return line
+}
+
+// foreachLine runs fn on each line of x.
+// Each line (except for possibly the last) ends in '\n'.
+// It returns the first non-nil error returned by fn.
+func foreachLine(x []byte, fn func(line []byte) error) error {
+	for len(x) > 0 {
+		nl := bytesIndexByte(x, '\n')
+		if nl == -1 {
+			return fn(x)
+		}
+		line := x[:nl+1]
+		x = x[nl+1:]
+		if err := fn(line); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// foreachField runs fn on each non-empty run of non-space bytes in x.
+// It returns the first non-nil error returned by fn.
+func foreachField(x []byte, fn func(field []byte) error) error {
+	x = trimSpace(x)
+	for len(x) > 0 {
+		sp := bytesIndexByte(x, ' ')
+		if sp == -1 {
+			return fn(x)
+		}
+		if field := trimSpace(x[:sp]); len(field) > 0 {
+			if err := fn(field); err != nil {
+				return err
+			}
+		}
+		x = trimSpace(x[sp+1:])
+	}
+	return nil
+}
+
+// bytesIndexByte is bytes.IndexByte. It returns the index of the
+// first instance of c in s, or -1 if c is not present in s.
+func bytesIndexByte(s []byte, c byte) int {
+	for i, b := range s {
+		if b == c {
+			return i
+		}
+	}
+	return -1
+}
+
+// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
+// suffix.
+func stringsHasSuffix(s, suffix string) bool {
+	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+// stringsHasSuffixFold reports whether s ends in suffix,
+// ASCII-case-insensitively.
+func stringsHasSuffixFold(s, suffix string) bool {
+	if len(suffix) > len(s) {
+		return false
+	}
+	for i := 0; i < len(suffix); i++ {
+		if lowerASCII(suffix[i]) != lowerASCII(s[len(s)-len(suffix)+i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
+func stringsHasPrefix(s, prefix string) bool {
+	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
+func readFull(r io.Reader) (all []byte, err error) {
+	buf := make([]byte, 1024)
+	for {
+		n, err := r.Read(buf)
+		all = append(all, buf[:n]...)
+		if err == io.EOF {
+			return all, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+}
diff --git a/src/net/parse_test.go b/src/net/parse_test.go
index 7b213b7..f5359d8 100644
--- a/src/net/parse_test.go
+++ b/src/net/parse_test.go
@@ -15,20 +15,20 @@
 	// /etc/services file does not exist on android, plan9, windows.
 	switch runtime.GOOS {
 	case "android", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	filename := "/etc/services" // a nice big file
 
 	fd, err := os.Open(filename)
 	if err != nil {
-		t.Fatalf("open %s: %v", filename, err)
+		t.Fatal(err)
 	}
 	defer fd.Close()
 	br := bufio.NewReader(fd)
 
 	file, err := open(filename)
 	if file == nil {
-		t.Fatalf("net.open(%s) = nil", filename)
+		t.Fatal(err)
 	}
 	defer file.close()
 
@@ -41,8 +41,7 @@
 		}
 		line, ok := file.readLine()
 		if (berr != nil) != !ok || bline != line {
-			t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v",
-				filename, lineno, byteno, bline, berr, line, ok)
+			t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v", filename, lineno, byteno, bline, berr, line, ok)
 		}
 		if !ok {
 			break
diff --git a/src/net/pipe.go b/src/net/pipe.go
index f1a2eca..5fc830b 100644
--- a/src/net/pipe.go
+++ b/src/net/pipe.go
@@ -55,13 +55,13 @@
 }
 
 func (p *pipe) SetDeadline(t time.Time) error {
-	return errors.New("net.Pipe does not support deadlines")
+	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
 }
 
 func (p *pipe) SetReadDeadline(t time.Time) error {
-	return errors.New("net.Pipe does not support deadlines")
+	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
 }
 
 func (p *pipe) SetWriteDeadline(t time.Time) error {
-	return errors.New("net.Pipe does not support deadlines")
+	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
 }
diff --git a/src/net/pipe_test.go b/src/net/pipe_test.go
index afe4f24..60c3920 100644
--- a/src/net/pipe_test.go
+++ b/src/net/pipe_test.go
@@ -10,10 +10,10 @@
 	"testing"
 )
 
-func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
+func checkPipeWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
 	n, err := w.Write(data)
 	if err != nil {
-		t.Errorf("write: %v", err)
+		t.Error(err)
 	}
 	if n != len(data) {
 		t.Errorf("short write: %d != %d", n, len(data))
@@ -21,11 +21,11 @@
 	c <- 0
 }
 
-func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
+func checkPipeRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
 	buf := make([]byte, len(data)+10)
 	n, err := r.Read(buf)
 	if err != wantErr {
-		t.Errorf("read: %v", err)
+		t.Error(err)
 		return
 	}
 	if n != len(data) || !bytes.Equal(buf[0:n], data) {
@@ -34,23 +34,22 @@
 	}
 }
 
-// Test a simple read/write/close sequence.
+// TestPipe tests a simple read/write/close sequence.
 // Assumes that the underlying io.Pipe implementation
 // is solid and we're just testing the net wrapping.
-
 func TestPipe(t *testing.T) {
 	c := make(chan int)
 	cli, srv := Pipe()
-	go checkWrite(t, cli, []byte("hello, world"), c)
-	checkRead(t, srv, []byte("hello, world"), nil)
+	go checkPipeWrite(t, cli, []byte("hello, world"), c)
+	checkPipeRead(t, srv, []byte("hello, world"), nil)
 	<-c
-	go checkWrite(t, srv, []byte("line 2"), c)
-	checkRead(t, cli, []byte("line 2"), nil)
+	go checkPipeWrite(t, srv, []byte("line 2"), c)
+	checkPipeRead(t, cli, []byte("line 2"), nil)
 	<-c
-	go checkWrite(t, cli, []byte("a third line"), c)
-	checkRead(t, srv, []byte("a third line"), nil)
+	go checkPipeWrite(t, cli, []byte("a third line"), c)
+	checkPipeRead(t, srv, []byte("a third line"), nil)
 	<-c
 	go srv.Close()
-	checkRead(t, cli, nil, io.EOF)
+	checkPipeRead(t, cli, nil, io.EOF)
 	cli.Close()
 }
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index a1e766d..b700091 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -40,7 +40,7 @@
 		}
 	case "unixpacket":
 		switch runtime.GOOS {
-		case "android", "darwin", "nacl", "openbsd", "plan9", "windows":
+		case "android", "darwin", "nacl", "plan9", "windows":
 			fallthrough
 		case "freebsd": // FreeBSD 8 and below don't support unixpacket
 			return false
@@ -103,15 +103,26 @@
 		return false
 	}
 
-	// Test functionality of IPv6 communication using AF_INET6
-	// sockets.
+	// Test functionality of IPv4 communication using AF_INET and
+	// IPv6 communication using AF_INET6 sockets.
+	if !supportsIPv4 && ip.To4() != nil {
+		return false
+	}
 	if !supportsIPv6 && ip.To16() != nil && ip.To4() == nil {
 		return false
 	}
+	cip := ParseIP(client)
+	if cip != nil {
+		if !supportsIPv4 && cip.To4() != nil {
+			return false
+		}
+		if !supportsIPv6 && cip.To16() != nil && cip.To4() == nil {
+			return false
+		}
+	}
 
 	// Test functionality of IPv4 communication using AF_INET6
 	// sockets.
-	cip := ParseIP(client)
 	if !supportsIPv4map && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
 		// At this point, we prefer IPv4 when ip is nil.
 		// See favoriteAddrFamily for further information.
diff --git a/src/net/port.go b/src/net/port.go
index c24f4ed..a2a5387 100644
--- a/src/net/port.go
+++ b/src/net/port.go
@@ -18,7 +18,7 @@
 		}
 	}
 	if p < 0 || p > 0xFFFF {
-		return 0, &AddrError{"invalid port", port}
+		return 0, &AddrError{Err: "invalid port", Addr: port}
 	}
 	return p, nil
 }
diff --git a/src/net/port_test.go b/src/net/port_test.go
index 4811ade..2dacd97 100644
--- a/src/net/port_test.go
+++ b/src/net/port_test.go
@@ -9,14 +9,12 @@
 	"testing"
 )
 
-type portTest struct {
-	netw string
-	name string
-	port int
-	ok   bool
-}
-
-var porttests = []portTest{
+var portTests = []struct {
+	network string
+	name    string
+	port    int
+	ok      bool
+}{
 	{"tcp", "echo", 7, true},
 	{"tcp", "discard", 9, true},
 	{"tcp", "systat", 11, true},
@@ -46,14 +44,12 @@
 func TestLookupPort(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	for i := 0; i < len(porttests); i++ {
-		tt := porttests[i]
-		if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
-			t.Errorf("LookupPort(%q, %q) = %v, %v; want %v",
-				tt.netw, tt.name, port, err, tt.port)
+	for _, tt := range portTests {
+		if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
+			t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", tt.network, tt.name, port, err, tt.port)
 		}
 	}
 }
diff --git a/src/net/port_unix.go b/src/net/port_unix.go
index 348c771..badf8ab 100644
--- a/src/net/port_unix.go
+++ b/src/net/port_unix.go
@@ -69,5 +69,5 @@
 			return
 		}
 	}
-	return 0, &AddrError{"unknown port", network + "/" + service}
+	return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
 }
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index 3a16ec5..c6ef23b 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -8,7 +8,6 @@
 package net
 
 import (
-	"io/ioutil"
 	"os"
 	"runtime"
 	"testing"
@@ -21,33 +20,19 @@
 //	golang.org/x/net/ipv6
 //	golang.org/x/net/icmp
 
-// testUnixAddr uses ioutil.TempFile to get a name that is unique. It
-// also uses /tmp directory in case it is prohibited to create UNIX
-// sockets in TMPDIR.
-func testUnixAddr() string {
-	f, err := ioutil.TempFile("", "nettest")
-	if err != nil {
-		panic(err)
-	}
-	addr := f.Name()
-	f.Close()
-	os.Remove(addr)
-	return addr
-}
-
 func TestTCPListenerSpecificMethods(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	ln, err := ListenTCP("tcp4", la)
 	if err != nil {
-		t.Fatalf("ListenTCP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	ln.Addr()
@@ -55,21 +40,21 @@
 
 	if c, err := ln.Accept(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("TCPListener.Accept failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 	if c, err := ln.AcceptTCP(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("TCPListener.AcceptTCP failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 
 	if f, err := ln.File(); err != nil {
-		condFatalf(t, "TCPListener.File failed: %v", err)
+		condFatalf(t, "%v", err)
 	} else {
 		f.Close()
 	}
@@ -78,25 +63,30 @@
 func TestTCPConnSpecificMethods(t *testing.T) {
 	la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	ln, err := ListenTCP("tcp4", la)
 	if err != nil {
-		t.Fatalf("ListenTCP failed: %v", err)
+		t.Fatal(err)
 	}
-	defer ln.Close()
-	ln.Addr()
-
-	done := make(chan int)
-	go transponder(t, ln, done)
-
-	ra, err := ResolveTCPAddr("tcp4", ln.Addr().String())
+	ch := make(chan error, 1)
+	handler := func(ls *localServer, ln Listener) { transponder(ls.Listener, ch) }
+	ls, err := (&streamListener{Listener: ln}).newLocalServer()
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	ra, err := ResolveTCPAddr("tcp4", ls.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 	c, err := DialTCP("tcp4", nil, ra)
 	if err != nil {
-		t.Fatalf("DialTCP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.SetKeepAlive(false)
@@ -110,24 +100,26 @@
 	c.SetWriteDeadline(time.Now().Add(someTimeout))
 
 	if _, err := c.Write([]byte("TCPCONN TEST")); err != nil {
-		t.Fatalf("TCPConn.Write failed: %v", err)
+		t.Fatal(err)
 	}
 	rb := make([]byte, 128)
 	if _, err := c.Read(rb); err != nil {
-		t.Fatalf("TCPConn.Read failed: %v", err)
+		t.Fatal(err)
 	}
 
-	<-done
+	for err := range ch {
+		t.Error(err)
+	}
 }
 
 func TestUDPConnSpecificMethods(t *testing.T) {
 	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ResolveUDPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenUDP("udp4", la)
 	if err != nil {
-		t.Fatalf("ListenUDP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.LocalAddr()
@@ -141,27 +133,27 @@
 	wb := []byte("UDPCONN TEST")
 	rb := make([]byte, 128)
 	if _, err := c.WriteToUDP(wb, c.LocalAddr().(*UDPAddr)); err != nil {
-		t.Fatalf("UDPConn.WriteToUDP failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c.ReadFromUDP(rb); err != nil {
-		t.Fatalf("UDPConn.ReadFromUDP failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c.WriteMsgUDP(wb, nil, c.LocalAddr().(*UDPAddr)); err != nil {
-		condFatalf(t, "UDPConn.WriteMsgUDP failed: %v", err)
+		condFatalf(t, "%v", err)
 	}
 	if _, _, _, _, err := c.ReadMsgUDP(rb, nil); err != nil {
-		condFatalf(t, "UDPConn.ReadMsgUDP failed: %v", err)
+		condFatalf(t, "%v", err)
 	}
 
 	if f, err := c.File(); err != nil {
-		condFatalf(t, "UDPConn.File failed: %v", err)
+		condFatalf(t, "%v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("UDPConn.WriteToUDP or WriteMsgUDP panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
@@ -176,11 +168,11 @@
 
 	la, err := ResolveIPAddr("ip4", "127.0.0.1")
 	if err != nil {
-		t.Fatalf("ResolveIPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenIP("ip4:icmp", la)
 	if err != nil {
-		t.Fatalf("ListenIP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.LocalAddr()
@@ -192,14 +184,14 @@
 	c.SetWriteBuffer(2048)
 
 	if f, err := c.File(); err != nil {
-		condFatalf(t, "IPConn.File failed: %v", err)
+		condFatalf(t, "%v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("IPConn.WriteToIP or WriteMsgIP panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
@@ -216,11 +208,11 @@
 	addr := testUnixAddr()
 	la, err := ResolveUnixAddr("unix", addr)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	ln, err := ListenUnix("unix", la)
 	if err != nil {
-		t.Fatalf("ListenUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	defer os.Remove(addr)
@@ -229,21 +221,21 @@
 
 	if c, err := ln.Accept(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("UnixListener.Accept failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 	if c, err := ln.AcceptUnix(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("UnixListener.AcceptUnix failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 
 	if f, err := ln.File(); err != nil {
-		t.Fatalf("UnixListener.File failed: %v", err)
+		t.Fatal(err)
 	} else {
 		f.Close()
 	}
@@ -258,11 +250,11 @@
 
 	a1, err := ResolveUnixAddr("unixgram", addr1)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c1, err := DialUnix("unixgram", a1, nil)
 	if err != nil {
-		t.Fatalf("DialUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c1.Close()
 	defer os.Remove(addr1)
@@ -276,11 +268,11 @@
 
 	a2, err := ResolveUnixAddr("unixgram", addr2)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c2, err := DialUnix("unixgram", a2, nil)
 	if err != nil {
-		t.Fatalf("DialUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c2.Close()
 	defer os.Remove(addr2)
@@ -294,11 +286,11 @@
 
 	a3, err := ResolveUnixAddr("unixgram", addr3)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c3, err := ListenUnixgram("unixgram", a3)
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c3.Close()
 	defer os.Remove(addr3)
@@ -315,39 +307,39 @@
 	rb2 := make([]byte, 128)
 	rb3 := make([]byte, 128)
 	if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil {
-		t.Fatalf("UnixConn.WriteMsgUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil {
-		t.Fatalf("UnixConn.ReadMsgUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, err := c2.WriteToUnix(wb, a1); err != nil {
-		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c1.ReadFromUnix(rb1); err != nil {
-		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, err := c3.WriteToUnix(wb, a1); err != nil {
-		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c1.ReadFromUnix(rb1); err != nil {
-		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, err := c2.WriteToUnix(wb, a3); err != nil {
-		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c3.ReadFromUnix(rb3); err != nil {
-		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
+		t.Fatal(err)
 	}
 
 	if f, err := c1.File(); err != nil {
-		t.Fatalf("UnixConn.File failed: %v", err)
+		t.Fatal(err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("UnixConn.WriteToUnix or WriteMsgUnix panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go
index 83728d5..6e6e881 100644
--- a/src/net/rpc/server.go
+++ b/src/net/rpc/server.go
@@ -13,6 +13,7 @@
 	Only methods that satisfy these criteria will be made available for remote access;
 	other methods will be ignored:
 
+		- the method's type is exported.
 		- the method is exported.
 		- the method has two arguments, both exported (or builtin) types.
 		- the method's second argument is a pointer.
@@ -216,7 +217,7 @@
 
 // Register publishes in the server the set of methods of the
 // receiver value that satisfy the following conditions:
-//	- exported method
+//	- exported method of exported type
 //	- two arguments, both of exported type
 //	- the second argument is a pointer
 //	- one return value, of type error
diff --git a/src/net/sendfile_dragonfly.go b/src/net/sendfile_dragonfly.go
index bc88fd3..a9cf3fe 100644
--- a/src/net/sendfile_dragonfly.go
+++ b/src/net/sendfile_dragonfly.go
@@ -91,13 +91,16 @@
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile together)
-			err = &OpError{"sendfile", c.net, c.raddr, err1}
+			// don't implement sendfile)
+			err = err1
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_freebsd.go b/src/net/sendfile_freebsd.go
index ffc1472..d0bf603 100644
--- a/src/net/sendfile_freebsd.go
+++ b/src/net/sendfile_freebsd.go
@@ -91,13 +91,16 @@
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile together)
-			err = &OpError{"sendfile", c.net, c.raddr, err1}
+			// don't implement sendfile)
+			err = err1
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_linux.go b/src/net/sendfile_linux.go
index 5e11763..5ca41c3 100644
--- a/src/net/sendfile_linux.go
+++ b/src/net/sendfile_linux.go
@@ -64,13 +64,16 @@
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile together)
-			err = &OpError{"sendfile", c.net, c.raddr, err1}
+			// don't implement sendfile)
+			err = err1
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_solaris.go b/src/net/sendfile_solaris.go
new file mode 100644
index 0000000..0966575
--- /dev/null
+++ b/src/net/sendfile_solaris.go
@@ -0,0 +1,110 @@
+// 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 (
+	"io"
+	"os"
+	"syscall"
+)
+
+// Not strictly needed, but very helpful for debugging, see issue #10221.
+//go:cgo_import_dynamic _ _ "libsendfile.so"
+//go:cgo_import_dynamic _ _ "libsocket.so"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// sendFile copies the contents of r to c using the sendfile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
+	// Solaris uses 0 as the "until EOF" value. If you pass in more bytes than the
+	// file contains, it will loop back to the beginning ad nauseam until it's sent
+	// exactly the number of bytes told to. As such, we need to know exactly how many
+	// bytes to send.
+	var remain int64 = 0
+
+	lr, ok := r.(*io.LimitedReader)
+	if ok {
+		remain, r = lr.N, lr.R
+		if remain <= 0 {
+			return 0, nil, true
+		}
+	}
+	f, ok := r.(*os.File)
+	if !ok {
+		return 0, nil, false
+	}
+
+	if remain == 0 {
+		fi, err := f.Stat()
+		if err != nil {
+			return 0, err, false
+		}
+
+		remain = fi.Size()
+	}
+
+	// The other quirk with Solaris's sendfile implementation is that it doesn't
+	// use the current position of the file -- if you pass it offset 0, it starts
+	// from offset 0. There's no way to tell it "start from current position", so
+	// we have to manage that explicitly.
+	pos, err := f.Seek(0, os.SEEK_CUR)
+	if err != nil {
+		return 0, err, false
+	}
+
+	if err := c.writeLock(); err != nil {
+		return 0, err, true
+	}
+	defer c.writeUnlock()
+
+	dst := c.sysfd
+	src := int(f.Fd())
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		pos1 := pos
+		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
+		if n > 0 {
+			pos += int64(n)
+			written += int64(n)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = c.pd.WaitWrite(); err1 == nil {
+				continue
+			}
+		}
+		if err1 == syscall.EINTR {
+			continue
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	if lr != nil {
+		lr.N = remain
+	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
+	return written, err, written > 0
+}
diff --git a/src/net/sendfile_stub.go b/src/net/sendfile_stub.go
index 03426ef..a0760b4 100644
--- a/src/net/sendfile_stub.go
+++ b/src/net/sendfile_stub.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.
 
-// +build darwin nacl netbsd openbsd solaris
+// +build darwin nacl netbsd openbsd
 
 package net
 
diff --git a/src/net/sendfile_windows.go b/src/net/sendfile_windows.go
index b128ba2..f3f3b54 100644
--- a/src/net/sendfile_windows.go
+++ b/src/net/sendfile_windows.go
@@ -46,7 +46,7 @@
 		return syscall.TransmitFile(o.fd.sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
 	})
 	if err != nil {
-		return 0, err, false
+		return 0, os.NewSyscallError("transmitfile", err), false
 	}
 	if lr != nil {
 		lr.N -= int64(done)
diff --git a/src/net/server_test.go b/src/net/server_test.go
index 479c181..fe0006b 100644
--- a/src/net/server_test.go
+++ b/src/net/server_test.go
@@ -5,413 +5,384 @@
 package net
 
 import (
-	"flag"
-	"io"
 	"os"
 	"testing"
-	"time"
 )
 
-var streamConnServerTests = []struct {
-	snet  string // server side
-	saddr string
-	cnet  string // client side
-	caddr string
-	empty bool // test with empty data
+var tcpServerTests = []struct {
+	snet, saddr string // server endpoint
+	tnet, taddr string // target endpoint for client
 }{
-	{snet: "tcp", saddr: ":0", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::]:0", cnet: "tcp", caddr: "::1"},
+	{snet: "tcp", saddr: ":0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "::1"},
 
-	{snet: "tcp", saddr: ":0", cnet: "tcp", caddr: "::1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp", caddr: "::1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp", caddr: "::1"},
-	{snet: "tcp", saddr: "[::]:0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: ":0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "127.0.0.1"},
 
-	{snet: "tcp", saddr: ":0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::]:0", cnet: "tcp6", caddr: "::1"},
+	{snet: "tcp", saddr: ":0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"},
 
-	{snet: "tcp", saddr: ":0", cnet: "tcp6", caddr: "::1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp6", caddr: "::1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp6", caddr: "::1"},
-	{snet: "tcp", saddr: "[::]:0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: ":0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp4", taddr: "127.0.0.1"},
 
-	{snet: "tcp", saddr: "127.0.0.1:0", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::1]:0", cnet: "tcp", caddr: "::1"},
+	{snet: "tcp", saddr: "127.0.0.1:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::1]:0", tnet: "tcp", taddr: "::1"},
 
-	{snet: "tcp4", saddr: ":0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp4", saddr: "0.0.0.0:0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: ":0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"},
 
-	{snet: "tcp4", saddr: "127.0.0.1:0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "127.0.0.1:0", tnet: "tcp4", taddr: "127.0.0.1"},
 
-	{snet: "tcp6", saddr: ":0", cnet: "tcp6", caddr: "::1"},
-	{snet: "tcp6", saddr: "[::]:0", cnet: "tcp6", caddr: "::1"},
+	{snet: "tcp6", saddr: ":0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp6", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"},
 
-	{snet: "tcp6", saddr: "[::1]:0", cnet: "tcp6", caddr: "::1"},
-
-	{snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
-	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local"},
+	{snet: "tcp6", saddr: "[::1]:0", tnet: "tcp6", taddr: "::1"},
 }
 
-func TestStreamConnServer(t *testing.T) {
-	for _, tt := range streamConnServerTests {
-		if !testableListenArgs(tt.snet, tt.saddr, tt.caddr) {
-			t.Logf("skipping %s test", tt.snet+":"+tt.saddr+"->"+tt.caddr)
+// TestTCPServer tests concurrent accept-read-write servers.
+func TestTCPServer(t *testing.T) {
+	const N = 3
+
+	for i, tt := range tcpServerTests {
+		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
+			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
 			continue
 		}
 
-		listening := make(chan string)
-		done := make(chan int)
-		switch tt.snet {
-		case "unix":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
-		}
-
-		go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
-		taddr := <-listening // wait for server to start
-
-		switch tt.cnet {
-		case "tcp", "tcp4", "tcp6":
-			_, port, err := SplitHostPort(taddr)
-			if err != nil {
-				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
-			}
-			taddr = JoinHostPort(tt.caddr, port)
-		}
-
-		runStreamConnClient(t, tt.cnet, taddr, tt.empty)
-		<-done // make sure server stopped
-
-		switch tt.snet {
-		case "unix":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
-		}
-	}
-}
-
-var seqpacketConnServerTests = []struct {
-	net   string
-	saddr string // server address
-	caddr string // client address
-	empty bool   // test with empty data
-}{
-	{net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
-	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
-}
-
-func TestSeqpacketConnServer(t *testing.T) {
-	for _, tt := range seqpacketConnServerTests {
-		if !testableListenArgs(tt.net, tt.saddr, tt.caddr) {
-			t.Logf("skipping %s test", tt.net+":"+tt.saddr+"->"+tt.caddr)
-			continue
-		}
-		listening := make(chan string)
-		done := make(chan int)
-		switch tt.net {
-		case "unixpacket":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
-		}
-
-		go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
-		taddr := <-listening // wait for server to start
-
-		runStreamConnClient(t, tt.net, taddr, tt.empty)
-		<-done // make sure server stopped
-
-		switch tt.net {
-		case "unixpacket":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
-		}
-	}
-}
-
-func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
-	defer close(done)
-	l, err := Listen(net, laddr)
-	if err != nil {
-		t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
-		listening <- "<nil>"
-		return
-	}
-	defer l.Close()
-	listening <- l.Addr().String()
-
-	echo := func(rw io.ReadWriter, done chan<- int) {
-		buf := make([]byte, 1024)
-		for {
-			n, err := rw.Read(buf[0:])
-			if err != nil || n == 0 || string(buf[:n]) == "END" {
-				break
-			}
-			rw.Write(buf[0:n])
-		}
-		close(done)
-	}
-
-run:
-	for {
-		c, err := l.Accept()
+		ln, err := Listen(tt.snet, tt.saddr)
 		if err != nil {
-			t.Logf("Accept failed: %v", err)
-			continue run
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
 		}
-		echodone := make(chan int)
-		go echo(c, echodone)
-		<-echodone // make sure echo stopped
-		c.Close()
-		break run
+
+		var lss []*localServer
+		var tpchs []chan error
+		defer func() {
+			for _, ls := range lss {
+				ls.teardown()
+			}
+		}()
+		for i := 0; i < N; i++ {
+			ls, err := (&streamListener{Listener: ln}).newLocalServer()
+			if err != nil {
+				t.Fatal(err)
+			}
+			lss = append(lss, ls)
+			tpchs = append(tpchs, make(chan error, 1))
+		}
+		for i := 0; i < N; i++ {
+			ch := tpchs[i]
+			handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+			if err := lss[i].buildup(handler); err != nil {
+				t.Fatal(err)
+			}
+		}
+
+		var trchs []chan error
+		for i := 0; i < N; i++ {
+			_, port, err := SplitHostPort(lss[i].Listener.Addr().String())
+			if err != nil {
+				t.Fatal(err)
+			}
+			d := Dialer{Timeout: someTimeout}
+			c, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port))
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer c.Close()
+			trchs = append(trchs, make(chan error, 1))
+			go transceiver(c, []byte("TCP SERVER TEST"), trchs[i])
+		}
+
+		for _, ch := range trchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
+		for _, ch := range tpchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
 	}
 }
 
-func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
-	c, err := Dial(net, taddr)
-	if err != nil {
-		t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
-	}
-	defer c.Close()
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
-
-	var wb []byte
-	if !isEmpty {
-		wb = []byte("StreamConnClient by Dial\n")
-	}
-	if n, err := c.Write(wb); err != nil || n != len(wb) {
-		t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
-
-	rb := make([]byte, 1024)
-	if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
-
-	// Send explicit ending for unixpacket.
-	// Older Linux kernels do not stop reads on close.
-	switch net {
-	case "unixpacket":
-		c.Write([]byte("END"))
-	}
-}
-
-// Do not test empty datagrams by default.
-// It causes unexplained timeouts on some systems,
-// including Snow Leopard.  I think that the kernel
-// doesn't quite expect them.
-var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
-
-var datagramPacketConnServerTests = []struct {
-	snet  string // server side
-	saddr string
-	cnet  string // client side
-	caddr string
-	dial  bool // test with Dial or DialUnix
-	empty bool // test with empty data
+var unixAndUnixpacketServerTests = []struct {
+	network, address string
 }{
-	{snet: "udp", saddr: ":0", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::]:0", cnet: "udp", caddr: "::1"},
+	{"unix", testUnixAddr()},
+	{"unix", "@nettest/go/unix"},
 
-	{snet: "udp", saddr: ":0", cnet: "udp", caddr: "::1"},
-	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp", caddr: "::1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp", caddr: "::1"},
-	{snet: "udp", saddr: "[::]:0", cnet: "udp", caddr: "127.0.0.1"},
-
-	{snet: "udp", saddr: ":0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::]:0", cnet: "udp6", caddr: "::1"},
-
-	{snet: "udp", saddr: ":0", cnet: "udp6", caddr: "::1"},
-	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp6", caddr: "::1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp6", caddr: "::1"},
-	{snet: "udp", saddr: "[::]:0", cnet: "udp4", caddr: "127.0.0.1"},
-
-	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:127.0.0.1]:0", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1"},
-
-	{snet: "udp4", saddr: ":0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp4", saddr: "0.0.0.0:0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp4", caddr: "127.0.0.1"},
-
-	{snet: "udp4", saddr: "127.0.0.1:0", cnet: "udp4", caddr: "127.0.0.1"},
-
-	{snet: "udp6", saddr: ":0", cnet: "udp6", caddr: "::1"},
-	{snet: "udp6", saddr: "[::]:0", cnet: "udp6", caddr: "::1"},
-
-	{snet: "udp6", saddr: "[::1]:0", cnet: "udp6", caddr: "::1"},
-
-	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", dial: true},
-	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", empty: true},
-	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
-
-	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", dial: true},
-	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", empty: true},
-	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", dial: true, empty: true},
-
-	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()},
-	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true},
-	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true},
-	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true},
-
-	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local"},
+	{"unixpacket", testUnixAddr()},
+	{"unixpacket", "@nettest/go/unixpacket"},
 }
 
-func TestDatagramPacketConnServer(t *testing.T) {
-	if !*testDatagram {
-		return
-	}
+// TestUnixAndUnixpacketServer tests concurrent accept-read-write
+// servers
+func TestUnixAndUnixpacketServer(t *testing.T) {
+	const N = 3
 
-	for _, tt := range datagramPacketConnServerTests {
-		if !testableListenArgs(tt.snet, tt.saddr, tt.caddr) {
-			t.Logf("skipping %s test", tt.snet+":"+tt.saddr+"->"+tt.caddr)
+	for i, tt := range unixAndUnixpacketServerTests {
+		if !testableListenArgs(tt.network, tt.address, "") {
+			t.Logf("skipping %s test", tt.network+" "+tt.address)
 			continue
 		}
 
-		listening := make(chan string)
-		done := make(chan int)
-		switch tt.snet {
-		case "unixgram":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
+		ln, err := Listen(tt.network, tt.address)
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
 		}
 
-		go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
-		taddr := <-listening // wait for server to start
-
-		switch tt.cnet {
-		case "udp", "udp4", "udp6":
-			_, port, err := SplitHostPort(taddr)
-			if err != nil {
-				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
+		var lss []*localServer
+		var tpchs []chan error
+		defer func() {
+			for _, ls := range lss {
+				ls.teardown()
 			}
-			taddr = JoinHostPort(tt.caddr, port)
-			tt.caddr = JoinHostPort(tt.caddr, "0")
+		}()
+		for i := 0; i < N; i++ {
+			ls, err := (&streamListener{Listener: ln}).newLocalServer()
+			if err != nil {
+				t.Fatal(err)
+			}
+			lss = append(lss, ls)
+			tpchs = append(tpchs, make(chan error, 1))
+		}
+		for i := 0; i < N; i++ {
+			ch := tpchs[i]
+			handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+			if err := lss[i].buildup(handler); err != nil {
+				t.Fatal(err)
+			}
+		}
+
+		var trchs []chan error
+		for i := 0; i < N; i++ {
+			d := Dialer{Timeout: someTimeout}
+			c, err := d.Dial(lss[i].Listener.Addr().Network(), lss[i].Listener.Addr().String())
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer os.Remove(c.LocalAddr().String())
+			defer c.Close()
+			trchs = append(trchs, make(chan error, 1))
+			go transceiver(c, []byte("UNIX AND UNIXPACKET SERVER TEST"), trchs[i])
+		}
+
+		for _, ch := range trchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
+		for _, ch := range tpchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
+	}
+}
+
+var udpServerTests = []struct {
+	snet, saddr string // server endpoint
+	tnet, taddr string // target endpoint for client
+	dial        bool   // test with Dial
+}{
+	{snet: "udp", saddr: ":0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "::1"},
+
+	{snet: "udp", saddr: ":0", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "127.0.0.1"},
+
+	{snet: "udp", saddr: ":0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp6", taddr: "::1"},
+
+	{snet: "udp", saddr: ":0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp4", taddr: "127.0.0.1"},
+
+	{snet: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:127.0.0.1]:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1"},
+
+	{snet: "udp4", saddr: ":0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"},
+
+	{snet: "udp4", saddr: "127.0.0.1:0", tnet: "udp4", taddr: "127.0.0.1"},
+
+	{snet: "udp6", saddr: ":0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp6", saddr: "[::]:0", tnet: "udp6", taddr: "::1"},
+
+	{snet: "udp6", saddr: "[::1]:0", tnet: "udp6", taddr: "::1"},
+
+	{snet: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1", dial: true},
+
+	{snet: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1", dial: true},
+}
+
+func TestUDPServer(t *testing.T) {
+	for i, tt := range udpServerTests {
+		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
+			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
+			continue
+		}
+
+		c1, err := ListenPacket(tt.snet, tt.saddr)
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+
+		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		tpch := make(chan error, 1)
+		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+
+		trch := make(chan error, 1)
+		_, port, err := SplitHostPort(ls.PacketConn.LocalAddr().String())
+		if err != nil {
+			t.Fatal(err)
 		}
 		if tt.dial {
-			runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
-		} else {
-			runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
-		}
-		<-done // tell server to stop
-		<-done // make sure server stopped
-
-		switch tt.snet {
-		case "unixgram":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
-		}
-	}
-}
-
-func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
-	c, err := ListenPacket(net, laddr)
-	if err != nil {
-		t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
-		listening <- "<nil>"
-		done <- 1
-		return
-	}
-	defer c.Close()
-	listening <- c.LocalAddr().String()
-
-	buf := make([]byte, 1024)
-run:
-	for {
-		c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
-		n, ra, err := c.ReadFrom(buf[0:])
-		if nerr, ok := err.(Error); ok && nerr.Timeout() {
-			select {
-			case done <- 1:
-				break run
-			default:
-				continue run
+			d := Dialer{Timeout: someTimeout}
+			c2, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port))
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
 			}
+			defer c2.Close()
+			go transceiver(c2, []byte("UDP SERVER TEST"), trch)
+		} else {
+			c2, err := ListenPacket(tt.tnet, JoinHostPort(tt.taddr, "0"))
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer c2.Close()
+			dst, err := ResolveUDPAddr(tt.tnet, JoinHostPort(tt.taddr, port))
+			if err != nil {
+				t.Fatal(err)
+			}
+			go packetTransceiver(c2, []byte("UDP SERVER TEST"), dst, trch)
 		}
-		if err != nil {
-			break run
-		}
-		if _, err = c.WriteTo(buf[0:n], ra); err != nil {
-			t.Errorf("WriteTo(%v) failed: %v", ra, err)
-			break run
-		}
-	}
-	done <- 1
-}
 
-func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
-	var c Conn
-	var err error
-	switch net {
-	case "udp", "udp4", "udp6":
-		c, err = Dial(net, taddr)
-		if err != nil {
-			t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
+		for err := range trch {
+			t.Errorf("#%d: %v", i, err)
 		}
-	case "unixgram":
-		c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net})
-		if err != nil {
-			t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
+		for err := range tpch {
+			t.Errorf("#%d: %v", i, err)
 		}
 	}
-	defer c.Close()
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
-
-	var wb []byte
-	if !isEmpty {
-		wb = []byte("DatagramConnClient by Dial\n")
-	}
-	if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
-
-	rb := make([]byte, 1024)
-	if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
 }
 
-func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
-	var ra Addr
-	var err error
-	switch net {
-	case "udp", "udp4", "udp6":
-		ra, err = ResolveUDPAddr(net, taddr)
-		if err != nil {
-			t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
-		}
-	case "unixgram":
-		ra, err = ResolveUnixAddr(net, taddr)
-		if err != nil {
-			t.Fatalf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
-		}
-	}
-	c, err := ListenPacket(net, laddr)
-	if err != nil {
-		t.Fatalf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
-	}
-	defer c.Close()
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
+var unixgramServerTests = []struct {
+	saddr string // server endpoint
+	caddr string // client endpoint
+	dial  bool   // test with Dial
+}{
+	{saddr: testUnixAddr(), caddr: testUnixAddr()},
+	{saddr: testUnixAddr(), caddr: testUnixAddr(), dial: true},
 
-	var wb []byte
-	if !isEmpty {
-		wb = []byte("DatagramPacketConnClient by ListenPacket\n")
-	}
-	if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
-		t.Fatalf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
-	}
+	{saddr: "@nettest/go/unixgram/server", caddr: "@nettest/go/unixgram/client"},
+}
 
-	rb := make([]byte, 1024)
-	if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
+func TestUnixgramServer(t *testing.T) {
+	for i, tt := range unixgramServerTests {
+		if !testableListenArgs("unixgram", tt.saddr, "") {
+			t.Logf("skipping %s test", "unixgram "+tt.saddr+"->"+tt.caddr)
+			continue
+		}
+
+		c1, err := ListenPacket("unixgram", tt.saddr)
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+
+		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		tpch := make(chan error, 1)
+		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+
+		trch := make(chan error, 1)
+		if tt.dial {
+			d := Dialer{Timeout: someTimeout, LocalAddr: &UnixAddr{Net: "unixgram", Name: tt.caddr}}
+			c2, err := d.Dial("unixgram", ls.PacketConn.LocalAddr().String())
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer os.Remove(c2.LocalAddr().String())
+			defer c2.Close()
+			go transceiver(c2, []byte(c2.LocalAddr().String()), trch)
+		} else {
+			c2, err := ListenPacket("unixgram", tt.caddr)
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer os.Remove(c2.LocalAddr().String())
+			defer c2.Close()
+			go packetTransceiver(c2, []byte("UNIXGRAM SERVER TEST"), ls.PacketConn.LocalAddr(), trch)
+		}
+
+		for err := range trch {
+			t.Errorf("#%d: %v", i, err)
+		}
+		for err := range tpch {
+			t.Errorf("#%d: %v", i, err)
+		}
 	}
 }
diff --git a/src/net/sock_cloexec.go b/src/net/sock_cloexec.go
index 842d7d5..616a101 100644
--- a/src/net/sock_cloexec.go
+++ b/src/net/sock_cloexec.go
@@ -9,7 +9,10 @@
 
 package net
 
-import "syscall"
+import (
+	"os"
+	"syscall"
+)
 
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
@@ -20,8 +23,12 @@
 	// introduced in 10 kernel. If we get an EINVAL error on Linux
 	// or EPROTONOSUPPORT error on FreeBSD, fall back to using
 	// socket without them.
-	if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) {
-		return s, err
+	switch err {
+	case nil:
+		return s, nil
+	default:
+		return -1, os.NewSyscallError("socket", err)
+	case syscall.EPROTONOSUPPORT, syscall.EINVAL:
 	}
 
 	// See ../syscall/exec_unix.go for description of ForkLock.
@@ -32,11 +39,11 @@
 	}
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return -1, err
+		return -1, os.NewSyscallError("socket", err)
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
 		closeFunc(s)
-		return -1, err
+		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
 }
@@ -50,8 +57,10 @@
 	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
 	// error on Linux, fall back to using accept.
 	switch err {
-	default: // nil and errors other than the ones listed
-		return ns, sa, err
+	case nil:
+		return ns, sa, nil
+	default: // errors other than the ones listed
+		return -1, sa, os.NewSyscallError("accept4", err)
 	case syscall.ENOSYS: // syscall missing
 	case syscall.EINVAL: // some Linux use this instead of ENOSYS
 	case syscall.EACCES: // some Linux use this instead of ENOSYS
@@ -68,11 +77,11 @@
 		syscall.CloseOnExec(ns)
 	}
 	if err != nil {
-		return -1, nil, err
+		return -1, nil, os.NewSyscallError("accept", err)
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
 		closeFunc(ns)
-		return -1, nil, err
+		return -1, nil, os.NewSyscallError("setnonblock", err)
 	}
 	return ns, sa, nil
 }
diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go
index 013944e..2634a6b 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -17,8 +17,6 @@
 type sockaddr interface {
 	Addr
 
-	netaddr
-
 	// family returns the platform-dependent address family
 	// identifier.
 	family() int
@@ -165,7 +163,7 @@
 			return os.NewSyscallError("bind", err)
 		}
 	}
-	if err := syscall.Listen(fd.sysfd, backlog); err != nil {
+	if err := listenFunc(fd.sysfd, backlog); err != nil {
 		return os.NewSyscallError("listen", err)
 	}
 	if err := fd.init(); err != nil {
diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go
index 591861f..888e70b 100644
--- a/src/net/sock_windows.go
+++ b/src/net/sock_windows.go
@@ -4,7 +4,10 @@
 
 package net
 
-import "syscall"
+import (
+	"os"
+	"syscall"
+)
 
 func maxListenerBacklog() int {
 	// TODO: Implement this
@@ -20,5 +23,8 @@
 		syscall.CloseOnExec(s)
 	}
 	syscall.ForkLock.RUnlock()
-	return s, err
+	if err != nil {
+		return syscall.InvalidHandle, os.NewSyscallError("socket", err)
+	}
+	return s, nil
 }
diff --git a/src/net/sys_cloexec.go b/src/net/sys_cloexec.go
index 5a631aa..ba266e6 100644
--- a/src/net/sys_cloexec.go
+++ b/src/net/sys_cloexec.go
@@ -9,7 +9,10 @@
 
 package net
 
-import "syscall"
+import (
+	"os"
+	"syscall"
+)
 
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
@@ -22,11 +25,11 @@
 	}
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return -1, err
+		return -1, os.NewSyscallError("socket", err)
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
 		closeFunc(s)
-		return -1, err
+		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
 }
@@ -44,11 +47,11 @@
 		syscall.CloseOnExec(ns)
 	}
 	if err != nil {
-		return -1, nil, err
+		return -1, nil, os.NewSyscallError("accept", err)
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
 		closeFunc(ns)
-		return -1, nil, err
+		return -1, nil, os.NewSyscallError("setnonblock", err)
 	}
 	return ns, sa, nil
 }
diff --git a/src/net/tcp_test.go b/src/net/tcp_test.go
index 434c9c6..6229df2 100644
--- a/src/net/tcp_test.go
+++ b/src/net/tcp_test.go
@@ -5,7 +5,6 @@
 package net
 
 import (
-	"fmt"
 	"io"
 	"reflect"
 	"runtime"
@@ -59,8 +58,7 @@
 }
 
 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
-	uninstallTestHooks()
-	defer installTestHooks()
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
 
 	const msgLen = 512
 	conns := b.N
@@ -79,7 +77,7 @@
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)
 		if n != len(buf) || err != nil {
-			b.Logf("Write failed: %v", err)
+			b.Log(err)
 			return false
 		}
 		return true
@@ -89,7 +87,7 @@
 			n, err := c.Read(buf)
 			read += n
 			if err != nil {
-				b.Logf("Read failed: %v", err)
+				b.Log(err)
 				return false
 			}
 		}
@@ -97,7 +95,7 @@
 	}
 	ln, err := Listen("tcp", laddr)
 	if err != nil {
-		b.Fatalf("Listen failed: %v", err)
+		b.Fatal(err)
 	}
 	defer ln.Close()
 	serverSem := make(chan bool, numConcurrent)
@@ -137,7 +135,7 @@
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				b.Logf("Dial failed: %v", err)
+				b.Log(err)
 				return
 			}
 			defer c.Close()
@@ -170,13 +168,13 @@
 }
 
 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
+	testHookUninstaller.Do(func() { uninstallTestHooks() })
+
 	// The benchmark creates GOMAXPROCS client/server pairs.
 	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
 	// The benchmark stresses concurrent reading and writing to the same connection.
 	// Such pattern is used in net/http and net/rpc.
 
-	uninstallTestHooks()
-	defer installTestHooks()
 	b.StopTimer()
 
 	P := runtime.GOMAXPROCS(0)
@@ -188,7 +186,7 @@
 	servers := make([]Conn, P)
 	ln, err := Listen("tcp", laddr)
 	if err != nil {
-		b.Fatalf("Listen failed: %v", err)
+		b.Fatal(err)
 	}
 	defer ln.Close()
 	done := make(chan bool)
@@ -196,7 +194,7 @@
 		for p := 0; p < P; p++ {
 			s, err := ln.Accept()
 			if err != nil {
-				b.Errorf("Accept failed: %v", err)
+				b.Error(err)
 				return
 			}
 			servers[p] = s
@@ -206,7 +204,7 @@
 	for p := 0; p < P; p++ {
 		c, err := Dial("tcp", ln.Addr().String())
 		if err != nil {
-			b.Fatalf("Dial failed: %v", err)
+			b.Fatal(err)
 		}
 		clients[p] = c
 	}
@@ -229,7 +227,7 @@
 				buf[0] = v
 				_, err := c.Write(buf[:])
 				if err != nil {
-					b.Errorf("Write failed: %v", err)
+					b.Error(err)
 					return
 				}
 			}
@@ -245,7 +243,7 @@
 			for i := 0; i < N; i++ {
 				_, err := s.Read(buf[:])
 				if err != nil {
-					b.Errorf("Read failed: %v", err)
+					b.Error(err)
 					return
 				}
 				pipe <- buf[0]
@@ -264,7 +262,7 @@
 				buf[0] = v
 				_, err := s.Write(buf[:])
 				if err != nil {
-					b.Errorf("Write failed: %v", err)
+					b.Error(err)
 					return
 				}
 			}
@@ -278,7 +276,7 @@
 			for i := 0; i < N; i++ {
 				_, err := c.Read(buf[:])
 				if err != nil {
-					b.Errorf("Read failed: %v", err)
+					b.Error(err)
 					return
 				}
 			}
@@ -289,7 +287,7 @@
 }
 
 type resolveTCPAddrTest struct {
-	net           string
+	network       string
 	litAddrOrName string
 	addr          *TCPAddr
 	err           error
@@ -299,8 +297,8 @@
 	{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
 	{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
 
-	{"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil},
-	{"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
+	{"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+	{"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
 
 	{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
 	{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
@@ -313,41 +311,26 @@
 	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
 }
 
-func init() {
-	if ifi := loopbackInterface(); ifi != nil {
-		index := fmt.Sprintf("%v", ifi.Index)
-		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
-			{"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil},
-			{"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
-		}...)
-	}
-	if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
-		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
-			{"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5}, nil},
-			{"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 6}, nil},
-			{"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil},
-		}...)
-	}
-}
-
 func TestResolveTCPAddr(t *testing.T) {
-	for _, tt := range resolveTCPAddrTests {
-		addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName)
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+
+	for i, tt := range resolveTCPAddrTests {
+		addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
 		if err != tt.err {
-			t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err)
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(addr, tt.addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
 		}
-		if !reflect.DeepEqual(addr, tt.addr) {
-			t.Fatalf("ResolveTCPAddr(%q, %q) = %#v, want %#v", tt.net, tt.litAddrOrName, addr, tt.addr)
+		if err != nil {
+			continue
 		}
-		if err == nil {
-			str := addr.String()
-			addr1, err := ResolveTCPAddr(tt.net, str)
-			if err != nil {
-				t.Fatalf("ResolveTCPAddr(%q, %q) [from %q]: %v", tt.net, str, tt.litAddrOrName, err)
-			}
-			if !reflect.DeepEqual(addr1, addr) {
-				t.Fatalf("ResolveTCPAddr(%q, %q) [from %q] = %#v, want %#v", tt.net, str, tt.litAddrOrName, addr1, addr)
-			}
+		rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
+		if err != nil {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(rtaddr, addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
 		}
 	}
 }
@@ -363,13 +346,13 @@
 
 func TestTCPListenerName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range tcpListenerNameTests {
 		ln, err := ListenTCP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatalf("ListenTCP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer ln.Close()
 		la := ln.Addr()
@@ -381,7 +364,7 @@
 
 func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 	if !supportsIPv6 {
 		t.Skip("ipv6 is not supported")
@@ -415,25 +398,31 @@
 			{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
 		}...)
 	}
-	for _, tt := range tests {
+	for i, tt := range tests {
 		ln, err := Listen(tt.net, tt.addr)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
-			t.Logf("Listen failed: %v", err)
+			t.Log(err)
 			continue
 		}
-		defer ln.Close()
+		ls, err := (&streamListener{Listener: ln}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		ch := make(chan error, 1)
+		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 		if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		done := make(chan int)
-		go transponder(t, ln, done)
-
-		c, err := Dial(tt.net, ln.Addr().String())
+		c, err := Dial(tt.net, ls.Listener.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
 		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
@@ -444,14 +433,16 @@
 		}
 
 		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 		b := make([]byte, 32)
 		if _, err := c.Read(b); err != nil {
-			t.Fatalf("Conn.Read failed: %v", err)
+			t.Fatal(err)
 		}
 
-		<-done
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
+		}
 	}
 }
 
@@ -459,7 +450,7 @@
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	const N = 10
 	var wg sync.WaitGroup
@@ -555,7 +546,7 @@
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)
 		if n != len(buf) || err != nil {
-			t.Logf("Write failed: %v", err)
+			t.Log(err)
 			return false
 		}
 		return true
@@ -565,7 +556,7 @@
 			n, err := c.Read(buf)
 			read += n
 			if err != nil {
-				t.Logf("Read failed: %v", err)
+				t.Log(err)
 				return false
 			}
 		}
@@ -574,7 +565,7 @@
 
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	// Acceptor.
@@ -605,7 +596,7 @@
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				t.Logf("Dial failed: %v", err)
+				t.Log(err)
 				return
 			}
 			defer c.Close()
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index fbadad6..b7c95b2 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -32,13 +32,6 @@
 	return a.IP.IsUnspecified()
 }
 
-func (a *TCPAddr) toAddr() Addr {
-	if a == nil {
-		return nil
-	}
-	return a
-}
-
 // ResolveTCPAddr parses addr as a TCP address of the form "host:port"
 // or "[ipv6-host%zone]:port" and resolves a pair of domain name and
 // port name on the network net, which must be "tcp", "tcp4" or
@@ -53,9 +46,9 @@
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	a, err := resolveInternetAddr(net, addr, noDeadline)
+	addrs, err := internetAddrList(net, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return a.toAddr().(*TCPAddr), nil
+	return addrs.first(isIPv4).(*TCPAddr), nil
 }
diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go
index ae21942..bc3f8fc 100644
--- a/src/net/tcpsock_plan9.go
+++ b/src/net/tcpsock_plan9.go
@@ -23,7 +23,11 @@
 
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
-	return genericReadFrom(c, r)
+	n, err := genericReadFrom(c, r)
+	if err != nil && err != io.EOF {
+		err = &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -32,7 +36,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeRead()
+	err := c.fd.closeRead()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -41,7 +49,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeWrite()
+	err := c.fd.closeWrite()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -57,7 +69,7 @@
 // some operating systems after sec seconds have elapsed any remaining
 // unsent data may be discarded.
 func (c *TCPConn) SetLinger(sec int) error {
-	return syscall.EPLAN9
+	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // SetKeepAlive sets whether the operating system should send
@@ -66,7 +78,10 @@
 	if !c.ok() {
 		return syscall.EPLAN9
 	}
-	return setKeepAlive(c.fd, keepalive)
+	if err := setKeepAlive(c.fd, keepalive); err != nil {
+		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
@@ -74,7 +89,10 @@
 	if !c.ok() {
 		return syscall.EPLAN9
 	}
-	return setKeepAlivePeriod(c.fd, d)
+	if err := setKeepAlivePeriod(c.fd, d); err != nil {
+		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetNoDelay controls whether the operating system should delay
@@ -82,7 +100,7 @@
 // algorithm).  The default is true (no delay), meaning that data is
 // sent as soon as possible after a Write.
 func (c *TCPConn) SetNoDelay(noDelay bool) error {
-	return syscall.EPLAN9
+	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -99,10 +117,10 @@
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{"dial", net, raddr, UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{"dial", net, nil, errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: errMissingAddress}
 	}
 	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
@@ -151,9 +169,13 @@
 	}
 	if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
 		l.fd.ctl.Close()
-		return &OpError{"close", l.fd.ctl.Name(), l.fd.laddr, err}
+		return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
-	return l.fd.ctl.Close()
+	err := l.fd.ctl.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return err
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
@@ -167,7 +189,10 @@
 	if l == nil || l.fd == nil || l.fd.ctl == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.setDeadline(t)
+	if err := l.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -177,7 +202,13 @@
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) { return l.dup() }
+func (l *TCPListener) File() (f *os.File, err error) {
+	f, err = l.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
 
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
@@ -187,7 +218,7 @@
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{"listen", net, laddr, UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &TCPAddr{}
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index 024dcd4..1f43521 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -53,16 +53,23 @@
 
 func newTCPConn(fd *netFD) *TCPConn {
 	c := &TCPConn{conn{fd}}
-	c.SetNoDelay(true)
+	setNoDelay(c.fd, true)
 	return c
 }
 
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
 	if n, err, handled := sendFile(c.fd, r); handled {
+		if err != nil && err != io.EOF {
+			err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+		}
 		return n, err
 	}
-	return genericReadFrom(c, r)
+	n, err := genericReadFrom(c, r)
+	if err != nil && err != io.EOF {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -71,7 +78,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeRead()
+	err := c.fd.closeRead()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -80,7 +91,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeWrite()
+	err := c.fd.closeWrite()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -99,7 +114,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setLinger(c.fd, sec)
+	if err := setLinger(c.fd, sec); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetKeepAlive sets whether the operating system should send
@@ -108,7 +126,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setKeepAlive(c.fd, keepalive)
+	if err := setKeepAlive(c.fd, keepalive); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
@@ -116,7 +137,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setKeepAlivePeriod(c.fd, d)
+	if err := setKeepAlivePeriod(c.fd, d); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetNoDelay controls whether the operating system should delay
@@ -127,7 +151,10 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setNoDelay(c.fd, noDelay)
+	if err := setNoDelay(c.fd, noDelay); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -137,10 +164,10 @@
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: errMissingAddress}
 	}
 	return dialTCP(net, laddr, raddr, noDeadline)
 }
@@ -180,7 +207,7 @@
 	}
 
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	return newTCPConn(fd), nil
 }
@@ -226,7 +253,7 @@
 	}
 	fd, err := l.fd.accept()
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
 	return newTCPConn(fd), nil
 }
@@ -247,7 +274,11 @@
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.Close()
+	err := l.fd.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return err
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
@@ -261,7 +292,10 @@
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.setDeadline(t)
+	if err := l.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -271,7 +305,13 @@
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
+func (l *TCPListener) File() (f *os.File, err error) {
+	f, err = l.fd.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
 
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
@@ -281,14 +321,14 @@
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &TCPAddr{}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return &TCPListener{fd}, nil
 }
diff --git a/src/net/tcpsockopt_solaris.go b/src/net/tcpsockopt_solaris.go
new file mode 100644
index 0000000..31f5df0
--- /dev/null
+++ b/src/net/tcpsockopt_solaris.go
@@ -0,0 +1,35 @@
+// 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 (
+	"os"
+	"syscall"
+	"time"
+)
+
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	// The kernel expects milliseconds so round to next highest
+	// millisecond.
+	d += (time.Millisecond - time.Nanosecond)
+	msecs := int(d / time.Millisecond)
+
+	// Normally we'd do
+	//	syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs)
+	// here, but we can't because Solaris does not have TCP_KEEPINTVL.
+	// Solaris has TCP_KEEPALIVE_ABORT_THRESHOLD, but it's not the same
+	// thing, it refers to the total time until aborting (not between
+	// probes), and it uses an exponential backoff algorithm instead of
+	// waiting the same time between probes. We can't hope for the best
+	// and do it anyway, like on Darwin, because Solaris might eventually
+	// allocate a constant with a different meaning for the value of
+	// TCP_KEEPINTVL on illumos.
+
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs))
+}
diff --git a/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go
index c9f604c..c8970d1 100644
--- a/src/net/tcpsockopt_unix.go
+++ b/src/net/tcpsockopt_unix.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.
 
-// +build freebsd linux netbsd solaris
+// +build freebsd linux netbsd
 
 package net
 
diff --git a/src/net/tcpsockopt_windows.go b/src/net/tcpsockopt_windows.go
index 091f523..ae2d7c8 100644
--- a/src/net/tcpsockopt_windows.go
+++ b/src/net/tcpsockopt_windows.go
@@ -28,5 +28,5 @@
 	ret := uint32(0)
 	size := uint32(unsafe.Sizeof(ka))
 	err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
-	return os.NewSyscallError("WSAIoctl", err)
+	return os.NewSyscallError("wsaioctl", err)
 }
diff --git a/src/net/testdata/openbsd-resolv.conf b/src/net/testdata/openbsd-resolv.conf
new file mode 100644
index 0000000..8281a91
--- /dev/null
+++ b/src/net/testdata/openbsd-resolv.conf
@@ -0,0 +1,5 @@
+# Generated by vio0 dhclient
+search c.symbolic-datum-552.internal.
+nameserver 169.254.169.254
+nameserver 10.240.0.1
+lookup file bind
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index 9ef0c4d..cafa375 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -8,408 +8,710 @@
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net/internal/socktest"
 	"runtime"
+	"sync"
 	"testing"
 	"time"
 )
 
-func isTimeout(err error) bool {
-	e, ok := err.(Error)
-	return ok && e.Timeout()
+var dialTimeoutTests = []struct {
+	timeout time.Duration
+	delta   time.Duration // for deadline
+
+	guard time.Duration
+	max   time.Duration
+}{
+	// Tests that dial timeouts, deadlines in the past work.
+	{-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond},
+	{0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond},
+	{-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline
+
+	{50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
+	{0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
+	{50 * time.Millisecond, 5 * time.Second, 100 * time.Millisecond, time.Second}, // timeout over deadline
 }
 
-type copyRes struct {
-	n   int64
-	err error
-	d   time.Duration
+func TestDialTimeout(t *testing.T) {
+	origTestHookDialChannel := testHookDialChannel
+	defer func() { testHookDialChannel = origTestHookDialChannel }()
+	defer sw.Set(socktest.FilterConnect, nil)
+
+	for i, tt := range dialTimeoutTests {
+		switch runtime.GOOS {
+		case "plan9", "windows":
+			testHookDialChannel = func() { time.Sleep(tt.guard) }
+			if runtime.GOOS == "plan9" {
+				break
+			}
+			fallthrough
+		default:
+			sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+				time.Sleep(tt.guard)
+				return nil, errTimedout
+			})
+		}
+
+		ch := make(chan error)
+		d := Dialer{Timeout: tt.timeout}
+		if tt.delta != 0 {
+			d.Deadline = time.Now().Add(tt.delta)
+		}
+		max := time.NewTimer(tt.max)
+		defer max.Stop()
+		go func() {
+			// This dial never starts to send any TCP SYN
+			// segment because of above socket filter and
+			// test hook.
+			c, err := d.Dial("tcp", "127.0.0.1:0")
+			if err == nil {
+				err = fmt.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
+				c.Close()
+			}
+			ch <- err
+		}()
+
+		select {
+		case <-max.C:
+			t.Fatalf("#%d: Dial didn't return in an expected time", i)
+		case err := <-ch:
+			if perr := parseDialError(err); perr != nil {
+				t.Errorf("#%d: %v", i, perr)
+			}
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatalf("#%d: %v", i, err)
+			}
+		}
+	}
+}
+
+var acceptTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that accept deadlines in the past work, even if
+	// there's incoming connections available.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{50 * time.Millisecond, [2]error{nil, errTimeout}},
 }
 
 func TestAcceptTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t).(*TCPListener)
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
 	defer ln.Close()
-	ln.SetDeadline(time.Now().Add(-1 * time.Second))
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+
+	for i, tt := range acceptTimeoutTests {
+		if tt.timeout < 0 {
+			go func() {
+				c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+				if err != nil {
+					t.Error(err)
+					return
+				}
+				var b [1]byte
+				c.Read(b[:])
+				c.Close()
+			}()
+		}
+
+		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("$%d: %v", i, err)
+		}
+		for j, xerr := range tt.xerrs {
+			for {
+				c, err := ln.Accept()
+				if xerr != nil {
+					if perr := parseAcceptError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					c.Close()
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				break
+			}
+		}
 	}
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+}
+
+func TestAcceptTimeoutMustReturn(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	ln.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
 	}
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
-	}
-	ln.SetDeadline(noDeadline)
-	errc := make(chan error)
+	defer ln.Close()
+
+	max := time.NewTimer(time.Second)
+	defer max.Stop()
+	ch := make(chan error)
 	go func() {
-		_, err := ln.Accept()
-		errc <- err
+		if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil {
+			t.Error(err)
+		}
+		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(10 * time.Millisecond)); err != nil {
+			t.Error(err)
+		}
+		c, err := ln.Accept()
+		if err == nil {
+			c.Close()
+		}
+		ch <- err
 	}()
-	time.Sleep(100 * time.Millisecond)
+
 	select {
-	case err := <-errc:
-		t.Fatalf("Expected Accept() to not return, but it returned with %v\n", err)
-	default:
-	}
-	ln.Close()
-	switch nerr := <-errc; err := nerr.(type) {
-	case *OpError:
-		if err.Err != errClosing {
-			t.Fatalf("Accept: expected err %v, got %v", errClosing, err)
+	case <-max.C:
+		ln.Close()
+		<-ch // wait for tester goroutine to stop
+		t.Fatal("Accept didn't return in an expected time")
+	case err := <-ch:
+		if perr := parseAcceptError(err); perr != nil {
+			t.Error(perr)
 		}
-	default:
-		if err != errClosing {
-			t.Fatalf("Accept: expected err %v, got %v", errClosing, err)
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
 		}
 	}
 }
 
+func TestAcceptTimeoutMustNotReturn(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	max := time.NewTimer(100 * time.Millisecond)
+	defer max.Stop()
+	ch := make(chan error)
+	go func() {
+		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil {
+			t.Error(err)
+		}
+		_, err := ln.Accept()
+		ch <- err
+	}()
+
+	select {
+	case err := <-ch:
+		if perr := parseAcceptError(err); perr != nil {
+			t.Error(perr)
+		}
+		t.Fatalf("expected Accept to not return, but it returned with %v", err)
+	case <-max.C:
+		ln.Close()
+		<-ch // wait for tester goroutine to stop
+	}
+}
+
+var readTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that read deadlines work, even if there's data ready
+	// to be read.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
 func TestReadTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-	c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
+	handler := func(ls *localServer, ln Listener) {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		c.Write([]byte("READ TIMEOUT TEST"))
+		defer c.Close()
+	}
+	ls, err := newLocalServer("tcp")
 	if err != nil {
-		t.Fatalf("Connect: %v", err)
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 	defer c.Close()
-	c.SetDeadline(time.Now().Add(time.Hour))
-	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
-	buf := make([]byte, 1)
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+
+	for i, tt := range readTimeoutTests {
+		if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		var b [1]byte
+		for j, xerr := range tt.xerrs {
+			for {
+				n, err := c.Read(b[:])
+				if xerr != nil {
+					if perr := parseReadError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
+				}
+				break
+			}
+		}
 	}
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+}
+
+func TestReadTimeoutMustNotReturn(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
 	}
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
-	c.SetReadDeadline(noDeadline)
-	c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
-	errc := make(chan error)
+	defer c.Close()
+
+	max := time.NewTimer(100 * time.Millisecond)
+	defer max.Stop()
+	ch := make(chan error)
 	go func() {
-		_, err := c.Read(buf)
-		errc <- err
+		if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetReadDeadline(noDeadline); err != nil {
+			t.Error(err)
+		}
+		var b [1]byte
+		_, err := c.Read(b[:])
+		ch <- err
 	}()
-	time.Sleep(100 * time.Millisecond)
+
 	select {
-	case err := <-errc:
-		t.Fatalf("Expected Read() to not return, but it returned with %v\n", err)
-	default:
-	}
-	c.Close()
-	switch nerr := <-errc; err := nerr.(type) {
-	case *OpError:
-		if err.Err != errClosing {
-			t.Fatalf("Read: expected err %v, got %v", errClosing, err)
+	case err := <-ch:
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
 		}
-	default:
-		if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044
-			break
+		t.Fatalf("expected Read to not return, but it returned with %v", err)
+	case <-max.C:
+		c.Close()
+		err := <-ch // wait for tester goroutine to stop
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
 		}
-		if err != errClosing {
-			t.Fatalf("Read: expected err %v, got %v", errClosing, err)
+		if err == io.EOF && runtime.GOOS == "nacl" { // see golang.org/issue/8044
+			return
+		}
+		if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() {
+			t.Fatal(err)
 		}
 	}
 }
 
+var readFromTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that read deadlines work, even if there's data ready
+	// to be read.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
+func TestReadFromTimeout(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
+	}
+
+	ch := make(chan Addr)
+	defer close(ch)
+	handler := func(ls *localPacketServer, c PacketConn) {
+		if dst, ok := <-ch; ok {
+			c.WriteTo([]byte("READFROM TIMEOUT TEST"), dst)
+		}
+	}
+	ls, err := newLocalPacketServer("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	host, _, err := SplitHostPort(ls.PacketConn.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	c, err := ListenPacket(ls.PacketConn.LocalAddr().Network(), JoinHostPort(host, "0"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+	ch <- c.LocalAddr()
+
+	for i, tt := range readFromTimeoutTests {
+		if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		var b [1]byte
+		for j, xerr := range tt.xerrs {
+			for {
+				n, _, err := c.ReadFrom(b[:])
+				if xerr != nil {
+					if perr := parseReadError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
+				}
+				break
+			}
+		}
+	}
+}
+
+var writeTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that write deadlines work, even if there's buffer
+	// space available to write.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{10 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
 func TestWriteTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-	c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
-	if err != nil {
-		t.Fatalf("Connect: %v", err)
-	}
-	defer c.Close()
-	c.SetDeadline(time.Now().Add(time.Hour))
-	c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
-	buf := make([]byte, 4096)
-	writeUntilTimeout := func() {
-		for {
-			_, err := c.Write(buf)
-			if err != nil {
-				if isTimeout(err) {
-					return
-				}
-				t.Fatalf("Write: expected err %v, got %v", errTimeout, err)
-			}
-		}
-	}
-	writeUntilTimeout()
-	c.SetDeadline(time.Now().Add(10 * time.Millisecond))
-	writeUntilTimeout()
-	writeUntilTimeout()
-	c.SetWriteDeadline(noDeadline)
-	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
-	errc := make(chan error)
-	go func() {
-		for {
-			_, err := c.Write(buf)
-			if err != nil {
-				errc <- err
-			}
-		}
-	}()
-	time.Sleep(100 * time.Millisecond)
-	select {
-	case err := <-errc:
-		t.Fatalf("Expected Write() to not return, but it returned with %v\n", err)
-	default:
-	}
-	c.Close()
-	switch nerr := <-errc; err := nerr.(type) {
-	case *OpError:
-		if err.Err != errClosing {
-			t.Fatalf("Write: expected err %v, got %v", errClosing, err)
-		}
-	default:
-		if err != errClosing {
-			t.Fatalf("Write: expected err %v, got %v", errClosing, err)
-		}
-	}
-}
-
-func testTimeout(t *testing.T, net, addr string, readFrom bool) {
-	c, err := Dial(net, addr)
-	if err != nil {
-		t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
-		return
-	}
-	defer c.Close()
-	what := "Read"
-	if readFrom {
-		what = "ReadFrom"
-	}
-
-	errc := make(chan error, 1)
-	go func() {
-		t0 := time.Now()
-		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		var b [100]byte
-		var n int
-		var err error
-		if readFrom {
-			n, _, err = c.(PacketConn).ReadFrom(b[0:])
-		} else {
-			n, err = c.Read(b[0:])
-		}
-		t1 := time.Now()
-		if n != 0 || err == nil || !err.(Error).Timeout() {
-			errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
-			return
-		}
-		if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
-			errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
-			return
-		}
-		errc <- nil
-	}()
-	select {
-	case err := <-errc:
-		if err != nil {
-			t.Error(err)
-		}
-	case <-time.After(1 * time.Second):
-		t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
-	}
-}
-
-func TestTimeoutUDP(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	// set up a listener that won't talk back
-	listening := make(chan string)
-	done := make(chan int)
-	go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
-	addr := <-listening
-
-	testTimeout(t, "udp", addr, false)
-	testTimeout(t, "udp", addr, true)
-	<-done
-}
-
-func TestTimeoutTCP(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	// set up a listener that won't talk back
-	listening := make(chan string)
-	done := make(chan int)
-	go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
-	addr := <-listening
-
-	testTimeout(t, "tcp", addr, false)
-	<-done
-}
-
-func TestDeadlineReset(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
+	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer ln.Close()
-	tl := ln.(*TCPListener)
-	tl.SetDeadline(time.Now().Add(1 * time.Minute))
-	tl.SetDeadline(noDeadline) // reset it
-	errc := make(chan error, 1)
-	go func() {
-		_, err := ln.Accept()
-		errc <- err
-	}()
-	select {
-	case <-time.After(50 * time.Millisecond):
-		// Pass.
-	case err := <-errc:
-		// Accept should never return; we never
-		// connected to it.
-		t.Errorf("unexpected return from Accept; err=%v", err)
-	}
-}
 
-func TestTimeoutAccept(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ln.Close()
-	tl := ln.(*TCPListener)
-	tl.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	errc := make(chan error, 1)
-	go func() {
-		_, err := ln.Accept()
-		errc <- err
-	}()
-	select {
-	case <-time.After(1 * time.Second):
-		// Accept shouldn't block indefinitely
-		t.Errorf("Accept didn't return in an expected time")
-	case <-errc:
-		// Pass.
-	}
-}
-
-func TestReadWriteDeadline(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	const (
-		readTimeout  = 50 * time.Millisecond
-		writeTimeout = 250 * time.Millisecond
-	)
-	checkTimeout := func(command string, start time.Time, should time.Duration) {
-		is := time.Now().Sub(start)
-		d := is - should
-		if d < -30*time.Millisecond || !testing.Short() && 150*time.Millisecond < d {
-			t.Errorf("%s timeout test failed: is=%v should=%v\n", command, is, should)
-		}
-	}
-
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("ListenTCP on :0: %v", err)
-	}
-	defer ln.Close()
-
-	lnquit := make(chan bool)
-
-	go func() {
-		c, err := ln.Accept()
+	for i, tt := range writeTimeoutTests {
+		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
 		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
+			t.Fatal(err)
 		}
 		defer c.Close()
-		lnquit <- true
-	}()
 
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-
-	start := time.Now()
-	err = c.SetReadDeadline(start.Add(readTimeout))
-	if err != nil {
-		t.Fatalf("SetReadDeadline: %v", err)
-	}
-	err = c.SetWriteDeadline(start.Add(writeTimeout))
-	if err != nil {
-		t.Fatalf("SetWriteDeadline: %v", err)
-	}
-
-	quit := make(chan bool)
-
-	go func() {
-		var buf [10]byte
-		_, err := c.Read(buf[:])
-		if err == nil {
-			t.Errorf("Read should not succeed")
+		if err := c.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
 		}
-		checkTimeout("Read", start, readTimeout)
-		quit <- true
-	}()
-
-	go func() {
-		var buf [10000]byte
-		for {
-			_, err := c.Write(buf[:])
-			if err != nil {
+		for j, xerr := range tt.xerrs {
+			for {
+				n, err := c.Write([]byte("WRITE TIMEOUT TEST"))
+				if xerr != nil {
+					if perr := parseWriteError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n)
+				}
 				break
 			}
 		}
-		checkTimeout("Write", start, writeTimeout)
-		quit <- true
-	}()
-
-	<-quit
-	<-quit
-	<-lnquit
+	}
 }
 
-type neverEnding byte
-
-func (b neverEnding) Read(p []byte) (n int, err error) {
-	for i := range p {
-		p[i] = byte(b)
+func TestWriteTimeoutMustNotReturn(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	return len(p), nil
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	max := time.NewTimer(100 * time.Millisecond)
+	defer max.Stop()
+	ch := make(chan error)
+	go func() {
+		if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetWriteDeadline(noDeadline); err != nil {
+			t.Error(err)
+		}
+		var b [1]byte
+		for {
+			if _, err := c.Write(b[:]); err != nil {
+				ch <- err
+				break
+			}
+		}
+	}()
+
+	select {
+	case err := <-ch:
+		if perr := parseWriteError(err); perr != nil {
+			t.Error(perr)
+		}
+		t.Fatalf("expected Write to not return, but it returned with %v", err)
+	case <-max.C:
+		c.Close()
+		err := <-ch // wait for tester goroutine to stop
+		if perr := parseWriteError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() {
+			t.Fatal(err)
+		}
+	}
+}
+
+var writeToTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that write deadlines work, even if there's buffer
+	// space available to write.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{10 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
+func TestWriteToTimeout(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c1, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c1.Close()
+
+	host, _, err := SplitHostPort(c1.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for i, tt := range writeToTimeoutTests {
+		c2, err := ListenPacket(c1.LocalAddr().Network(), JoinHostPort(host, "0"))
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c2.Close()
+
+		if err := c2.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		for j, xerr := range tt.xerrs {
+			for {
+				n, err := c2.WriteTo([]byte("WRITETO TIMEOUT TEST"), c1.LocalAddr())
+				if xerr != nil {
+					if perr := parseWriteError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n)
+				}
+				break
+			}
+		}
+	}
+}
+
+func TestReadTimeoutFluctuation(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	max := time.NewTimer(time.Second)
+	defer max.Stop()
+	ch := make(chan error)
+	go timeoutReceiver(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
+
+	select {
+	case <-max.C:
+		t.Fatal("Read took over 1s; expected 0.1s")
+	case err := <-ch:
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestReadFromTimeoutFluctuation(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c1, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c1.Close()
+
+	c2, err := Dial(c1.LocalAddr().Network(), c1.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c2.Close()
+
+	max := time.NewTimer(time.Second)
+	defer max.Stop()
+	ch := make(chan error)
+	go timeoutPacketReceiver(c2.(PacketConn), 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
+
+	select {
+	case <-max.C:
+		t.Fatal("ReadFrom took over 1s; expected 0.1s")
+	case err := <-ch:
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestWriteTimeoutFluctuation(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	max := time.NewTimer(time.Second)
+	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")
+	case err := <-ch:
+		if perr := parseWriteError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
+		}
+	}
 }
 
 func TestVariousDeadlines1Proc(t *testing.T) {
@@ -420,36 +722,57 @@
 	testVariousDeadlines(t, 4)
 }
 
+type neverEnding byte
+
+func (b neverEnding) Read(p []byte) (int, error) {
+	for i := range p {
+		p[i] = byte(b)
+	}
+	return len(p), nil
+}
+
 func testVariousDeadlines(t *testing.T, maxProcs int) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
-	ln := newLocalListener(t)
-	defer ln.Close()
-	acceptc := make(chan error, 1)
 
-	// The server, with no timeouts of its own, sending bytes to clients
-	// as fast as it can.
-	servec := make(chan copyRes)
-	go func() {
+	type result struct {
+		n   int64
+		err error
+		d   time.Duration
+	}
+
+	ch := make(chan error, 1)
+	pasvch := make(chan result)
+	handler := func(ls *localServer, ln Listener) {
 		for {
 			c, err := ln.Accept()
 			if err != nil {
-				acceptc <- err
+				ch <- err
 				return
 			}
+			// The server, with no timeouts of its own,
+			// sending bytes to clients as fast as it can.
 			go func() {
 				t0 := time.Now()
 				n, err := io.Copy(c, neverEnding('a'))
-				d := time.Since(t0)
+				dt := time.Since(t0)
 				c.Close()
-				servec <- copyRes{n, err, d}
+				pasvch <- result{n, err, dt}
 			}()
 		}
-	}()
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
 
 	for _, timeout := range []time.Duration{
 		1 * time.Nanosecond,
@@ -483,236 +806,133 @@
 			name := fmt.Sprintf("%v run %d/%d", timeout, run+1, numRuns)
 			t.Log(name)
 
-			c, err := Dial("tcp", ln.Addr().String())
+			c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 			if err != nil {
-				t.Fatalf("Dial: %v", err)
+				t.Fatal(err)
 			}
-			clientc := make(chan copyRes)
-			go func() {
-				t0 := time.Now()
-				c.SetDeadline(t0.Add(timeout))
-				n, err := io.Copy(ioutil.Discard, c)
-				d := time.Since(t0)
-				c.Close()
-				clientc <- copyRes{n, err, d}
-			}()
 
 			tooLong := 5 * time.Second
+			max := time.NewTimer(tooLong)
+			defer max.Stop()
+			actvch := make(chan result)
+			go func() {
+				t0 := time.Now()
+				if err := c.SetDeadline(t0.Add(timeout)); err != nil {
+					t.Error(err)
+				}
+				n, err := io.Copy(ioutil.Discard, c)
+				dt := time.Since(t0)
+				c.Close()
+				actvch <- result{n, err, dt}
+			}()
+
 			select {
-			case res := <-clientc:
-				if isTimeout(res.err) {
+			case res := <-actvch:
+				if nerr, ok := res.err.(Error); ok && nerr.Timeout() {
 					t.Logf("for %v, good client timeout after %v, reading %d bytes", name, res.d, res.n)
 				} else {
-					t.Fatalf("for %v: client Copy = %d, %v (want timeout)", name, res.n, res.err)
+					t.Fatalf("for %v, client Copy = %d, %v; want timeout", name, res.n, res.err)
 				}
-			case <-time.After(tooLong):
-				t.Fatalf("for %v: timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
+			case <-max.C:
+				t.Fatalf("for %v, timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
 			}
 
 			select {
-			case res := <-servec:
-				t.Logf("for %v: server in %v wrote %d, %v", name, res.d, res.n, res.err)
-			case err := <-acceptc:
-				t.Fatalf("for %v: server Accept = %v", name, err)
-			case <-time.After(tooLong):
+			case res := <-pasvch:
+				t.Logf("for %v, server in %v wrote %d: %v", name, res.d, res.n, res.err)
+			case err := <-ch:
+				t.Fatalf("for %v, Accept = %v", name, err)
+			case <-max.C:
 				t.Fatalf("for %v, timeout waiting for server to finish writing", name)
 			}
 		}
 	}
 }
 
-// TestReadDeadlineDataAvailable tests that read deadlines work, even
-// if there's data ready to be read.
-func TestReadDeadlineDataAvailable(t *testing.T) {
+// TestReadWriteProlongedTimeout tests concurrent deadline
+// modification. Known to cause data races in the past.
+func TestReadWriteProlongedTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-
-	servec := make(chan copyRes)
-	const msg = "data client shouldn't read, even though it'll be waiting"
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Errorf("Accept: %v", err)
+			t.Error(err)
 			return
 		}
 		defer c.Close()
-		n, err := c.Write([]byte(msg))
-		servec <- copyRes{n: int64(n), err: err}
-	}()
 
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-	if res := <-servec; res.err != nil || res.n != int64(len(msg)) {
-		t.Fatalf("unexpected server Write: n=%d, err=%v; want n=%d, err=nil", res.n, res.err, len(msg))
-	}
-	c.SetReadDeadline(time.Now().Add(-5 * time.Second)) // in the psat.
-	buf := make([]byte, len(msg)/2)
-	n, err := c.Read(buf)
-	if n > 0 || !isTimeout(err) {
-		t.Fatalf("client read = %d (%q) err=%v; want 0, timeout", n, buf[:n], err)
-	}
-}
-
-// TestWriteDeadlineBufferAvailable tests that write deadlines work, even
-// if there's buffer space available to write.
-func TestWriteDeadlineBufferAvailable(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t)
-	defer ln.Close()
-
-	servec := make(chan copyRes)
-	go func() {
-		c, err := ln.Accept()
-		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
-		}
-		defer c.Close()
-		c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past
-		n, err := c.Write([]byte{'x'})
-		servec <- copyRes{n: int64(n), err: err}
-	}()
-
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-	res := <-servec
-	if res.n != 0 {
-		t.Errorf("Write = %d; want 0", res.n)
-	}
-	if !isTimeout(res.err) {
-		t.Errorf("Write error = %v; want timeout", res.err)
-	}
-}
-
-// TestAcceptDeadlineConnectionAvailable tests that accept deadlines work, even
-// if there's incoming connections available.
-func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t).(*TCPListener)
-	defer ln.Close()
-
-	go func() {
-		c, err := Dial("tcp", ln.Addr().String())
-		if err != nil {
-			t.Errorf("Dial: %v", err)
-			return
-		}
-		defer c.Close()
-		var buf [1]byte
-		c.Read(buf[:]) // block until the connection or listener is closed
-	}()
-	time.Sleep(10 * time.Millisecond)
-	ln.SetDeadline(time.Now().Add(-5 * time.Second)) // in the past
-	c, err := ln.Accept()
-	if err == nil {
-		defer c.Close()
-	}
-	if !isTimeout(err) {
-		t.Fatalf("Accept: got %v; want timeout", err)
-	}
-}
-
-// TestConnectDeadlineInThePast tests that connect deadlines work, even
-// if the connection can be established w/o blocking.
-func TestConnectDeadlineInThePast(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t).(*TCPListener)
-	defer ln.Close()
-
-	go func() {
-		c, err := ln.Accept()
-		if err == nil {
-			defer c.Close()
-		}
-	}()
-	time.Sleep(10 * time.Millisecond)
-	c, err := DialTimeout("tcp", ln.Addr().String(), -5*time.Second) // in the past
-	if err == nil {
-		defer c.Close()
-	}
-	if !isTimeout(err) {
-		t.Fatalf("DialTimeout: got %v; want timeout", err)
-	}
-}
-
-// TestProlongTimeout tests concurrent deadline modification.
-// Known to cause data races in the past.
-func TestProlongTimeout(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t)
-	defer ln.Close()
-	connected := make(chan bool)
-	go func() {
-		s, err := ln.Accept()
-		connected <- true
-		if err != nil {
-			t.Errorf("ln.Accept: %v", err)
-			return
-		}
-		defer s.Close()
-		s.SetDeadline(time.Now().Add(time.Hour))
+		var wg sync.WaitGroup
+		wg.Add(2)
 		go func() {
-			var buf [4096]byte
+			defer wg.Done()
+			var b [1]byte
 			for {
-				_, err := s.Write(buf[:])
-				if err != nil {
-					break
+				if err := c.SetReadDeadline(time.Now().Add(time.Hour)); err != nil {
+					if perr := parseCommonError(err); perr != nil {
+						t.Error(perr)
+					}
+					t.Error(err)
+					return
 				}
-				s.SetDeadline(time.Now().Add(time.Hour))
+				if _, err := c.Read(b[:]); err != nil {
+					if perr := parseReadError(err); perr != nil {
+						t.Error(perr)
+					}
+					return
+				}
 			}
 		}()
-		buf := make([]byte, 1)
-		for {
-			_, err := s.Read(buf)
-			if err != nil {
-				break
+		go func() {
+			defer wg.Done()
+			var b [1]byte
+			for {
+				if err := c.SetWriteDeadline(time.Now().Add(time.Hour)); err != nil {
+					if perr := parseCommonError(err); perr != nil {
+						t.Error(perr)
+					}
+					t.Error(err)
+					return
+				}
+				if _, err := c.Write(b[:]); err != nil {
+					if perr := parseWriteError(err); perr != nil {
+						t.Error(perr)
+					}
+					return
+				}
 			}
-			s.SetDeadline(time.Now().Add(time.Hour))
-		}
-	}()
-	c, err := Dial("tcp", ln.Addr().String())
+		}()
+		wg.Wait()
+	}
+	ls, err := newLocalServer("tcp")
 	if err != nil {
-		t.Fatalf("DialTCP: %v", err)
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 	defer c.Close()
-	<-connected
-	for i := 0; i < 1024; i++ {
-		var buf [1]byte
-		c.Write(buf[:])
+
+	var b [1]byte
+	for i := 0; i < 1000; i++ {
+		c.Write(b[:])
+		c.Read(b[:])
 	}
 }
 
-func TestDeadlineRace(t *testing.T) {
+func TestReadWriteDeadlineRace(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl", "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	N := 1000
@@ -720,28 +940,54 @@
 		N = 50
 	}
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-	ln := newLocalListener(t)
-	defer ln.Close()
-	c, err := Dial("tcp", ln.Addr().String())
+
+	ln, err := newLocalListener("tcp")
 	if err != nil {
-		t.Fatalf("Dial: %v", err)
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 	defer c.Close()
-	done := make(chan bool)
+
+	var wg sync.WaitGroup
+	wg.Add(3)
 	go func() {
-		t := time.NewTicker(2 * time.Microsecond).C
+		defer wg.Done()
+		tic := time.NewTicker(2 * time.Microsecond)
+		defer tic.Stop()
 		for i := 0; i < N; i++ {
-			if err := c.SetDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+			if err := c.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+				if perr := parseCommonError(err); perr != nil {
+					t.Error(perr)
+				}
 				break
 			}
-			<-t
+			if err := c.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+				if perr := parseCommonError(err); perr != nil {
+					t.Error(perr)
+				}
+				break
+			}
+			<-tic.C
 		}
-		done <- true
 	}()
-	var buf [1]byte
-	for i := 0; i < N; i++ {
-		c.Read(buf[:]) // ignore possible timeout errors
-	}
-	c.Close()
-	<-done
+	go func() {
+		defer wg.Done()
+		var b [1]byte
+		for i := 0; i < N; i++ {
+			c.Read(b[:]) // ignore possible timeout errors
+		}
+	}()
+	go func() {
+		defer wg.Done()
+		var b [1]byte
+		for i := 0; i < N; i++ {
+			c.Write(b[:]) // ignore possible timeout errors
+		}
+	}()
+	wg.Wait() // wait for tester goroutine to stop
 }
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
index 2be2c31..2213468 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -7,78 +7,63 @@
 import (
 	"reflect"
 	"runtime"
-	"strings"
 	"testing"
 	"time"
 )
 
-func TestResolveUDPAddr(t *testing.T) {
-	for _, tt := range resolveTCPAddrTests {
-		net := strings.Replace(tt.net, "tcp", "udp", -1)
-		addr, err := ResolveUDPAddr(net, tt.litAddrOrName)
-		if err != tt.err {
-			t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, tt.litAddrOrName, err)
-		}
-		if !reflect.DeepEqual(addr, (*UDPAddr)(tt.addr)) {
-			t.Fatalf("ResolveUDPAddr(%q, %q) = %#v, want %#v", net, tt.litAddrOrName, addr, tt.addr)
-		}
-		if err == nil {
-			str := addr.String()
-			addr1, err := ResolveUDPAddr(net, str)
-			if err != nil {
-				t.Fatalf("ResolveUDPAddr(%q, %q) [from %q]: %v", net, str, tt.litAddrOrName, err)
-			}
-			if !reflect.DeepEqual(addr1, addr) {
-				t.Fatalf("ResolveUDPAddr(%q, %q) [from %q] = %#v, want %#v", net, str, tt.litAddrOrName, addr1, addr)
-			}
-		}
-	}
+type resolveUDPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *UDPAddr
+	err           error
 }
 
-func TestReadFromUDP(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS)
-	}
+var resolveUDPAddrTests = []resolveUDPAddrTest{
+	{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
+	{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
 
-	ra, err := ResolveUDPAddr("udp", "127.0.0.1:7")
-	if err != nil {
-		t.Fatal(err)
-	}
+	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
 
-	la, err := ResolveUDPAddr("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
+	{"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
+	{"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
 
-	c, err := ListenUDP("udp", la)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
+	{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
+	{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
 
-	_, err = c.WriteToUDP([]byte("a"), ra)
-	if err != nil {
-		t.Fatal(err)
-	}
+	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
 
-	err = c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	if err != nil {
-		t.Fatal(err)
-	}
-	b := make([]byte, 1)
-	_, _, err = c.ReadFromUDP(b)
-	if err == nil {
-		t.Fatal("ReadFromUDP should fail")
-	} else if !isTimeout(err) {
-		t.Fatal(err)
+	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+}
+
+func TestResolveUDPAddr(t *testing.T) {
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+
+	for i, tt := range resolveUDPAddrTests {
+		addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
+		if err != tt.err {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(addr, tt.addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
+		}
+		if err != nil {
+			continue
+		}
+		rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String())
+		if err != nil {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(rtaddr, addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+		}
 	}
 }
 
 func TestWriteToUDP(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	c, err := ListenPacket("udp", "127.0.0.1:0")
@@ -103,35 +88,33 @@
 		t.Fatal(err)
 	}
 
-	_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra)
+	b := []byte("CONNECTED-MODE SOCKET")
+	_, err = c.(*UDPConn).WriteToUDP(b, ra)
 	if err == nil {
-		t.Fatal("WriteToUDP should fail")
+		t.Fatal("should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-
-	_, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra)
+	_, err = c.(*UDPConn).WriteTo(b, ra)
 	if err == nil {
-		t.Fatal("WriteTo should fail")
+		t.Fatal("should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-
-	_, err = c.Write([]byte("Connection-oriented mode socket"))
+	_, err = c.Write(b)
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	_, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-oriented mode socket"), nil, ra)
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
 	if err == nil {
-		t.Fatal("WriteMsgUDP should fail")
+		t.Fatal("should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteMsgUDP should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-oriented mode socket"), nil, nil)
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
 	switch runtime.GOOS {
 	case "nacl", "windows": // see golang.org/issue/9252
 		t.Skipf("not implemented yet on %s", runtime.GOOS)
@@ -154,29 +137,27 @@
 		t.Fatal(err)
 	}
 
-	_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra)
+	b := []byte("UNCONNECTED-MODE SOCKET")
+	_, err = c.(*UDPConn).WriteToUDP(b, ra)
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	_, err = c.WriteTo([]byte("Connection-less mode socket"), ra)
+	_, err = c.WriteTo(b, ra)
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	_, err = c.(*UDPConn).Write([]byte("Connection-less mode socket"))
+	_, err = c.(*UDPConn).Write(b)
 	if err == nil {
-		t.Fatal("Write should fail")
+		t.Fatal("should fail")
 	}
-
-	_, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-less mode socket"), nil, nil)
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
 	if err == nil {
-		t.Fatal("WriteMsgUDP should fail")
+		t.Fatal("should fail")
 	}
 	if err != nil && err.(*OpError).Err != errMissingAddress {
-		t.Fatalf("WriteMsgUDP should fail as errMissingAddress: %v", err)
+		t.Fatalf("should fail as errMissingAddress: %v", err)
 	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-less mode socket"), nil, ra)
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
 	switch runtime.GOOS {
 	case "nacl", "windows": // see golang.org/issue/9252
 		t.Skipf("not implemented yet on %s", runtime.GOOS)
@@ -198,13 +179,13 @@
 
 func TestUDPConnLocalName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range udpConnLocalNameTests {
 		c, err := ListenUDP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatalf("ListenUDP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
 		la := c.LocalAddr()
@@ -218,7 +199,7 @@
 	for _, laddr := range []string{"", "127.0.0.1:0"} {
 		c1, err := ListenPacket("udp", "127.0.0.1:0")
 		if err != nil {
-			t.Fatalf("ListenUDP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c1.Close()
 
@@ -226,12 +207,12 @@
 		if laddr != "" {
 			var err error
 			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
-				t.Fatalf("ResolveUDPAddr failed: %v", err)
+				t.Fatal(err)
 			}
 		}
 		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
 		if err != nil {
-			t.Fatalf("DialUDP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c2.Close()
 
@@ -254,7 +235,7 @@
 
 func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 	if !supportsIPv6 {
 		t.Skip("ipv6 is not supported")
@@ -297,7 +278,7 @@
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
-			t.Logf("ListenPacket failed: %v", err)
+			t.Log(err)
 			continue
 		}
 		defer c1.Close()
@@ -307,7 +288,7 @@
 
 		c2, err := Dial(tt.net, c1.LocalAddr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c2.Close()
 		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
@@ -318,11 +299,11 @@
 		}
 
 		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 		b := make([]byte, 32)
 		if _, from, err := c1.ReadFrom(b); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			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)
@@ -330,3 +311,77 @@
 		}
 	}
 }
+
+func TestUDPZeroBytePayload(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	for _, genericRead := range []bool{false, true} {
+		n, err := c.WriteTo(nil, c.LocalAddr())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if n != 0 {
+			t.Errorf("got %d; want 0", n)
+		}
+		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var b [1]byte
+		if genericRead {
+			_, err = c.(Conn).Read(b[:])
+		} else {
+			_, _, err = c.ReadFrom(b[:])
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatal(err)
+			}
+		}
+	}
+}
+
+func TestUDPZeroByteBuffer(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	b := []byte("UDP ZERO BYTE BUFFER TEST")
+	for _, genericRead := range []bool{false, true} {
+		n, err := c.WriteTo(b, c.LocalAddr())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if n != len(b) {
+			t.Errorf("got %d; want %d", n, len(b))
+		}
+		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		if genericRead {
+			_, err = c.(Conn).Read(nil)
+		} else {
+			_, _, err = c.ReadFrom(nil)
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows retruns WSAEMSGSIZ
+				t.Fatal(err)
+			}
+		}
+	}
+}
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 532f7d5..5291a3e 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -32,13 +32,6 @@
 	return a.IP.IsUnspecified()
 }
 
-func (a *UDPAddr) toAddr() Addr {
-	if a == nil {
-		return nil
-	}
-	return a
-}
-
 // ResolveUDPAddr parses addr as a UDP address of the form "host:port"
 // or "[ipv6-host%zone]:port" and resolves a pair of domain name and
 // port name on the network net, which must be "udp", "udp4" or
@@ -53,9 +46,9 @@
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	a, err := resolveInternetAddr(net, addr, noDeadline)
+	addrs, err := internetAddrList(net, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return a.toAddr().(*UDPAddr), nil
+	return addrs.first(isIPv4).(*UDPAddr), nil
 }
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 2692726..949f666 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -33,10 +33,10 @@
 	buf := make([]byte, udpHeaderSize+len(b))
 	m, err := c.fd.data.Read(buf)
 	if err != nil {
-		return
+		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	if m < udpHeaderSize {
-		return 0, nil, errors.New("short read reading UDP header")
+		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")}
 	}
 	buf = buf[:m]
 
@@ -59,7 +59,7 @@
 // flags that were set on the packet and the source address of the
 // packet.
 func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-	return 0, 0, 0, nil, syscall.EPLAN9
+	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // WriteToUDP writes a UDP packet to addr via c, copying the payload
@@ -74,7 +74,7 @@
 		return 0, syscall.EINVAL
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
 	}
 	h := new(udpHeader)
 	h.raddr = addr.IP.To16()
@@ -86,7 +86,10 @@
 	buf := make([]byte, udpHeaderSize+len(b))
 	i := copy(buf, h.Bytes())
 	copy(buf[i:], b)
-	return c.fd.data.Write(buf)
+	if _, err := c.fd.data.Write(buf); err != nil {
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return len(b), nil
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -96,7 +99,7 @@
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
@@ -107,7 +110,7 @@
 // out-of-band data is copied from oob.  It returns the number of
 // payload and out-of-band bytes written.
 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
-	return 0, 0, syscall.EPLAN9
+	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // DialUDP connects to the remote address raddr on the network net,
@@ -124,10 +127,10 @@
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, UnknownNetworkError(net)
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{"dial", net, nil, errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: errMissingAddress}
 	}
 	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
@@ -175,7 +178,7 @@
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, UnknownNetworkError(net)
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &UDPAddr{}
@@ -186,11 +189,11 @@
 	}
 	_, err = l.ctl.WriteString("headers")
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	fd, err := l.netFD()
 	return newUDPConn(fd), err
@@ -201,5 +204,5 @@
 // interface to join.  ListenMulticastUDP uses default multicast
 // interface if ifi is nil.
 func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: syscall.EPLAN9}
 }
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 9733e7b..2e43068 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -53,10 +53,11 @@
 // ReadFromUDP can be made to time out and return an error with
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
-func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
+func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
+	var addr *UDPAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
@@ -64,7 +65,10 @@
 	case *syscall.SockaddrInet6:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
 	}
-	return
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, addr, err
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
@@ -73,7 +77,10 @@
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromUDP(b)
-	return n, addr.toAddr(), err
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
 }
 
 // ReadMsgUDP reads a packet from c, copying the payload into b and
@@ -93,6 +100,9 @@
 	case *syscall.SockaddrInet6:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return
 }
 
@@ -108,16 +118,20 @@
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
 	}
-	return c.fd.writeTo(b, sa)
+	n, err := c.fd.writeTo(b, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return n, err
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -127,7 +141,7 @@
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
@@ -142,16 +156,21 @@
 		return 0, 0, syscall.EINVAL
 	}
 	if c.fd.isConnected && addr != nil {
-		return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
 	}
 	if !c.fd.isConnected && addr == nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
 	}
-	sa, err := addr.sockaddr(c.fd.family)
+	var sa syscall.Sockaddr
+	sa, err = addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
 	}
-	return c.fd.writeMsg(b, oob, sa)
+	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return
 }
 
 // DialUDP connects to the remote address raddr on the network net,
@@ -161,10 +180,10 @@
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: errMissingAddress}
 	}
 	return dialUDP(net, laddr, raddr, noDeadline)
 }
@@ -172,7 +191,7 @@
 func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
 	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	return newUDPConn(fd), nil
 }
@@ -188,14 +207,14 @@
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &UDPAddr{}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return newUDPConn(fd), nil
 }
@@ -208,25 +227,25 @@
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: UnknownNetworkError(net)}
 	}
 	if gaddr == nil || gaddr.IP == nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: errMissingAddress}
 	}
 	fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, 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, Addr: &IPAddr{IP: ip4}, Err: err}
+			return nil, &OpError{Op: "listen", Net: net, 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, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
+			return nil, &OpError{Op: "listen", Net: net, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
 		}
 	}
 	return c, nil
diff --git a/src/net/unicast_posix_test.go b/src/net/unicast_posix_test.go
deleted file mode 100644
index ab7ef40..0000000
--- a/src/net/unicast_posix_test.go
+++ /dev/null
@@ -1,469 +0,0 @@
-// Copyright 2011 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 !plan9
-
-package net
-
-import (
-	"runtime"
-	"syscall"
-	"testing"
-)
-
-var listenerTests = []struct {
-	net      string
-	laddr    string
-	ipv6     bool // test with underlying AF_INET6 socket
-	wildcard bool // test with wildcard address
-}{
-	{net: "tcp", laddr: "", wildcard: true},
-	{net: "tcp", laddr: "0.0.0.0", wildcard: true},
-	{net: "tcp", laddr: "[::ffff:0.0.0.0]", wildcard: true},
-	{net: "tcp", laddr: "[::]", ipv6: true, wildcard: true},
-
-	{net: "tcp", laddr: "127.0.0.1"},
-	{net: "tcp", laddr: "[::ffff:127.0.0.1]"},
-	{net: "tcp", laddr: "[::1]", ipv6: true},
-
-	{net: "tcp4", laddr: "", wildcard: true},
-	{net: "tcp4", laddr: "0.0.0.0", wildcard: true},
-	{net: "tcp4", laddr: "[::ffff:0.0.0.0]", wildcard: true},
-
-	{net: "tcp4", laddr: "127.0.0.1"},
-	{net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
-
-	{net: "tcp6", laddr: "", ipv6: true, wildcard: true},
-	{net: "tcp6", laddr: "[::]", ipv6: true, wildcard: true},
-
-	{net: "tcp6", laddr: "[::1]", ipv6: true},
-}
-
-// TestTCPListener tests both single and double listen to a test
-// listener with same address family, same listening address and
-// same port.
-func TestTCPListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	for _, tt := range listenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
-			continue
-		}
-		if tt.ipv6 && !supportsIPv6 {
-			continue
-		}
-		l1, port := usableListenPort(t, tt.net, tt.laddr)
-		checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
-		l2, err := Listen(tt.net, tt.laddr+":"+port)
-		checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
-		l1.Close()
-	}
-}
-
-// TestUDPListener tests both single and double listen to a test
-// listener with same address family, same listening address and
-// same port.
-func TestUDPListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	toudpnet := func(net string) string {
-		switch net {
-		case "tcp":
-			return "udp"
-		case "tcp4":
-			return "udp4"
-		case "tcp6":
-			return "udp6"
-		}
-		return "<nil>"
-	}
-
-	for _, tt := range listenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
-			continue
-		}
-		if tt.ipv6 && !supportsIPv6 {
-			continue
-		}
-		tt.net = toudpnet(tt.net)
-		l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
-		checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
-		l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
-		checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
-		l1.Close()
-	}
-}
-
-var dualStackListenerTests = []struct {
-	net1     string // first listener
-	laddr1   string
-	net2     string // second listener
-	laddr2   string
-	wildcard bool  // test with wildcard address
-	xerr     error // expected error value, nil or other
-}{
-	// Test cases and expected results for the attemping 2nd listen on the same port
-	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
-	// ------------------------------------------------------------------------------------
-	// "tcp"  ""                 "tcp"  ""                    -        -       -       -
-	// "tcp"  ""                 "tcp"  "0.0.0.0"             -        -       -       -
-	// "tcp"  "0.0.0.0"          "tcp"  ""                    -        -       -       -
-	// ------------------------------------------------------------------------------------
-	// "tcp"  ""                 "tcp"  "[::]"                -        -       -       ok
-	// "tcp"  "[::]"             "tcp"  ""                    -        -       -       ok
-	// "tcp"  "0.0.0.0"          "tcp"  "[::]"                -        -       -       ok
-	// "tcp"  "[::]"             "tcp"  "0.0.0.0"             -        -       -       ok
-	// "tcp"  "[::ffff:0.0.0.0]" "tcp"  "[::]"                -        -       -       ok
-	// "tcp"  "[::]"             "tcp"  "[::ffff:0.0.0.0]"    -        -       -       ok
-	// ------------------------------------------------------------------------------------
-	// "tcp4" ""                 "tcp6" ""                    ok       ok      ok      ok
-	// "tcp6" ""                 "tcp4" ""                    ok       ok      ok      ok
-	// "tcp4" "0.0.0.0"          "tcp6" "[::]"                ok       ok      ok      ok
-	// "tcp6" "[::]"             "tcp4" "0.0.0.0"             ok       ok      ok      ok
-	// ------------------------------------------------------------------------------------
-	// "tcp"  "127.0.0.1"        "tcp"  "[::1]"               ok       ok      ok      ok
-	// "tcp"  "[::1]"            "tcp"  "127.0.0.1"           ok       ok      ok      ok
-	// "tcp4" "127.0.0.1"        "tcp6" "[::1]"               ok       ok      ok      ok
-	// "tcp6" "[::1]"            "tcp4" "127.0.0.1"           ok       ok      ok      ok
-	//
-	// Platform default configurations:
-	// darwin, kernel version 11.3.0
-	//	net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
-	// freebsd, kernel version 8.2
-	//	net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
-	// linux, kernel version 3.0.0
-	//	net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
-	// openbsd, kernel version 5.0
-	//	net.inet6.ip6.v6only=1 (overriding is prohibited)
-
-	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
-
-	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::ffff:0.0.0.0]", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "[::ffff:0.0.0.0]", wildcard: true, xerr: syscall.EADDRINUSE},
-
-	{net1: "tcp4", laddr1: "", net2: "tcp6", laddr2: "", wildcard: true},
-	{net1: "tcp6", laddr1: "", net2: "tcp4", laddr2: "", wildcard: true},
-	{net1: "tcp4", laddr1: "0.0.0.0", net2: "tcp6", laddr2: "[::]", wildcard: true},
-	{net1: "tcp6", laddr1: "[::]", net2: "tcp4", laddr2: "0.0.0.0", wildcard: true},
-
-	{net1: "tcp", laddr1: "127.0.0.1", net2: "tcp", laddr2: "[::1]"},
-	{net1: "tcp", laddr1: "[::1]", net2: "tcp", laddr2: "127.0.0.1"},
-	{net1: "tcp4", laddr1: "127.0.0.1", net2: "tcp6", laddr2: "[::1]"},
-	{net1: "tcp6", laddr1: "[::1]", net2: "tcp4", laddr2: "127.0.0.1"},
-}
-
-// TestDualStackTCPListener tests both single and double listen
-// to a test listener with various address families, different
-// listening address and same port.
-func TestDualStackTCPListener(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode, see issue 5001")
-	}
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-
-	for _, tt := range dualStackListenerTests {
-		if tt.wildcard && !*testExternal {
-			continue
-		}
-		switch runtime.GOOS {
-		case "openbsd":
-			if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
-				tt.xerr = nil
-			}
-		}
-		l1, port := usableListenPort(t, tt.net1, tt.laddr1)
-		laddr := tt.laddr1 + ":" + port
-		checkFirstListener(t, tt.net1, laddr, l1)
-		laddr = tt.laddr2 + ":" + port
-		l2, err := Listen(tt.net2, laddr)
-		checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
-		l1.Close()
-	}
-}
-
-// TestDualStackUDPListener tests both single and double listen
-// to a test listener with various address families, differnet
-// listening address and same port.
-func TestDualStackUDPListener(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode, see issue 5001")
-	}
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-
-	toudpnet := func(net string) string {
-		switch net {
-		case "tcp":
-			return "udp"
-		case "tcp4":
-			return "udp4"
-		case "tcp6":
-			return "udp6"
-		}
-		return "<nil>"
-	}
-
-	for _, tt := range dualStackListenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
-			continue
-		}
-		tt.net1 = toudpnet(tt.net1)
-		tt.net2 = toudpnet(tt.net2)
-		switch runtime.GOOS {
-		case "openbsd":
-			if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
-				tt.xerr = nil
-			}
-		}
-		l1, port := usableListenPacketPort(t, tt.net1, tt.laddr1)
-		laddr := tt.laddr1 + ":" + port
-		checkFirstListener(t, tt.net1, laddr, l1)
-		laddr = tt.laddr2 + ":" + port
-		l2, err := ListenPacket(tt.net2, laddr)
-		checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
-		l1.Close()
-	}
-}
-
-func usableListenPort(t *testing.T, net, laddr string) (l Listener, port string) {
-	var nladdr string
-	var err error
-	switch net {
-	default:
-		panic("usableListenPort net=" + net)
-	case "tcp", "tcp4", "tcp6":
-		l, err = Listen(net, laddr+":0")
-		if err != nil {
-			t.Fatalf("Probe Listen(%q, %q) failed: %v", net, laddr, err)
-		}
-		nladdr = l.(*TCPListener).Addr().String()
-	}
-	_, port, err = SplitHostPort(nladdr)
-	if err != nil {
-		t.Fatalf("SplitHostPort failed: %v", err)
-	}
-	return l, port
-}
-
-func usableListenPacketPort(t *testing.T, net, laddr string) (l PacketConn, port string) {
-	var nladdr string
-	var err error
-	switch net {
-	default:
-		panic("usableListenPacketPort net=" + net)
-	case "udp", "udp4", "udp6":
-		l, err = ListenPacket(net, laddr+":0")
-		if err != nil {
-			t.Fatalf("Probe ListenPacket(%q, %q) failed: %v", net, laddr, err)
-		}
-		nladdr = l.(*UDPConn).LocalAddr().String()
-	}
-	_, port, err = SplitHostPort(nladdr)
-	if err != nil {
-		t.Fatalf("SplitHostPort failed: %v", err)
-	}
-	return l, port
-}
-
-func differentWildcardAddr(i, j string) bool {
-	if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
-		return false
-	}
-	if i == "[::]" && j == "[::]" {
-		return false
-	}
-	return true
-}
-
-func checkFirstListener(t *testing.T, net, laddr string, l interface{}) {
-	switch net {
-	case "tcp":
-		fd := l.(*TCPListener).fd
-		checkDualStackAddrFamily(t, net, laddr, fd)
-	case "tcp4":
-		fd := l.(*TCPListener).fd
-		if fd.family != syscall.AF_INET {
-			t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
-		}
-	case "tcp6":
-		fd := l.(*TCPListener).fd
-		if fd.family != syscall.AF_INET6 {
-			t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-		}
-	case "udp":
-		fd := l.(*UDPConn).fd
-		checkDualStackAddrFamily(t, net, laddr, fd)
-	case "udp4":
-		fd := l.(*UDPConn).fd
-		if fd.family != syscall.AF_INET {
-			t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
-		}
-	case "udp6":
-		fd := l.(*UDPConn).fd
-		if fd.family != syscall.AF_INET6 {
-			t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-		}
-	default:
-		t.Fatalf("Unexpected network: %q", net)
-	}
-}
-
-func checkSecondListener(t *testing.T, net, laddr string, err error, l interface{}) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		if err == nil {
-			l.(*TCPListener).Close()
-			t.Fatalf("Second Listen(%q, %q) should fail", net, laddr)
-		}
-	case "udp", "udp4", "udp6":
-		if err == nil {
-			l.(*UDPConn).Close()
-			t.Fatalf("Second ListenPacket(%q, %q) should fail", net, laddr)
-		}
-	default:
-		t.Fatalf("Unexpected network: %q", net)
-	}
-}
-
-func checkDualStackSecondListener(t *testing.T, net, laddr string, xerr, err error, l interface{}) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		if xerr == nil && err != nil || xerr != nil && err == nil {
-			t.Fatalf("Second Listen(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
-		}
-		if err == nil {
-			l.(*TCPListener).Close()
-		}
-	case "udp", "udp4", "udp6":
-		if xerr == nil && err != nil || xerr != nil && err == nil {
-			t.Fatalf("Second ListenPacket(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
-		}
-		if err == nil {
-			l.(*UDPConn).Close()
-		}
-	default:
-		t.Fatalf("Unexpected network: %q", net)
-	}
-}
-
-func checkDualStackAddrFamily(t *testing.T, net, laddr string, fd *netFD) {
-	switch a := fd.laddr.(type) {
-	case *TCPAddr:
-		// If a node under test supports both IPv6 capability
-		// and IPv6 IPv4-mapping capability, we can assume
-		// that the node listens on a wildcard address with an
-		// AF_INET6 socket.
-		if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
-			if fd.family != syscall.AF_INET6 {
-				t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-			}
-		} else {
-			if fd.family != a.family() {
-				t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
-			}
-		}
-	case *UDPAddr:
-		// If a node under test supports both IPv6 capability
-		// and IPv6 IPv4-mapping capability, we can assume
-		// that the node listens on a wildcard address with an
-		// AF_INET6 socket.
-		if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
-			if fd.family != syscall.AF_INET6 {
-				t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-			}
-		} else {
-			if fd.family != a.family() {
-				t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
-			}
-		}
-	default:
-		t.Fatalf("Unexpected protocol address type: %T", a)
-	}
-}
-
-var prohibitionaryDialArgTests = []struct {
-	net  string
-	addr string
-}{
-	{"tcp6", "127.0.0.1"},
-	{"tcp6", "[::ffff:127.0.0.1]"},
-}
-
-func TestProhibitionaryDialArgs(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	// This test requires both IPv6 and IPv6 IPv4-mapping functionality.
-	if !supportsIPv4map || testing.Short() || !*testExternal {
-		return
-	}
-
-	l, port := usableListenPort(t, "tcp", "[::]")
-	defer l.Close()
-
-	for _, tt := range prohibitionaryDialArgTests {
-		c, err := Dial(tt.net, tt.addr+":"+port)
-		if err == nil {
-			c.Close()
-			t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
-		}
-	}
-}
-
-func TestWildWildcardListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	defer func() {
-		if p := recover(); p != nil {
-			t.Fatalf("Listen, ListenPacket or protocol-specific Listen panicked: %v", p)
-		}
-	}()
-
-	if ln, err := Listen("tcp", ""); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenPacket("udp", ""); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenTCP("tcp", nil); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenUDP("udp", nil); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenIP("ip:icmp", nil); err == nil {
-		ln.Close()
-	}
-}
diff --git a/src/net/unix_test.go b/src/net/unix_test.go
index 85d1ff4..59f5c2d 100644
--- a/src/net/unix_test.go
+++ b/src/net/unix_test.go
@@ -24,11 +24,11 @@
 	addr := testUnixAddr()
 	la, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenUnixgram("unixgram", la)
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
 	defer func() {
 		c.Close()
@@ -41,13 +41,13 @@
 		defer func() { off <- true }()
 		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
 		if err != nil {
-			t.Errorf("syscall.Socket failed: %v", err)
+			t.Error(err)
 			return
 		}
 		defer syscall.Close(s)
 		rsa := &syscall.SockaddrUnix{Name: addr}
 		if err := syscall.Sendto(s, data[:], 0, rsa); err != nil {
-			t.Errorf("syscall.Sendto failed: %v", err)
+			t.Error(err)
 			return
 		}
 	}()
@@ -57,72 +57,123 @@
 	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
 	n, from, err := c.ReadFrom(b)
 	if err != nil {
-		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
+		t.Fatal(err)
 	}
 	if from != nil {
-		t.Fatalf("neighbor address is %v", from)
+		t.Fatalf("unexpected peer address: %v", from)
 	}
 	if !bytes.Equal(b[:n], data[:]) {
-		t.Fatalf("got %v, want %v", b[:n], data[:])
+		t.Fatalf("got %v; want %v", b[:n], data[:])
 	}
 }
 
-func TestReadUnixgramWithZeroBytesBuffer(t *testing.T) {
+func TestUnixgramZeroBytePayload(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
+	c1, err := newLocalPacketListener("unixgram")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(c1.LocalAddr().String())
+	defer c1.Close()
+
+	c2, err := Dial("unixgram", c1.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(c2.LocalAddr().String())
+	defer c2.Close()
+
+	for _, genericRead := range []bool{false, true} {
+		n, err := c2.Write(nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if n != 0 {
+			t.Errorf("got %d; want 0", n)
+		}
+		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var b [1]byte
+		var peer Addr
+		if genericRead {
+			_, err = c1.(Conn).Read(b[:])
+		} else {
+			_, peer, err = c1.ReadFrom(b[:])
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+			if peer != nil { // peer is connected-mode
+				t.Fatalf("unexpected peer address: %v", peer)
+			}
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatal(err)
+			}
+		}
+	}
+}
+
+func TestUnixgramZeroByteBuffer(t *testing.T) {
 	if !testableNetwork("unixgram") {
 		t.Skip("unixgram test")
 	}
 	// issue 4352: Recvfrom failed with "address family not
 	// supported by protocol family" if zero-length buffer provided
 
-	addr := testUnixAddr()
-	la, err := ResolveUnixAddr("unixgram", addr)
+	c1, err := newLocalPacketListener("unixgram")
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
-	c, err := ListenUnixgram("unixgram", la)
-	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
-	}
-	defer func() {
-		c.Close()
-		os.Remove(addr)
-	}()
+	defer os.Remove(c1.LocalAddr().String())
+	defer c1.Close()
 
-	off := make(chan bool)
-	go func() {
-		defer func() { off <- true }()
-		c, err := DialUnix("unixgram", nil, la)
+	c2, err := Dial("unixgram", c1.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(c2.LocalAddr().String())
+	defer c2.Close()
+
+	b := []byte("UNIXGRAM ZERO BYTE BUFFER TEST")
+	for _, genericRead := range []bool{false, true} {
+		n, err := c2.Write(b)
 		if err != nil {
-			t.Errorf("DialUnix failed: %v", err)
-			return
+			t.Fatal(err)
 		}
-		defer c.Close()
-		if _, err := c.Write([]byte{1, 2, 3, 4, 5}); err != nil {
-			t.Errorf("UnixConn.Write failed: %v", err)
-			return
+		if n != len(b) {
+			t.Errorf("got %d; want %d", n, len(b))
 		}
-	}()
-
-	<-off
-	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-	_, from, err := c.ReadFrom(nil)
-	if err != nil {
-		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
-	}
-	if from != nil {
-		t.Fatalf("neighbor address is %v", from)
+		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var peer Addr
+		if genericRead {
+			_, err = c1.(Conn).Read(nil)
+		} else {
+			_, peer, err = c1.ReadFrom(nil)
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+			if peer != nil { // peer is connected-mode
+				t.Fatalf("unexpected peer address: %v", peer)
+			}
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatal(err)
+			}
+		}
 	}
 }
 
 func TestUnixgramAutobind(t *testing.T) {
 	if runtime.GOOS != "linux" {
-		t.Skip("skipping: autobind is linux only")
+		t.Skip("autobind is linux only")
 	}
 
 	laddr := &UnixAddr{Name: "", Net: "unixgram"}
 	c1, err := ListenUnixgram("unixgram", laddr)
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c1.Close()
 
@@ -137,7 +188,7 @@
 
 	c2, err := DialUnix("unixgram", nil, autoAddr)
 	if err != nil {
-		t.Fatalf("DialUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c2.Close()
 
@@ -148,13 +199,13 @@
 
 func TestUnixAutobindClose(t *testing.T) {
 	if runtime.GOOS != "linux" {
-		t.Skip("skipping: autobind is linux only")
+		t.Skip("autobind is linux only")
 	}
 
 	laddr := &UnixAddr{Name: "", Net: "unix"}
 	ln, err := ListenUnix("unix", laddr)
 	if err != nil {
-		t.Fatalf("ListenUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	ln.Close()
 }
@@ -167,11 +218,11 @@
 	addr := testUnixAddr()
 	laddr, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenPacket("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ListenPacket failed: %v", err)
+		t.Fatal(err)
 	}
 	defer os.Remove(addr)
 	defer c.Close()
@@ -183,27 +234,28 @@
 func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
 	c, err := Dial("unixgram", raddr.String())
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 
-	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil {
-		t.Fatal("WriteToUnix should fail")
+	b := []byte("CONNECTED-MODE SOCKET")
+	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err == nil {
+		t.Fatal("should fail")
 	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil {
-		t.Fatal("WriteTo should fail")
+	if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil {
+		t.Fatal("should fail")
 	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, _, err = c.(*UnixConn).WriteMsgUnix([]byte("Connection-oriented mode socket"), nil, raddr); err == nil {
-		t.Fatal("WriteTo should fail")
+	if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil {
+		t.Fatal("should fail")
 	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil {
-		t.Fatalf("Write failed: %v", err)
+	if _, err := c.Write(b); err != nil {
+		t.Fatal(err)
 	}
 }
 
@@ -211,22 +263,23 @@
 	addr := testUnixAddr()
 	c, err := ListenPacket("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ListenPacket failed: %v", err)
+		t.Fatal(err)
 	}
 	defer os.Remove(addr)
 	defer c.Close()
 
-	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil {
-		t.Fatalf("WriteToUnix failed: %v", err)
+	b := []byte("UNCONNECTED-MODE SOCKET")
+	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil {
+		t.Fatal(err)
 	}
-	if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil {
-		t.Fatalf("WriteTo failed: %v", err)
+	if _, err := c.WriteTo(b, raddr); err != nil {
+		t.Fatal(err)
 	}
-	if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil {
-		t.Fatalf("WriteMsgUnix failed: %v", err)
+	if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil {
+		t.Fatal(err)
 	}
-	if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil {
-		t.Fatal("Write should fail")
+	if _, err := c.(*UnixConn).Write(b); err == nil {
+		t.Fatal("should fail")
 	}
 }
 
@@ -235,32 +288,34 @@
 		t.Skip("unix test")
 	}
 
+	handler := func(ls *localServer, ln Listener) {}
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
 		ta, err := ResolveUnixAddr("unix", taddr)
 		if err != nil {
-			t.Fatalf("ResolveUnixAddr failed: %v", err)
+			t.Fatal(err)
 		}
 		ln, err := ListenUnix("unix", ta)
 		if err != nil {
-			t.Fatalf("ListenUnix failed: %v", err)
+			t.Fatal(err)
 		}
-		defer func() {
-			ln.Close()
-			os.Remove(taddr)
-		}()
-
-		done := make(chan int)
-		go transponder(t, ln, done)
+		ls, err := (&streamListener{Listener: ln}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 
 		la, err := ResolveUnixAddr("unix", laddr)
 		if err != nil {
-			t.Fatalf("ResolveUnixAddr failed: %v", err)
+			t.Fatal(err)
 		}
 		c, err := DialUnix("unix", la, ta)
 		if err != nil {
-			t.Fatalf("DialUnix failed: %v", err)
+			t.Fatal(err)
 		}
 		defer func() {
 			c.Close()
@@ -269,7 +324,7 @@
 			}
 		}()
 		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
-			t.Fatalf("UnixConn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 
 		switch runtime.GOOS {
@@ -288,8 +343,6 @@
 				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
 			}
 		}
-
-		<-done
 	}
 }
 
@@ -303,11 +356,11 @@
 		taddr := testUnixAddr()
 		ta, err := ResolveUnixAddr("unixgram", taddr)
 		if err != nil {
-			t.Fatalf("ResolveUnixAddr failed: %v", err)
+			t.Fatal(err)
 		}
 		c1, err := ListenUnixgram("unixgram", ta)
 		if err != nil {
-			t.Fatalf("ListenUnixgram failed: %v", err)
+			t.Fatal(err)
 		}
 		defer func() {
 			c1.Close()
@@ -317,12 +370,12 @@
 		var la *UnixAddr
 		if laddr != "" {
 			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
-				t.Fatalf("ResolveUnixAddr failed: %v", err)
+				t.Fatal(err)
 			}
 		}
 		c2, err := DialUnix("unixgram", la, ta)
 		if err != nil {
-			t.Fatalf("DialUnix failed: %v", err)
+			t.Fatal(err)
 		}
 		defer func() {
 			c2.Close()
@@ -346,7 +399,7 @@
 		}
 		for _, ca := range connAddrs {
 			if !reflect.DeepEqual(ca.got, ca.want) {
-				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+				t.Fatalf("got %#v; want %#v", ca.got, ca.want)
 			}
 		}
 	}
diff --git a/src/net/unixsock.go b/src/net/unixsock.go
index 8595584..94c4c39 100644
--- a/src/net/unixsock.go
+++ b/src/net/unixsock.go
@@ -23,13 +23,6 @@
 	return a.Name
 }
 
-func (a *UnixAddr) toAddr() Addr {
-	if a == nil {
-		return nil
-	}
-	return a
-}
-
 // ResolveUnixAddr parses addr as a Unix domain socket address.
 // The string net gives the network name, "unix", "unixgram" or
 // "unixpacket".
diff --git a/src/net/unixsock_plan9.go b/src/net/unixsock_plan9.go
index 64a511d..c31907b 100644
--- a/src/net/unixsock_plan9.go
+++ b/src/net/unixsock_plan9.go
@@ -24,12 +24,12 @@
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadMsgUnix reads a packet from c, copying the payload into b and
@@ -37,7 +37,7 @@
 // bytes copied into b, the number of bytes copied into oob, the flags
 // that were set on the packet, and the source address of the packet.
 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
-	return 0, 0, 0, nil, syscall.EPLAN9
+	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // WriteToUnix writes a packet to addr via c, copying the payload from b.
@@ -47,31 +47,31 @@
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // WriteTo implements the PacketConn WriteTo method.
 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // WriteMsgUnix writes a packet to addr via c, copying the payload
 // from b and the associated out-of-band data from oob.  It returns
 // the number of payload and out-of-band bytes written.
 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
-	return 0, 0, syscall.EPLAN9
+	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseRead() error {
-	return syscall.EPLAN9
+	return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseWrite() error {
-	return syscall.EPLAN9
+	return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -82,36 +82,38 @@
 }
 
 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: syscall.EPLAN9}
 }
 
 // UnixListener is a Unix domain socket listener.  Clients should
 // typically use variables of type Listener instead of assuming Unix
 // domain sockets.
-type UnixListener struct{}
+type UnixListener struct {
+	fd *netFD
+}
 
 // ListenUnix announces on the Unix domain socket laddr and returns a
 // Unix listener.  The network net must be "unix" or "unixpacket".
 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: syscall.EPLAN9}
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
 // connection.
 func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // Accept implements the Accept method in the Listener interface; it
 // waits for the next call and returns a generic Conn.
 func (l *UnixListener) Accept() (Conn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // Close stops listening on the Unix address.  Already accepted
 // connections are not closed.
 func (l *UnixListener) Close() error {
-	return syscall.EPLAN9
+	return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // Addr returns the listener's network address.
@@ -122,7 +124,7 @@
 // SetDeadline sets the deadline associated with the listener.
 // A zero time value disables the deadline.
 func (l *UnixListener) SetDeadline(t time.Time) error {
-	return syscall.EPLAN9
+	return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -133,7 +135,7 @@
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
 func (l *UnixListener) File() (*os.File, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // ListenUnixgram listens for incoming Unix datagram packets addressed
@@ -141,5 +143,5 @@
 // The returned connection's ReadFrom and WriteTo methods can be used
 // to receive and send packets with per-packet addressing.
 func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: syscall.EPLAN9}
 }
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index d7127d9..005d248 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -113,10 +113,11 @@
 // ReadFromUnix can be made to time out and return an error with
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
-func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
+func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
+	var addr *UnixAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
@@ -124,7 +125,10 @@
 			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
-	return
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, addr, err
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
@@ -133,7 +137,10 @@
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromUnix(b)
-	return n, addr.toAddr(), err
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
 }
 
 // ReadMsgUnix reads a packet from c, copying the payload into b and
@@ -151,6 +158,9 @@
 			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return
 }
 
@@ -160,21 +170,25 @@
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
 	}
 	if addr.Net != sotypeToNet(c.fd.sotype) {
-		return 0, syscall.EAFNOSUPPORT
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EAFNOSUPPORT}
 	}
 	sa := &syscall.SockaddrUnix{Name: addr.Name}
-	return c.fd.writeTo(b, sa)
+	n, err := c.fd.writeTo(b, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return n, err
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -184,7 +198,7 @@
 	}
 	a, ok := addr.(*UnixAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToUnix(b, a)
 }
@@ -197,16 +211,20 @@
 		return 0, 0, syscall.EINVAL
 	}
 	if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
 	}
+	var sa syscall.Sockaddr
 	if addr != nil {
 		if addr.Net != sotypeToNet(c.fd.sotype) {
-			return 0, 0, syscall.EAFNOSUPPORT
+			return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EAFNOSUPPORT}
 		}
-		sa := &syscall.SockaddrUnix{Name: addr.Name}
-		return c.fd.writeMsg(b, oob, sa)
+		sa = &syscall.SockaddrUnix{Name: addr.Name}
 	}
-	return c.fd.writeMsg(b, oob, nil)
+	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
+	}
+	return
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
@@ -215,7 +233,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeRead()
+	err := c.fd.closeRead()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
@@ -224,7 +246,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeWrite()
+	err := c.fd.closeWrite()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -234,7 +260,7 @@
 	switch net {
 	case "unix", "unixgram", "unixpacket":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	return dialUnix(net, laddr, raddr, noDeadline)
 }
@@ -242,7 +268,7 @@
 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
 	fd, err := unixSocket(net, laddr, raddr, "dial", deadline)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	return newUnixConn(fd), nil
 }
@@ -261,16 +287,16 @@
 	switch net {
 	case "unix", "unixpacket":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: errMissingAddress}
 	}
 	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
-	return &UnixListener{fd, fd.laddr.String()}, nil
+	return &UnixListener{fd: fd, path: fd.laddr.String()}, nil
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
@@ -281,10 +307,9 @@
 	}
 	fd, err := l.fd.accept()
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
-	c := newUnixConn(fd)
-	return c, nil
+	return newUnixConn(fd), nil
 }
 
 // Accept implements the Accept method in the Listener interface; it
@@ -317,7 +342,11 @@
 	if l.path[0] != '@' {
 		syscall.Unlink(l.path)
 	}
-	return l.fd.Close()
+	err := l.fd.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // Addr returns the listener's network address.
@@ -327,11 +356,14 @@
 
 // SetDeadline sets the deadline associated with the listener.
 // A zero time value disables the deadline.
-func (l *UnixListener) SetDeadline(t time.Time) (err error) {
+func (l *UnixListener) SetDeadline(t time.Time) error {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.setDeadline(t)
+	if err := l.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -341,7 +373,13 @@
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() }
+func (l *UnixListener) File() (f *os.File, err error) {
+	f, err = l.fd.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
 
 // ListenUnixgram listens for incoming Unix datagram packets addressed
 // to the local address laddr.  The network net must be "unixgram".
@@ -351,14 +389,14 @@
 	switch net {
 	case "unixgram":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: errMissingAddress}
 	}
 	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return newUnixConn(fd), nil
 }
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 0ad68cc..917dcb0 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -51,6 +51,7 @@
 
 const (
 	encodePath encoding = 1 + iota
+	encodeHost
 	encodeUserPassword
 	encodeQueryComponent
 	encodeFragment
@@ -64,6 +65,9 @@
 
 // Return true if the specified character should be escaped when
 // appearing in a URL string, according to RFC 3986.
+//
+// Please be informed that for now shouldEscape does not check all
+// reserved characters correctly. See golang.org/issue/5684.
 func shouldEscape(c byte, mode encoding) bool {
 	// §2.3 Unreserved characters (alphanum)
 	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
@@ -92,6 +96,10 @@
 			// that too.
 			return c == '@' || c == '/' || c == '?' || c == ':'
 
+		case encodeHost: // §3.2.1
+			// The RFC allows ':'.
+			return c != ':'
+
 		case encodeQueryComponent: // §3.4
 			// The RFC reserves (so we must escape) everything.
 			return true
@@ -101,6 +109,13 @@
 			// everything, so escape nothing.
 			return false
 		}
+
+	case '[', ']': // §2.2 Reserved characters (reserved)
+		switch mode {
+		case encodeHost: // §3.2.1
+			// The RFC allows '[', ']'.
+			return false
+		}
 	}
 
 	// Everything else must be escaped.
@@ -401,10 +416,6 @@
 		if err != nil {
 			goto Error
 		}
-		if strings.Contains(url.Host, "%") {
-			err = errors.New("hexadecimal escape in host")
-			goto Error
-		}
 	}
 	if url.Path, err = unescape(rest, encodePath); err != nil {
 		goto Error
@@ -418,26 +429,76 @@
 func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 	i := strings.LastIndex(authority, "@")
 	if i < 0 {
-		host = authority
-		return
+		host, err = parseHost(authority)
+	} else {
+		host, err = parseHost(authority[i+1:])
 	}
-	userinfo, host := authority[:i], authority[i+1:]
+	if err != nil {
+		return nil, "", err
+	}
+	if i < 0 {
+		return nil, host, nil
+	}
+	userinfo := authority[:i]
 	if strings.Index(userinfo, ":") < 0 {
 		if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
-			return
+			return nil, "", err
 		}
 		user = User(userinfo)
 	} else {
 		username, password := split(userinfo, ":", true)
 		if username, err = unescape(username, encodeUserPassword); err != nil {
-			return
+			return nil, "", err
 		}
 		if password, err = unescape(password, encodeUserPassword); err != nil {
-			return
+			return nil, "", err
 		}
 		user = UserPassword(username, password)
 	}
-	return
+	return user, host, nil
+}
+
+// parseHost parses host as an authority without user information.
+func parseHost(host string) (string, error) {
+	litOrName := host
+	if strings.HasPrefix(host, "[") {
+		// Parse an IP-Literal in RFC 3986 and RFC 6874.
+		// E.g., "[fe80::1], "[fe80::1%25en0]"
+		//
+		// RFC 4007 defines "%" as a delimiter character in
+		// the textual representation of IPv6 addresses.
+		// Per RFC 6874, in URIs that "%" is encoded as "%25".
+		i := strings.LastIndex(host[1:], "]")
+		if i < 0 {
+			return "", errors.New("missing ']' in host")
+		}
+		// Parse a host subcomponent without a ZoneID in RFC
+		// 6874 because the ZoneID is allowed to use the
+		// percent encoded form.
+		j := strings.Index(host[1:1+i], "%25")
+		if j < 0 {
+			litOrName = host[1 : 1+i]
+		} else {
+			litOrName = host[1 : 1+j]
+		}
+	}
+	// A URI containing an IP-Literal without a ZoneID or
+	// IPv4address in RFC 3986 and RFC 6847 must not be
+	// percent-encoded.
+	//
+	// A URI containing a DNS registered name in RFC 3986 is
+	// allowed to be percent-encoded, though we don't use it for
+	// now to avoid messing up with the gap between allowed
+	// characters in URI and allowed characters in DNS.
+	// See golang.org/issue/7991.
+	if strings.Contains(litOrName, "%") {
+		return "", errors.New("percent-encoded characters in host")
+	}
+	var err error
+	if host, err = unescape(host, encodeHost); err != nil {
+		return "", err
+	}
+	return host, nil
 }
 
 // String reassembles the URL into a valid URL string.
@@ -475,7 +536,7 @@
 				buf.WriteByte('@')
 			}
 			if h := u.Host; h != "" {
-				buf.WriteString(h)
+				buf.WriteString(escape(h, encodeHost))
 			}
 		}
 		if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go
index d8b19d8..a2a8fe0 100644
--- a/src/net/url/url_test.go
+++ b/src/net/url/url_test.go
@@ -289,6 +289,86 @@
 		},
 		"",
 	},
+	// host subcomponent; IPv4 address in RFC 3986
+	{
+		"http://192.168.0.1/",
+		&URL{
+			Scheme: "http",
+			Host:   "192.168.0.1",
+			Path:   "/",
+		},
+		"",
+	},
+	// host and port subcomponents; IPv4 address in RFC 3986
+	{
+		"http://192.168.0.1:8080/",
+		&URL{
+			Scheme: "http",
+			Host:   "192.168.0.1:8080",
+			Path:   "/",
+		},
+		"",
+	},
+	// host subcomponent; IPv6 address in RFC 3986
+	{
+		"http://[fe80::1]/",
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1]",
+			Path:   "/",
+		},
+		"",
+	},
+	// host and port subcomponents; IPv6 address in RFC 3986
+	{
+		"http://[fe80::1]:8080/",
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1]:8080",
+			Path:   "/",
+		},
+		"",
+	},
+	// host subcomponent; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25en0]/", // alphanum zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en0]",
+			Path:   "/",
+		},
+		"",
+	},
+	// host and port subcomponents; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25en0]:8080/", // alphanum zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en0]:8080",
+			Path:   "/",
+		},
+		"",
+	},
+	// host subcomponent; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25%65%6e%301-._~]/", // percent-encoded+unreserved zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en01-._~]",
+			Path:   "/",
+		},
+		"http://[fe80::1%25en01-._~]/",
+	},
+	// host and port subcomponents; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25%65%6e%301-._~]:8080/", // percent-encoded+unreserved zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en01-._~]:8080",
+			Path:   "/",
+		},
+		"http://[fe80::1%25en01-._~]:8080/",
+	},
 }
 
 // more useful string for debugging than fmt's struct printer
@@ -358,9 +438,33 @@
 	{"/", true},
 	{pathThatLooksSchemeRelative, true},
 	{"//not.a.user@%66%6f%6f.com/just/a/path/also", true},
+	{"*", true},
+	{"http://192.168.0.1/", true},
+	{"http://192.168.0.1:8080/", true},
+	{"http://[fe80::1]/", true},
+	{"http://[fe80::1]:8080/", true},
+
+	// Tests exercising RFC 6874 compliance:
+	{"http://[fe80::1%25en0]/", true},                 // with alphanum zone identifier
+	{"http://[fe80::1%25en0]:8080/", true},            // with alphanum zone identifier
+	{"http://[fe80::1%25%65%6e%301-._~]/", true},      // with percent-encoded+unreserved zone identifier
+	{"http://[fe80::1%25%65%6e%301-._~]:8080/", true}, // with percent-encoded+unreserved zone identifier
+
 	{"foo.html", false},
 	{"../dir/", false},
-	{"*", true},
+	{"http://192.168.0.%31/", false},
+	{"http://192.168.0.%31:8080/", false},
+	{"http://[fe80::%31]/", false},
+	{"http://[fe80::%31]:8080/", false},
+	{"http://[fe80::%31%25en0]/", false},
+	{"http://[fe80::%31%25en0]:8080/", false},
+
+	// These two cases are valid as textual representations as
+	// described in RFC 4007, but are not valid as address
+	// literals with IPv6 zone identifiers in URIs as described in
+	// RFC 6874.
+	{"http://[fe80::1%en0]/", false},
+	{"http://[fe80::1%en0]:8080/", false},
 }
 
 func TestParseRequestURI(t *testing.T) {
diff --git a/src/os/env.go b/src/os/env.go
index 4bc6dad..a4ede15 100644
--- a/src/os/env.go
+++ b/src/os/env.go
@@ -81,6 +81,15 @@
 	return v
 }
 
+// LookupEnv retrieves the value of the environment variable named
+// by the key. If the variable is present in the environment the
+// value (which may be empty) is returned and the boolean is true.
+// Otherwise the returned value will be empty and the boolean will
+// be false.
+func LookupEnv(key string) (string, bool) {
+	return syscall.Getenv(key)
+}
+
 // Setenv sets the value of the environment variable named by the key.
 // It returns an error, if any.
 func Setenv(key, value string) error {
diff --git a/src/os/env_test.go b/src/os/env_test.go
index e618067..d1074cd 100644
--- a/src/os/env_test.go
+++ b/src/os/env_test.go
@@ -94,3 +94,20 @@
 		t.Fatal("Unsetenv didn't clear TestUnsetenv")
 	}
 }
+
+func TestLookupEnv(t *testing.T) {
+	const smallpox = "SMALLPOX"      // No one has smallpox.
+	value, ok := LookupEnv(smallpox) // Should not exist.
+	if ok || value != "" {
+		t.Fatalf("%s=%q", smallpox, value)
+	}
+	defer Unsetenv(smallpox)
+	err := Setenv(smallpox, "virus")
+	if err != nil {
+		t.Fatalf("failed to release smallpox virus")
+	}
+	value, ok = LookupEnv(smallpox)
+	if !ok {
+		t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken")
+	}
+}
diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go
deleted file mode 100644
index 3e6504f..0000000
--- a/src/os/error_windows_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2012 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 os_test
-
-import (
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"testing"
-)
-
-func TestErrIsExistAfterRename(t *testing.T) {
-	dir, err := ioutil.TempDir("", "go-build")
-	if err != nil {
-		t.Fatalf("Create temp directory: %v", err)
-	}
-	defer os.RemoveAll(dir)
-
-	src := filepath.Join(dir, "src")
-	dest := filepath.Join(dir, "dest")
-
-	f, err := os.Create(src)
-	if err != nil {
-		t.Fatalf("Create file %v: %v", src, err)
-	}
-	f.Close()
-	err = os.Rename(src, dest)
-	if err != nil {
-		t.Fatalf("Rename %v to %v: %v", src, dest, err)
-	}
-
-	f, err = os.Create(src)
-	if err != nil {
-		t.Fatalf("Create file %v: %v", src, err)
-	}
-	f.Close()
-	err = os.Rename(src, dest)
-	if err == nil {
-		t.Fatal("Rename should have failed")
-	}
-	if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
-		t.Fatal(s)
-		return
-	}
-}
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index bb0c3ac..c515bfc 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -32,6 +32,9 @@
 }
 
 // Cmd represents an external command being prepared or run.
+//
+// A Cmd cannot be reused after calling its Run, Output or CombinedOutput
+// methods.
 type Cmd struct {
 	// Path is the path of the command to run.
 	//
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index d3dec57..db84eab 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -27,10 +27,12 @@
 	"time"
 )
 
+// iOS cannot fork
+var iOS = runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
+
 func helperCommand(t *testing.T, s ...string) *exec.Cmd {
-	if runtime.GOOS == "nacl" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm") {
-		// iOS cannot fork
-		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+	if runtime.GOOS == "nacl" || iOS {
+		t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 	}
 	cs := []string{"-test.run=TestHelperProcess", "--"}
 	cs = append(cs, s...)
@@ -50,8 +52,8 @@
 }
 
 func TestCommandRelativeName(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		t.Skip("skipping on darwin/arm")
+	if iOS {
+		t.Skip("skipping on darwin/%s, cannot fork", runtime.GOARCH)
 	}
 
 	// Run our own binary as a relative path
@@ -428,10 +430,9 @@
 	switch runtime.GOOS {
 	case "nacl", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
-	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping test on %s/%s", runtime.GOOS, runtime.GOARCH)
-		}
+	}
+	if iOS {
+		t.Skipf("skipping test on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 	}
 
 	// Ensure that file descriptors have not already been leaked into
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index 132594e..6850884 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -319,7 +319,7 @@
 	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
 }
 
-// Variant of LastIndex from the strings package.
+// LastIndexByte from the strings package.
 func lastIndex(s string, sep byte) int {
 	for i := len(s) - 1; i >= 0; i-- {
 		if s[i] == sep {
diff --git a/src/os/file_posix.go b/src/os/file_posix.go
index fbb3b5e..8f10617 100644
--- a/src/os/file_posix.go
+++ b/src/os/file_posix.go
@@ -28,14 +28,6 @@
 	}
 }
 
-func rename(oldname, newname string) error {
-	e := syscall.Rename(oldname, newname)
-	if e != nil {
-		return &LinkError{"rename", oldname, newname, e}
-	}
-	return nil
-}
-
 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
 func syscallMode(i FileMode) (o uint32) {
 	o |= uint32(i.Perm())
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 3fb70d6..142f885 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -12,6 +12,14 @@
 	"syscall"
 )
 
+func rename(oldname, newname string) error {
+	e := syscall.Rename(oldname, newname)
+	if e != nil {
+		return &LinkError{"rename", oldname, newname, e}
+	}
+	return nil
+}
+
 // File represents an open file descriptor.
 type File struct {
 	*file
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index fa07367..9444ac5 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -5,6 +5,7 @@
 package os
 
 import (
+	"internal/syscall/windows"
 	"io"
 	"runtime"
 	"sync"
@@ -460,6 +461,14 @@
 	return &PathError{"remove", name, e}
 }
 
+func rename(oldname, newname string) error {
+	e := windows.Rename(oldname, newname)
+	if e != nil {
+		return &LinkError{"rename", oldname, newname, e}
+	}
+	return nil
+}
+
 // Pipe returns a connected pair of Files; reads from r return bytes written to w.
 // It returns the files and an error, if any.
 func Pipe() (r *File, w *File, err error) {
@@ -481,20 +490,18 @@
 
 // TempDir returns the default directory to use for temporary files.
 func TempDir() string {
-	const pathSep = '\\'
-	dirw := make([]uint16, syscall.MAX_PATH)
-	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-	if n > uint32(len(dirw)) {
-		dirw = make([]uint16, n)
-		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-		if n > uint32(len(dirw)) {
-			n = 0
+	n := uint32(syscall.MAX_PATH)
+	for {
+		b := make([]uint16, n)
+		n, _ = syscall.GetTempPath(uint32(len(b)), &b[0])
+		if n > uint32(len(b)) {
+			continue
 		}
+		if n > 0 && b[n-1] == '\\' {
+			n--
+		}
+		return string(utf16.Decode(b[:n]))
 	}
-	if n > 0 && dirw[n-1] == pathSep {
-		n--
-	}
-	return string(utf16.Decode(dirw[0:n]))
 }
 
 // Link creates newname as a hard link to the oldname file.
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 4ce6b7e..b1fc998 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -53,7 +53,8 @@
 			},
 		}
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			wd, err := syscall.Getwd()
 			if err != nil {
 				wd = err.Error()
@@ -131,7 +132,8 @@
 	case "android", "windows":
 		return TempDir()
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			return TempDir()
 		}
 	}
@@ -323,7 +325,8 @@
 	case "android":
 		dir = "/system/bin"
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			wd, err := Getwd()
 			if err != nil {
 				t.Fatal(err)
@@ -534,15 +537,10 @@
 }
 
 func TestHardLink(t *testing.T) {
-	// Hardlinks are not supported under windows or Plan 9.
-	switch runtime.GOOS {
-	case "plan9":
-		return
-	case "darwin":
-		if runtime.GOARCH == "arm" {
-			defer chtmpdir(t)()
-		}
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9, hardlinks not supported")
 	}
+	defer chtmpdir(t)()
 	from, to := "hardlinktestfrom", "hardlinktestto"
 	Remove(from) // Just in case.
 	file, err := Create(to)
@@ -582,6 +580,9 @@
 // chtmpdir changes the working directory to a new temporary directory and
 // provides a cleanup function. Used when PWD is read-only.
 func chtmpdir(t *testing.T) func() {
+	if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") {
+		return func() {} // only needed on darwin/arm{,64}
+	}
 	oldwd, err := Getwd()
 	if err != nil {
 		t.Fatalf("chtmpdir: %v", err)
@@ -609,11 +610,8 @@
 		if !supportsSymlinks {
 			t.Skipf("skipping on %s", runtime.GOOS)
 		}
-	case "darwin":
-		if runtime.GOARCH == "arm" {
-			defer chtmpdir(t)()
-		}
 	}
+	defer chtmpdir(t)()
 	from, to := "symlinktestfrom", "symlinktestto"
 	Remove(from) // Just in case.
 	file, err := Create(to)
@@ -679,11 +677,8 @@
 		if !supportsSymlinks {
 			t.Skipf("skipping on %s", runtime.GOOS)
 		}
-	case "darwin":
-		if runtime.GOARCH == "arm" {
-			defer chtmpdir(t)()
-		}
 	}
+	defer chtmpdir(t)()
 	s := "0123456789abcdef"
 	// Long, but not too long: a common limit is 255.
 	s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
@@ -704,17 +699,18 @@
 }
 
 func TestRename(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		defer chtmpdir(t)()
-	}
+	defer chtmpdir(t)()
 	from, to := "renamefrom", "renameto"
-	Remove(to) // Just in case.
+	// Ensure we are not testing the overwrite case here.
+	Remove(from)
+	Remove(to)
+
 	file, err := Create(from)
 	if err != nil {
-		t.Fatalf("open %q failed: %v", to, err)
+		t.Fatalf("open %q failed: %v", from, err)
 	}
 	if err = file.Close(); err != nil {
-		t.Errorf("close %q failed: %v", to, err)
+		t.Errorf("close %q failed: %v", from, err)
 	}
 	err = Rename(from, to)
 	if err != nil {
@@ -727,6 +723,50 @@
 	}
 }
 
+func TestRenameOverwriteDest(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9")
+	}
+	defer chtmpdir(t)()
+	from, to := "renamefrom", "renameto"
+	// Just in case.
+	Remove(from)
+	Remove(to)
+
+	toData := []byte("to")
+	fromData := []byte("from")
+
+	err := ioutil.WriteFile(to, toData, 0777)
+	if err != nil {
+		t.Fatalf("write file %q failed: %v", to, err)
+	}
+
+	err = ioutil.WriteFile(from, fromData, 0777)
+	if err != nil {
+		t.Fatalf("write file %q failed: %v", from, err)
+	}
+	err = Rename(from, to)
+	if err != nil {
+		t.Fatalf("rename %q, %q failed: %v", to, from, err)
+	}
+	defer Remove(to)
+
+	_, err = Stat(from)
+	if err == nil {
+		t.Errorf("from file %q still exists", from)
+	}
+	if err != nil && !IsNotExist(err) {
+		t.Fatalf("stat from: %v", err)
+	}
+	toFi, err := Stat(to)
+	if err != nil {
+		t.Fatalf("stat %q failed: %v", to, err)
+	}
+	if toFi.Size() != int64(len(fromData)) {
+		t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
+	}
+}
+
 func exec(t *testing.T, dir, cmd string, args []string, expect string) {
 	r, w, err := Pipe()
 	if err != nil {
@@ -758,8 +798,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
@@ -942,7 +983,8 @@
 	case "plan9":
 		dirs = []string{"/", "/usr"}
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			d1, err := ioutil.TempDir("", "d1")
 			if err != nil {
 				t.Fatalf("TempDir: %v", err)
@@ -998,6 +1040,64 @@
 	fd.Close()
 }
 
+// Test that Chdir+Getwd is program-wide.
+func TestProgWideChdir(t *testing.T) {
+	const N = 10
+	c := make(chan bool)
+	cpwd := make(chan string)
+	for i := 0; i < N; i++ {
+		go func(i int) {
+			// Lock half the goroutines in their own operating system
+			// thread to exercise more scheduler possibilities.
+			if i%2 == 1 {
+				// On Plan 9, after calling LockOSThread, the goroutines
+				// run on different processes which don't share the working
+				// directory. This used to be an issue because Go expects
+				// the working directory to be program-wide.
+				// See issue 9428.
+				runtime.LockOSThread()
+			}
+			<-c
+			pwd, err := Getwd()
+			if err != nil {
+				t.Errorf("Getwd on goroutine %d: %v", i, err)
+				return
+			}
+			cpwd <- pwd
+		}(i)
+	}
+	oldwd, err := Getwd()
+	if err != nil {
+		t.Fatal("Getwd: %v", err)
+	}
+	d, err := ioutil.TempDir("", "test")
+	if err != nil {
+		t.Fatal("TempDir: %v", err)
+	}
+	defer func() {
+		if err := Chdir(oldwd); err != nil {
+			t.Fatal("Chdir: %v", err)
+		}
+		RemoveAll(d)
+	}()
+	if err := Chdir(d); err != nil {
+		t.Fatal("Chdir: %v", err)
+	}
+	// OS X sets TMPDIR to a symbolic link.
+	// So we resolve our working directory again before the test.
+	d, err = Getwd()
+	if err != nil {
+		t.Fatal("Getwd: %v", err)
+	}
+	close(c)
+	for i := 0; i < N; i++ {
+		pwd := <-cpwd
+		if pwd != d {
+			t.Errorf("Getwd returned %q; want %q", pwd, d)
+		}
+	}
+}
+
 func TestSeek(t *testing.T) {
 	f := newFile("TestSeek", t)
 	defer Remove(f.Name())
@@ -1162,8 +1262,9 @@
 	case "android", "nacl", "plan9":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	case "windows":
 		testWindowsHostname(t)
@@ -1244,9 +1345,7 @@
 }
 
 func TestAppend(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		defer chtmpdir(t)()
-	}
+	defer chtmpdir(t)()
 	const f = "append.txt"
 	defer Remove(f)
 	s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
@@ -1310,9 +1409,7 @@
 }
 
 func TestSameFile(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		defer chtmpdir(t)()
-	}
+	defer chtmpdir(t)()
 	fa, err := Create("a")
 	if err != nil {
 		t.Fatalf("Create(a): %v", err)
@@ -1436,7 +1533,8 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
 		}
 	}
@@ -1483,7 +1581,8 @@
 		// TODO: golang.org/issue/8206
 		t.Skipf("skipping test on plan9; see issue 8206")
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			t.Skipf("skipping test on %s/%s, no fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
diff --git a/src/os/path_test.go b/src/os/path_test.go
index 50d2c36..f985381 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -208,7 +208,8 @@
 	case "android", "plan9", "windows":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			t.Skipf("skipping on darwin/%s, mkdir returns EPERM", runtime.GOARCH)
 		}
 	}
diff --git a/src/os/signal/signal_windows_test.go b/src/os/signal/signal_windows_test.go
index 45c86f0..f3e6706 100644
--- a/src/os/signal/signal_windows_test.go
+++ b/src/os/signal/signal_windows_test.go
@@ -10,7 +10,6 @@
 	"os"
 	"os/exec"
 	"path/filepath"
-	"runtime"
 	"syscall"
 	"testing"
 	"time"
@@ -32,9 +31,6 @@
 }
 
 func TestCtrlBreak(t *testing.T) {
-	if runtime.GOARCH == "386" {
-		t.Skip("known failing test on windows/386, see https://golang.org/issue/10215")
-	}
 	// create source file
 	const source = `
 package main
diff --git a/src/os/types.go b/src/os/types.go
index 473d431..9d6f8e1 100644
--- a/src/os/types.go
+++ b/src/os/types.go
@@ -53,7 +53,7 @@
 	// Mask for the type bits. For regular files, none will be set.
 	ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
 
-	ModePerm FileMode = 0777 // permission bits
+	ModePerm FileMode = 0777 // Unix permission bits
 )
 
 func (m FileMode) String() string {
diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go
index 0871473..f4f603e 100644
--- a/src/os/user/lookup_unix.go
+++ b/src/os/user/lookup_unix.go
@@ -17,6 +17,7 @@
 )
 
 /*
+#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
@@ -24,7 +25,12 @@
 
 static int mygetpwuid_r(int uid, struct passwd *pwd,
 	char *buf, size_t buflen, struct passwd **result) {
- return getpwuid_r(uid, pwd, buf, buflen, result);
+	return getpwuid_r(uid, pwd, buf, buflen, result);
+}
+
+static int mygetpwnam_r(const char *name, struct passwd *pwd,
+	char *buf, size_t buflen, struct passwd **result) {
+	return getpwnam_r(name, pwd, buf, buflen, result);
 }
 */
 import "C"
@@ -67,7 +73,11 @@
 	if lookupByName {
 		nameC := C.CString(username)
 		defer C.free(unsafe.Pointer(nameC))
-		rv = C.getpwnam_r(nameC,
+		// mygetpwnam_r is a wrapper around getpwnam_r to avoid
+		// passing a size_t to getpwnam_r, because for unknown
+		// reasons passing a size_t to getpwnam_r doesn't work on
+		// Solaris.
+		rv = C.mygetpwnam_r(nameC,
 			&pwd,
 			(*C.char)(buf),
 			C.size_t(bufSize),
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index aac7911..4ecaada 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -420,9 +420,12 @@
 }
 
 func TestWalk(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		restore := chtmpdir(t)
-		defer restore()
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			restore := chtmpdir(t)
+			defer restore()
+		}
 	}
 	makeTree(t)
 	errors := make([]error, 0, 10)
@@ -1033,8 +1036,11 @@
 }
 
 func TestBug3486(t *testing.T) { // http://golang.org/issue/3486
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		}
 	}
 	root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test")
 	if err != nil {
diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go
index 327c2c8..4b38f6f 100644
--- a/src/path/filepath/symlink_windows.go
+++ b/src/path/filepath/symlink_windows.go
@@ -14,18 +14,17 @@
 		return "", err
 	}
 	b := p // GetShortPathName says we can reuse buffer
-	n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
-	if err != nil {
-		return "", err
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
+	n := uint32(len(b))
+	for {
 		n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
 		if err != nil {
 			return "", err
 		}
+		if n <= uint32(len(b)) {
+			return syscall.UTF16ToString(b[:n]), nil
+		}
+		b = make([]uint16, n)
 	}
-	return syscall.UTF16ToString(b), nil
 }
 
 func toLong(path string) (string, error) {
@@ -34,19 +33,17 @@
 		return "", err
 	}
 	b := p // GetLongPathName says we can reuse buffer
-	n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
-	if err != nil {
-		return "", err
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
+	n := uint32(len(b))
+	for {
 		n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
 		if err != nil {
 			return "", err
 		}
+		if n <= uint32(len(b)) {
+			return syscall.UTF16ToString(b[:n]), nil
+		}
+		b = make([]uint16, n)
 	}
-	b = b[:n]
-	return syscall.UTF16ToString(b), nil
 }
 
 func evalSymlinks(path string) (string, error) {
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 2be32f3..877b2ef 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -15,6 +15,7 @@
 	. "reflect"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 	"testing"
@@ -3388,26 +3389,242 @@
 }
 
 func TestArrayOf(t *testing.T) {
-	// TODO(rsc): Finish ArrayOf and enable-test.
-	t.Skip("ArrayOf is not finished (and not exported)")
-
 	// check construction and use of type not in binary
-	type T int
-	at := ArrayOf(10, TypeOf(T(1)))
-	v := New(at).Elem()
-	for i := 0; i < v.Len(); i++ {
-		v.Index(i).Set(ValueOf(T(i)))
-	}
-	s := fmt.Sprint(v.Interface())
-	want := "[0 1 2 3 4 5 6 7 8 9]"
-	if s != want {
-		t.Errorf("constructed array = %s, want %s", s, want)
+	for _, table := range []struct {
+		n          int
+		value      func(i int) interface{}
+		comparable bool
+		want       string
+	}{
+		{
+			n:          0,
+			value:      func(i int) interface{} { type Tint int; return Tint(i) },
+			comparable: true,
+			want:       "[]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tint int; return Tint(i) },
+			comparable: true,
+			want:       "[0 1 2 3 4 5 6 7 8 9]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tfloat float64; return Tfloat(i) },
+			comparable: true,
+			want:       "[0 1 2 3 4 5 6 7 8 9]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstring string; return Tstring(strconv.Itoa(i)) },
+			comparable: true,
+			want:       "[0 1 2 3 4 5 6 7 8 9]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstruct struct{ V int }; return Tstruct{i} },
+			comparable: true,
+			want:       "[{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tint int; return []Tint{Tint(i)} },
+			comparable: false,
+			want:       "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tint int; return [1]Tint{Tint(i)} },
+			comparable: true,
+			want:       "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstruct struct{ V [1]int }; return Tstruct{[1]int{i}} },
+			comparable: true,
+			want:       "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstruct struct{ V []int }; return Tstruct{[]int{i}} },
+			comparable: false,
+			want:       "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type TstructUV struct{ U, V int }; return TstructUV{i, i} },
+			comparable: true,
+			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
+		},
+		{
+			n: 10,
+			value: func(i int) interface{} {
+				type TstructUV struct {
+					U int
+					V float64
+				}
+				return TstructUV{i, float64(i)}
+			},
+			comparable: true,
+			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
+		},
+	} {
+		at := ArrayOf(table.n, TypeOf(table.value(0)))
+		v := New(at).Elem()
+		vok := New(at).Elem()
+		vnot := New(at).Elem()
+		for i := 0; i < v.Len(); i++ {
+			v.Index(i).Set(ValueOf(table.value(i)))
+			vok.Index(i).Set(ValueOf(table.value(i)))
+			j := i
+			if i+1 == v.Len() {
+				j = i + 1
+			}
+			vnot.Index(i).Set(ValueOf(table.value(j))) // make it differ only by last element
+		}
+		s := fmt.Sprint(v.Interface())
+		if s != table.want {
+			t.Errorf("constructed array = %s, want %s", s, table.want)
+		}
+
+		if table.comparable != at.Comparable() {
+			t.Errorf("constructed array (%#v) is comparable=%v, want=%v", v.Interface(), at.Comparable(), table.comparable)
+		}
+		if table.comparable {
+			if table.n > 0 {
+				if DeepEqual(vnot.Interface(), v.Interface()) {
+					t.Errorf(
+						"arrays (%#v) compare ok (but should not)",
+						v.Interface(),
+					)
+				}
+			}
+			if !DeepEqual(vok.Interface(), v.Interface()) {
+				t.Errorf(
+					"arrays (%#v) compare NOT-ok (but should)",
+					v.Interface(),
+				)
+			}
+		}
 	}
 
 	// check that type already in binary is found
+	type T int
 	checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
 }
 
+func TestArrayOfGC(t *testing.T) {
+	type T *uintptr
+	tt := TypeOf(T(nil))
+	const n = 100
+	var x []interface{}
+	for i := 0; i < n; i++ {
+		v := New(ArrayOf(n, tt)).Elem()
+		for j := 0; j < v.Len(); j++ {
+			p := new(uintptr)
+			*p = uintptr(i*n + j)
+			v.Index(j).Set(ValueOf(p).Convert(tt))
+		}
+		x = append(x, v.Interface())
+	}
+	runtime.GC()
+
+	for i, xi := range x {
+		v := ValueOf(xi)
+		for j := 0; j < v.Len(); j++ {
+			k := v.Index(j).Elem().Interface()
+			if k != uintptr(i*n+j) {
+				t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
+			}
+		}
+	}
+}
+
+func TestArrayOfAlg(t *testing.T) {
+	at := ArrayOf(6, TypeOf(byte(0)))
+	v1 := New(at).Elem()
+	v2 := New(at).Elem()
+	if v1.Interface() != v1.Interface() {
+		t.Errorf("constructed array %v not equal to itself", v1.Interface())
+	}
+	v1.Index(5).Set(ValueOf(byte(1)))
+	if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 {
+		t.Errorf("constructed arrays %v and %v should not be equal", i1, i2)
+	}
+
+	at = ArrayOf(6, TypeOf([]int(nil)))
+	v1 = New(at).Elem()
+	shouldPanic(func() { _ = v1.Interface() == v1.Interface() })
+}
+
+func TestArrayOfGenericAlg(t *testing.T) {
+	at1 := ArrayOf(5, TypeOf(string("")))
+	at := ArrayOf(6, at1)
+	v1 := New(at).Elem()
+	v2 := New(at).Elem()
+	if v1.Interface() != v1.Interface() {
+		t.Errorf("constructed array %v not equal to itself", v1.Interface())
+	}
+
+	v1.Index(0).Index(0).Set(ValueOf("abc"))
+	v2.Index(0).Index(0).Set(ValueOf("efg"))
+	if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 {
+		t.Errorf("constructed arrays %v and %v should not be equal", i1, i2)
+	}
+
+	v1.Index(0).Index(0).Set(ValueOf("abc"))
+	v2.Index(0).Index(0).Set(ValueOf((v1.Index(0).Index(0).String() + " ")[:3]))
+	if i1, i2 := v1.Interface(), v2.Interface(); i1 != i2 {
+		t.Errorf("constructed arrays %v and %v should be equal", i1, i2)
+	}
+
+	// Test hash
+	m := MakeMap(MapOf(at, TypeOf(int(0))))
+	m.SetMapIndex(v1, ValueOf(1))
+	if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+		t.Errorf("constructed arrays %v and %v have different hashes", i1, i2)
+	}
+}
+
+func TestArrayOfDirectIface(t *testing.T) {
+	{
+		type T [1]*byte
+		i1 := Zero(TypeOf(T{})).Interface()
+		v1 := ValueOf(&i1).Elem()
+		p1 := v1.InterfaceData()[1]
+
+		i2 := Zero(ArrayOf(1, PtrTo(TypeOf(int8(0))))).Interface()
+		v2 := ValueOf(&i2).Elem()
+		p2 := v2.InterfaceData()[1]
+
+		if p1 != 0 {
+			t.Errorf("got p1=%v. want=%v", p1, nil)
+		}
+
+		if p2 != 0 {
+			t.Errorf("got p2=%v. want=%v", p2, nil)
+		}
+	}
+	{
+		type T [0]*byte
+		i1 := Zero(TypeOf(T{})).Interface()
+		v1 := ValueOf(&i1).Elem()
+		p1 := v1.InterfaceData()[1]
+
+		i2 := Zero(ArrayOf(0, PtrTo(TypeOf(int8(0))))).Interface()
+		v2 := ValueOf(&i2).Elem()
+		p2 := v2.InterfaceData()[1]
+
+		if p1 == 0 {
+			t.Errorf("got p1=%v. want=not-%v", p1, nil)
+		}
+
+		if p2 == 0 {
+			t.Errorf("got p2=%v. want=not-%v", p2, nil)
+		}
+	}
+}
+
 func TestSliceOf(t *testing.T) {
 	// check construction and use of type not in binary
 	type T int
@@ -3663,6 +3880,67 @@
 	}
 }
 
+func TestTypelinksSorted(t *testing.T) {
+	var last string
+	for i, n := range TypeLinks() {
+		if n < last {
+			t.Errorf("typelinks not sorted: %q [%d] > %q [%d]", last, i-1, n, i)
+		}
+		last = n
+	}
+}
+
+func TestFuncOf(t *testing.T) {
+	// check construction and use of type not in binary
+	type K string
+	type V float64
+
+	fn := func(args []Value) []Value {
+		if len(args) != 1 {
+			t.Errorf("args == %v, want exactly one arg", args)
+		} else if args[0].Type() != TypeOf(K("")) {
+			t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K("")))
+		} else if args[0].String() != "gopher" {
+			t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher")
+		}
+		return []Value{ValueOf(V(3.14))}
+	}
+	v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn)
+
+	outs := v.Call([]Value{ValueOf(K("gopher"))})
+	if len(outs) != 1 {
+		t.Fatalf("v.Call returned %v, want exactly one result", outs)
+	} else if outs[0].Type() != TypeOf(V(0)) {
+		t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0)))
+	}
+	f := outs[0].Float()
+	if f != 3.14 {
+		t.Errorf("constructed func returned %f, want %f", f, 3.14)
+	}
+
+	// check that types already in binary are found
+	type T1 int
+	testCases := []struct {
+		in, out  []Type
+		variadic bool
+		want     interface{}
+	}{
+		{in: []Type{TypeOf(T1(0))}, want: (func(T1))(nil)},
+		{in: []Type{TypeOf(int(0))}, want: (func(int))(nil)},
+		{in: []Type{SliceOf(TypeOf(int(0)))}, variadic: true, want: (func(...int))(nil)},
+		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false)}, want: (func(int) bool)(nil)},
+		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)},
+	}
+	for _, tt := range testCases {
+		checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want)
+	}
+
+	// check that variadic requires last element be a slice.
+	FuncOf([]Type{TypeOf(1), TypeOf(""), SliceOf(TypeOf(false))}, nil, true)
+	shouldPanic(func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) })
+	shouldPanic(func() { FuncOf(nil, nil, true) })
+}
+
 type B1 struct {
 	X int
 	Y int
diff --git a/src/reflect/example_test.go b/src/reflect/example_test.go
index cca28ee..8ebf976 100644
--- a/src/reflect/example_test.go
+++ b/src/reflect/example_test.go
@@ -6,6 +6,8 @@
 
 import (
 	"fmt"
+	"io"
+	"os"
 	"reflect"
 )
 
@@ -64,3 +66,16 @@
 	// Output:
 	// blue gopher
 }
+
+func ExampleTypeOf() {
+	// As interface types are only used for static typing, a
+	// common idiom to find the reflection Type for an interface
+	// type Foo is to use a *Foo value.
+	writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()
+
+	fileType := reflect.TypeOf((*os.File)(nil))
+	fmt.Println(fileType.Implements(writerType))
+
+	// Output:
+	// true
+}
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go
index 9f06324..c89e9c1 100644
--- a/src/reflect/export_test.go
+++ b/src/reflect/export_test.go
@@ -15,7 +15,6 @@
 	return v.flag&flagRO != 0
 }
 
-var ArrayOf = arrayOf
 var CallGC = &callGC
 
 const PtrSize = ptrSize
@@ -44,3 +43,13 @@
 	ptrs = ft.kind&kindNoPointers == 0
 	return
 }
+
+func TypeLinks() []string {
+	var r []string
+	for _, m := range typelinks() {
+		for _, t := range m {
+			r = append(r, *t.string)
+		}
+	}
+	return r
+}
diff --git a/src/reflect/type.go b/src/reflect/type.go
index ccd1454..5315bd3 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -246,6 +246,7 @@
 // so that code cannot convert from, say, *arrayType to *ptrType.
 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
@@ -262,11 +263,11 @@
 // a copy of runtime.typeAlg
 type typeAlg struct {
 	// function for hashing objects of this type
-	// (ptr to object, size, seed) -> hash
-	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
+	// (ptr to object, seed) -> hash
+	hash func(unsafe.Pointer, uintptr) uintptr
 	// function for comparing objects of this type
-	// (ptr to object A, ptr to object B, size) -> ==?
-	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
+	// (ptr to object A, ptr to object B) -> ==?
+	equal func(unsafe.Pointer, unsafe.Pointer) bool
 }
 
 // Method on non-interface type
@@ -1009,8 +1010,8 @@
 	return t.FieldByNameFunc(func(s string) bool { return s == name })
 }
 
-// TypeOf returns the reflection Type of the value in the interface{}.
-// TypeOf(nil) returns nil.
+// TypeOf returns the reflection Type that represents the dynamic type of i.
+// If i is a nil interface value, TypeOf returns nil.
 func TypeOf(i interface{}) Type {
 	eface := *(*emptyInterface)(unsafe.Pointer(&i))
 	return toType(eface.typ)
@@ -1057,6 +1058,17 @@
 		return &p.rtype
 	}
 
+	// Look in known types.
+	s := "*" + *t.string
+	for _, tt := range typesByString(s) {
+		p = (*ptrType)(unsafe.Pointer(tt))
+		if p.elem == t {
+			ptrMap.m[t] = p
+			ptrMap.Unlock()
+			return &p.rtype
+		}
+	}
+
 	// Create a new ptrType starting with the description
 	// of an *unsafe.Pointer.
 	p = new(ptrType)
@@ -1064,7 +1076,6 @@
 	prototype := *(**ptrType)(unsafe.Pointer(&iptr))
 	*p = *prototype
 
-	s := "*" + *t.string
 	p.string = &s
 
 	// For the type structures linked into the binary, the
@@ -1150,7 +1161,7 @@
 		for j := 0; j < len(v.methods); j++ {
 			tm := &t.methods[i]
 			vm := &v.methods[j]
-			if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
+			if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
 				if i++; i >= len(t.methods) {
 					return true
 				}
@@ -1167,7 +1178,7 @@
 	for j := 0; j < len(v.methods); j++ {
 		tm := &t.methods[i]
 		vm := &v.methods[j]
-		if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
+		if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
 			if i++; i >= len(t.methods) {
 				return true
 			}
@@ -1301,39 +1312,48 @@
 // there can be more than one with a given string.
 // Only types we might want to look up are included:
 // channels, maps, slices, and arrays.
-func typelinks() []*rtype
+func typelinks() [][]*rtype
 
 // typesByString returns the subslice of typelinks() whose elements have
 // the given string representation.
 // It may be empty (no known types with that string) or may have
 // multiple elements (multiple types with that string).
 func typesByString(s string) []*rtype {
-	typ := typelinks()
+	typs := typelinks()
+	var ret []*rtype
 
-	// We are looking for the first index i where the string becomes >= s.
-	// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
-	i, j := 0, len(typ)
-	for i < j {
-		h := i + (j-i)/2 // avoid overflow when computing h
-		// i ≤ h < j
-		if !(*typ[h].string >= s) {
-			i = h + 1 // preserves f(i-1) == false
-		} else {
-			j = h // preserves f(j) == true
+	for _, typ := range typs {
+		// We are looking for the first index i where the string becomes >= s.
+		// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
+		i, j := 0, len(typ)
+		for i < j {
+			h := i + (j-i)/2 // avoid overflow when computing h
+			// i ≤ h < j
+			if !(*typ[h].string >= s) {
+				i = h + 1 // preserves f(i-1) == false
+			} else {
+				j = h // preserves f(j) == true
+			}
+		}
+		// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
+
+		// Having found the first, linear scan forward to find the last.
+		// We could do a second binary search, but the caller is going
+		// to do a linear scan anyway.
+		j = i
+		for j < len(typ) && *typ[j].string == s {
+			j++
+		}
+
+		if j > i {
+			if ret == nil {
+				ret = typ[i:j:j]
+			} else {
+				ret = append(ret, typ[i:j]...)
+			}
 		}
 	}
-	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
-
-	// Having found the first, linear scan forward to find the last.
-	// We could do a second binary search, but the caller is going
-	// to do a linear scan anyway.
-	j = i
-	for j < len(typ) && *typ[j].string == s {
-		j++
-	}
-
-	// This slice will be empty if the string is not found.
-	return typ[i:j]
+	return ret
 }
 
 // The lookupCache caches ChanOf, MapOf, and SliceOf lookups.
@@ -1387,6 +1407,14 @@
 	return t
 }
 
+// The funcLookupCache caches FuncOf lookups.
+// FuncOf does not share the common lookupCache since cacheKey is not
+// sufficient to represent functions unambiguously.
+var funcLookupCache struct {
+	sync.RWMutex
+	m map[uint32][]*rtype // keyed by hash calculated in FuncOf
+}
+
 // ChanOf returns the channel type with the given direction and element type.
 // For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
 //
@@ -1507,6 +1535,120 @@
 	return cachePut(ckey, &mt.rtype)
 }
 
+// FuncOf returns the function type with the given argument and result types.
+// For example if k represents int and e represents string,
+// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
+//
+// The variadic argument controls whether the function is variadic. FuncOf
+// panics if the in[len(in)-1] does not represent a slice and variadic is
+// true.
+func FuncOf(in, out []Type, variadic bool) Type {
+	if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) {
+		panic("reflect.FuncOf: last arg of variadic func must be slice")
+	}
+
+	// Make a func type.
+	var ifunc interface{} = (func())(nil)
+	prototype := *(**funcType)(unsafe.Pointer(&ifunc))
+	ft := new(funcType)
+	*ft = *prototype
+
+	// Build a hash and minimally populate ft.
+	var hash uint32
+	var fin, fout []*rtype
+	for _, in := range in {
+		t := in.(*rtype)
+		fin = append(fin, t)
+		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
+	}
+	if variadic {
+		hash = fnv1(hash, 'v')
+	}
+	hash = fnv1(hash, '.')
+	for _, out := range out {
+		t := out.(*rtype)
+		fout = append(fout, t)
+		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
+	}
+	ft.hash = hash
+	ft.in = fin
+	ft.out = fout
+	ft.dotdotdot = variadic
+
+	// Look in cache.
+	funcLookupCache.RLock()
+	for _, t := range funcLookupCache.m[hash] {
+		if haveIdenticalUnderlyingType(&ft.rtype, t) {
+			funcLookupCache.RUnlock()
+			return t
+		}
+	}
+	funcLookupCache.RUnlock()
+
+	// Not in cache, lock and retry.
+	funcLookupCache.Lock()
+	defer funcLookupCache.Unlock()
+	if funcLookupCache.m == nil {
+		funcLookupCache.m = make(map[uint32][]*rtype)
+	}
+	for _, t := range funcLookupCache.m[hash] {
+		if haveIdenticalUnderlyingType(&ft.rtype, t) {
+			return t
+		}
+	}
+
+	// Look in known types for the same string representation.
+	str := funcStr(ft)
+	for _, tt := range typesByString(str) {
+		if haveIdenticalUnderlyingType(&ft.rtype, tt) {
+			funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
+			return tt
+		}
+	}
+
+	// Populate the remaining fields of ft and store in cache.
+	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
+}
+
+// funcStr builds a string representation of a funcType.
+func funcStr(ft *funcType) string {
+	repr := make([]byte, 0, 64)
+	repr = append(repr, "func("...)
+	for i, t := range ft.in {
+		if i > 0 {
+			repr = append(repr, ", "...)
+		}
+		if ft.dotdotdot && i == len(ft.in)-1 {
+			repr = append(repr, "..."...)
+			repr = append(repr, *(*sliceType)(unsafe.Pointer(t)).elem.string...)
+		} else {
+			repr = append(repr, *t.string...)
+		}
+	}
+	repr = append(repr, ')')
+	if l := len(ft.out); l == 1 {
+		repr = append(repr, ' ')
+	} else if l > 1 {
+		repr = append(repr, " ("...)
+	}
+	for i, t := range ft.out {
+		if i > 0 {
+			repr = append(repr, ", "...)
+		}
+		repr = append(repr, *t.string...)
+	}
+	if len(ft.out) > 1 {
+		repr = append(repr, ')')
+	}
+	return string(repr)
+}
+
 // isReflexive reports whether the == operation on the type is reflexive.
 // That is, x == x for all values x of type t.
 func isReflexive(t *rtype) bool {
@@ -1684,12 +1826,14 @@
 	}
 	// overflow
 	gc.append(bitsPointer)
+	ptrdata := gc.size
 	if runtime.GOARCH == "amd64p32" {
 		gc.append(bitsScalar)
 	}
 
 	b := new(rtype)
 	b.size = gc.size
+	b.ptrdata = ptrdata
 	b.kind = kind
 	b.gc[0], _ = gc.finalize()
 	s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
@@ -1737,26 +1881,24 @@
 //
 // If the resulting type would be larger than the available address space,
 // ArrayOf panics.
-//
-// TODO(rsc): Unexported for now. Export once the alg field is set correctly
-// for the type. This may require significant work.
-//
-// TODO(rsc): TestArrayOf is also disabled. Re-enable.
-func arrayOf(count int, elem Type) Type {
+func ArrayOf(count int, elem Type) Type {
 	typ := elem.(*rtype)
+	// call SliceOf here as it calls cacheGet/cachePut.
+	// ArrayOf also calls cacheGet/cachePut and thus may modify the state of
+	// the lookupCache mutex.
 	slice := SliceOf(elem)
 
 	// Look in cache.
 	ckey := cacheKey{Array, typ, nil, uintptr(count)}
-	if slice := cacheGet(ckey); slice != nil {
-		return slice
+	if array := cacheGet(ckey); array != nil {
+		return array
 	}
 
 	// Look in known types.
 	s := "[" + strconv.Itoa(count) + "]" + *typ.string
 	for _, tt := range typesByString(s) {
-		slice := (*sliceType)(unsafe.Pointer(tt))
-		if slice.elem == typ {
+		array := (*arrayType)(unsafe.Pointer(tt))
+		if array.elem == typ {
 			return cachePut(ckey, tt)
 		}
 	}
@@ -1766,7 +1908,6 @@
 	prototype := *(**arrayType)(unsafe.Pointer(&iarray))
 	array := new(arrayType)
 	*array = *prototype
-	// TODO: Set extra kind bits correctly.
 	array.string = &s
 	array.hash = fnv1(typ.hash, '[')
 	for n := uint32(count); n > 0; n >>= 8 {
@@ -1779,17 +1920,73 @@
 		panic("reflect.ArrayOf: array size would exceed virtual address space")
 	}
 	array.size = typ.size * uintptr(count)
+	if count > 0 && typ.ptrdata != 0 {
+		array.ptrdata = typ.size*uintptr(count-1) + typ.ptrdata
+	}
 	array.align = typ.align
 	array.fieldAlign = typ.fieldAlign
-	// TODO: array.alg
-	// TODO: array.gc
-	// TODO:
 	array.uncommonType = nil
 	array.ptrToThis = nil
-	array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
+	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
+	} else {
+		array.kind &^= kindNoPointers
+	}
+
+	etyp := typ.common()
+	esize := etyp.Size()
+	ealg := etyp.alg
+
+	array.alg = new(typeAlg)
+	if ealg.equal != nil {
+		eequal := ealg.equal
+		array.alg.equal = func(p, q unsafe.Pointer) bool {
+			for i := 0; i < count; i++ {
+				pi := arrayAt(p, i, esize)
+				qi := arrayAt(q, i, esize)
+				if !eequal(pi, qi) {
+					return false
+				}
+
+			}
+			return true
+		}
+	}
+	if ealg.hash != nil {
+		ehash := ealg.hash
+		array.alg.hash = func(ptr unsafe.Pointer, seed uintptr) uintptr {
+			o := seed
+			for i := 0; i < count; i++ {
+				o = ehash(arrayAt(ptr, i, esize), o)
+			}
+			return o
+		}
+	}
+
+	switch {
+	case count == 1 && !ifaceIndir(typ):
+		// array of 1 direct iface type can be direct
+		array.kind |= kindDirectIface
+	default:
+		array.kind &^= kindDirectIface
+	}
+
 	return cachePut(ckey, &array.rtype)
 }
 
@@ -1893,6 +2090,7 @@
 	// 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 {
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 27f9c2d..fb9e85a 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -848,7 +848,7 @@
 		}
 		tt := (*sliceType)(unsafe.Pointer(v.typ))
 		typ := tt.elem
-		val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+		val := arrayAt(s.Data, i, typ.size)
 		fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
 		return Value{typ, val, fl}
 
@@ -857,7 +857,7 @@
 		if uint(i) >= uint(s.Len) {
 			panic("reflect: string index out of range")
 		}
-		p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
+		p := arrayAt(s.Data, i, 1)
 		fl := v.flag&flagRO | flag(Uint8) | flagIndir
 		return Value{uint8Type, p, fl}
 	}
@@ -1540,7 +1540,7 @@
 		if i < 0 || j < i || j > s.Len {
 			panic("reflect.Value.Slice: string slice index out of bounds")
 		}
-		t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
+		t := stringHeader{arrayAt(s.Data, i, 1), j - i}
 		return Value{v.typ, unsafe.Pointer(&t), v.flag}
 	}
 
@@ -1556,7 +1556,7 @@
 	s.Len = j - i
 	s.Cap = cap - i
 	if cap-i > 0 {
-		s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+		s.Data = arrayAt(base, i, typ.elem.Size())
 	} else {
 		// do not advance pointer, to avoid pointing beyond end of slice
 		s.Data = base
@@ -1608,7 +1608,7 @@
 	s.Len = j - i
 	s.Cap = k - i
 	if k-i > 0 {
-		s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+		s.Data = arrayAt(base, i, typ.elem.Size())
 	} else {
 		// do not advance pointer, to avoid pointing beyond end of slice
 		s.Data = base
@@ -1622,6 +1622,8 @@
 // String is a special case because of Go's String method convention.
 // Unlike the other getters, it does not panic if v's Kind is not String.
 // Instead, it returns a string of the form "<T value>" where T is v's type.
+// The fmt package treats Values specially. It does not call their String
+// method implicitly but instead prints the concrete values they hold.
 func (v Value) String() string {
 	switch k := v.kind(); k {
 	case Invalid:
@@ -1765,6 +1767,12 @@
 	}
 }
 
+// arrayAt returns the i-th element of p, a C-array whose elements are
+// eltSize wide (in bytes).
+func arrayAt(p unsafe.Pointer, i int, eltSize uintptr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(p) + uintptr(i)*eltSize)
+}
+
 // grow grows the slice s so that it can hold extra more values, allocating
 // more capacity if needed. It also returns the old and new slice lengths.
 func grow(s Value, extra int) (Value, int, int) {
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index 01ea374..d78ae6a 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -489,6 +489,17 @@
 	}
 }
 
+// Check that the same machine can be used with the standard matcher
+// and then the backtracker when there are no captures.
+func TestSwitchBacktrack(t *testing.T) {
+	re := MustCompile(`a|b`)
+	long := make([]byte, maxBacktrackVector+1)
+
+	// The following sequence of Match calls used to panic. See issue #10319.
+	re.Match(long)     // triggers standard matcher
+	re.Match(long[:1]) // triggers backtracker
+}
+
 func BenchmarkLiteral(b *testing.B) {
 	x := strings.Repeat("x", 50) + "y"
 	b.StopTimer()
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
index 824014b..fd95604 100644
--- a/src/regexp/backtrack.go
+++ b/src/regexp/backtrack.go
@@ -36,7 +36,6 @@
 
 	end     int
 	cap     []int
-	reqcap  bool // whether any captures are requested
 	input   input
 	jobs    []job
 	visited []uint32
@@ -47,6 +46,9 @@
 // maxBitStateLen returns the maximum length of a string to search with
 // the backtracker using prog.
 func maxBitStateLen(prog *syntax.Prog) int {
+	if !shouldBacktrack(prog) {
+		return 0
+	}
 	return maxBacktrackVector / len(prog.Inst)
 }
 
@@ -54,7 +56,7 @@
 // or notBacktrack if the size of the prog exceeds the maximum size that
 // the backtracker will be run for.
 func newBitState(prog *syntax.Prog) *bitState {
-	if len(prog.Inst) > maxBacktrackProg {
+	if !shouldBacktrack(prog) {
 		return notBacktrack
 	}
 	return &bitState{
@@ -62,13 +64,17 @@
 	}
 }
 
+// shouldBacktrack reports whether the program is too
+// long for the backtracker to run.
+func shouldBacktrack(prog *syntax.Prog) bool {
+	return len(prog.Inst) <= maxBacktrackProg
+}
+
 // reset resets the state of the backtracker.
-// end is the end position in the input. ncap and reqcap are the number
-// of the machine's capture registers and the number of user-requested
-// captures respectively.
-func (b *bitState) reset(end int, ncap int, reqcap int) {
+// end is the end position in the input.
+// ncap is the number of captures.
+func (b *bitState) reset(end int, ncap int) {
 	b.end = end
-	b.reqcap = reqcap > 0
 
 	if cap(b.jobs) == 0 {
 		b.jobs = make([]job, 0, 256)
@@ -86,8 +92,10 @@
 		}
 	}
 
-	if len(b.cap) < ncap {
+	if cap(b.cap) < ncap {
 		b.cap = make([]int, ncap)
+	} else {
+		b.cap = b.cap[:ncap]
 	}
 	for i := range b.cap {
 		b.cap[i] = -1
@@ -262,7 +270,7 @@
 		case syntax.InstMatch:
 			// We found a match. If the caller doesn't care
 			// where the match is, no point going further.
-			if !b.reqcap {
+			if len(b.cap) == 0 {
 				m.matched = true
 				return m.matched
 			}
@@ -270,7 +278,9 @@
 			// Record best match so far.
 			// Only need to check end point, because this entire
 			// call is only considering one start position.
-			b.cap[1] = pos
+			if len(b.cap) > 1 {
+				b.cap[1] = pos
+			}
 			if !m.matched || (longest && pos > 0 && pos > m.matchcap[1]) {
 				copy(m.matchcap, b.cap)
 			}
@@ -296,7 +306,7 @@
 }
 
 // backtrack runs a backtracking search of prog on the input starting at pos.
-func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
+func (m *machine) backtrack(i input, pos int, end int, ncap int) bool {
 	if !i.canCheckPrefix() {
 		panic("backtrack called for a RuneReader")
 	}
@@ -311,15 +321,18 @@
 	}
 
 	b := m.b
-	b.reset(end, len(m.matchcap), reqcap)
+	b.reset(end, ncap)
 
+	m.matchcap = m.matchcap[:ncap]
 	for i := range m.matchcap {
 		m.matchcap[i] = -1
 	}
 
 	// Anchored search must start at the beginning of the input
 	if startCond&syntax.EmptyBeginText != 0 {
-		b.cap[0] = pos
+		if len(b.cap) > 0 {
+			b.cap[0] = pos
+		}
 		return m.tryBacktrack(b, i, uint32(m.p.Start), pos)
 	}
 
@@ -340,7 +353,9 @@
 			pos += advance
 		}
 
-		b.cap[0] = pos
+		if len(b.cap) > 0 {
+			b.cap[0] = pos
+		}
 		if m.tryBacktrack(b, i, uint32(m.p.Start), pos) {
 			// Match must be leftmost; done.
 			return true
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index b1bf405..669b80e 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -24,8 +24,8 @@
 // complexity, over all possible strings over a given alphabet,
 // up to a given size.  Rather than try to link with RE2, we read a
 // log file containing the test cases and the expected matches.
-// The log file, re2.txt, is generated by running 'make exhaustive-log'
-// in the open source RE2 distribution.  http://code.google.com/p/re2/
+// The log file, re2-exhaustive.txt, is generated by running 'make log'
+// in the open source RE2 distribution https://github.com/google/re2/.
 //
 // The test file format is a sequence of stanzas like:
 //
@@ -59,8 +59,8 @@
 // a capital letter are test names printed during RE2's test suite
 // and are echoed into t but otherwise ignored.
 //
-// At time of writing, re2.txt is 32 MB but compresses to 760 kB,
-// so we store re2.txt.gz in the repository and decompress it on the fly.
+// At time of writing, re2-exhaustive.txt is 59 MB but compresses to 385 kB,
+// so we store re2-exhaustive.txt.bz2 in the repository and decompress it on the fly.
 //
 func TestRE2Search(t *testing.T) {
 	testRE2(t, "testdata/re2-search.txt")
@@ -713,3 +713,15 @@
 		t.Errorf("longest match was %q, want %q", g, w)
 	}
 }
+
+// TestProgramTooLongForBacktrace tests that a regex which is too long
+// for the backtracker still executes properly.
+func TestProgramTooLongForBacktrack(t *testing.T) {
+	longRegex := MustCompile(`(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twentyone|twentytwo|twentythree|twentyfour|twentyfive|twentysix|twentyseven|twentyeight|twentynine|thirty|thirtyone|thirtytwo|thirtythree|thirtyfour|thirtyfive|thirtysix|thirtyseven|thirtyeight|thirtynine|forty|fortyone|fortytwo|fortythree|fortyfour|fortyfive|fortysix|fortyseven|fortyeight|fortynine|fifty|fiftyone|fiftytwo|fiftythree|fiftyfour|fiftyfive|fiftysix|fiftyseven|fiftyeight|fiftynine|sixty|sixtyone|sixtytwo|sixtythree|sixtyfour|sixtyfive|sixtysix|sixtyseven|sixtyeight|sixtynine|seventy|seventyone|seventytwo|seventythree|seventyfour|seventyfive|seventysix|seventyseven|seventyeight|seventynine|eighty|eightyone|eightytwo|eightythree|eightyfour|eightyfive|eightysix|eightyseven|eightyeight|eightynine|ninety|ninetyone|ninetytwo|ninetythree|ninetyfour|ninetyfive|ninetysix|ninetyseven|ninetyeight|ninetynine|onehundred)`)
+	if !longRegex.MatchString("two") {
+		t.Errorf("longRegex.MatchString(\"two\") was false, want true")
+	}
+	if longRegex.MatchString("xxx") {
+		t.Errorf("longRegex.MatchString(\"xxx\") was true, want false")
+	}
+}
diff --git a/src/regexp/testdata/README b/src/regexp/testdata/README
index b1b301b..58cec82 100644
--- a/src/regexp/testdata/README
+++ b/src/regexp/testdata/README
@@ -19,5 +19,6 @@
 RE2 Test Files
 
 re2-exhaustive.txt.bz2 and re2-search.txt are built by running
-'make log' in the RE2 distribution.  http://code.google.com/p/re2/.
+'make log' in the RE2 distribution https://github.com/google/re2/
+
 The exhaustive file is compressed because it is huge.
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 659c8d7..c666836 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -38,6 +38,8 @@
 	alg_max
 )
 
+// typeAlg is also copied/used in reflect/type.go.
+// keep them in sync.
 type typeAlg struct {
 	// function for hashing objects of this type
 	// (ptr to object, seed) -> hash
@@ -281,7 +283,7 @@
 }
 
 func bytesHash(b []byte, seed uintptr) uintptr {
-	s := (*sliceStruct)(unsafe.Pointer(&b))
+	s := (*slice)(unsafe.Pointer(&b))
 	return memhash(s.array, seed, uintptr(s.len))
 }
 
@@ -305,7 +307,7 @@
 
 // Testing adapter for memclr
 func memclrBytes(b []byte) {
-	s := (*sliceStruct)(unsafe.Pointer(&b))
+	s := (*slice)(unsafe.Pointer(&b))
 	memclr(s.array, uintptr(s.len))
 }
 
diff --git a/src/runtime/arch1_arm64.go b/src/runtime/arch1_arm64.go
index 49a56b6..549a635 100644
--- a/src/runtime/arch1_arm64.go
+++ b/src/runtime/arch1_arm64.go
@@ -9,7 +9,7 @@
 	_BigEndian        = 0
 	_CacheLineSize    = 32
 	_RuntimeGogoBytes = 64
-	_PhysPageSize     = 4096
+	_PhysPageSize     = 4096*(1-goos_darwin) + 16384*goos_darwin
 	_PCQuantum        = 4
 	_Int64Align       = 8
 	hugePageSize      = 0
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 3472e07..1336201 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -1296,9 +1296,8 @@
 	MOVL	a+0(FP), SI
 	MOVL	b+4(FP), DI
 	MOVL	size+8(FP), BX
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, ret+12(FP)
-	RET
+	LEAL	ret+12(FP), AX
+	JMP	runtime·memeqbody(SB)
 
 // memequal_varlen(a, b unsafe.Pointer) bool
 TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
@@ -1307,9 +1306,8 @@
 	CMPL    SI, DI
 	JEQ     eq
 	MOVL    4(DX), BX    // compiler stores size at offset 4 in the closure
-	CALL    runtime·memeqbody(SB)
-	MOVB    AX, ret+8(FP)
-	RET
+	LEAL	ret+8(FP), AX
+	JMP	runtime·memeqbody(SB)
 eq:
 	MOVB    $1, ret+8(FP)
 	RET
@@ -1325,9 +1323,8 @@
 	CMPL	SI, DI
 	JEQ	same
 	MOVL	s1len+4(FP), BX
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, v+16(FP)
-	RET
+	LEAL	v+16(FP), AX
+	JMP	runtime·memeqbody(SB)
 same:
 	MOVB	$1, v+16(FP)
 	RET
@@ -1335,22 +1332,21 @@
 TEXT bytes·Equal(SB),NOSPLIT,$0-25
 	MOVL	a_len+4(FP), BX
 	MOVL	b_len+16(FP), CX
-	XORL	AX, AX
 	CMPL	BX, CX
 	JNE	eqret
 	MOVL	a+0(FP), SI
 	MOVL	b+12(FP), DI
-	CALL	runtime·memeqbody(SB)
+	LEAL	ret+24(FP), AX
+	JMP	runtime·memeqbody(SB)
 eqret:
-	MOVB	AX, ret+24(FP)
+	MOVB	$0, ret+24(FP)
 	RET
 
 // a in SI
 // b in DI
 // count in BX
+// address of result byte in AX
 TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
-	XORL	AX, AX
-
 	CMPL	BX, $4
 	JB	small
 
@@ -1381,6 +1377,7 @@
 	SUBL	$64, BX
 	CMPL	DX, $0xffff
 	JEQ	hugeloop
+	MOVB	$0, (AX)
 	RET
 
 	// 4 bytes at a time using 32-bit register
@@ -1394,6 +1391,7 @@
 	SUBL	$4, BX
 	CMPL	CX, DX
 	JEQ	bigloop
+	MOVB	$0, (AX)
 	RET
 
 	// remaining 0-4 bytes
@@ -1401,7 +1399,7 @@
 	MOVL	-4(SI)(BX*1), CX
 	MOVL	-4(DI)(BX*1), DX
 	CMPL	CX, DX
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 small:
@@ -1438,7 +1436,7 @@
 	SUBL	SI, DI
 	SHLL	CX, DI
 equal:
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
@@ -1446,18 +1444,16 @@
 	MOVL	s1_len+4(FP), BX
 	MOVL	s2_base+8(FP), DI
 	MOVL	s2_len+12(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVL	AX, ret+16(FP)
-	RET
+	LEAL	ret+16(FP), AX
+	JMP	runtime·cmpbody(SB)
 
 TEXT bytes·Compare(SB),NOSPLIT,$0-28
 	MOVL	s1+0(FP), SI
 	MOVL	s1+4(FP), BX
 	MOVL	s2+12(FP), DI
 	MOVL	s2+16(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVL	AX, ret+24(FP)
-	RET
+	LEAL	ret+24(FP), AX
+	JMP	runtime·cmpbody(SB)
 
 TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
 	MOVL	s+0(FP), SI
@@ -1492,14 +1488,13 @@
 //   DI = b
 //   BX = alen
 //   DX = blen
-// output:
-//   AX = 1/0/-1
+//   AX = address of return word (set to 1/0/-1)
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
+	MOVL	DX, BP
+	SUBL	BX, DX // DX = blen-alen
+	CMOVLGT	BX, BP // BP = min(alen, blen)
 	CMPL	SI, DI
 	JEQ	allsame
-	CMPL	BX, DX
-	MOVL	DX, BP
-	CMOVLLT	BX, BP // BP = min(alen, blen)
 	CMPL	BP, $4
 	JB	small
 	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
@@ -1510,8 +1505,8 @@
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
-	PMOVMSKB X1, AX
-	XORL	$0xffff, AX	// convert EQ to NE
+	PMOVMSKB X1, BX
+	XORL	$0xffff, BX	// convert EQ to NE
 	JNE	diff16	// branch if at least one byte is not equal
 	ADDL	$16, SI
 	ADDL	$16, DI
@@ -1519,20 +1514,21 @@
 	JMP	largeloop
 
 diff16:
-	BSFL	AX, BX	// index of first byte that differs
-	XORL	AX, AX
+	BSFL	BX, BX	// index of first byte that differs
+	XORL	DX, DX
 	MOVB	(SI)(BX*1), CX
 	CMPB	CX, (DI)(BX*1)
-	SETHI	AX
-	LEAL	-1(AX*2), AX	// convert 1/0 to +1/-1
+	SETHI	DX
+	LEAL	-1(DX*2), DX	// convert 1/0 to +1/-1
+	MOVL	DX, (AX)
 	RET
 
 mediumloop:
 	CMPL	BP, $4
 	JBE	_0through4
-	MOVL	(SI), AX
+	MOVL	(SI), BX
 	MOVL	(DI), CX
-	CMPL	AX, CX
+	CMPL	BX, CX
 	JNE	diff4
 	ADDL	$4, SI
 	ADDL	$4, DI
@@ -1540,19 +1536,20 @@
 	JMP	mediumloop
 
 _0through4:
-	MOVL	-4(SI)(BP*1), AX
+	MOVL	-4(SI)(BP*1), BX
 	MOVL	-4(DI)(BP*1), CX
-	CMPL	AX, CX
+	CMPL	BX, CX
 	JEQ	allsame
 
 diff4:
-	BSWAPL	AX	// reverse order of bytes
+	BSWAPL	BX	// reverse order of bytes
 	BSWAPL	CX
-	XORL	AX, CX	// find bit differences
+	XORL	BX, CX	// find bit differences
 	BSRL	CX, CX	// index of highest bit difference
-	SHRL	CX, AX	// move a's bit to bottom
-	ANDL	$1, AX	// mask bit
-	LEAL	-1(AX*2), AX // 1/0 => +1/-1
+	SHRL	CX, BX	// move a's bit to bottom
+	ANDL	$1, BX	// mask bit
+	LEAL	-1(BX*2), BX // 1/0 => +1/-1
+	MOVL	BX, (AX)
 	RET
 
 	// 0-3 bytes in common
@@ -1590,812 +1587,20 @@
 	BSRL	DI, CX	// index of highest bit difference
 	SHRL	CX, SI	// move a's bit to bottom
 	ANDL	$1, SI	// mask bit
-	LEAL	-1(SI*2), AX // 1/0 => +1/-1
+	LEAL	-1(SI*2), BX // 1/0 => +1/-1
+	MOVL	BX, (AX)
 	RET
 
 	// all the bytes in common are the same, so we just need
 	// to compare the lengths.
 allsame:
-	XORL	AX, AX
+	XORL	BX, BX
 	XORL	CX, CX
-	CMPL	BX, DX
-	SETGT	AX	// 1 if alen > blen
+	TESTL	DX, DX
+	SETLT	BX	// 1 if alen > blen
 	SETEQ	CX	// 1 if alen == blen
-	LEAL	-1(CX)(AX*2), AX	// 1,0,-1 result
-	RET
-
-// A Duff's device for zeroing memory.
-// The compiler jumps to computed addresses within
-// this routine to zero chunks of memory.  Do not
-// change this code without also changing the code
-// in ../../cmd/8g/ggen.c:clearfat.
-// AX: zero
-// DI: ptr to memory to be zeroed
-// DI is updated as a side effect.
-TEXT runtime·duffzero(SB), NOSPLIT, $0-0
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	RET
-
-// A Duff's device for copying memory.
-// The compiler jumps to computed addresses within
-// this routine to copy chunks of memory.  Source
-// and destination must not overlap.  Do not
-// change this code without also changing the code
-// in ../../cmd/6g/cgen.c:sgen.
-// SI: ptr to source memory
-// DI: ptr to destination memory
-// SI and DI are updated as a side effect.
-
-// NOTE: this is equivalent to a sequence of MOVSL but
-// for some reason MOVSL is really slow.
-TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
+	LEAL	-1(CX)(BX*2), BX	// 1,0,-1 result
+	MOVL	BX, (AX)
 	RET
 
 TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
@@ -2433,12 +1638,6 @@
 	// traceback from goexit1 must hit code range of goexit
 	BYTE	$0x90	// NOP
 
-TEXT runtime·getg(SB),NOSPLIT,$0-4
-	get_tls(CX)
-	MOVL	g(CX), AX
-	MOVL	AX, ret+0(FP)
-	RET
-
 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
 	MOVL	addr+0(FP), AX
 	PREFETCHT0	(AX)
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index fdea053..36353d1 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -530,6 +530,9 @@
 	MOVQ	AX, ret+16(FP)
 	RET
 
+TEXT runtime·xadduintptr(SB), NOSPLIT, $0-24
+	JMP	runtime·xadd64(SB)
+
 TEXT runtime·xchg(SB), NOSPLIT, $0-20
 	MOVQ	ptr+0(FP), BX
 	MOVL	new+8(FP), AX
@@ -1259,9 +1262,8 @@
 	MOVQ	a+0(FP), SI
 	MOVQ	b+8(FP), DI
 	MOVQ	size+16(FP), BX
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, ret+24(FP)
-	RET
+	LEAQ	ret+24(FP), AX
+	JMP	runtime·memeqbody(SB)
 
 // memequal_varlen(a, b unsafe.Pointer) bool
 TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17
@@ -1270,9 +1272,8 @@
 	CMPQ	SI, DI
 	JEQ	eq
 	MOVQ	8(DX), BX    // compiler stores size at offset 8 in the closure
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, ret+16(FP)
-	RET
+	LEAQ	ret+16(FP), AX
+	JMP	runtime·memeqbody(SB)
 eq:
 	MOVB	$1, ret+16(FP)
 	RET
@@ -1288,9 +1289,8 @@
 	CMPQ	SI, DI
 	JEQ	eq
 	MOVQ	s1len+8(FP), BX
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, v+32(FP)
-	RET
+	LEAQ	v+32(FP), AX
+	JMP	runtime·memeqbody(SB)
 eq:
 	MOVB	$1, v+32(FP)
 	RET
@@ -1298,9 +1298,8 @@
 // a in SI
 // b in DI
 // count in BX
+// address of result byte in AX
 TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
-	XORQ	AX, AX
-
 	CMPQ	BX, $8
 	JB	small
 	
@@ -1329,6 +1328,7 @@
 	SUBQ	$64, BX
 	CMPL	DX, $0xffff
 	JEQ	hugeloop
+	MOVB	$0, (AX)
 	RET
 
 	// 8 bytes at a time using 64-bit register
@@ -1342,6 +1342,7 @@
 	SUBQ	$8, BX
 	CMPQ	CX, DX
 	JEQ	bigloop
+	MOVB	$0, (AX)
 	RET
 
 	// remaining 0-8 bytes
@@ -1349,7 +1350,7 @@
 	MOVQ	-8(SI)(BX*1), CX
 	MOVQ	-8(DI)(BX*1), DX
 	CMPQ	CX, DX
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 small:
@@ -1384,7 +1385,7 @@
 	SUBQ	SI, DI
 	SHLQ	CX, DI
 equal:
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 TEXT runtime·cmpstring(SB),NOSPLIT,$0-40
@@ -1392,26 +1393,23 @@
 	MOVQ	s1_len+8(FP), BX
 	MOVQ	s2_base+16(FP), DI
 	MOVQ	s2_len+24(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVQ	AX, ret+32(FP)
-	RET
+	LEAQ	ret+32(FP), R9
+	JMP	runtime·cmpbody(SB)
 
 TEXT bytes·Compare(SB),NOSPLIT,$0-56
 	MOVQ	s1+0(FP), SI
 	MOVQ	s1+8(FP), BX
 	MOVQ	s2+24(FP), DI
 	MOVQ	s2+32(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVQ	AX, res+48(FP)
-	RET
+	LEAQ	res+48(FP), R9
+	JMP	runtime·cmpbody(SB)
 
 // input:
 //   SI = a
 //   DI = b
 //   BX = alen
 //   DX = blen
-// output:
-//   AX = 1/0/-1
+//   R9 = address of output word (stores -1/0/1 here)
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
 	CMPQ	SI, DI
 	JEQ	allsame
@@ -1443,6 +1441,7 @@
 	CMPB	CX, (DI)(BX*1)
 	SETHI	AX
 	LEAQ	-1(AX*2), AX	// convert 1/0 to +1/-1
+	MOVQ	AX, (R9)
 	RET
 
 	// 0 through 16 bytes left, alen>=8, blen>=8
@@ -1468,6 +1467,7 @@
 	SHRQ	CX, AX	// move a's bit to bottom
 	ANDQ	$1, AX	// mask bit
 	LEAQ	-1(AX*2), AX // 1/0 => +1/-1
+	MOVQ	AX, (R9)
 	RET
 
 	// 0-7 bytes in common
@@ -1506,6 +1506,7 @@
 	SHRQ	CX, SI	// move a's bit to bottom
 	ANDQ	$1, SI	// mask bit
 	LEAQ	-1(SI*2), AX // 1/0 => +1/-1
+	MOVQ	AX, (R9)
 	RET
 
 allsame:
@@ -1515,30 +1516,28 @@
 	SETGT	AX	// 1 if alen > blen
 	SETEQ	CX	// 1 if alen == blen
 	LEAQ	-1(CX)(AX*2), AX	// 1,0,-1 result
+	MOVQ	AX, (R9)
 	RET
 
 TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
 	MOVQ s+0(FP), SI
 	MOVQ s_len+8(FP), BX
 	MOVB c+24(FP), AL
-	CALL runtime·indexbytebody(SB)
-	MOVQ AX, ret+32(FP)
-	RET
+	LEAQ ret+32(FP), R8
+	JMP  runtime·indexbytebody(SB)
 
 TEXT strings·IndexByte(SB),NOSPLIT,$0-32
 	MOVQ s+0(FP), SI
 	MOVQ s_len+8(FP), BX
 	MOVB c+16(FP), AL
-	CALL runtime·indexbytebody(SB)
-	MOVQ AX, ret+24(FP)
-	RET
+	LEAQ ret+24(FP), R8
+	JMP  runtime·indexbytebody(SB)
 
 // input:
 //   SI: data
 //   BX: data len
 //   AL: byte sought
-// output:
-//   AX
+//   R8: address to put result
 TEXT runtime·indexbytebody(SB),NOSPLIT,$0
 	MOVQ SI, DI
 
@@ -1597,7 +1596,7 @@
 	JZ success
 
 failure:
-	MOVQ $-1, AX
+	MOVQ $-1, (R8)
 	RET
 
 // handle for lengths < 16
@@ -1605,7 +1604,7 @@
 	MOVQ BX, CX
 	REPN; SCASB
 	JZ success
-	MOVQ $-1, AX
+	MOVQ $-1, (R8)
 	RET
 
 // we've found the chunk containing the byte
@@ -1615,821 +1614,26 @@
 	BSFW DX, DX
 	SUBQ SI, DI
 	ADDQ DI, DX
-	MOVQ DX, AX
+	MOVQ DX, (R8)
 	RET
 
 success:
 	SUBQ SI, DI
 	SUBL $1, DI
-	MOVQ DI, AX
+	MOVQ DI, (R8)
 	RET
 
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
 	MOVQ	a_len+8(FP), BX
 	MOVQ	b_len+32(FP), CX
-	XORQ	AX, AX
 	CMPQ	BX, CX
 	JNE	eqret
 	MOVQ	a+0(FP), SI
 	MOVQ	b+24(FP), DI
-	CALL	runtime·memeqbody(SB)
+	LEAQ	ret+48(FP), AX
+	JMP	runtime·memeqbody(SB)
 eqret:
-	MOVB	AX, ret+48(FP)
-	RET
-
-// A Duff's device for zeroing memory.
-// The compiler jumps to computed addresses within
-// this routine to zero chunks of memory.  Do not
-// change this code without also changing the code
-// in ../../cmd/6g/ggen.c:clearfat.
-// AX: zero
-// DI: ptr to memory to be zeroed
-// DI is updated as a side effect.
-TEXT runtime·duffzero(SB), NOSPLIT, $0-0
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	RET
-
-// A Duff's device for copying memory.
-// The compiler jumps to computed addresses within
-// this routine to copy chunks of memory.  Source
-// and destination must not overlap.  Do not
-// change this code without also changing the code
-// in ../../cmd/6g/cgen.c:sgen.
-// SI: ptr to source memory
-// DI: ptr to destination memory
-// SI and DI are updated as a side effect.
-
-// NOTE: this is equivalent to a sequence of MOVSQ but
-// for some reason that is 3.5x slower than this code.
-// The STOSQ above seem fine, though.
-TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
+	MOVB	$0, ret+48(FP)
 	RET
 
 TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
@@ -2468,12 +1672,6 @@
 	// traceback from goexit1 must hit code range of goexit
 	BYTE	$0x90	// NOP
 
-TEXT runtime·getg(SB),NOSPLIT,$0-8
-	get_tls(CX)
-	MOVQ	g(CX), AX
-	MOVQ	AX, ret+0(FP)
-	RET
-
 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
 	MOVQ	addr+0(FP), AX
 	PREFETCHT0	(AX)
@@ -2493,3 +1691,10 @@
 	MOVQ	addr+0(FP), AX
 	PREFETCHNTA	(AX)
 	RET
+
+// This is called from .init_array and follows the platform, not Go, ABI.
+TEXT runtime·addmoduledata(SB),NOSPLIT,$0-8
+	MOVQ	runtime·lastmoduledatap(SB), AX
+	MOVQ	DI, moduledata_next(AX)
+	MOVQ	DI, runtime·lastmoduledatap(SB)
+	RET
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index e144c40..5e9210f 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -483,6 +483,9 @@
 	MOVQ	AX, ret+16(FP)
 	RET
 
+TEXT runtime·xadduintptr(SB), NOSPLIT, $0-12
+	JMP	runtime·xadd(SB)
+
 TEXT runtime·xchg(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
@@ -1096,12 +1099,6 @@
 	// traceback from goexit1 must hit code range of goexit
 	BYTE	$0x90	// NOP
 
-TEXT runtime·getg(SB),NOSPLIT,$0-4
-	get_tls(CX)
-	MOVL	g(CX), AX
-	MOVL	AX, ret+0(FP)
-	RET
-
 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
 	MOVL	addr+0(FP), AX
 	PREFETCHT0	(AX)
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index a5f6bde..e69b1ef 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -782,33 +782,31 @@
 	MOVB	R0, ret+8(FP)
 	RET
 
-TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
+TEXT runtime·cmpstring(SB),NOSPLIT,$-4-20
 	MOVW	s1_base+0(FP), R2
 	MOVW	s1_len+4(FP), R0
 	MOVW	s2_base+8(FP), R3
 	MOVW	s2_len+12(FP), R1
-	BL	runtime·cmpbody(SB)
-	MOVW	R8, ret+16(FP)
-	RET
+	ADD	$20, R13, R7
+	B	runtime·cmpbody(SB)
 
-TEXT bytes·Compare(SB),NOSPLIT,$0-28
+TEXT bytes·Compare(SB),NOSPLIT,$-4-28
 	MOVW	s1+0(FP), R2
 	MOVW	s1+4(FP), R0
 	MOVW	s2+12(FP), R3
 	MOVW	s2+16(FP), R1
-	BL	runtime·cmpbody(SB)
-	MOVW	R8, ret+24(FP)
-	RET
+	ADD	$28, R13, R7
+	B	runtime·cmpbody(SB)
 
 // On entry:
 // R0 is the length of s1
 // R1 is the length of s2
 // R2 points to the start of s1
 // R3 points to the start of s2
+// R7 points to return value (-1/0/1 will be written here)
 //
 // On exit:
-// R8 is -1/0/+1
-// R5, R4, and R6 are clobbered
+// R4, R5, and R6 are clobbered
 TEXT runtime·cmpbody(SB),NOSPLIT,$-4-0
 	CMP 	R0, R1
 	MOVW 	R0, R6
@@ -823,14 +821,16 @@
 	CMP	R4, R5
 	BEQ	loop
 	// bytes differed
-	MOVW.LT	$1, R8
-	MOVW.GT	$-1, R8
+	MOVW.LT	$1, R0
+	MOVW.GT	$-1, R0
+	MOVW	R0, (R7)
 	RET
 samebytes:
 	CMP	R0, R1
-	MOVW.LT	$1, R8
-	MOVW.GT	$-1, R8
-	MOVW.EQ	$0, R8
+	MOVW.LT	$1, R0
+	MOVW.GT	$-1, R0
+	MOVW.EQ	$0, R0
+	MOVW	R0, (R7)
 	RET
 
 // eqstring tests whether two strings are equal.
@@ -936,414 +936,6 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-// A Duff's device for zeroing memory.
-// The compiler jumps to computed addresses within
-// this routine to zero chunks of memory.  Do not
-// change this code without also changing the code
-// in ../../cmd/5g/ggen.c:clearfat.
-// R0: zero
-// R1: ptr to memory to be zeroed
-// R1 is updated as a side effect.
-TEXT runtime·duffzero(SB),NOSPLIT,$0-0
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	RET
-
-// A Duff's device for copying memory.
-// The compiler jumps to computed addresses within
-// this routine to copy chunks of memory.  Source
-// and destination must not overlap.  Do not
-// change this code without also changing the code
-// in ../../cmd/5g/cgen.c:sgen.
-// R0: scratch space
-// R1: ptr to source memory
-// R2: ptr to destination memory
-// R1 and R2 are updated as a side effect
-TEXT runtime·duffcopy(SB),NOSPLIT,$0-0
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	RET
-
 TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
 	MOVW	g_m(g), R1
 	MOVW	m_fastrand(R1), R0
@@ -1392,10 +984,6 @@
 	// traceback from goexit1 must hit code range of goexit
 	MOVW	R0, R0	// NOP
 
-TEXT runtime·getg(SB),NOSPLIT,$-4-4
-	MOVW	g, ret+0(FP)
-	RET
-
 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
 	RET
 
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index 0068e84..03488a6 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -4,6 +4,7 @@
 
 #include "go_asm.h"
 #include "go_tls.h"
+#include "tls_arm64.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -32,7 +33,19 @@
 	CMP	$0, R12
 	BEQ	nocgo
 
-	BL	runtime·abort(SB)
+	MRS_TPIDR_R0			// load TLS base pointer
+	MOVD	R0, R3			// arg 3: TLS base pointer
+#ifdef TLSG_IS_VARIABLE
+	MOVD	$runtime·tls_g(SB), R2 	// arg 2: tlsg
+#else
+	MOVD	$0x10, R2		// arg 2: tlsg TODO(minux): hardcoded for linux
+#endif
+	MOVD	$setg_gcc<>(SB), R1	// arg 1: setg
+	MOVD	g, R0			// arg 0: G
+	BL	(R12)
+	MOVD	_cgo_init(SB), R12
+	CMP	$0, R12
+	BEQ	nocgo
 
 nocgo:
 	// update stackguard after _cgo_init
@@ -456,6 +469,20 @@
 TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
 	B	runtime·atomicstore64(SB)
 
+// AES hashing not implemented for ARM64, issue #10109.
+TEXT runtime·aeshash(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+
 // bool casp(void **val, void *old, void *new)
 // Atomically:
 //	if(*val == old){
@@ -504,62 +531,61 @@
 // asmcgocall(void(*fn)(void*), void *arg)
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
-// See cgocall.c for more details.
+// See cgocall.go for more details.
 TEXT ·asmcgocall(SB),NOSPLIT,$0-16
-	MOVD	fn+0(FP), R3
-	MOVD	arg+8(FP), R4
+	MOVD	fn+0(FP), R1
+	MOVD	arg+8(FP), R0
 	BL	asmcgocall<>(SB)
 	RET
 
 TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-20
-	MOVD	fn+0(FP), R3
-	MOVD	arg+8(FP), R4
+	MOVD	fn+0(FP), R1
+	MOVD	arg+8(FP), R0
 	BL	asmcgocall<>(SB)
 	MOVW	R0, ret+16(FP)
 	RET
 
-// asmcgocall common code. fn in R3, arg in R4. returns errno in R0.
+// asmcgocall common code. fn in R1, arg in R0. returns errno in R0.
 TEXT asmcgocall<>(SB),NOSPLIT,$0-0
 	MOVD	RSP, R2		// save original stack pointer
-	MOVD	g, R5
+	MOVD	g, R4
 
 	// Figure out if we need to switch to m->g0 stack.
 	// We get called to create new OS threads too, and those
 	// come in on the m->g0 stack already.
-	MOVD	g_m(g), R6
-	MOVD	m_g0(R6), R6
-	CMP	R6, g
+	MOVD	g_m(g), R8
+	MOVD	m_g0(R8), R3
+	CMP	R3, g
 	BEQ	g0
+	MOVD	R0, R9	// gosave<> and save_g might clobber R0
 	BL	gosave<>(SB)
-	MOVD	R6, g
+	MOVD	R3, g
 	BL	runtime·save_g(SB)
-	MOVD	(g_sched+gobuf_sp)(g), R13
-	MOVD	R13, RSP
+	MOVD	(g_sched+gobuf_sp)(g), R0
+	MOVD	R0, RSP
+	MOVD	R9, R0
 
 	// Now on a scheduling stack (a pthread-created stack).
 g0:
-	// Save room for two of our pointers, plus 32 bytes of callee
-	// save area that lives on the caller stack.
+	// Save room for two of our pointers /*, plus 32 bytes of callee
+	// save area that lives on the caller stack. */
 	MOVD	RSP, R13
-	SUB	$48, R13
-	AND	$~15, R13	// 16-byte alignment for gcc ABI
+	SUB	$16, R13
 	MOVD	R13, RSP
-	MOVD	R5, 40(RSP)	// save old g on stack
-	MOVD	(g_stack+stack_hi)(R5), R5
-	SUB	R2, R5
-	MOVD	R5, 32(RSP)	// save depth in old g stack (can't just save RSP, as stack might be copied during a callback)
-	MOVD	R0, 0(RSP)	// clear back chain pointer (TODO can we give it real back trace information?)
-	// This is a "global call", so put the global entry point in r12
-	MOVD	R3, R12
-	MOVD	R4, R0
-	BL	(R12)
+	MOVD	R4, 0(RSP)	// save old g on stack
+	MOVD	(g_stack+stack_hi)(R4), R4
+	SUB	R2, R4
+	MOVD	R4, 8(RSP)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
+	BL	(R1)
+	MOVD	R0, R9
 
 	// Restore g, stack pointer.  R0 is errno, so don't touch it
-	MOVD	40(RSP), g
+	MOVD	0(RSP), g
 	BL	runtime·save_g(SB)
 	MOVD	(g_stack+stack_hi)(g), R5
-	MOVD	32(RSP), R6
+	MOVD	8(RSP), R6
 	SUB	R6, R5
+	MOVD	R9, R0
 	MOVD	R5, RSP
 	RET
 
@@ -567,27 +593,26 @@
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
 TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
-	MOVD	$fn+0(FP), R3
-	MOVD	R3, 8(RSP)
-	MOVD	frame+8(FP), R3
-	MOVD	R3, 16(RSP)
-	MOVD	framesize+16(FP), R3
-	MOVD	R3, 24(RSP)
-	MOVD	$runtime·cgocallback_gofunc(SB), R3
-	BL	(R3)
+	MOVD	$fn+0(FP), R0
+	MOVD	R0, 8(RSP)
+	MOVD	frame+8(FP), R0
+	MOVD	R0, 16(RSP)
+	MOVD	framesize+16(FP), R0
+	MOVD	R0, 24(RSP)
+	MOVD	$runtime·cgocallback_gofunc(SB), R0
+	BL	(R0)
 	RET
 
 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
-// See cgocall.c for more details.
+// See cgocall.go for more details.
 TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
 	NO_LOCAL_POINTERS
 
-	// Load m and g from thread-local storage.
+	// Load g from thread-local storage.
 	MOVB	runtime·iscgo(SB), R3
-	CMP	$0, R3 
+	CMP	$0, R3
 	BEQ	nocgo
-	// TODO(aram):
-	BL runtime·abort(SB)
+	BL	runtime·load_g(SB)
 nocgo:
 
 	// If g is nil, Go did not create the current thread.
@@ -598,8 +623,8 @@
 	CMP	$0, g
 	BNE	havem
 	MOVD	g, savedm-8(SP) // g is zero, so is m.
-	MOVD	$runtime·needm(SB), R3
-	BL	(R3)
+	MOVD	$runtime·needm(SB), R0
+	BL	(R0)
 
 	// Set m->sched.sp = SP, so that if a panic happens
 	// during the function we are about to execute, it will
@@ -612,8 +637,8 @@
 	// and then systemstack will try to use it. If we don't set it here,
 	// that restored SP will be uninitialized (typically 0) and
 	// will not be usable.
-	MOVD	g_m(g), R3
-	MOVD	m_g0(R3), R3
+	MOVD	g_m(g), R8
+	MOVD	m_g0(R8), R3
 	MOVD	RSP, R0
 	MOVD	R0, (g_sched+gobuf_sp)(R3)
 
@@ -624,7 +649,8 @@
 	// Save current m->g0->sched.sp on stack and then set it to SP.
 	// Save current sp in m->g0->sched.sp in preparation for
 	// switch back to m->curg stack.
-	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP).
+	// NOTE: unwindm knows that the saved g->sched.sp is at 16(RSP) aka savedsp-16(SP).
+	// Beware that the frame size is actually 32.
 	MOVD	m_g0(R8), R3
 	MOVD	(g_sched+gobuf_sp)(R3), R4
 	MOVD	R4, savedsp-16(SP)
@@ -650,15 +676,16 @@
 	BL	runtime·save_g(SB)
 	MOVD	(g_sched+gobuf_sp)(g), R4 // prepare stack as R4
 	MOVD	(g_sched+gobuf_pc)(g), R5
-	MOVD	R5, -24(R4)
-	MOVD	$-24(R4), R0
+	MOVD	R5, -(24+8)(R4)	// maintain 16-byte SP alignment
+	MOVD	$-(24+8)(R4), R0
 	MOVD	R0, RSP
 	BL	runtime·cgocallbackg(SB)
 
 	// Restore g->sched (== m->curg->sched) from saved values.
 	MOVD	0(RSP), R5
 	MOVD	R5, (g_sched+gobuf_pc)(g)
-	MOVD	$24(RSP), R4
+	MOVD	RSP, R4
+	ADD	$(24+8), R4, R4
 	MOVD	R4, (g_sched+gobuf_sp)(g)
 
 	// Switch back to m->g0's stack and restore m->g0->sched.sp.
@@ -677,13 +704,30 @@
 	MOVD	savedm-8(SP), R6
 	CMP	$0, R6
 	BNE	droppedm
-	MOVD	$runtime·dropm(SB), R3
-	BL	(R3)
+	MOVD	$runtime·dropm(SB), R0
+	BL	(R0)
 droppedm:
 
 	// Done!
 	RET
 
+// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
+// Must obey the gcc calling convention.
+TEXT _cgo_topofstack(SB),NOSPLIT,$16
+	// g (R28) and REGTMP (R27)  might be clobbered by load_g. They
+	// are callee-save in the gcc calling convention, so save them.
+	MOVD	R27, savedR27-8(SP)
+	MOVD	g, saveG-16(SP)
+
+	BL	runtime·load_g(SB)
+	MOVD	g_m(g), R0
+	MOVD	m_curg(R0), R0
+	MOVD	(g_stack+stack_hi)(R0), R0
+
+	MOVD	saveG-16(SP), g
+	MOVD	savedR28-8(SP), R27
+	RET
+
 // void setg(G*); set g. for use by needm.
 TEXT runtime·setg(SB), NOSPLIT, $0-8
 	MOVD	gg+0(FP), g
@@ -691,23 +735,14 @@
 	BL	runtime·save_g(SB)
 	RET
 
-// save_g saves the g register into pthread-provided
-// thread-local memory, so that we can call externally compiled
-// ppc64 code that will overwrite this register.
-//
-// If !iscgo, this is a no-op.
-TEXT runtime·save_g(SB),NOSPLIT,$-8-0
-	MOVB	runtime·iscgo(SB), R0
-	CMP	$0, R0
-	BEQ	nocgo
-
-	// TODO: implement cgo.
-	BL	runtime·abort(SB)
-
-nocgo:
+// void setg_gcc(G*); set g called from gcc
+TEXT setg_gcc<>(SB),NOSPLIT,$8
+	MOVD	R0, g
+	MOVD	R27, savedR27-8(SP)
+	BL	runtime·save_g(SB)
+	MOVD	savedR27-8(SP), R27
 	RET
 
-
 TEXT runtime·getcallerpc(SB),NOSPLIT,$-8-16
 	MOVD	0(RSP), R0
 	MOVD	R0, ret+8(FP)
@@ -783,6 +818,56 @@
 	MOVB	R3, ret+16(FP)
 	RET
 
+TEXT runtime·cmpstring(SB),NOSPLIT,$-4-40
+	MOVD	s1_base+0(FP), R2
+	MOVD	s1_len+8(FP), R0
+	MOVD	s2_base+16(FP), R3
+	MOVD	s2_len+24(FP), R1
+	ADD	$40, RSP, R7
+	B	runtime·cmpbody<>(SB)
+
+TEXT bytes·Compare(SB),NOSPLIT,$-4-56
+	MOVD	s1+0(FP), R2
+	MOVD	s1+8(FP), R0
+	MOVD	s2+24(FP), R3
+	MOVD	s2+32(FP), R1
+	ADD	$56, RSP, R7
+	B	runtime·cmpbody<>(SB)
+
+// On entry:
+// R0 is the length of s1
+// R1 is the length of s2
+// R2 points to the start of s1
+// R3 points to the start of s2
+// R7 points to return value (-1/0/1 will be written here)
+//
+// On exit:
+// R4, R5, and R6 are clobbered
+TEXT runtime·cmpbody<>(SB),NOSPLIT,$-4-0
+	CMP	R0, R1
+	CSEL    LT, R1, R0, R6 // R6 is min(R0, R1)
+
+	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
+loop:
+	CMP	R2, R6
+	BEQ	samebytes // all compared bytes were the same; compare lengths
+	MOVBU.P	1(R2), R4
+	MOVBU.P	1(R3), R5
+	CMP	R4, R5
+	BEQ	loop
+	// bytes differed
+	MOVD	$1, R4
+	CSNEG	LT, R4, R4, R4
+	MOVD	R4, (R7)
+	RET
+samebytes:
+	MOVD	$1, R4
+	CMP	R0, R1
+	CSNEG	LT, R4, R4, R4
+	CSEL	EQ, ZR, R4, R4
+	MOVD	R4, (R7)
+	RET
+
 // eqstring tests whether two strings are equal.
 // The compiler guarantees that strings passed
 // to eqstring have equal length.
@@ -881,145 +966,6 @@
 	MOVB	R0, ret+48(FP)
 	RET
 
-// A Duff's device for zeroing memory.
-// The compiler jumps to computed addresses within
-// this routine to zero chunks of memory.  Do not
-// change this code without also changing the code
-// in ../cmd/7g/ggen.c:/^clearfat.
-// ZR: always zero
-// R16 (aka REGRT1): ptr to memory to be zeroed - 8
-// On return, R16 points to the last zeroed dword.
-TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	MOVD.W	ZR, 8(R16)
-	RET
-
 TEXT runtime·fastrand1(SB),NOSPLIT,$-8-4
 	MOVD	g_m(g), R1
 	MOVWU	m_fastrand(R1), R0
@@ -1042,10 +988,6 @@
 	MOVD	R0, R0	// NOP
 	BL	runtime·goexit1(SB)	// does not return
 
-TEXT runtime·getg(SB),NOSPLIT,$-8-8
-	MOVD	g, ret+0(FP)
-	RET
-
 // TODO(aram): use PRFM here.
 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
 	RET
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 10461bb..53870f6 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -686,11 +686,11 @@
 	BL	asmcgocall<>(SB)
 	RET
 
-TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-24
+TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-20
 	MOVD	fn+0(FP), R3
 	MOVD	arg+8(FP), R4
 	BL	asmcgocall<>(SB)
-	MOVD	R3, ret+16(FP)
+	MOVW	R3, ret+16(FP)
 	RET
 
 // asmcgocall common code. fn in R3, arg in R4. returns errno in R3.
@@ -1093,146 +1093,6 @@
 	MOVD	R3, ret+24(FP)
 	RETURN
 
-
-// A Duff's device for zeroing memory.
-// The compiler jumps to computed addresses within
-// this routine to zero chunks of memory.  Do not
-// change this code without also changing the code
-// in ../../cmd/9g/ggen.c:/^clearfat.
-// R0: always zero
-// R3 (aka REGRT1): ptr to memory to be zeroed - 8
-// On return, R3 points to the last zeroed dword.
-TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	MOVDU	R0, 8(R3)
-	RETURN
-
 TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
 	MOVD	g_m(g), R4
 	MOVWZ	m_fastrand(R4), R3
@@ -1274,10 +1134,6 @@
 	// traceback from goexit1 must hit code range of goexit
 	MOVD	R0, R0	// NOP
 
-TEXT runtime·getg(SB),NOSPLIT,$-8-8
-	MOVD	g, ret+0(FP)
-	RETURN
-
 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
 	RETURN
 
diff --git a/src/runtime/atomic_386.go b/src/runtime/atomic_386.go
index 7828c66..f8d589e 100644
--- a/src/runtime/atomic_386.go
+++ b/src/runtime/atomic_386.go
@@ -32,6 +32,10 @@
 	}
 }
 
+//go:noescape
+//go:linkname xadduintptr runtime.xadd
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
 //go:nosplit
 func xchg64(ptr *uint64, new uint64) uint64 {
 	for {
diff --git a/src/runtime/atomic_amd64x.go b/src/runtime/atomic_amd64x.go
index e539387..edcc6d6 100644
--- a/src/runtime/atomic_amd64x.go
+++ b/src/runtime/atomic_amd64x.go
@@ -37,6 +37,9 @@
 func xadd64(ptr *uint64, delta int64) uint64
 
 //go:noescape
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:noescape
 func xchg(ptr *uint32, new uint32) uint32
 
 //go:noescape
diff --git a/src/runtime/atomic_arm.go b/src/runtime/atomic_arm.go
index 75206ab..02a1f35 100644
--- a/src/runtime/atomic_arm.go
+++ b/src/runtime/atomic_arm.go
@@ -27,6 +27,10 @@
 	}
 }
 
+//go:noescape
+//go:linkname xadduintptr runtime.xadd
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
 //go:nosplit
 func xchg(addr *uint32, v uint32) uint32 {
 	for {
diff --git a/src/runtime/atomic_arm64.go b/src/runtime/atomic_arm64.go
index 6a78a8d..a377e3e 100644
--- a/src/runtime/atomic_arm64.go
+++ b/src/runtime/atomic_arm64.go
@@ -13,6 +13,10 @@
 func xadd64(ptr *uint64, delta int64) uint64
 
 //go:noescape
+//go:linkname xadduintptr runtime.xadd64
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:noescape
 func xchg(ptr *uint32, new uint32) uint32
 
 //go:noescape
diff --git a/src/runtime/atomic_ppc64x.go b/src/runtime/atomic_ppc64x.go
index 17c642d..b58ee5a 100644
--- a/src/runtime/atomic_ppc64x.go
+++ b/src/runtime/atomic_ppc64x.go
@@ -15,6 +15,10 @@
 func xadd64(ptr *uint64, delta int64) uint64
 
 //go:noescape
+//go:linkname xadduintptr runtime.xadd64
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:noescape
 func xchg(ptr *uint32, new uint32) uint32
 
 //go:noescape
diff --git a/src/runtime/atomic_test.go b/src/runtime/atomic_test.go
new file mode 100644
index 0000000..2699103
--- /dev/null
+++ b/src/runtime/atomic_test.go
@@ -0,0 +1,66 @@
+// 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 runtime_test
+
+import (
+	"runtime"
+	"testing"
+	"unsafe"
+)
+
+func runParallel(N, iter int, f func()) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(int(N)))
+	done := make(chan bool)
+	for i := 0; i < N; i++ {
+		go func() {
+			for j := 0; j < iter; j++ {
+				f()
+			}
+			done <- true
+		}()
+	}
+	for i := 0; i < N; i++ {
+		<-done
+	}
+}
+
+func TestXadduintptr(t *testing.T) {
+	const N = 20
+	const iter = 100000
+	inc := uintptr(100)
+	total := uintptr(0)
+	runParallel(N, iter, func() {
+		runtime.Xadduintptr(&total, inc)
+	})
+	if want := uintptr(N * iter * inc); want != total {
+		t.Fatalf("xadduintpr error, want %d, got %d", want, total)
+	}
+	total = 0
+	runParallel(N, iter, func() {
+		runtime.Xadduintptr(&total, inc)
+		runtime.Xadduintptr(&total, uintptr(-int64(inc)))
+	})
+	if total != 0 {
+		t.Fatalf("xadduintpr total error, want %d, got %d", 0, total)
+	}
+}
+
+// Tests that xadduintptr correctly updates 64-bit values.  The place where
+// we actually do so is mstats.go, functions mSysStat{Inc,Dec}.
+func TestXadduintptrOnUint64(t *testing.T) {
+	if runtime.BigEndian != 0 {
+		// On big endian architectures, we never use xadduintptr to update
+		// 64-bit values and hence we skip the test.  (Note that functions
+		// mSysStat{Inc,Dec} in mstats.go have explicit checks for
+		// big-endianness.)
+		return
+	}
+	const inc = 100
+	val := uint64(0)
+	runtime.Xadduintptr((*uintptr)(unsafe.Pointer(&val)), inc)
+	if inc != val {
+		t.Fatalf("xadduintptr should increase lower-order bits, want %d, got %d", inc, val)
+	}
+}
diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go
index 5dc83c0..d8ae6ec 100644
--- a/src/runtime/cgo.go
+++ b/src/runtime/cgo.go
@@ -14,12 +14,16 @@
 //go:linkname _cgo_malloc _cgo_malloc
 //go:linkname _cgo_free _cgo_free
 //go:linkname _cgo_thread_start _cgo_thread_start
+//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
+//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
 
 var (
-	_cgo_init         unsafe.Pointer
-	_cgo_malloc       unsafe.Pointer
-	_cgo_free         unsafe.Pointer
-	_cgo_thread_start unsafe.Pointer
+	_cgo_init                     unsafe.Pointer
+	_cgo_malloc                   unsafe.Pointer
+	_cgo_free                     unsafe.Pointer
+	_cgo_thread_start             unsafe.Pointer
+	_cgo_sys_thread_create        unsafe.Pointer
+	_cgo_notify_runtime_init_done unsafe.Pointer
 )
 
 // iscgo is set to true by the runtime/cgo package
diff --git a/src/runtime/cgo/asm_arm64.s b/src/runtime/cgo/asm_arm64.s
new file mode 100644
index 0000000..be03993
--- /dev/null
+++ b/src/runtime/cgo/asm_arm64.s
@@ -0,0 +1,57 @@
+// 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"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),NOSPLIT,$-8
+	/*
+	 * We still need to save all callee save register as before, and then
+	 *  push 2 args for fn (R1 and R2).
+	 * Also note that at procedure entry in 7g world, 8(RSP) will be the
+	 *  first arg.
+	 * TODO(minux): use LDP/STP here if it matters.
+	 */
+	SUB	$128, RSP
+	MOVD	R1, (8*1)(RSP)
+	MOVD	R2, (8*2)(RSP)
+	MOVD	R19, (8*3)(RSP)
+	MOVD	R20, (8*4)(RSP)
+	MOVD	R21, (8*5)(RSP)
+	MOVD	R22, (8*6)(RSP)
+	MOVD	R23, (8*7)(RSP)
+	MOVD	R24, (8*8)(RSP)
+	MOVD	R25, (8*9)(RSP)
+	MOVD	R26, (8*10)(RSP)
+	MOVD	R27, (8*11)(RSP)
+	MOVD	g, (8*12)(RSP)
+	MOVD	R29, (8*13)(RSP)
+	MOVD	R30, (8*14)(RSP)
+
+	MOVD	R0, R19
+
+	// Initialize Go ABI environment
+	BL      runtime·reginit(SB)
+	BL	runtime·load_g(SB)
+	BL	(R19)
+
+	MOVD	(8*1)(RSP), R1
+	MOVD	(8*2)(RSP), R2
+	MOVD	(8*3)(RSP), R19
+	MOVD	(8*4)(RSP), R20
+	MOVD	(8*5)(RSP), R21
+	MOVD	(8*6)(RSP), R22
+	MOVD	(8*7)(RSP), R23
+	MOVD	(8*8)(RSP), R24
+	MOVD	(8*9)(RSP), R25
+	MOVD	(8*10)(RSP), R26
+	MOVD	(8*11)(RSP), R27
+	MOVD	(8*12)(RSP), g
+	MOVD	(8*13)(RSP), R29
+	MOVD	(8*14)(RSP), R30
+	ADD	$128, RSP
+	RET
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
index 1e8b590..1682341 100644
--- a/src/runtime/cgo/callbacks.go
+++ b/src/runtime/cgo/callbacks.go
@@ -22,32 +22,6 @@
 //go:cgo_export_static crosscall2
 //go:cgo_export_dynamic crosscall2
 
-// Allocate memory.  This allocates the requested number of bytes in
-// memory controlled by the Go runtime.  The allocated memory will be
-// zeroed.  You are responsible for ensuring that the Go garbage
-// collector can see a pointer to the allocated memory for as long as
-// it is valid, e.g., by storing a pointer in a local variable in your
-// C function, or in memory allocated by the Go runtime.  If the only
-// pointers are in a C global variable or in memory allocated via
-// malloc, then the Go garbage collector may collect the memory.
-
-// Call like this in code compiled with gcc:
-//   struct { size_t len; void *ret; } a;
-//   a.len = /* number of bytes to allocate */;
-//   crosscall2(_cgo_allocate, &a, sizeof a);
-//   /* Here a.ret is a pointer to the allocated memory.  */
-
-//go:linkname _runtime_cgo_allocate_internal runtime._cgo_allocate_internal
-var _runtime_cgo_allocate_internal byte
-
-//go:linkname _cgo_allocate _cgo_allocate
-//go:cgo_export_static _cgo_allocate
-//go:cgo_export_dynamic _cgo_allocate
-//go:nosplit
-func _cgo_allocate(a unsafe.Pointer, n int32) {
-	_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_allocate_internal), a, uintptr(n))
-}
-
 // Panic.  The argument is converted into a Go string.
 
 // Call like this in code compiled with gcc:
@@ -91,5 +65,31 @@
 var x_cgo_thread_start byte
 var _cgo_thread_start = &x_cgo_thread_start
 
+// Creates a new system thread without updating any Go state.
+//
+// This method is invoked during shared library loading to create a new OS
+// thread to perform the runtime initialization.  This method is similar to
+// _cgo_sys_thread_start except that it doesn't update any Go state.
+
+//go:cgo_import_static x_cgo_sys_thread_create
+//go:linkname x_cgo_sys_thread_create x_cgo_sys_thread_create
+//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
+var x_cgo_sys_thread_create byte
+var _cgo_sys_thread_create = &x_cgo_sys_thread_create
+
+// Notifies that the runtime has been intialized.
+//
+// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
+// to ensure that the runtime has been initialized before the CGO call is
+// executed.  This is necessary for shared libraries where we kickoff runtime
+// initialization in a separate thread and return without waiting for this
+// thread to complete the init.
+
+//go:cgo_import_static x_cgo_notify_runtime_init_done
+//go:linkname x_cgo_notify_runtime_init_done x_cgo_notify_runtime_init_done
+//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
+var x_cgo_notify_runtime_init_done byte
+var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
+
 //go:cgo_export_static _cgo_topofstack
 //go:cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index 510a817..cb24678 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -11,8 +11,9 @@
 
 /*
 
-#cgo darwin,!arm LDFLAGS: -lpthread
+#cgo darwin,!arm,!arm64 LDFLAGS: -lpthread
 #cgo darwin,arm LDFLAGS: -framework CoreFoundation
+#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
 #cgo dragonfly LDFLAGS: -lpthread
 #cgo freebsd LDFLAGS: -lpthread
 #cgo android LDFLAGS: -llog
@@ -23,5 +24,7 @@
 
 #cgo CFLAGS: -Wall -Werror
 
+#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS
+
 */
 import "C"
diff --git a/src/runtime/cgo/gcc_arm64.S b/src/runtime/cgo/gcc_arm64.S
new file mode 100644
index 0000000..7677ec1
--- /dev/null
+++ b/src/runtime/cgo/gcc_arm64.S
@@ -0,0 +1,57 @@
+// 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.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+// Apple's ld64 wants 4-byte alignment for ARM code sections.
+// .align in both Apple as and GNU as treat n as aligning to 2**n bytes.
+.align	2
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the 7g tool chain, where all registers are caller save.
+ * Called from standard ARM EABI, where x19-x29 are callee-save, so they
+ * must be saved explicitly, along with x30 (LR).
+ */
+.globl EXT(crosscall1)
+EXT(crosscall1):
+	stp x19, x20, [sp, #-16]!
+	stp x21, x22, [sp, #-16]!
+	stp x23, x24, [sp, #-16]!
+	stp x25, x26, [sp, #-16]!
+	stp x27, x28, [sp, #-16]!
+	stp x29, x30, [sp, #-16]!
+	mov x29, sp
+
+	mov x19, x0
+	mov x20, x1
+	mov x0, x2
+
+	blr x20
+	blr x19
+
+	ldp x29, x30, [sp], #16
+	ldp x27, x28, [sp], #16
+	ldp x25, x26, [sp], #16
+	ldp x23, x24, [sp], #16
+	ldp x21, x22, [sp], #16
+	ldp x19, x20, [sp], #16
+	ret
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+	b 1b
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
new file mode 100644
index 0000000..b64a063
--- /dev/null
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -0,0 +1,157 @@
+// 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.
+
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h> /* for strerror */
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "libcgo.h"
+
+#include <CoreFoundation/CFBundle.h>
+#include <CoreFoundation/CFString.h>
+
+#define magic (0xc476c475c47957UL)
+
+// inittls allocates a thread-local storage slot for g.
+//
+// It finds the first available slot using pthread_key_create and uses
+// it as the offset value for runtime.tlsg.
+static void
+inittls(void **tlsg, void **tlsbase)
+{
+	pthread_key_t k;
+	int i, err;
+
+	err = pthread_key_create(&k, nil);
+	if(err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
+		abort();
+	}
+	//fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug
+	pthread_setspecific(k, (void*)magic);
+	// The first key should be at 257.
+	for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+		if (*(tlsbase+i) == (void*)magic) {
+			*tlsg = (void*)(i*sizeof(void *));
+			pthread_setspecific(k, 0);
+			return;
+		}
+	}
+	fprintf(stderr, "runtime/cgo: could not find pthread key.\n");
+	abort();
+}
+
+static void *threadentry(void*);
+void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	pthread_attr_t attr;
+	sigset_t ign, oset;
+	pthread_t p;
+	size_t size;
+	int err;
+
+	//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+	pthread_attr_init(&attr);
+	size = 0;
+	pthread_attr_getstacksize(&attr, &size);
+	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
+	ts->g->stackhi = size;
+	err = pthread_create(&p, &attr, threadentry, ts);
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	darwin_arm_init_thread_exception_port();
+
+	crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+	return nil;
+}
+
+// init_working_dir sets the current working directory to the app root.
+// By default darwin/arm processes start in "/".
+static void
+init_working_dir()
+{
+	CFBundleRef bundle = CFBundleGetMainBundle();
+	if (bundle == NULL) {
+		fprintf(stderr, "runtime/cgo: no main bundle\n");
+		return;
+	}
+	CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
+	if (url_ref == NULL) {
+		fprintf(stderr, "runtime/cgo: no Info.plist URL\n");
+		return;
+	}
+	CFStringRef url_str_ref = CFURLGetString(url_ref);
+	char url[MAXPATHLEN];
+        if (!CFStringGetCString(url_str_ref, url, sizeof(url), kCFStringEncodingUTF8)) {
+		fprintf(stderr, "runtime/cgo: cannot get URL string\n");
+		return;
+	}
+
+	// url is of the form "file:///path/to/Info.plist".
+	// strip it down to the working directory "/path/to".
+	int url_len = strlen(url);
+	if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
+		fprintf(stderr, "runtime/cgo: bad URL: %s\n", url);
+		return;
+	}
+	url[url_len-sizeof("/Info.plist")+1] = 0;
+	char *dir = &url[0] + sizeof("file://")-1;
+
+	if (chdir(dir) != 0) {
+		fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
+	}
+
+	// No-op to set a breakpoint on, immediately after the real chdir.
+	// Gives the test harness in go_darwin_arm_exec (which uses lldb) a
+	// chance to move the working directory.
+	getwd(dir);
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+	pthread_attr_t attr;
+	size_t size;
+
+	//fprintf(stderr, "x_cgo_init = %p\n", &x_cgo_init); // aid debugging in presence of ASLR
+	setg_gcc = setg;
+	pthread_attr_init(&attr);
+	pthread_attr_getstacksize(&attr, &size);
+	g->stacklo = (uintptr)&attr - size + 4096;
+	pthread_attr_destroy(&attr);
+
+	// yes, tlsbase from mrs might not be correctly aligned.
+	inittls(tlsg, (void**)((uintptr)tlsbase & ~7));
+
+	darwin_arm_init_mach_exception_handler();
+	darwin_arm_init_thread_exception_port();
+
+	init_working_dir();
+}
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
new file mode 100644
index 0000000..c3e94f5
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -0,0 +1,42 @@
+// 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 netbsd solaris
+// +build !ppc64,!ppc64le
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // strerror
+
+static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
+static int runtime_init_done;
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	pthread_t p;
+	int err = pthread_create(&p, NULL, func, arg);
+	if (err != 0) {
+		fprintf(stderr, "pthread_create failed: %s", strerror(err));
+		abort();
+	}
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	pthread_mutex_lock(&runtime_init_mu);
+	while (runtime_init_done == 0) {
+		pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
+	}
+	pthread_mutex_unlock(&runtime_init_mu);
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	pthread_mutex_lock(&runtime_init_mu);
+	runtime_init_done = 1;
+	pthread_cond_broadcast(&runtime_init_cond);
+	pthread_mutex_unlock(&runtime_init_mu);
+}
diff --git a/src/runtime/cgo/gcc_libinit_linux_ppc64x.c b/src/runtime/cgo/gcc_libinit_linux_ppc64x.c
new file mode 100644
index 0000000..82413a5
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_linux_ppc64x.c
@@ -0,0 +1,26 @@
+// 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.
+
+// TODO: see issue #10410
+// +build linux
+// +build ppc64 ppc64le
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
+	abort();
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	// TODO(spetrovic): implement this method.
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	// TODO(spetrovic): implement this method.
+}
\ No newline at end of file
diff --git a/src/runtime/cgo/gcc_libinit_openbsd.c b/src/runtime/cgo/gcc_libinit_openbsd.c
new file mode 100644
index 0000000..7e5b646
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_openbsd.c
@@ -0,0 +1,22 @@
+// 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 <stdio.h>
+#include <stdlib.h>
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
+	abort();
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	// TODO(spetrovic): implement this method.
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	// TODO(spetrovic): implement this method.
+}
\ No newline at end of file
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c
new file mode 100644
index 0000000..7e5b646
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_windows.c
@@ -0,0 +1,22 @@
+// 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 <stdio.h>
+#include <stdlib.h>
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
+	abort();
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	// TODO(spetrovic): implement this method.
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	// TODO(spetrovic): implement this method.
+}
\ No newline at end of file
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
new file mode 100644
index 0000000..ea11cf5
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_arm64.c
@@ -0,0 +1,73 @@
+// 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 <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	pthread_attr_t attr;
+	sigset_t ign, oset;
+	pthread_t p;
+	size_t size;
+	int err;
+
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+	// Not sure why the memset is necessary here,
+	// but without it, we get a bogus stack size
+	// out of pthread_attr_getstacksize.  C'est la Linux.
+	memset(&attr, 0, sizeof attr);
+	pthread_attr_init(&attr);
+	size = 0;
+	pthread_attr_getstacksize(&attr, &size);
+	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
+	ts->g->stackhi = size;
+	err = pthread_create(&p, &attr, threadentry, ts);
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+	if (err != 0) {
+		fatalf("pthread_create failed: %s", strerror(err));
+	}
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+	return nil;
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+	pthread_attr_t attr;
+	size_t size;
+
+	setg_gcc = setg;
+	pthread_attr_init(&attr);
+	pthread_attr_getstacksize(&attr, &size);
+	g->stacklo = (uintptr)&attr - size + 4096;
+	pthread_attr_destroy(&attr);
+
+	if (x_cgo_inittls) {
+		x_cgo_inittls(tlsg, tlsbase);
+	}
+}
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
index af0fc5d..ca29dcb 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -2,7 +2,7 @@
 // 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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include "libcgo.h"
 
diff --git a/src/runtime/cgo/gcc_signal_darwin_armx.c b/src/runtime/cgo/gcc_signal_darwin_armx.c
index cb32898..e36fe26 100644
--- a/src/runtime/cgo/gcc_signal_darwin_armx.c
+++ b/src/runtime/cgo/gcc_signal_darwin_armx.c
@@ -15,14 +15,11 @@
 // chance to resolve exceptions before the task handler, so we can generate
 // the panic and avoid lldb's SIGSEGV handler.
 //
-// If you want to debug a segfault under lldb, compile the standard library
-// with the build tag lldb:
-//
-//	go test -tags lldb -installsuffix lldb
+// The dist tool enables this by build flag when testing.
 
-// +build darwin,arm,!lldb
-
-// TODO(crawshaw): darwin,arm64,!lldb
+// +build lldb
+// +build darwin
+// +build arm arm64
 
 #include <limits.h>
 #include <pthread.h>
@@ -77,9 +74,31 @@
 
 	// Bounce call to sigpanic through asm that makes it look like
 	// we call sigpanic directly from the faulting code.
+#ifdef __arm64__
+	thread_state.ts_64.__x[1] = thread_state.ts_64.__lr;
+	thread_state.ts_64.__x[2] = thread_state.ts_64.__pc;
+	thread_state.ts_64.__pc = x_cgo_panicmem;
+#else
 	thread_state.ts_32.__r[1] = thread_state.ts_32.__lr;
 	thread_state.ts_32.__r[2] = thread_state.ts_32.__pc;
 	thread_state.ts_32.__pc = x_cgo_panicmem;
+#endif
+
+	if (0) {
+		// Useful debugging logic when panicmem is broken.
+		//
+		// Sends the first SIGSEGV and lets lldb catch the
+		// second one, avoiding a loop that locks up iOS
+		// devices requiring a hard reboot.
+		fprintf(stderr, "runtime/cgo: caught exc_bad_access\n");
+		fprintf(stderr, "__lr = %llx\n", thread_state.ts_64.__lr);
+		fprintf(stderr, "__pc = %llx\n", thread_state.ts_64.__pc);
+		static int pass1 = 0;
+		if (pass1) {
+			return KERN_FAILURE;
+		}
+		pass1 = 1;
+	}
 
 	ret = thread_set_state(thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t)&thread_state, state_count);
 	if (ret) {
@@ -174,9 +193,10 @@
 	}
 
 	// Start a thread to handle exceptions.
+	uintptr_t port_set = (uintptr_t)mach_exception_handler_port_set;
 	pthread_attr_init(&attr);
 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-	ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)mach_exception_handler_port_set);
+	ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)port_set);
 	if (ret) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %d\n", ret);
 		abort();
diff --git a/src/runtime/cgo/gcc_signal_darwin_lldb.c b/src/runtime/cgo/gcc_signal_darwin_lldb.c
index d3a3ddd..b26315f 100644
--- a/src/runtime/cgo/gcc_signal_darwin_lldb.c
+++ b/src/runtime/cgo/gcc_signal_darwin_lldb.c
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !lldb
 // +build darwin
 // +build arm arm64
-// +build lldb
 
 #include <stdint.h>
 
diff --git a/src/runtime/cgo/gcc_solaris_amd64.c b/src/runtime/cgo/gcc_solaris_amd64.c
new file mode 100644
index 0000000..72ace56
--- /dev/null
+++ b/src/runtime/cgo/gcc_solaris_amd64.c
@@ -0,0 +1,75 @@
+// 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 <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include <ucontext.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+	ucontext_t ctx;
+
+	setg_gcc = setg;
+	if (getcontext(&ctx) != 0)
+		perror("runtime/cgo: getcontext failed");
+	g->stacklo = (uintptr_t)ctx.uc_stack.ss_sp;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	pthread_attr_t attr;
+	sigset_t ign, oset;
+	pthread_t p;
+	void *base;
+	size_t size;
+	int err;
+
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+	pthread_attr_init(&attr);
+
+	if (pthread_attr_getstack(&attr, &base, &size) != 0)
+		perror("runtime/cgo: pthread_attr_getstack failed");
+	if (size == 0) {
+		ts->g->stackhi = 2 << 20;
+		if (pthread_attr_setstack(&attr, NULL, ts->g->stackhi) != 0)
+			perror("runtime/cgo: pthread_attr_setstack failed");
+	} else {
+		ts->g->stackhi = size;
+	}
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	err = pthread_create(&p, &attr, threadentry, ts);
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
+}
+
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	/*
+	 * Set specific keys.
+	 */
+	setg_gcc((void*)ts.g);
+
+	crosscall_amd64(ts.fn);
+	return nil;
+}
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
index 6d4f23e..bda2499 100644
--- a/src/runtime/cgo/libcgo.h
+++ b/src/runtime/cgo/libcgo.h
@@ -45,11 +45,22 @@
 extern void (*_cgo_thread_start)(ThreadStart *ts);
 
 /*
+ * Creates a new operating system thread without updating any Go state
+ * (OS dependent).
+ */
+extern void (*_cgo_sys_thread_create)(void* (*func)(void*), void* arg);
+
+/*
  * Creates the new operating system thread (OS, arch dependent).
  */
 void _cgo_sys_thread_start(ThreadStart *ts);
 
 /*
+ * Waits for the Go runtime to be initialized (OS dependent).
+ */
+void _cgo_wait_runtime_init_done();
+
+/*
  * Call fn in the 6c world.
  */
 void crosscall_amd64(void (*fn)(void));
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
index 97c8c6a..20d5703 100644
--- a/src/runtime/cgo/setenv.go
+++ b/src/runtime/cgo/setenv.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.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package cgo
 
diff --git a/src/runtime/cgo/signal_darwin_arm64.s b/src/runtime/cgo/signal_darwin_arm64.s
new file mode 100644
index 0000000..83062d4
--- /dev/null
+++ b/src/runtime/cgo/signal_darwin_arm64.s
@@ -0,0 +1,42 @@
+// 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"
+
+// panicmem is the entrypoint for SIGSEGV as intercepted via a
+// mach thread port as EXC_BAD_ACCESS. As the segfault may have happened
+// in C code, we first need to load_g then call panicmem.
+//
+//	R1 - LR at moment of fault
+//	R2 - PC at moment of fault
+TEXT ·panicmem(SB),NOSPLIT,$-8
+	// If in external C code, we need to load the g register.
+	BL  runtime·load_g(SB)
+	CMP $0, g
+	BNE ongothread
+
+	// On a foreign thread.
+	// TODO(crawshaw): call badsignal
+	MOVW $139, R1
+	MOVW R1, (RSP)
+	B    runtime·exit(SB)
+
+ongothread:
+	// Trigger a SIGSEGV panic.
+	//
+	// The goal is to arrange the stack so it looks like the runtime
+	// function sigpanic was called from the PC that faulted. It has
+	// to be sigpanic, as the stack unwinding code in traceback.go
+	// looks explicitly for it.
+	//
+	// To do this we call into runtime·setsigsegv, which sets the
+	// appropriate state inside the g object. We give it the faulting
+	// PC on the stack, then put it in the LR before calling sigpanic.
+	STP.W (R1, R2), -16(RSP)
+	BL runtime·setsigsegv(SB)
+	LDP.P 16(RSP), (R1, R2)
+
+	MOVD R1, 8(RSP)
+	MOVD R2, R30 // link register
+	B runtime·sigpanic(SB)
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 052830d..c01d616 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -132,12 +132,6 @@
 //go:nosplit
 func endcgo(mp *m) {
 	mp.ncgo--
-	if mp.ncgo == 0 {
-		// We are going back to Go and are not in a recursive
-		// call.  Let the GC collect any memory allocated via
-		// _cgo_allocate that is no longer referenced.
-		mp.cgomal = nil
-	}
 
 	if raceenabled {
 		raceacquire(unsafe.Pointer(&racecgosync))
@@ -193,6 +187,14 @@
 		systemstack(newextram)
 	}
 
+	if gp.m.ncgo == 0 {
+		// The C call to Go came from a thread not currently running
+		// any Go. In the case of -buildmode=c-archive or c-shared,
+		// this call may be coming in before package initialization
+		// is complete. Wait until it is.
+		<-main_init_done
+	}
+
 	// Add entry to defer stack in case of panic.
 	restore := true
 	defer unwindm(&restore)
@@ -218,6 +220,10 @@
 		// On arm, stack frame is two words and there's a saved LR between
 		// SP and the stack frame and between the stack frame and the arguments.
 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
+	case "arm64":
+		// On arm64, stack frame is four words and there's a saved LR between
+		// SP and the stack frame and between the stack frame and the arguments.
+		cb = (*args)(unsafe.Pointer(sp + 5*ptrSize))
 	case "amd64":
 		// On amd64, stack frame is one word, plus caller PC.
 		if framepointer_enabled {
@@ -268,6 +274,8 @@
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp))
 	case "arm":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4))
+	case "arm64":
+		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
 	case "ppc64", "ppc64le":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 8))
 	}
diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go
index 20ce87d..f93acab 100644
--- a/src/runtime/cgocallback.go
+++ b/src/runtime/cgocallback.go
@@ -4,35 +4,8 @@
 
 package runtime
 
-import "unsafe"
-
 // These functions are called from C code via cgo/callbacks.go.
 
-// Allocate memory.  This allocates the requested number of bytes in
-// memory controlled by the Go runtime.  The allocated memory will be
-// zeroed.  You are responsible for ensuring that the Go garbage
-// collector can see a pointer to the allocated memory for as long as
-// it is valid, e.g., by storing a pointer in a local variable in your
-// C function, or in memory allocated by the Go runtime.  If the only
-// pointers are in a C global variable or in memory allocated via
-// malloc, then the Go garbage collector may collect the memory.
-//
-// TODO(rsc,iant): This memory is untyped.
-// Either we need to add types or we need to stop using it.
-
-func _cgo_allocate_internal(len uintptr) unsafe.Pointer {
-	if len == 0 {
-		len = 1
-	}
-	ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0])
-	c := new(cgomal)
-	c.alloc = ret
-	gp := getg()
-	c.next = gp.m.cgomal
-	gp.m.cgomal = c
-	return ret
-}
-
 // Panic.
 
 func _cgo_panic_internal(p *byte) {
diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go
index 0b918bb..9119371 100644
--- a/src/runtime/chan_test.go
+++ b/src/runtime/chan_test.go
@@ -528,7 +528,7 @@
 func TestShrinkStackDuringBlockedSend(t *testing.T) {
 	// make sure that channel operations still work when we are
 	// blocked on a channel send and we shrink the stack.
-	// NOTE: this test probably won't fail unless stack1.go:StackDebug
+	// NOTE: this test probably won't fail unless stack1.go:stackDebug
 	// is set to >= 1.
 	const n = 10
 	c := make(chan int)
diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go
index 055b2af..0790852 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -396,8 +396,8 @@
 }
 
 func uintptrBytes(p []uintptr) (ret []byte) {
-	pp := (*sliceStruct)(unsafe.Pointer(&p))
-	rp := (*sliceStruct)(unsafe.Pointer(&ret))
+	pp := (*slice)(unsafe.Pointer(&p))
+	rp := (*slice)(unsafe.Pointer(&ret))
 
 	rp.array = pp.array
 	rp.len = pp.len * int(unsafe.Sizeof(p[0]))
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index 01ffed9..6c6576a 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -57,7 +57,7 @@
 	case "plan9", "windows":
 		t.Skipf("no pthreads on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH != "arm" {
+		if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" {
 			// static constructor needs external linking, but we don't support
 			// external linking on OS X 10.6.
 			out, err := exec.Command("uname", "-r").Output()
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 7bb3d28..975defd 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -42,8 +42,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, no fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
diff --git a/src/runtime/debug/garbage_test.go b/src/runtime/debug/garbage_test.go
index d263626..bf7f276 100644
--- a/src/runtime/debug/garbage_test.go
+++ b/src/runtime/debug/garbage_test.go
@@ -88,8 +88,8 @@
 var big = make([]byte, 1<<20)
 
 func TestFreeOSMemory(t *testing.T) {
-	if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOOS == "nacl" {
-		t.Skip("issue 9993; scavenger temporarily disabled on systems with 64k pages")
+	if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOOS == "nacl" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm64") {
+		t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages")
 	}
 	var ms1, ms2 runtime.MemStats
 
diff --git a/src/runtime/defs_darwin_arm64.go b/src/runtime/defs_darwin_arm64.go
new file mode 100644
index 0000000..3cc77c1
--- /dev/null
+++ b/src/runtime/defs_darwin_arm64.go
@@ -0,0 +1,248 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_darwin.go
+
+package runtime
+
+import "unsafe"
+
+const (
+	_EINTR  = 0x4
+	_EFAULT = 0xe
+
+	_PROT_NONE  = 0x0
+	_PROT_READ  = 0x1
+	_PROT_WRITE = 0x2
+	_PROT_EXEC  = 0x4
+
+	_MAP_ANON    = 0x1000
+	_MAP_PRIVATE = 0x2
+	_MAP_FIXED   = 0x10
+
+	_MADV_DONTNEED = 0x4
+	_MADV_FREE     = 0x5
+
+	_MACH_MSG_TYPE_MOVE_RECEIVE   = 0x10
+	_MACH_MSG_TYPE_MOVE_SEND      = 0x11
+	_MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+	_MACH_MSG_TYPE_COPY_SEND      = 0x13
+	_MACH_MSG_TYPE_MAKE_SEND      = 0x14
+	_MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+	_MACH_MSG_TYPE_COPY_RECEIVE   = 0x16
+
+	_MACH_MSG_PORT_DESCRIPTOR         = 0x0
+	_MACH_MSG_OOL_DESCRIPTOR          = 0x1
+	_MACH_MSG_OOL_PORTS_DESCRIPTOR    = 0x2
+	_MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+	_MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+	_MACH_SEND_MSG  = 0x1
+	_MACH_RCV_MSG   = 0x2
+	_MACH_RCV_LARGE = 0x4
+
+	_MACH_SEND_TIMEOUT   = 0x10
+	_MACH_SEND_INTERRUPT = 0x40
+	_MACH_SEND_ALWAYS    = 0x10000
+	_MACH_SEND_TRAILER   = 0x20000
+	_MACH_RCV_TIMEOUT    = 0x100
+	_MACH_RCV_NOTIFY     = 0x200
+	_MACH_RCV_INTERRUPT  = 0x400
+	_MACH_RCV_OVERWRITE  = 0x1000
+
+	_NDR_PROTOCOL_2_0      = 0x0
+	_NDR_INT_BIG_ENDIAN    = 0x0
+	_NDR_INT_LITTLE_ENDIAN = 0x1
+	_NDR_FLOAT_IEEE        = 0x0
+	_NDR_CHAR_ASCII        = 0x0
+
+	_SA_SIGINFO   = 0x40
+	_SA_RESTART   = 0x2
+	_SA_ONSTACK   = 0x1
+	_SA_USERTRAMP = 0x100
+	_SA_64REGSET  = 0x200
+
+	_SIGHUP    = 0x1
+	_SIGINT    = 0x2
+	_SIGQUIT   = 0x3
+	_SIGILL    = 0x4
+	_SIGTRAP   = 0x5
+	_SIGABRT   = 0x6
+	_SIGEMT    = 0x7
+	_SIGFPE    = 0x8
+	_SIGKILL   = 0x9
+	_SIGBUS    = 0xa
+	_SIGSEGV   = 0xb
+	_SIGSYS    = 0xc
+	_SIGPIPE   = 0xd
+	_SIGALRM   = 0xe
+	_SIGTERM   = 0xf
+	_SIGURG    = 0x10
+	_SIGSTOP   = 0x11
+	_SIGTSTP   = 0x12
+	_SIGCONT   = 0x13
+	_SIGCHLD   = 0x14
+	_SIGTTIN   = 0x15
+	_SIGTTOU   = 0x16
+	_SIGIO     = 0x17
+	_SIGXCPU   = 0x18
+	_SIGXFSZ   = 0x19
+	_SIGVTALRM = 0x1a
+	_SIGPROF   = 0x1b
+	_SIGWINCH  = 0x1c
+	_SIGINFO   = 0x1d
+	_SIGUSR1   = 0x1e
+	_SIGUSR2   = 0x1f
+
+	_FPE_INTDIV = 0x7
+	_FPE_INTOVF = 0x8
+	_FPE_FLTDIV = 0x1
+	_FPE_FLTOVF = 0x2
+	_FPE_FLTUND = 0x3
+	_FPE_FLTRES = 0x4
+	_FPE_FLTINV = 0x5
+	_FPE_FLTSUB = 0x6
+
+	_BUS_ADRALN = 0x1
+	_BUS_ADRERR = 0x2
+	_BUS_OBJERR = 0x3
+
+	_SEGV_MAPERR = 0x1
+	_SEGV_ACCERR = 0x2
+
+	_ITIMER_REAL    = 0x0
+	_ITIMER_VIRTUAL = 0x1
+	_ITIMER_PROF    = 0x2
+
+	_EV_ADD       = 0x1
+	_EV_DELETE    = 0x2
+	_EV_CLEAR     = 0x20
+	_EV_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+	msgh_descriptor_count uint32
+}
+
+type machheader struct {
+	msgh_bits        uint32
+	msgh_size        uint32
+	msgh_remote_port uint32
+	msgh_local_port  uint32
+	msgh_reserved    uint32
+	msgh_id          int32
+}
+
+type machndr struct {
+	mig_vers     uint8
+	if_vers      uint8
+	reserved1    uint8
+	mig_encoding uint8
+	int_rep      uint8
+	char_rep     uint8
+	float_rep    uint8
+	reserved2    uint8
+}
+
+type machport struct {
+	name        uint32
+	pad1        uint32
+	pad2        uint16
+	disposition uint8
+	_type       uint8
+}
+
+type stackt struct {
+	ss_sp     *byte
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type sigactiont struct {
+	__sigaction_u [8]byte
+	sa_tramp      unsafe.Pointer
+	sa_mask       uint32
+	sa_flags      int32
+}
+
+type siginfo struct {
+	si_signo  int32
+	si_errno  int32
+	si_code   int32
+	si_pid    int32
+	si_uid    uint32
+	si_status int32
+	si_addr   *byte
+	si_value  [8]byte
+	si_band   int64
+	__pad     [7]uint64
+}
+
+type timeval struct {
+	tv_sec    int64
+	tv_usec   int32
+	pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = x
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+type exceptionstate64 struct {
+	far uint64 // virtual fault addr
+	esr uint32 // exception syndrome
+	exc uint32 // number of arm exception taken
+}
+
+type regs64 struct {
+	x     [29]uint64 // registers x0 to x28
+	fp    uint64     // frame register, x29
+	lr    uint64     // link register, x30
+	sp    uint64     // stack pointer, x31
+	pc    uint64     // program counter
+	cpsr  uint32     // current program status register
+	__pad uint32
+}
+
+type neonstate64 struct {
+	v    [64]uint64 // actually [32]uint128
+	fpsr uint32
+	fpcr uint32
+}
+
+type mcontext64 struct {
+	es exceptionstate64
+	ss regs64
+	ns neonstate64
+}
+
+type ucontext struct {
+	uc_onstack  int32
+	uc_sigmask  uint32
+	uc_stack    stackt
+	uc_link     *ucontext
+	uc_mcsize   uint64
+	uc_mcontext *mcontext64
+}
+
+type keventt struct {
+	ident  uint64
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
diff --git a/src/runtime/defs_windows_386.go b/src/runtime/defs_windows_386.go
index c860f74..bac6ce7 100644
--- a/src/runtime/defs_windows_386.go
+++ b/src/runtime/defs_windows_386.go
@@ -107,6 +107,22 @@
 func (c *context) setip(x uintptr) { c.eip = uint32(x) }
 func (c *context) setsp(x uintptr) { c.esp = uint32(x) }
 
+func dumpregs(r *context) {
+	print("eax     ", hex(r.eax), "\n")
+	print("ebx     ", hex(r.ebx), "\n")
+	print("ecx     ", hex(r.ecx), "\n")
+	print("edx     ", hex(r.edx), "\n")
+	print("edi     ", hex(r.edi), "\n")
+	print("esi     ", hex(r.esi), "\n")
+	print("ebp     ", hex(r.ebp), "\n")
+	print("esp     ", hex(r.esp), "\n")
+	print("eip     ", hex(r.eip), "\n")
+	print("eflags  ", hex(r.eflags), "\n")
+	print("cs      ", hex(r.segcs), "\n")
+	print("fs      ", hex(r.segfs), "\n")
+	print("gs      ", hex(r.seggs), "\n")
+}
+
 type overlapped struct {
 	internal     uint32
 	internalhigh uint32
diff --git a/src/runtime/defs_windows_amd64.go b/src/runtime/defs_windows_amd64.go
index d1e55ec..6e04568 100644
--- a/src/runtime/defs_windows_amd64.go
+++ b/src/runtime/defs_windows_amd64.go
@@ -122,6 +122,29 @@
 func (c *context) setip(x uintptr) { c.rip = uint64(x) }
 func (c *context) setsp(x uintptr) { c.rsp = uint64(x) }
 
+func dumpregs(r *context) {
+	print("rax     ", hex(r.rax), "\n")
+	print("rbx     ", hex(r.rbx), "\n")
+	print("rcx     ", hex(r.rcx), "\n")
+	print("rdi     ", hex(r.rdi), "\n")
+	print("rsi     ", hex(r.rsi), "\n")
+	print("rbp     ", hex(r.rbp), "\n")
+	print("rsp     ", hex(r.rsp), "\n")
+	print("r8      ", hex(r.r8), "\n")
+	print("r9      ", hex(r.r9), "\n")
+	print("r10     ", hex(r.r10), "\n")
+	print("r11     ", hex(r.r11), "\n")
+	print("r12     ", hex(r.r12), "\n")
+	print("r13     ", hex(r.r13), "\n")
+	print("r14     ", hex(r.r14), "\n")
+	print("r15     ", hex(r.r15), "\n")
+	print("rip     ", hex(r.rip), "\n")
+	print("rflags  ", hex(r.eflags), "\n")
+	print("cs      ", hex(r.segcs), "\n")
+	print("fs      ", hex(r.segfs), "\n")
+	print("gs      ", hex(r.seggs), "\n")
+}
+
 type overlapped struct {
 	internal     uint64
 	internalhigh uint64
diff --git a/src/runtime/duff_386.s b/src/runtime/duff_386.s
new file mode 100644
index 0000000..5575455
--- /dev/null
+++ b/src/runtime/duff_386.s
@@ -0,0 +1,779 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	RET
+
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	RET
diff --git a/src/runtime/duff_amd64.s b/src/runtime/duff_amd64.s
new file mode 100644
index 0000000..0b51228
--- /dev/null
+++ b/src/runtime/duff_amd64.s
@@ -0,0 +1,841 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	RET
+
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	RET
diff --git a/src/runtime/duff_arm.s b/src/runtime/duff_arm.s
new file mode 100644
index 0000000..da9f0cb
--- /dev/null
+++ b/src/runtime/duff_arm.s
@@ -0,0 +1,523 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	RET
+
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	RET
diff --git a/src/runtime/duff_arm64.s b/src/runtime/duff_arm64.s
new file mode 100644
index 0000000..6d4bb15
--- /dev/null
+++ b/src/runtime/duff_arm64.s
@@ -0,0 +1,138 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	RET
+
+// TODO: Implement runtime·duffcopy.
diff --git a/src/runtime/duff_ppc64x.s b/src/runtime/duff_ppc64x.s
new file mode 100644
index 0000000..1206fed
--- /dev/null
+++ b/src/runtime/duff_ppc64x.s
@@ -0,0 +1,140 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+// +build ppc64 ppc64le
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	RETURN
+
+// TODO: Implement runtime·duffcopy.
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index b988020..0e2588b 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -23,14 +23,14 @@
 	}
 	n := seek(fd, 0, 2)
 	if n <= 0 {
-		close(fd)
+		closefd(fd)
 		return ""
 	}
 
 	p := make([]byte, n)
 
 	r := pread(fd, unsafe.Pointer(&p[0]), int32(n), 0)
-	close(fd)
+	closefd(fd)
 	if r < 0 {
 		return ""
 	}
diff --git a/src/cmd/internal/obj/arm/util.go b/src/runtime/export_linux_test.go
similarity index 68%
rename from src/cmd/internal/obj/arm/util.go
rename to src/runtime/export_linux_test.go
index f036c5f..c8b9746 100644
--- a/src/cmd/internal/obj/arm/util.go
+++ b/src/runtime/export_linux_test.go
@@ -2,11 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package arm
+// Export guts for testing.
 
-func bool2int(b bool) int {
-	if b {
-		return 1
-	}
-	return 0
-}
+package runtime
+
+var NewOSProc0 = newosproc0
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 71fbcde..e0c8b17 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -17,10 +17,14 @@
 var Fcmp64 = fcmp64
 var Fintto64 = fintto64
 var F64toint = f64toint
+var Sqrt = sqrt
 
 var Entersyscall = entersyscall
 var Exitsyscall = exitsyscall
 var LockedOSThread = lockedOSThread
+var Xadduintptr = xadduintptr
+
+var FuncPC = funcPC
 
 type LFNode struct {
 	Next    uint64
@@ -76,8 +80,10 @@
 	s := (*slice)(unsafe.Pointer(&ret))
 	systemstack(func() {
 		var len uintptr
-		getgcmask(e.data, e._type, &s.array, &len)
-		s.len = uint(len)
+		var a *byte
+		getgcmask(e.data, e._type, &a, &len)
+		s.array = unsafe.Pointer(a)
+		s.len = int(len)
 		s.cap = s.len
 	})
 	return
@@ -119,9 +125,11 @@
 type Uintreg uintreg
 
 var Open = open
-var Close = close
+var Close = closefd
 var Read = read
 var Write = write
 
 func Envs() []string     { return envs }
 func SetEnvs(e []string) { envs = e }
+
+var BigEndian = _BigEndian
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index f353a4e..66b0353 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -12,21 +12,21 @@
 
 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
 func TestGCInfo(t *testing.T) {
-	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
-	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar))
-	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, nonStackInfo(infoBigStruct()))
-	verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString))
-	verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice))
-	verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface))
-	verifyGCInfo(t, "bss iface", &bssIface, nonStackInfo(infoIface))
+	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
+	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
+	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
+	verifyGCInfo(t, "bss string", &bssString, infoString)
+	verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
+	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
+	verifyGCInfo(t, "bss iface", &bssIface, infoIface)
 
-	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr))
-	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar))
-	verifyGCInfo(t, "data BigStruct", &dataBigStruct, nonStackInfo(infoBigStruct()))
-	verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString))
-	verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice))
-	verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface))
-	verifyGCInfo(t, "data iface", &dataIface, nonStackInfo(infoIface))
+	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
+	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
+	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
+	verifyGCInfo(t, "data string", &dataString, infoString)
+	verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
+	verifyGCInfo(t, "data eface", &dataEface, infoEface)
+	verifyGCInfo(t, "data iface", &dataIface, infoIface)
 
 	verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
 	verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
@@ -37,12 +37,12 @@
 	verifyGCInfo(t, "stack iface", new(Iface), infoIface)
 
 	for i := 0; i < 10; i++ {
-		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
-		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar))
-		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), nonStackInfo(infoBigStruct()))
-		verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString))
-		verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
-		verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface))
+		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)
 	}
 
 }
@@ -130,25 +130,25 @@
 		return []byte{
 			typePointer,                                                // q *int
 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
-			typePointer, typeDead, typeDead, // r []byte
+			typePointer, typeScalar, typeScalar, // r []byte
 			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
-			typePointer, typeDead, // i string
+			typePointer, typeScalar, // i string
 		}
 	case "arm64", "amd64", "ppc64", "ppc64le":
 		return []byte{
 			typePointer,                        // q *int
 			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
-			typePointer, typeDead, typeDead, // r []byte
+			typePointer, typeScalar, typeScalar, // r []byte
 			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
-			typePointer, typeDead, // i string
+			typePointer, typeScalar, // i string
 		}
 	case "amd64p32":
 		return []byte{
 			typePointer,                                                // q *int
 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
-			typePointer, typeDead, typeDead, // r []byte
-			typeScalar, typeScalar, typeDead, typeScalar, typeScalar, // t int; y uint16; u uint64
-			typePointer, typeDead, // i string
+			typePointer, typeScalar, typeScalar, // r []byte
+			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
+			typePointer, typeScalar, // i string
 		}
 	default:
 		panic("unknown arch")
@@ -183,8 +183,8 @@
 	dataEface     interface{} = 42
 	dataIface     Iface       = IfaceImpl(42)
 
-	infoString = []byte{typePointer, typeDead}
-	infoSlice  = []byte{typePointer, typeDead, typeDead}
+	infoString = []byte{typePointer, typeScalar}
+	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
 	infoEface  = []byte{typePointer, typePointer}
 	infoIface  = []byte{typePointer, typePointer}
 )
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index aaaef48..9ca3399 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -96,9 +96,6 @@
 
 	// sentinel bucket ID for iterator checks
 	noCheck = 1<<(8*ptrSize) - 1
-
-	// trigger a garbage collection at every alloc called from this code
-	checkgc = false
 )
 
 // A header for a Go map.
@@ -246,16 +243,10 @@
 	// If hint is large zeroing this memory could take a while.
 	buckets := bucket
 	if B != 0 {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		buckets = newarray(t.bucket, uintptr(1)<<B)
 	}
 
 	// initialize Hmap
-	if checkgc {
-		memstats.next_gc = memstats.heap_alloc
-	}
 	if h == nil {
 		h = (*hmap)(newobject(t.hmap))
 	}
@@ -430,9 +421,6 @@
 	hash := alg.hash(key, uintptr(h.hash0))
 
 	if h.buckets == nil {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		h.buckets = newarray(t.bucket, 1)
 	}
 
@@ -493,9 +481,6 @@
 
 	if inserti == nil {
 		// all current buckets are full, allocate a new one.
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		newb := (*bmap)(newobject(t.bucket))
 		h.setoverflow(t, b, newb)
 		inserti = &newb.tophash[0]
@@ -505,17 +490,11 @@
 
 	// store new key/value at insert position
 	if t.indirectkey {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		kmem := newobject(t.key)
 		*(*unsafe.Pointer)(insertk) = kmem
 		insertk = kmem
 	}
 	if t.indirectvalue {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		vmem := newobject(t.elem)
 		*(*unsafe.Pointer)(insertv) = vmem
 		insertv = vmem
@@ -776,9 +755,6 @@
 		throw("evacuation not done in time")
 	}
 	oldbuckets := h.buckets
-	if checkgc {
-		memstats.next_gc = memstats.heap_alloc
-	}
 	newbuckets := newarray(t.bucket, uintptr(1)<<(h.B+1))
 	flags := h.flags &^ (iterator | oldIterator)
 	if h.flags&iterator != 0 {
@@ -879,9 +855,6 @@
 				if (hash & newbit) == 0 {
 					b.tophash[i] = evacuatedX
 					if xi == bucketCnt {
-						if checkgc {
-							memstats.next_gc = memstats.heap_alloc
-						}
 						newx := (*bmap)(newobject(t.bucket))
 						h.setoverflow(t, x, newx)
 						x = newx
@@ -906,9 +879,6 @@
 				} else {
 					b.tophash[i] = evacuatedY
 					if yi == bucketCnt {
-						if checkgc {
-							memstats.next_gc = memstats.heap_alloc
-						}
 						newy := (*bmap)(newobject(t.bucket))
 						h.setoverflow(t, y, newy)
 						y = newy
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index 090a490..e18aa79 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -237,18 +237,10 @@
 // dump kinds & offsets of interesting fields in bv
 func dumpbv(cbv *bitvector, offset uintptr) {
 	bv := gobv(*cbv)
-	for i := uintptr(0); i < uintptr(bv.n); i += typeBitsWidth {
-		switch bv.bytedata[i/8] >> (i % 8) & typeMask {
-		default:
-			throw("unexpected pointer bits")
-		case typeDead:
-			// typeDead has already been processed in makeheapobjbv.
-			// We should only see it in stack maps, in which case we should continue processing.
-		case typeScalar:
-			// ok
-		case typePointer:
+	for i := uintptr(0); i < uintptr(bv.n); i++ {
+		if bv.bytedata[i/8]>>(i%8)&1 == 1 {
 			dumpint(fieldKindPtr)
-			dumpint(uint64(offset + i/typeBitsWidth*ptrSize))
+			dumpint(uint64(offset + i*ptrSize))
 		}
 	}
 }
@@ -278,7 +270,7 @@
 	var bv bitvector
 	if stkmap != nil && stkmap.n > 0 {
 		bv = stackmapdata(stkmap, pcdata)
-		dumpbvtypes(&bv, unsafe.Pointer(s.varp-uintptr(bv.n/typeBitsWidth*ptrSize)))
+		dumpbvtypes(&bv, unsafe.Pointer(s.varp-uintptr(bv.n*ptrSize)))
 	} else {
 		bv.n = -1
 	}
@@ -326,7 +318,7 @@
 	} else if stkmap.n > 0 {
 		// Locals bitmap information, scan just the pointers in
 		// locals.
-		dumpbv(&bv, s.varp-uintptr(bv.n)/typeBitsWidth*ptrSize-s.sp)
+		dumpbv(&bv, s.varp-uintptr(bv.n)*ptrSize-s.sp)
 	}
 	dumpint(fieldKindEol)
 
@@ -431,19 +423,20 @@
 }
 
 func dumproots() {
+	// TODO(mwhudson): dump datamask etc from all objects
 	// data segment
-	dumpbvtypes(&gcdatamask, unsafe.Pointer(themoduledata.data))
+	dumpbvtypes(&firstmoduledata.gcdatamask, unsafe.Pointer(firstmoduledata.data))
 	dumpint(tagData)
-	dumpint(uint64(themoduledata.data))
-	dumpmemrange(unsafe.Pointer(themoduledata.data), themoduledata.edata-themoduledata.data)
-	dumpfields(gcdatamask)
+	dumpint(uint64(firstmoduledata.data))
+	dumpmemrange(unsafe.Pointer(firstmoduledata.data), firstmoduledata.edata-firstmoduledata.data)
+	dumpfields(firstmoduledata.gcdatamask)
 
 	// bss segment
-	dumpbvtypes(&gcbssmask, unsafe.Pointer(themoduledata.bss))
+	dumpbvtypes(&firstmoduledata.gcbssmask, unsafe.Pointer(firstmoduledata.bss))
 	dumpint(tagBSS)
-	dumpint(uint64(themoduledata.bss))
-	dumpmemrange(unsafe.Pointer(themoduledata.bss), themoduledata.ebss-themoduledata.bss)
-	dumpfields(gcbssmask)
+	dumpint(uint64(firstmoduledata.bss))
+	dumpmemrange(unsafe.Pointer(firstmoduledata.bss), firstmoduledata.ebss-firstmoduledata.bss)
+	dumpfields(firstmoduledata.gcbssmask)
 
 	// MSpan.types
 	allspans := h_allspans
@@ -650,7 +643,7 @@
 	}
 }
 
-var dumphdr = []byte("go1.4 heap dump\n")
+var dumphdr = []byte("go1.5 heap dump\n")
 
 func mdump() {
 	// make sure we're done sweeping
@@ -719,18 +712,21 @@
 func makeheapobjbv(p uintptr, size uintptr) bitvector {
 	// Extend the temp buffer if necessary.
 	nptr := size / ptrSize
-	if uintptr(len(tmpbuf)) < nptr*typeBitsWidth/8+1 {
+	if uintptr(len(tmpbuf)) < nptr/8+1 {
 		if tmpbuf != nil {
 			sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
 		}
-		n := nptr*typeBitsWidth/8 + 1
+		n := nptr/8 + 1
 		p := sysAlloc(n, &memstats.other_sys)
 		if p == nil {
 			throw("heapdump: out of memory")
 		}
 		tmpbuf = (*[1 << 30]byte)(p)[:n]
 	}
-	// Convert heap bitmap to type bitmap.
+	// Convert heap bitmap to pointer bitmap.
+	for i := uintptr(0); i < nptr/8+1; i++ {
+		tmpbuf[i] = 0
+	}
 	i := uintptr(0)
 	hbits := heapBitsForAddr(p)
 	for ; i < nptr; i++ {
@@ -739,8 +735,9 @@
 			break // end of object
 		}
 		hbits = hbits.next()
-		tmpbuf[i*typeBitsWidth/8] &^= (typeMask << ((i * typeBitsWidth) % 8))
-		tmpbuf[i*typeBitsWidth/8] |= bits << ((i * typeBitsWidth) % 8)
+		if bits == typePointer {
+			tmpbuf[i/8] |= 1 << (i % 8)
+		}
 	}
-	return bitvector{int32(i * typeBitsWidth), &tmpbuf[0]}
+	return bitvector{int32(i), &tmpbuf[0]}
 }
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 0d4989b..656bb4b 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -94,7 +94,7 @@
 		itype := i._type
 		for ; j < nt; j++ {
 			t := &x.mhdr[j]
-			if t.mtyp == itype && t.name == iname && t.pkgpath == ipkgpath {
+			if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
 				if m != nil {
 					*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn
 				}
diff --git a/src/runtime/lfstack_darwin_arm64.go b/src/runtime/lfstack_darwin_arm64.go
new file mode 100644
index 0000000..54cae39
--- /dev/null
+++ b/src/runtime/lfstack_darwin_arm64.go
@@ -0,0 +1,25 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+// In addition to the 16 bits taken from the top, we can take 3 from the
+// bottom, because node must be pointer-aligned, giving a total of 19 bits
+// of count.
+const (
+	addrBits = 48
+	cntBits  = 64 - addrBits + 3
+)
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+	return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+	node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
+	cnt = uintptr(val & (1<<cntBits - 1))
+	return
+}
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index fde58e2..1619ccb 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -155,7 +155,10 @@
 	// See http://golang.org/issue/5402 and http://golang.org/issue/5236.
 	// On other 64-bit platforms, we limit the arena to 128GB, or 37 bits.
 	// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
-	_MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32
+	// On Darwin/arm64, we cannot reserve more than ~5GB of virtual memory,
+	// but as most devices have less than 4GB of physical memory anyway, we
+	// try to be conservative here, and only ask for a 2GB heap.
+	_MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows)*(1-goos_darwin*goarch_arm64))*37 + goos_darwin*goarch_arm64*31 + (1-_64bit)*32
 	_MHeapMap_Bits      = _MHeapMap_TotalBits - _PageShift
 
 	_MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1)
@@ -257,14 +260,18 @@
 		// However, on arm64, we ignore all this advice above and slam the
 		// allocation at 0x40 << 32 because when using 4k pages with 3-level
 		// translation buffers, the user address space is limited to 39 bits
+		// On darwin/arm64, the address space is even smaller.
 		arenaSize := round(_MaxMem, _PageSize)
 		bitmapSize = arenaSize / (ptrSize * 8 / 4)
 		spansSize = arenaSize / _PageSize * ptrSize
 		spansSize = round(spansSize, _PageSize)
 		for i := 0; i <= 0x7f; i++ {
-			if GOARCH == "arm64" {
+			switch {
+			case GOARCH == "arm64" && GOOS == "darwin":
+				p = uintptr(i)<<40 | uintptrMask&(0x0013<<28)
+			case GOARCH == "arm64":
 				p = uintptr(i)<<40 | uintptrMask&(0x0040<<32)
-			} else {
+			default:
 				p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
 			}
 			pSize = bitmapSize + spansSize + arenaSize + _PageSize
@@ -322,7 +329,7 @@
 			// So adjust it upward a little bit ourselves: 1/4 MB to get
 			// away from the running binary image and then round up
 			// to a MB boundary.
-			p = round(themoduledata.end+(1<<18), 1<<20)
+			p = round(firstmoduledata.end+(1<<18), 1<<20)
 			pSize = bitmapSize + spansSize + arenaSize + _PageSize
 			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
 			if p != 0 {
@@ -616,7 +623,7 @@
 				}
 			}
 		}
-		c.local_cachealloc += intptr(size)
+		c.local_cachealloc += size
 	} else {
 		var s *mspan
 		shouldhelpgc = true
@@ -640,6 +647,16 @@
 			dataSize = unsafe.Sizeof(_defer{})
 		}
 		heapBitsSetType(uintptr(x), size, dataSize, typ)
+		if dataSize > typ.size {
+			// Array allocation. If there are any
+			// pointers, GC has to scan to the last
+			// element.
+			if typ.ptrdata != 0 {
+				c.local_scan += dataSize - typ.size + typ.ptrdata
+			}
+		} else {
+			c.local_scan += typ.ptrdata
+		}
 	}
 
 	// GCmarkterminate allocates black
@@ -648,7 +665,7 @@
 	// a race marking the bit.
 	if gcphase == _GCmarktermination {
 		systemstack(func() {
-			gcmarknewobject_m(uintptr(x))
+			gcmarknewobject_m(uintptr(x), size)
 		})
 	}
 
@@ -677,15 +694,14 @@
 		}
 	}
 
-	if shouldtriggergc() {
+	if shouldhelpgc && shouldtriggergc() {
 		startGC(gcBackgroundMode)
-	} else if shouldhelpgc && atomicloaduint(&bggc.working) == 1 {
-		// bggc.lock not taken since race on bggc.working is benign.
-		// At worse we don't call gchelpwork.
-		// Delay the gchelpwork until the epilogue so that it doesn't
-		// interfere with the inner working of malloc such as
-		// mcache refills that might happen while doing the gchelpwork
-		systemstack(gchelpwork)
+	} else if gcBlackenEnabled != 0 {
+		// Assist garbage collector. We delay this until the
+		// epilogue so that it doesn't interfere with the
+		// inner working of malloc such as mcache refills that
+		// might happen while doing the gcAssistAlloc.
+		gcAssistAlloc(size, shouldhelpgc)
 	}
 
 	return x
@@ -784,7 +800,7 @@
 // There is no associated free operation.
 // Intended for things like function/type/debug-related persistent data.
 // If align is 0, uses default align (currently 8).
-func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer {
+func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
 	const (
 		chunk    = 256 << 10
 		maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
@@ -805,13 +821,13 @@
 	}
 
 	if size >= maxBlock {
-		return sysAlloc(size, stat)
+		return sysAlloc(size, sysStat)
 	}
 
 	mp := acquirem()
 	var persistent *persistentAlloc
-	if mp != nil && mp.p != nil {
-		persistent = &mp.p.palloc
+	if mp != nil && mp.p != 0 {
+		persistent = &mp.p.ptr().palloc
 	} else {
 		lock(&globalAlloc.mutex)
 		persistent = &globalAlloc.persistentAlloc
@@ -834,9 +850,9 @@
 		unlock(&globalAlloc.mutex)
 	}
 
-	if stat != &memstats.other_sys {
-		xadd64(stat, int64(size))
-		xadd64(&memstats.other_sys, -int64(size))
+	if sysStat != &memstats.other_sys {
+		mSysStatInc(sysStat, size)
+		mSysStatDec(&memstats.other_sys, size)
 	}
 	return p
 }
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index e6183e7..eb58817 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -76,13 +76,6 @@
 	}
 }
 
-// needwb reports whether a write barrier is needed now
-// (otherwise the write can be made directly).
-//go:nosplit
-func needwb() bool {
-	return gcphase == _GCmark || gcphase == _GCmarktermination || mheap_.shadow_enabled
-}
-
 // Write barrier calls must not happen during critical GC and scheduler
 // related operations. In particular there are times when the GC assumes
 // that the world is stopped but scheduler related code is still being
@@ -92,10 +85,6 @@
 // the p associated with an m. We use the fact that m.p == nil to indicate
 // that we are in one these critical section and throw if the write is of
 // a pointer to a heap object.
-// The p, m, and g pointers are the pointers that are used by the scheduler
-// and need to be operated on without write barriers. We use
-// the setPNoWriteBarrier, setMNoWriteBarrier and setGNowriteBarrier to
-// avoid having to do the write barrier.
 //go:nosplit
 func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
 	mp := acquirem()
@@ -104,7 +93,7 @@
 		return
 	}
 	systemstack(func() {
-		if mp.p == nil && memstats.enablegc && !mp.inwb && inheap(src) {
+		if mp.p == 0 && memstats.enablegc && !mp.inwb && inheap(src) {
 			throw("writebarrierptr_nostore1 called with mp.p == nil")
 		}
 		mp.inwb = true
@@ -118,7 +107,7 @@
 // but if we do that, Go inserts a write barrier on *dst = src.
 //go:nosplit
 func writebarrierptr(dst *uintptr, src uintptr) {
-	if !needwb() {
+	if !writeBarrierEnabled {
 		*dst = src
 		return
 	}
@@ -159,7 +148,7 @@
 // Do not reapply.
 //go:nosplit
 func writebarrierptr_nostore(dst *uintptr, src uintptr) {
-	if !needwb() {
+	if !writeBarrierEnabled {
 		return
 	}
 
@@ -228,7 +217,7 @@
 // typedmemmove copies a value of type t to dst from src.
 //go:nosplit
 func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
-	if !needwb() || (typ.kind&kindNoPointers) != 0 {
+	if !writeBarrierEnabled || (typ.kind&kindNoPointers) != 0 {
 		memmove(dst, src, typ.size)
 		return
 	}
@@ -270,7 +259,7 @@
 // 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 !needwb() || (typ.kind&kindNoPointers) != 0 || size < ptrSize {
+	if !writeBarrierEnabled || (typ.kind&kindNoPointers) != 0 || size < ptrSize {
 		memmove(dst, src, size)
 		return
 	}
@@ -313,7 +302,7 @@
 // not to be preempted before the write barriers have been run.
 //go:nosplit
 func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
-	if !needwb() || typ == nil || (typ.kind&kindNoPointers) != 0 || framesize-retoffset < ptrSize {
+	if !writeBarrierEnabled || typ == nil || (typ.kind&kindNoPointers) != 0 || framesize-retoffset < ptrSize {
 		return
 	}
 
@@ -353,9 +342,9 @@
 		racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
 	}
 
-	if !needwb() {
+	if !writeBarrierEnabled {
 		memmove(dstp, srcp, uintptr(n)*typ.size)
-		return int(n)
+		return n
 	}
 
 	systemstack(func() {
@@ -365,7 +354,7 @@
 			// out of the array they point into.
 			dstp = add(dstp, uintptr(n-1)*typ.size)
 			srcp = add(srcp, uintptr(n-1)*typ.size)
-			i := uint(0)
+			i := 0
 			for {
 				typedmemmove(typ, dstp, srcp)
 				if i++; i >= n {
@@ -377,7 +366,7 @@
 		} else {
 			// Copy forward, being careful not to move dstp/srcp
 			// out of the array they point into.
-			i := uint(0)
+			i := 0
 			for {
 				typedmemmove(typ, dstp, srcp)
 				if i++; i >= n {
@@ -426,58 +415,64 @@
 	memmove(p1, unsafe.Pointer(mheap_.arena_start), mheap_.arena_used-mheap_.arena_start)
 
 	mheap_.shadow_reserved = reserved
-	start := ^uintptr(0)
-	end := uintptr(0)
-	if start > themoduledata.noptrdata {
-		start = themoduledata.noptrdata
+
+	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)
 	}
-	if start > themoduledata.data {
-		start = themoduledata.data
-	}
-	if start > themoduledata.noptrbss {
-		start = themoduledata.noptrbss
-	}
-	if start > themoduledata.bss {
-		start = themoduledata.bss
-	}
-	if end < themoduledata.enoptrdata {
-		end = themoduledata.enoptrdata
-	}
-	if end < themoduledata.edata {
-		end = themoduledata.edata
-	}
-	if end < themoduledata.enoptrbss {
-		end = themoduledata.enoptrbss
-	}
-	if end < themoduledata.ebss {
-		end = themoduledata.ebss
-	}
-	start &^= _PhysPageSize - 1
-	end = round(end, _PhysPageSize)
-	mheap_.data_start = start
-	mheap_.data_end = end
-	reserved = false
-	p1 = sysReserveHigh(end-start, &reserved)
-	if p1 == nil {
-		throw("cannot map shadow data")
-	}
-	mheap_.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 {
-	var shadow *uintptr
-	if mheap_.data_start <= addr && addr < mheap_.data_end {
-		shadow = (*uintptr)(unsafe.Pointer(addr + mheap_.shadow_data))
-	} else if inheap(addr) {
-		shadow = (*uintptr)(unsafe.Pointer(addr + mheap_.shadow_heap))
+	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))
+		}
 	}
-	return shadow
+	if inheap(addr) {
+		return (*uintptr)(unsafe.Pointer(addr + mheap_.shadow_heap))
+	}
+	return nil
 }
 
 // istrackedptr reports whether the pointer value p requires a write barrier
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index ebee742..f0c7520 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -4,9 +4,20 @@
 
 // Garbage collector: type and heap bitmaps.
 //
+// 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
 //
-// The global variables (in the data and bss sections) and types that aren't too large
+// 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:
 //
@@ -17,7 +28,6 @@
 //
 // typeDead only appears in type bitmaps in Go type descriptors
 // and in type bitmaps embedded in the heap bitmap (see below).
-// It is not used in the type bitmap for the global variables.
 //
 // Heap bitmap
 //
@@ -71,9 +81,8 @@
 	typePointer            = 2
 	typePointerCheckmarked = 3
 
-	typeBitsWidth   = 2 // # of type bits per pointer-sized word
-	typeMask        = 1<<typeBitsWidth - 1
-	typeBitmapScale = ptrSize * (8 / typeBitsWidth) // number of data bytes per type bitmap byte
+	typeBitsWidth = 2 // # of type bits per pointer-sized word
+	typeMask      = 1<<typeBitsWidth - 1
 
 	heapBitsWidth   = 4
 	heapBitmapScale = ptrSize * (8 / heapBitsWidth) // number of data bytes per heap bitmap byte
@@ -154,17 +163,16 @@
 // return base == 0
 // otherwise return the base of the object.
 func heapBitsForObject(p uintptr) (base uintptr, hbits heapBits, s *mspan) {
-	if p < mheap_.arena_start || p >= mheap_.arena_used {
+	arenaStart := mheap_.arena_start
+	if p < arenaStart || p >= mheap_.arena_used {
 		return
 	}
-
+	off := p - arenaStart
+	idx := off >> _PageShift
 	// p points into the heap, but possibly to the middle of an object.
 	// Consult the span table to find the block beginning.
-	// TODO(rsc): Factor this out.
 	k := p >> _PageShift
-	x := k
-	x -= mheap_.arena_start >> _PageShift
-	s = h_spans[x]
+	s = h_spans[idx]
 	if s == nil || pageID(k) < s.start || p >= s.limit || s.state != mSpanInUse {
 		if s == nil || s.state == _MSpanStack {
 			// If s is nil, the virtual address has never been part of the heap.
@@ -190,21 +198,22 @@
 		}
 		return
 	}
-	base = s.base()
-	if p-base >= s.elemsize {
-		// n := (p - base) / s.elemsize, using division by multiplication
-		n := uintptr(uint64(p-base) >> s.divShift * uint64(s.divMul) >> s.divShift2)
-
-		const debugMagic = false
-		if debugMagic {
-			n2 := (p - base) / s.elemsize
-			if n != n2 {
-				println("runtime: bad div magic", (p - base), s.elemsize, s.divShift, s.divMul, s.divShift2)
-				throw("bad div magic")
-			}
+	// If this span holds object of a power of 2 size, just mask off the bits to
+	// the interior of the object. Otherwise use the size to get the base.
+	if s.baseMask != 0 {
+		// optimize for power of 2 sized objects.
+		base = s.base()
+		base = base + (p-base)&s.baseMask
+		// base = p & s.baseMask is faster for small spans,
+		// but doesn't work for large spans.
+		// Overall, it's faster to use the more general computation above.
+	} else {
+		base = s.base()
+		if p-base >= s.elemsize {
+			// n := (p - base) / s.elemsize, using division by multiplication
+			n := uintptr(uint64(p-base) >> s.divShift * uint64(s.divMul) >> s.divShift2)
+			base += n * s.elemsize
 		}
-
-		base += n * s.elemsize
 	}
 	// Now that we know the actual base, compute heapBits to return to caller.
 	hbits = heapBitsForAddr(base)
@@ -600,7 +609,7 @@
 // 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 (2-bits for data/bss otherwise).
+// 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
@@ -635,10 +644,10 @@
 					mask[pos/8] |= v
 					pos += heapBitsWidth
 				} else {
-					// 2-bits per word
-					v <<= pos % 8
-					mask[pos/8] |= v
-					pos += typeBitsWidth
+					// 1 bit per word, for data/bss bitmap
+					v >>= 1 // convert typePointer to 1, others to 0
+					mask[pos/8] |= v << (pos % 8)
+					pos++
 				}
 			}
 			prog = addb(prog, round(uintptr(siz)*typeBitsWidth, 8)/8)
@@ -668,13 +677,13 @@
 
 // Unrolls GC program prog for data/bss, returns dense GC mask.
 func unrollglobgcprog(prog *byte, size uintptr) bitvector {
-	masksize := round(round(size, ptrSize)/ptrSize*typeBitsWidth, 8) / 8
+	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*typeBitsWidth {
-		print("unrollglobgcprog: bad program size, got ", pos, ", expect ", size/ptrSize*typeBitsWidth, "\n")
+	if pos != size/ptrSize {
+		print("unrollglobgcprog: bad program size, got ", pos, ", expect ", size/ptrSize, "\n")
 		throw("unrollglobgcprog: bad program size")
 	}
 	if *prog != insEnd {
@@ -744,32 +753,34 @@
 	*mask = nil
 	*len = 0
 
-	const typeBitsPerByte = 8 / typeBitsWidth
-
 	// data
-	if themoduledata.data <= uintptr(p) && uintptr(p) < themoduledata.edata {
-		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 - themoduledata.data) / ptrSize
-			bits := (*(*byte)(add(unsafe.Pointer(gcdatamask.bytedata), off/typeBitsPerByte)) >> ((off % typeBitsPerByte) * typeBitsWidth)) & typeMask
-			*(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
+			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 - 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
+			}
+			return
 		}
-		return
-	}
 
-	// bss
-	if themoduledata.bss <= uintptr(p) && uintptr(p) < themoduledata.ebss {
-		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 - themoduledata.bss) / ptrSize
-			bits := (*(*byte)(add(unsafe.Pointer(gcbssmask.bytedata), off/typeBitsPerByte)) >> ((off % typeBitsPerByte) * typeBitsWidth)) & typeMask
-			*(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+		// bss
+		if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
+			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 - 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
+			}
+			return
 		}
-		return
 	}
 
 	// heap
@@ -780,7 +791,7 @@
 		*mask = &make([]byte, *len)[0]
 		for i := uintptr(0); i < n; i += ptrSize {
 			bits := heapBitsForAddr(base + i).typeBits()
-			*(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+			*addb(*mask, i/ptrSize) = bits
 		}
 		return
 	}
@@ -808,14 +819,15 @@
 			return
 		}
 		bv := stackmapdata(stkmap, pcdata)
-		size := uintptr(bv.n) / typeBitsWidth * ptrSize
+		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 := ((*(*byte)(add(unsafe.Pointer(bv.bytedata), off*typeBitsWidth/8))) >> ((off * typeBitsWidth) % 8)) & typeMask
-			*(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
+			bits := (*addb(bv.bytedata, off/8) >> (off % 8)) & 1
+			bits += 1 // convert 1-bit to 2-bit
+			*addb(*mask, i/ptrSize) = bits
 		}
 	}
 }
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
index 9ff4259..8c2a6b0 100644
--- a/src/runtime/mcache.go
+++ b/src/runtime/mcache.go
@@ -11,8 +11,9 @@
 type mcache struct {
 	// The following members are accessed on every malloc,
 	// so they are grouped here for better caching.
-	next_sample      int32  // trigger heap sample after allocating this many bytes
-	local_cachealloc intptr // bytes allocated (or freed) from cache since last lock of heap
+	next_sample      int32   // trigger heap sample after allocating this many bytes
+	local_cachealloc uintptr // bytes allocated from cache since last lock of heap
+	local_scan       uintptr // bytes of scannable heap allocated
 	// Allocator cache for tiny objects w/o pointers.
 	// See "Tiny allocator" comment in malloc.go.
 	tiny             unsafe.Pointer
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index 8aab903..915da69 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -29,6 +29,24 @@
 
 // Allocate a span to use in an MCache.
 func mCentral_CacheSpan(c *mcentral) *mspan {
+	// Perform proportional sweep work. We don't directly reuse
+	// the spans we're sweeping here for this allocation because
+	// these can hold any size class. We'll sweep one more span
+	// below and use that because it will have the right size
+	// class and be hot in our cache.
+	pagesOwed := int64(mheap_.sweepPagesPerByte * float64(memstats.heap_live-memstats.heap_marked))
+	if pagesOwed-int64(mheap_.pagesSwept) > 1 {
+		// Get the debt down to one page, which we're likely
+		// to take care of below (if we don't, that's fine;
+		// we'll pick up the slack later).
+		for pagesOwed-int64(atomicload64(&mheap_.pagesSwept)) > 1 {
+			if gosweepone() == ^uintptr(0) {
+				mheap_.sweepPagesPerByte = 0
+				break
+			}
+		}
+	}
+
 	lock(&c.lock)
 	sg := mheap_.sweepgen
 retry:
diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go
index c868977..ecab584 100644
--- a/src/runtime/mem_bsd.go
+++ b/src/runtime/mem_bsd.go
@@ -8,13 +8,15 @@
 
 import "unsafe"
 
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
 //go:nosplit
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
 	v := unsafe.Pointer(mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
 	if uintptr(v) < 4096 {
 		return nil
 	}
-	xadd64(stat, int64(n))
+	mSysStatInc(sysStat, n)
 	return v
 }
 
@@ -25,8 +27,11 @@
 func sysUsed(v unsafe.Pointer, n uintptr) {
 }
 
-func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
-	xadd64(stat, -int64(n))
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
 	munmap(v, n)
 }
 
@@ -51,10 +56,10 @@
 	return p
 }
 
-func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
 	const _ENOMEM = 12
 
-	xadd64(stat, int64(n))
+	mSysStatInc(sysStat, n)
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
 	if !reserved {
diff --git a/src/runtime/mem_darwin.go b/src/runtime/mem_darwin.go
index e3b8845..3bebd97 100644
--- a/src/runtime/mem_darwin.go
+++ b/src/runtime/mem_darwin.go
@@ -6,13 +6,15 @@
 
 import "unsafe"
 
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
 //go:nosplit
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
 	v := (unsafe.Pointer)(mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
 	if uintptr(v) < 4096 {
 		return nil
 	}
-	xadd64(stat, int64(n))
+	mSysStatInc(sysStat, n)
 	return v
 }
 
@@ -24,8 +26,11 @@
 func sysUsed(v unsafe.Pointer, n uintptr) {
 }
 
-func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
-	xadd64(stat, -int64(n))
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
 	munmap(v, n)
 }
 
@@ -46,8 +51,8 @@
 	_ENOMEM = 12
 )
 
-func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
-	xadd64(stat, int64(n))
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
 	p := (unsafe.Pointer)(mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0))
 	if uintptr(p) == _ENOMEM {
 		throw("runtime: out of memory")
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
index a78a03e..f988e75 100644
--- a/src/runtime/mem_linux.go
+++ b/src/runtime/mem_linux.go
@@ -48,8 +48,10 @@
 	return p
 }
 
+// Don't split the stack as this method may be invoked without a valid G, which
+// prevents us from allocating more stack.
 //go:nosplit
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
 	p := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
 	if uintptr(p) < 4096 {
 		if uintptr(p) == _EACCES {
@@ -62,7 +64,7 @@
 		}
 		return nil
 	}
-	xadd64(stat, int64(n))
+	mSysStatInc(sysStat, n)
 	return p
 }
 
@@ -93,8 +95,11 @@
 	}
 }
 
-func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
-	xadd64(stat, -int64(n))
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
 	munmap(v, n)
 }
 
@@ -128,8 +133,8 @@
 	return p
 }
 
-func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
-	xadd64(stat, int64(n))
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
 	if !reserved {
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
index 62c6a6f..755887f 100644
--- a/src/runtime/mem_plan9.go
+++ b/src/runtime/mem_plan9.go
@@ -116,7 +116,7 @@
 }
 
 func initBloc() {
-	bloc = memRound(themoduledata.end)
+	bloc = memRound(firstmoduledata.end)
 }
 
 func sbrk(n uintptr) unsafe.Pointer {
@@ -130,19 +130,19 @@
 	return unsafe.Pointer(bl)
 }
 
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
 	lock(&memlock)
 	p := memAlloc(n)
 	memCheck()
 	unlock(&memlock)
 	if p != nil {
-		xadd64(stat, int64(n))
+		mSysStatInc(sysStat, n)
 	}
 	return p
 }
 
-func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
-	xadd64(stat, -int64(n))
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
 	lock(&memlock)
 	memFree(v, n)
 	memCheck()
@@ -155,10 +155,10 @@
 func sysUsed(v unsafe.Pointer, n uintptr) {
 }
 
-func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
 	// sysReserve has already allocated all heap memory,
 	// but has not adjusted stats.
-	xadd64(stat, int64(n))
+	mSysStatInc(sysStat, n)
 }
 
 func sysFault(v unsafe.Pointer, n uintptr) {
diff --git a/src/runtime/mem_windows.go b/src/runtime/mem_windows.go
index a800cca..42aa7fb 100644
--- a/src/runtime/mem_windows.go
+++ b/src/runtime/mem_windows.go
@@ -18,9 +18,11 @@
 	_PAGE_NOACCESS  = 0x0001
 )
 
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
 //go:nosplit
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
-	xadd64(stat, int64(n))
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	mSysStatInc(sysStat, n)
 	return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_COMMIT|_MEM_RESERVE, _PAGE_READWRITE))
 }
 
@@ -74,8 +76,11 @@
 	}
 }
 
-func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
-	xadd64(stat, -int64(n))
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
 	r := stdcall3(_VirtualFree, uintptr(v), 0, _MEM_RELEASE)
 	if r == 0 {
 		throw("runtime: failed to release pages")
@@ -100,8 +105,8 @@
 	return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_RESERVE, _PAGE_READWRITE))
 }
 
-func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
-	xadd64(stat, int64(n))
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
 	p := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
 	if p != uintptr(v) {
 		throw("runtime: cannot map pages in arena address space")
diff --git a/src/runtime/memmove_test.go b/src/runtime/memmove_test.go
index 29c62cc..857f99b 100644
--- a/src/runtime/memmove_test.go
+++ b/src/runtime/memmove_test.go
@@ -206,6 +206,24 @@
 		_ = x
 	}
 }
+func BenchmarkClearFat40(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [40 / 4]uint32
+		_ = x
+	}
+}
+func BenchmarkClearFat48(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [48 / 4]uint32
+		_ = x
+	}
+}
+func BenchmarkClearFat56(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [56 / 4]uint32
+		_ = x
+	}
+}
 func BenchmarkClearFat64(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var x [64 / 4]uint32
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 2de7565..7e1773c 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -20,7 +20,7 @@
 var fing *g        // goroutine that runs finalizers
 var finq *finblock // list of finalizers that are to be executed
 var finc *finblock // cache of free blocks
-var finptrmask [_FinBlockSize / typeBitmapScale]byte
+var finptrmask [_FinBlockSize / ptrSize / 8]byte
 var fingwait bool
 var fingwake bool
 var allfin *finblock // list of all blocks
@@ -35,25 +35,31 @@
 }
 
 var finalizer1 = [...]byte{
-	// Each Finalizer is 5 words, ptr ptr uintptr ptr ptr.
-	// Each byte describes 4 words.
-	// Need 4 Finalizers described by 5 bytes before pattern repeats:
-	//	ptr ptr uintptr ptr ptr
-	//	ptr ptr uintptr ptr ptr
-	//	ptr ptr uintptr ptr ptr
-	//	ptr ptr uintptr ptr ptr
+	// Each Finalizer is 5 words, ptr ptr INT ptr ptr (INT = uintptr here)
+	// Each byte describes 8 words.
+	// Need 8 Finalizers described by 5 bytes before pattern repeats:
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
 	// aka
-	//	ptr ptr uintptr ptr
-	//	ptr ptr ptr uintptr
-	//	ptr ptr ptr ptr
-	//	uintptr ptr ptr ptr
-	//	ptr uintptr ptr ptr
+	//
+	//	ptr ptr INT ptr ptr ptr ptr INT
+	//	ptr ptr ptr ptr INT ptr ptr ptr
+	//	ptr INT ptr ptr ptr ptr INT ptr
+	//	ptr ptr ptr INT ptr ptr ptr ptr
+	//	INT ptr ptr ptr ptr INT ptr ptr
+	//
 	// Assumptions about Finalizer layout checked below.
-	typePointer | typePointer<<2 | typeScalar<<4 | typePointer<<6,
-	typePointer | typePointer<<2 | typePointer<<4 | typeScalar<<6,
-	typePointer | typePointer<<2 | typePointer<<4 | typePointer<<6,
-	typeScalar | typePointer<<2 | typePointer<<4 | typePointer<<6,
-	typePointer | typeScalar<<2 | typePointer<<4 | typePointer<<6,
+	1<<0 | 1<<1 | 0<<2 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 0<<7,
+	1<<0 | 1<<1 | 1<<2 | 1<<3 | 0<<4 | 1<<5 | 1<<6 | 1<<7,
+	1<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 | 0<<6 | 1<<7,
+	1<<0 | 1<<1 | 1<<2 | 0<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7,
+	0<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 | 1<<6 | 1<<7,
 }
 
 func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
@@ -72,8 +78,7 @@
 					unsafe.Offsetof(finalizer{}.arg) != ptrSize ||
 					unsafe.Offsetof(finalizer{}.nret) != 2*ptrSize ||
 					unsafe.Offsetof(finalizer{}.fint) != 3*ptrSize ||
-					unsafe.Offsetof(finalizer{}.ot) != 4*ptrSize ||
-					typeBitsWidth != 2) {
+					unsafe.Offsetof(finalizer{}.ot) != 4*ptrSize) {
 					throw("finalizer out of sync")
 				}
 				for i := range finptrmask {
@@ -289,11 +294,13 @@
 		// The relevant segments are: noptrdata, data, bss, noptrbss.
 		// We cannot assume they are in any order or even contiguous,
 		// due to external linking.
-		if themoduledata.noptrdata <= uintptr(e.data) && uintptr(e.data) < themoduledata.enoptrdata ||
-			themoduledata.data <= uintptr(e.data) && uintptr(e.data) < themoduledata.edata ||
-			themoduledata.bss <= uintptr(e.data) && uintptr(e.data) < themoduledata.ebss ||
-			themoduledata.noptrbss <= uintptr(e.data) && uintptr(e.data) < themoduledata.enoptrbss {
-			return
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			if datap.noptrdata <= uintptr(e.data) && uintptr(e.data) < datap.enoptrdata ||
+				datap.data <= uintptr(e.data) && uintptr(e.data) < datap.edata ||
+				datap.bss <= uintptr(e.data) && uintptr(e.data) < datap.ebss ||
+				datap.noptrbss <= uintptr(e.data) && uintptr(e.data) < datap.enoptrbss {
+				return
+			}
 		}
 		throw("runtime.SetFinalizer: pointer not in allocated block")
 	}
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 89f3fb5..9bd36d1 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -76,28 +76,25 @@
 //     Are things on the free lists black or white? How does the sweep phase work?
 
 // Concurrent sweep.
+//
 // The sweep phase proceeds concurrently with normal program execution.
 // The heap is swept span-by-span both lazily (when a goroutine needs another span)
 // and concurrently in a background goroutine (this helps programs that are not CPU bound).
-// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
-// and so next_gc calculation is tricky and happens as follows.
-// At the end of the stop-the-world phase next_gc is conservatively set based on total
-// heap size; all spans are marked as "needs sweeping".
-// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
-// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
-// closer to the target value. However, this is not enough to avoid over-allocating memory.
-// Consider that a goroutine wants to allocate a new span for a large object and
-// there are no free swept spans, but there are small-object unswept spans.
-// If the goroutine naively allocates a new span, it can surpass the yet-unknown
-// target next_gc value. In order to prevent such cases (1) when a goroutine needs
-// to allocate a new small-object span, it sweeps small-object spans for the same
-// object size until it frees at least one object; (2) when a goroutine needs to
-// allocate large-object span from heap, it sweeps spans until it frees at least
-// that many pages into heap. Together these two measures ensure that we don't surpass
-// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
-// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
-// but there can still be other one-page unswept spans which could be combined into a
-// two-page span.
+// At the end of STW mark termination all spans are marked as "needs sweeping".
+//
+// The background sweeper goroutine simply sweeps spans one-by-one.
+//
+// To avoid requesting more OS memory while there are unswept spans, when a
+// goroutine needs another span, it first attempts to reclaim that much memory
+// by sweeping. When a goroutine needs to allocate a new small-object span, it
+// sweeps small-object spans for the same object size until it frees at least
+// one object. When a goroutine needs to allocate large-object span from heap,
+// it sweeps spans until it frees at least that many pages into heap. There is
+// one case where this may not suffice: if a goroutine sweeps and frees two
+// nonadjacent one-page spans to the heap, it will allocate a new two-page
+// span, but there can still be other one-page unswept spans which could be
+// combined into a two-page span.
+//
 // It's critical to ensure that no operations proceed on unswept spans (that would corrupt
 // mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
 // so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
@@ -130,21 +127,12 @@
 	_RootCount       = 5
 )
 
-//go:linkname weak_cgo_allocate go.weak.runtime._cgo_allocate_internal
-var weak_cgo_allocate byte
-
-// Is _cgo_allocate linked into the binary?
-//go:nowritebarrier
-func have_cgo_allocate() bool {
-	return &weak_cgo_allocate != nil
-}
-
-var gcdatamask bitvector
-var gcbssmask bitvector
-
 // 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)
 
 // Initialized from $GOGC.  GOGC=off means no GC.
@@ -156,12 +144,25 @@
 	}
 
 	work.markfor = parforalloc(_MaxGcproc)
-	gcpercent = readgogc()
-	gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(themoduledata.gcdata)), themoduledata.edata-themoduledata.data)
-	gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(themoduledata.gcbss)), themoduledata.ebss-themoduledata.bss)
+	_ = 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)
+	}
 	memstats.next_gc = heapminimum
 }
 
+func readgogc() int32 {
+	p := gogetenv("GOGC")
+	if p == "" {
+		return 100
+	}
+	if p == "off" {
+		return -1
+	}
+	return int32(atoi(p))
+}
+
 // gcenable is called after the bulk of the runtime initialization,
 // just before we're about to start letting user code run.
 // It kicks off the background sweeper goroutine and enables GC.
@@ -179,14 +180,450 @@
 		in = -1
 	}
 	gcpercent = in
+	heapminimum = heapminimum * uint64(gcpercent) / 100
 	unlock(&mheap_.lock)
 	return out
 }
 
-// Trigger the concurrent GC when 1/triggerratio memory is available to allocate.
-// Adjust this ratio as part of a scheme to ensure that mutators have enough
-// memory to allocate in durring a concurrent GC cycle.
-var triggerratio = int64(8)
+// Garbage collector phase.
+// Indicates to write barrier and sychronization task to preform.
+var gcphase uint32
+var writeBarrierEnabled bool // compiler emits references to this in write barriers
+
+// gcBlackenEnabled is 1 if mutator assists and background mark
+// workers are allowed to blacken objects. This must only be set when
+// gcphase == _GCmark.
+var gcBlackenEnabled uint32
+
+const (
+	_GCoff             = iota // GC not running, write barrier disabled
+	_GCquiesce                // unused state
+	_GCstw                    // unused state
+	_GCscan                   // GC collecting roots into workbufs, write barrier disabled
+	_GCmark                   // GC marking from workbufs, write barrier ENABLED
+	_GCmarktermination        // GC mark termination: allocate black, P's help GC, write barrier ENABLED
+	_GCsweep                  // GC mark completed; sweeping in background, write barrier disabled
+)
+
+//go:nosplit
+func setGCPhase(x uint32) {
+	atomicstore(&gcphase, x)
+	writeBarrierEnabled = gcphase == _GCmark || gcphase == _GCmarktermination || mheap_.shadow_enabled
+}
+
+// gcMarkWorkerMode represents the mode that a concurrent mark worker
+// should operate in.
+//
+// Concurrent marking happens through four different mechanisms. One
+// is mutator assists, which happen in response to allocations and are
+// not scheduled. The other three are variations in the per-P mark
+// workers and are distinguished by gcMarkWorkerMode.
+type gcMarkWorkerMode int
+
+const (
+	// gcMarkWorkerDedicatedMode indicates that the P of a mark
+	// worker is dedicated to running that mark worker. The mark
+	// worker should run without preemption until concurrent mark
+	// is done.
+	gcMarkWorkerDedicatedMode gcMarkWorkerMode = iota
+
+	// gcMarkWorkerFractionalMode indicates that a P is currently
+	// running the "fractional" mark worker. The fractional worker
+	// is necessary when GOMAXPROCS*gcGoalUtilization is not an
+	// integer. The fractional worker should run until it is
+	// preempted and will be scheduled to pick up the fractional
+	// part of GOMAXPROCS*gcGoalUtilization.
+	gcMarkWorkerFractionalMode
+
+	// gcMarkWorkerIdleMode indicates that a P is running the mark
+	// worker because it has nothing else to do. The idle worker
+	// should run until it is preempted and account its time
+	// against gcController.idleMarkTime.
+	gcMarkWorkerIdleMode
+)
+
+// gcController implements the GC pacing controller that determines
+// when to trigger concurrent garbage collection and how much marking
+// work to do in mutator assists and background marking.
+//
+// It uses a feedback control algorithm to adjust the memstats.next_gc
+// trigger based on the heap growth and GC CPU utilization each cycle.
+// This algorithm optimizes for heap growth to match GOGC and for CPU
+// utilization between assist and background marking to be 25% of
+// GOMAXPROCS. The high-level design of this algorithm is documented
+// at http://golang.org/s/go15gcpacing.
+var gcController = gcControllerState{
+	// Initial trigger ratio guess.
+	triggerRatio: 7 / 8.0,
+}
+
+type gcControllerState struct {
+	// scanWork is the total scan work performed this cycle. This
+	// is updated atomically during the cycle. Updates may be
+	// batched arbitrarily, since the value is only read at the
+	// end of the cycle.
+	//
+	// Currently this is the bytes of heap scanned. For most uses,
+	// this is an opaque unit of work, but for estimation the
+	// definition is important.
+	scanWork int64
+
+	// bgScanCredit is the scan work credit accumulated by the
+	// concurrent background scan. This credit is accumulated by
+	// the background scan and stolen by mutator assists. This is
+	// updated atomically. Updates occur in bounded batches, since
+	// it is both written and read throughout the cycle.
+	bgScanCredit int64
+
+	// assistTime is the nanoseconds spent in mutator assists
+	// during this cycle. This is updated atomically. Updates
+	// occur in bounded batches, since it is both written and read
+	// throughout the cycle.
+	assistTime int64
+
+	// dedicatedMarkTime is the nanoseconds spent in dedicated
+	// mark workers during this cycle. This is updated atomically
+	// at the end of the concurrent mark phase.
+	dedicatedMarkTime int64
+
+	// fractionalMarkTime is the nanoseconds spent in the
+	// fractional mark worker during this cycle. This is updated
+	// atomically throughout the cycle and will be up-to-date if
+	// the fractional mark worker is not currently running.
+	fractionalMarkTime int64
+
+	// idleMarkTime is the nanoseconds spent in idle marking
+	// during this cycle. This is udpated atomically throughout
+	// the cycle.
+	idleMarkTime int64
+
+	// bgMarkStartTime is the absolute start time in nanoseconds
+	// that the background mark phase started.
+	bgMarkStartTime int64
+
+	// heapGoal is the goal memstats.heap_live for when this cycle
+	// ends. This is computed at the beginning of each cycle.
+	heapGoal uint64
+
+	// dedicatedMarkWorkersNeeded is the number of dedicated mark
+	// workers that need to be started. This is computed at the
+	// beginning of each cycle and decremented atomically as
+	// dedicated mark workers get started.
+	dedicatedMarkWorkersNeeded int64
+
+	// assistRatio is the ratio of allocated bytes to scan work
+	// that should be performed by mutator assists. This is
+	// computed at the beginning of each cycle.
+	assistRatio float64
+
+	// fractionalUtilizationGoal is the fraction of wall clock
+	// time that should be spent in the fractional mark worker.
+	// For example, if the overall mark utilization goal is 25%
+	// and GOMAXPROCS is 6, one P will be a dedicated mark worker
+	// and this will be set to 0.5 so that 50% of the time some P
+	// is in a fractional mark worker. This is computed at the
+	// beginning of each cycle.
+	fractionalUtilizationGoal float64
+
+	// triggerRatio is the heap growth ratio at which the garbage
+	// collection cycle should start. E.g., if this is 0.6, then
+	// GC should start when the live heap has reached 1.6 times
+	// the heap size marked by the previous cycle. This is updated
+	// at the end of of each cycle.
+	triggerRatio float64
+
+	// reviseTimer is a timer that triggers periodic revision of
+	// control variables during the cycle.
+	reviseTimer timer
+
+	_ [_CacheLineSize]byte
+
+	// fractionalMarkWorkersNeeded is the number of fractional
+	// mark workers that need to be started. This is either 0 or
+	// 1. This is potentially updated atomically at every
+	// scheduling point (hence it gets its own cache line).
+	fractionalMarkWorkersNeeded int64
+
+	_ [_CacheLineSize]byte
+}
+
+// startCycle resets the GC controller's state and computes estimates
+// for a new GC cycle. The caller must hold worldsema.
+func (c *gcControllerState) startCycle() {
+	c.scanWork = 0
+	c.bgScanCredit = 0
+	c.assistTime = 0
+	c.dedicatedMarkTime = 0
+	c.fractionalMarkTime = 0
+	c.idleMarkTime = 0
+
+	// If this is the first GC cycle or we're operating on a very
+	// small heap, fake heap_marked so it looks like next_gc is
+	// the appropriate growth from heap_marked, even though the
+	// real heap_marked may not have a meaningful value (on the
+	// first cycle) or may be much smaller (resulting in a large
+	// error response).
+	if memstats.next_gc <= heapminimum {
+		memstats.heap_marked = uint64(float64(memstats.next_gc) / (1 + c.triggerRatio))
+		memstats.heap_reachable = memstats.heap_marked
+	}
+
+	// Compute the heap goal for this cycle
+	c.heapGoal = memstats.heap_reachable + memstats.heap_reachable*uint64(gcpercent)/100
+
+	// Compute the total mark utilization goal and divide it among
+	// dedicated and fractional workers.
+	totalUtilizationGoal := float64(gomaxprocs) * gcGoalUtilization
+	c.dedicatedMarkWorkersNeeded = int64(totalUtilizationGoal)
+	c.fractionalUtilizationGoal = totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded)
+	if c.fractionalUtilizationGoal > 0 {
+		c.fractionalMarkWorkersNeeded = 1
+	} else {
+		c.fractionalMarkWorkersNeeded = 0
+	}
+
+	// Clear per-P state
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		p.gcAssistTime = 0
+	}
+
+	// Compute initial values for controls that are updated
+	// throughout the cycle.
+	c.revise()
+
+	// Set up a timer to revise periodically
+	c.reviseTimer.f = func(interface{}, uintptr) {
+		gcController.revise()
+	}
+	c.reviseTimer.period = 10 * 1000 * 1000
+	c.reviseTimer.when = nanotime() + c.reviseTimer.period
+	addtimer(&c.reviseTimer)
+}
+
+// revise updates the assist ratio during the GC cycle to account for
+// improved estimates. This should be called periodically during
+// concurrent mark.
+func (c *gcControllerState) revise() {
+	// Compute the expected scan work. This is a strict upper
+	// bound on the possible scan work in the current heap.
+	//
+	// You might consider dividing this by 2 (or by
+	// (100+GOGC)/100) to counter this over-estimation, but
+	// benchmarks show that this has almost no effect on mean
+	// mutator utilization, heap size, or assist time and it
+	// introduces the danger of under-estimating and letting the
+	// mutator outpace the garbage collector.
+	scanWorkExpected := memstats.heap_scan
+
+	// Compute the mutator assist ratio so by the time the mutator
+	// allocates the remaining heap bytes up to next_gc, it will
+	// have done (or stolen) the estimated amount of scan work.
+	heapDistance := int64(c.heapGoal) - int64(work.initialHeapLive)
+	if heapDistance <= 1024*1024 {
+		// heapDistance can be negative if GC start is delayed
+		// or if the allocation that pushed heap_live over
+		// next_gc is large or if the trigger is really close
+		// to GOGC. We don't want to set the assist negative
+		// (or divide by zero, or set it really high), so
+		// enforce a minimum on the distance.
+		heapDistance = 1024 * 1024
+	}
+	c.assistRatio = float64(scanWorkExpected) / float64(heapDistance)
+}
+
+// endCycle updates the GC controller state at the end of the
+// concurrent part of the GC cycle.
+func (c *gcControllerState) endCycle() {
+	h_t := c.triggerRatio // For debugging
+
+	// Proportional response gain for the trigger controller. Must
+	// be in [0, 1]. Lower values smooth out transient effects but
+	// take longer to respond to phase changes. Higher values
+	// react to phase changes quickly, but are more affected by
+	// transient changes. Values near 1 may be unstable.
+	const triggerGain = 0.5
+
+	// Stop the revise timer
+	deltimer(&c.reviseTimer)
+
+	// Compute next cycle trigger ratio. First, this computes the
+	// "error" for this cycle; that is, how far off the trigger
+	// was from what it should have been, accounting for both heap
+	// growth and GC CPU utilization. We computing the actual heap
+	// growth during this cycle and scale that by how far off from
+	// the goal CPU utilization we were (to estimate the heap
+	// growth if we had the desired CPU utilization). The
+	// difference between this estimate and the GOGC-based goal
+	// heap growth is the error.
+	goalGrowthRatio := float64(gcpercent) / 100
+	actualGrowthRatio := float64(memstats.heap_live)/float64(memstats.heap_marked) - 1
+	duration := nanotime() - c.bgMarkStartTime
+
+	// Assume background mark hit its utilization goal.
+	utilization := gcGoalUtilization
+	// Add assist utilization; avoid divide by zero.
+	if duration > 0 {
+		utilization += float64(c.assistTime) / float64(duration*int64(gomaxprocs))
+	}
+
+	triggerError := goalGrowthRatio - c.triggerRatio - utilization/gcGoalUtilization*(actualGrowthRatio-c.triggerRatio)
+
+	// Finally, we adjust the trigger for next time by this error,
+	// damped by the proportional gain.
+	c.triggerRatio += triggerGain * triggerError
+	if c.triggerRatio < 0 {
+		// This can happen if the mutator is allocating very
+		// quickly or the GC is scanning very slowly.
+		c.triggerRatio = 0
+	} else if c.triggerRatio > goalGrowthRatio*0.95 {
+		// Ensure there's always a little margin so that the
+		// mutator assist ratio isn't infinity.
+		c.triggerRatio = goalGrowthRatio * 0.95
+	}
+
+	if debug.gcpacertrace > 0 {
+		// Print controller state in terms of the design
+		// document.
+		H_m_prev := memstats.heap_marked
+		H_T := memstats.next_gc
+		h_a := actualGrowthRatio
+		H_a := memstats.heap_live
+		h_g := goalGrowthRatio
+		H_g := int64(float64(H_m_prev) * (1 + h_g))
+		u_a := utilization
+		u_g := gcGoalUtilization
+		W_a := c.scanWork
+		print("pacer: H_m_prev=", H_m_prev,
+			" h_t=", h_t, " H_T=", H_T,
+			" h_a=", h_a, " H_a=", H_a,
+			" h_g=", h_g, " H_g=", H_g,
+			" u_a=", u_a, " u_g=", u_g,
+			" W_a=", W_a,
+			" goalΔ=", goalGrowthRatio-h_t,
+			" actualΔ=", h_a-h_t,
+			" u_a/u_g=", u_a/u_g,
+			"\n")
+	}
+}
+
+// findRunnableGCWorker returns the background mark worker for _p_ if it
+// should be run. This must only be called when gcBlackenEnabled != 0.
+func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
+	if gcBlackenEnabled == 0 {
+		throw("gcControllerState.findRunnable: blackening not enabled")
+	}
+	if _p_.gcBgMarkWorker == nil {
+		throw("gcControllerState.findRunnable: no background mark worker")
+	}
+	if work.bgMarkDone != 0 {
+		// Background mark is done. Don't schedule background
+		// mark worker any more. (This is not just an
+		// optimization. Without this we can spin scheduling
+		// the background worker and having it return
+		// immediately with no work to do.)
+		return nil
+	}
+
+	decIfPositive := func(ptr *int64) bool {
+		if *ptr > 0 {
+			if xaddint64(ptr, -1) >= 0 {
+				return true
+			}
+			// We lost a race
+			xaddint64(ptr, +1)
+		}
+		return false
+	}
+
+	if decIfPositive(&c.dedicatedMarkWorkersNeeded) {
+		// This P is now dedicated to marking until the end of
+		// the concurrent mark phase.
+		_p_.gcMarkWorkerMode = gcMarkWorkerDedicatedMode
+		// TODO(austin): This P isn't going to run anything
+		// else for a while, so kick everything out of its run
+		// queue.
+	} else {
+		if _p_.gcw.wbuf == 0 && work.full == 0 && work.partial == 0 {
+			// No work to be done right now. This can
+			// happen at the end of the mark phase when
+			// there are still assists tapering off. Don't
+			// bother running background mark because
+			// it'll just return immediately.
+			return nil
+		}
+		if !decIfPositive(&c.fractionalMarkWorkersNeeded) {
+			// No more workers are need right now.
+			return nil
+		}
+
+		// This P has picked the token for the fractional worker.
+		// Is the GC currently under or at the utilization goal?
+		// If so, do more work.
+		//
+		// We used to check whether doing one time slice of work
+		// would remain under the utilization goal, but that has the
+		// effect of delaying work until the mutator has run for
+		// enough time slices to pay for the work. During those time
+		// slices, write barriers are enabled, so the mutator is running slower.
+		// Now instead we do the work whenever we're under or at the
+		// utilization work and pay for it by letting the mutator run later.
+		// This doesn't change the overall utilization averages, but it
+		// front loads the GC work so that the GC finishes earlier and
+		// write barriers can be turned off sooner, effectively giving
+		// the mutator a faster machine.
+		//
+		// The old, slower behavior can be restored by setting
+		//	gcForcePreemptNS = forcePreemptNS.
+		const gcForcePreemptNS = 0
+
+		// TODO(austin): We could fast path this and basically
+		// eliminate contention on c.fractionalMarkWorkersNeeded by
+		// precomputing the minimum time at which it's worth
+		// next scheduling the fractional worker. Then Ps
+		// don't have to fight in the window where we've
+		// passed that deadline and no one has started the
+		// worker yet.
+		//
+		// TODO(austin): Shorter preemption interval for mark
+		// worker to improve fairness and give this
+		// finer-grained control over schedule?
+		now := nanotime() - gcController.bgMarkStartTime
+		then := now + gcForcePreemptNS
+		timeUsed := c.fractionalMarkTime + gcForcePreemptNS
+		if then > 0 && float64(timeUsed)/float64(then) > c.fractionalUtilizationGoal {
+			// Nope, we'd overshoot the utilization goal
+			xaddint64(&c.fractionalMarkWorkersNeeded, +1)
+			return nil
+		}
+		_p_.gcMarkWorkerMode = gcMarkWorkerFractionalMode
+	}
+
+	// Run the background mark worker
+	gp := _p_.gcBgMarkWorker
+	casgstatus(gp, _Gwaiting, _Grunnable)
+	if trace.enabled {
+		traceGoUnpark(gp, 0)
+	}
+	return gp
+}
+
+// gcGoalUtilization is the goal CPU utilization for background
+// marking as a fraction of GOMAXPROCS.
+const gcGoalUtilization = 0.25
+
+// gcBgCreditSlack is the amount of scan work credit background
+// scanning can accumulate locally before updating
+// gcController.bgScanCredit. Lower values give mutator assists more
+// accurate accounting of background scanning. Higher values reduce
+// memory contention.
+const gcBgCreditSlack = 2000
+
+// gcAssistTimeSlack is the nanoseconds of mutator assist time that
+// can accumulate on a P before updating gcController.assistTime.
+const gcAssistTimeSlack = 5000
 
 // Determine whether to initiate a GC.
 // If the GC is already working no need to trigger another one.
@@ -194,11 +631,11 @@
 // have sufficient time to complete then more memory will be
 // requested from the OS increasing heap size thus allow future
 // GCs more time to complete.
-// memstat.heap_alloc and memstat.next_gc reads have benign races
+// memstat.heap_live read has a benign race.
 // A false negative simple does not start a GC, a false positive
 // will start a GC needlessly. Neither have correctness issues.
 func shouldtriggergc() bool {
-	return triggerratio*(int64(memstats.next_gc)-int64(memstats.heap_alloc)) <= int64(memstats.next_gc) && atomicloaduint(&bggc.working) == 0
+	return memstats.heap_live >= memstats.next_gc && atomicloaduint(&bggc.working) == 0
 }
 
 var work struct {
@@ -213,8 +650,39 @@
 	alldone note
 	markfor *parfor
 
+	bgMarkReady note   // signal background mark worker has started
+	bgMarkDone  uint32 // cas to 1 when at a background mark completion point
+
+	// Background mark completion signaling
+	bgMarkWake struct {
+		lock mutex
+		g    *g
+		wake bool
+	}
+
 	// Copy of mheap.allspans for marker or sweeper.
 	spans []*mspan
+
+	// totaltime is the CPU nanoseconds spent in GC since the
+	// program started if debug.gctrace > 0.
+	totaltime int64
+
+	// bytesMarked is the number of bytes marked this cycle. This
+	// includes bytes blackened in scanned objects, noscan objects
+	// that go straight to black, and permagrey objects scanned by
+	// markroot during the concurrent scan phase. This is updated
+	// atomically during the cycle. Updates may be batched
+	// arbitrarily, since the value is only read at the end of the
+	// cycle.
+	//
+	// Because of benign races during marking, this number may not
+	// be the exact number of marked bytes, but it should be very
+	// close.
+	bytesMarked uint64
+
+	// initialHeapLive is the value of memstats.heap_live at the
+	// beginning of this GC cycle.
+	initialHeapLive uint64
 }
 
 // GC runs a garbage collection.
@@ -249,16 +717,24 @@
 	}
 
 	// trigger concurrent GC
+	readied := false
 	lock(&bggc.lock)
 	if !bggc.started {
 		bggc.working = 1
 		bggc.started = true
+		readied = true
 		go backgroundgc()
 	} else if bggc.working == 0 {
 		bggc.working = 1
+		readied = true
 		ready(bggc.g, 0)
 	}
 	unlock(&bggc.lock)
+	if readied {
+		// This G just started or ready()d the GC goroutine.
+		// Switch directly to it by yielding.
+		Gosched()
+	}
 }
 
 // State of the background concurrent GC goroutine.
@@ -282,24 +758,42 @@
 }
 
 func gc(mode int) {
+	// debug.gctrace variables
+	var stwprocs, maxprocs int32
+	var tSweepTerm, tScan, tInstallWB, tMark, tMarkTerm int64
+	var heap0, heap1, heap2, heapGoal uint64
+
 	// Ok, we're doing it!  Stop everybody else
 	semacquire(&worldsema, false)
 
 	// Pick up the remaining unswept/not being swept spans concurrently
+	//
+	// This shouldn't happen if we're being invoked in background
+	// mode since proportional sweep should have just finished
+	// sweeping everything, but rounding errors, etc, may leave a
+	// few spans unswept. In forced mode, this is necessary since
+	// GC can be forced at any point in the sweeping cycle.
 	for gosweepone() != ^uintptr(0) {
 		sweep.nbgsweep++
 	}
 
-	mp := acquirem()
-	mp.preemptoff = "gcing"
-	releasem(mp)
-	gctimer.count++
 	if mode == gcBackgroundMode {
-		gctimer.cycle.sweepterm = nanotime()
+		gcBgMarkStartWorkers()
+	}
+	if debug.gctrace > 0 {
+		stwprocs, maxprocs = gcprocs(), gomaxprocs
+		tSweepTerm = nanotime()
+		if mode == gcBackgroundMode {
+			// We started GC when heap_live == next_gc,
+			// but the mutator may have allocated between
+			// then and now. Report heap when GC started.
+			heap0 = memstats.next_gc
+		} else {
+			heap0 = memstats.heap_live
+		}
 	}
 
 	if trace.enabled {
-		traceGoSched()
 		traceGCStart()
 	}
 
@@ -309,56 +803,98 @@
 	// reclaimed until the next GC cycle.
 	clearpools()
 
+	work.bytesMarked = 0
+	work.initialHeapLive = memstats.heap_live
+
 	if mode == gcBackgroundMode { // Do as much work concurrently as possible
+		gcController.startCycle()
+		heapGoal = gcController.heapGoal
+
 		systemstack(func() {
-			gcphase = _GCscan
+			setGCPhase(_GCscan)
 
 			// Concurrent scan.
 			starttheworld()
-			gctimer.cycle.scan = nanotime()
+			if debug.gctrace > 0 {
+				tScan = nanotime()
+			}
 			gcscan_m()
-			gctimer.cycle.installmarkwb = nanotime()
 
-			// Enter mark phase and enable write barriers.
-			stoptheworld()
-			gcphase = _GCmark
-
-			// Concurrent mark.
-			starttheworld()
+			// Enter mark phase. This enables write
+			// barriers.
+			if debug.gctrace > 0 {
+				tInstallWB = nanotime()
+			}
+			setGCPhase(_GCmark)
+			// Ensure all Ps have observed the phase
+			// change and have write barriers enabled
+			// before any blackening occurs.
+			forEachP(func(*p) {})
 		})
-		gctimer.cycle.mark = nanotime()
-		var gcw gcWork
-		gcDrain(&gcw)
-		gcw.dispose()
-		// Despite the barrier in gcDrain, gcDrainNs may still
-		// be doing work at this point. This is okay because
-		// 1) the gcDrainNs happen on the system stack, so
-		// they will flush their work to the global queues
-		// before we can stop the world, and 2) it's fine if
-		// we go into mark termination with some work queued.
+		// Concurrent mark.
+		gcBgMarkPrepare() // Must happen before assist enable.
+		// At this point all Ps have enabled the mark phase
+		// write barrier, thus maintaining the no white to
+		// black invariant. Mutator assists and mark workers
+		// can now be enabled to safely blacken grey objects.
+		atomicstore(&gcBlackenEnabled, 1)
+		if debug.gctrace > 0 {
+			tMark = nanotime()
+		}
+
+		// Wait for background mark completion.
+		lock(&work.bgMarkWake.lock)
+		if work.bgMarkWake.wake {
+			// Wakeup already happened
+			unlock(&work.bgMarkWake.lock)
+		} else {
+			work.bgMarkWake.g = getg()
+			goparkunlock(&work.bgMarkWake.lock, "mark wait (idle)", traceEvGoBlock, 1)
+		}
+		work.bgMarkWake.wake = false
+		work.bgMarkWake.g = nil
 
 		// Begin mark termination.
-		gctimer.cycle.markterm = nanotime()
+		if debug.gctrace > 0 {
+			tMarkTerm = nanotime()
+		}
 		systemstack(stoptheworld)
 		// 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.
+
+		// Flush the gcWork caches. This must be done before
+		// endCycle since endCycle depends on statistics kept
+		// in these caches.
+		gcFlushGCWork()
+
+		gcController.endCycle()
 	} else {
 		// For non-concurrent GC (mode != gcBackgroundMode)
 		// The g stacks have not been scanned so clear g state
 		// such that mark termination scans all stacks.
 		gcResetGState()
+
+		if debug.gctrace > 0 {
+			t := nanotime()
+			tScan, tInstallWB, tMark, tMarkTerm = t, t, t, t
+			heapGoal = heap0
+		}
 	}
 
 	// World is stopped.
 	// Start marktermination which includes enabling the write barrier.
-	gcphase = _GCmarktermination
+	atomicstore(&gcBlackenEnabled, 0)
+	setGCPhase(_GCmarktermination)
 
-	startTime := nanotime()
-	if mp != acquirem() {
-		throw("gcwork: rescheduled")
+	if debug.gctrace > 0 {
+		heap1 = memstats.heap_live
 	}
 
+	startTime := nanotime()
+
+	mp := acquirem()
+	mp.preemptoff = "gcing"
 	_g_ := getg()
 	_g_.m.traceback = 2
 	gp := _g_.m.curg
@@ -372,6 +908,9 @@
 	// need to switch to g0 so we can shrink the stack.
 	systemstack(func() {
 		gcMark(startTime)
+		if debug.gctrace > 0 {
+			heap2 = work.bytesMarked
+		}
 		if debug.gccheckmark > 0 {
 			// Run a full stop-the-world mark using checkmark bits,
 			// to check that we didn't forget to mark anything during
@@ -382,7 +921,7 @@
 		}
 
 		// marking is complete so we can turn the write barrier off
-		gcphase = _GCoff
+		setGCPhase(_GCoff)
 		gcSweep(mode)
 
 		if debug.gctrace > 1 {
@@ -396,9 +935,9 @@
 			// Still in STW but gcphase is _GCoff, reset to _GCmarktermination
 			// At this point all objects will be found during the gcMark which
 			// does a complete STW mark and object scan.
-			gcphase = _GCmarktermination
+			setGCPhase(_GCmarktermination)
 			gcMark(startTime)
-			gcphase = _GCoff // marking is done, turn off wb.
+			setGCPhase(_GCoff) // marking is done, turn off wb.
 			gcSweep(mode)
 		}
 	})
@@ -408,26 +947,13 @@
 
 	if trace.enabled {
 		traceGCDone()
-		traceGoStart()
 	}
 
 	// all done
 	mp.preemptoff = ""
 
-	if mode == gcBackgroundMode {
-		gctimer.cycle.sweep = nanotime()
-	}
-
 	semrelease(&worldsema)
 
-	if mode == gcBackgroundMode {
-		if gctimer.verbose > 1 {
-			GCprinttimes()
-		} else if gctimer.verbose > 0 {
-			calctimes() // ignore result
-		}
-	}
-
 	if gcphase != _GCoff {
 		throw("gc done but gcphase != _GCoff")
 	}
@@ -437,6 +963,54 @@
 	releasem(mp)
 	mp = nil
 
+	memstats.numgc++
+	if debug.gctrace > 0 {
+		tEnd := nanotime()
+
+		// Update work.totaltime
+		sweepTermCpu := int64(stwprocs) * (tScan - tSweepTerm)
+		scanCpu := tInstallWB - tScan
+		installWBCpu := int64(0)
+		// We report idle marking time below, but omit it from
+		// the overall utilization here since it's "free".
+		markCpu := gcController.assistTime + gcController.dedicatedMarkTime + gcController.fractionalMarkTime
+		markTermCpu := int64(stwprocs) * (tEnd - tMarkTerm)
+		cycleCpu := sweepTermCpu + scanCpu + installWBCpu + markCpu + markTermCpu
+		work.totaltime += cycleCpu
+
+		// Compute overall utilization
+		totalCpu := sched.totaltime + (tEnd-sched.procresizetime)*int64(gomaxprocs)
+		util := work.totaltime * 100 / totalCpu
+
+		var sbuf [24]byte
+		printlock()
+		print("gc #", memstats.numgc,
+			" @", string(itoaDiv(sbuf[:], uint64(tEnd-runtimeInitTime)/1e6, 3)), "s ",
+			util, "%: ",
+			(tScan-tSweepTerm)/1e6,
+			"+", (tInstallWB-tScan)/1e6,
+			"+", (tMark-tInstallWB)/1e6,
+			"+", (tMarkTerm-tMark)/1e6,
+			"+", (tEnd-tMarkTerm)/1e6, " ms clock, ",
+			sweepTermCpu/1e6,
+			"+", scanCpu/1e6,
+			"+", installWBCpu/1e6,
+			"+", gcController.assistTime/1e6,
+			"/", (gcController.dedicatedMarkTime+gcController.fractionalMarkTime)/1e6,
+			"/", gcController.idleMarkTime/1e6,
+			"+", markTermCpu/1e6, " ms cpu, ",
+			heap0>>20, "->", heap1>>20, "->", heap2>>20, " MB, ",
+			heapGoal>>20, " MB goal, ",
+			maxprocs, " P")
+		if mode != gcBackgroundMode {
+			print(" (forced)")
+		}
+		print("\n")
+		printunlock()
+	}
+	sweep.nbgsweep = 0
+	sweep.npausesweep = 0
+
 	// now that gc is done, kick off finalizer thread if needed
 	if !concurrentSweep {
 		// give the queued finalizers, if any, a chance to run
@@ -444,6 +1018,159 @@
 	}
 }
 
+// gcBgMarkStartWorkers prepares background mark worker goroutines.
+// These goroutines will not run until the mark phase, but they must
+// be started while the work is not stopped and from a regular G
+// stack. The caller must hold worldsema.
+func gcBgMarkStartWorkers() {
+	// Background marking is performed by per-P G's. Ensure that
+	// each P has a background GC G.
+	for _, p := range &allp {
+		if p == nil || p.status == _Pdead {
+			break
+		}
+		if p.gcBgMarkWorker == nil {
+			go gcBgMarkWorker(p)
+			notetsleepg(&work.bgMarkReady, -1)
+			noteclear(&work.bgMarkReady)
+		}
+	}
+}
+
+// gcBgMarkPrepare sets up state for background marking.
+// Mutator assists must not yet be enabled.
+func gcBgMarkPrepare() {
+	// Background marking will stop when the work queues are empty
+	// and there are no more workers (note that, since this is
+	// concurrent, this may be a transient state, but mark
+	// termination will clean it up). Between background workers
+	// and assists, we don't really know how many workers there
+	// will be, so we pretend to have an arbitrarily large number
+	// of workers, almost all of which are "waiting". While a
+	// worker is working it decrements nwait. If nproc == nwait,
+	// there are no workers.
+	work.nproc = ^uint32(0)
+	work.nwait = ^uint32(0)
+
+	// Background GC and assists race to set this to 1 on
+	// completion so that this only gets one "done" signal.
+	work.bgMarkDone = 0
+
+	gcController.bgMarkStartTime = nanotime()
+}
+
+func gcBgMarkWorker(p *p) {
+	// Register this G as the background mark worker for p.
+	if p.gcBgMarkWorker != nil {
+		throw("P already has a background mark worker")
+	}
+	gp := getg()
+
+	mp := acquirem()
+	p.gcBgMarkWorker = gp
+	// After this point, the background mark worker is scheduled
+	// cooperatively by gcController.findRunnable. Hence, it must
+	// never be preempted, as this would put it into _Grunnable
+	// and put it on a run queue. Instead, when the preempt flag
+	// is set, this puts itself into _Gwaiting to be woken up by
+	// gcController.findRunnable at the appropriate time.
+	notewakeup(&work.bgMarkReady)
+	for {
+		// Go to sleep until woken by gcContoller.findRunnable.
+		// We can't releasem yet since even the call to gopark
+		// may be preempted.
+		gopark(func(g *g, mp unsafe.Pointer) bool {
+			releasem((*m)(mp))
+			return true
+		}, unsafe.Pointer(mp), "mark worker (idle)", traceEvGoBlock, 0)
+
+		// Loop until the P dies and disassociates this
+		// worker. (The P may later be reused, in which case
+		// it will get a new worker.)
+		if p.gcBgMarkWorker != gp {
+			break
+		}
+
+		// Disable preemption so we can use the gcw. If the
+		// scheduler wants to preempt us, we'll stop draining,
+		// dispose the gcw, and then preempt.
+		mp = acquirem()
+
+		if gcBlackenEnabled == 0 {
+			throw("gcBgMarkWorker: blackening not enabled")
+		}
+
+		startTime := nanotime()
+
+		xadd(&work.nwait, -1)
+
+		done := false
+		switch p.gcMarkWorkerMode {
+		default:
+			throw("gcBgMarkWorker: unexpected gcMarkWorkerMode")
+		case gcMarkWorkerDedicatedMode:
+			gcDrain(&p.gcw, gcBgCreditSlack)
+			// gcDrain did the xadd(&work.nwait +1) to
+			// match the decrement above. It only returns
+			// at a mark completion point.
+			done = true
+		case gcMarkWorkerFractionalMode, gcMarkWorkerIdleMode:
+			gcDrainUntilPreempt(&p.gcw, gcBgCreditSlack)
+			// Was this the last worker and did we run out
+			// of work?
+			done = xadd(&work.nwait, +1) == work.nproc && work.full == 0 && work.partial == 0
+		}
+		// We're not in mark termination, so there's no need
+		// to dispose p.gcw.
+
+		// If this worker reached a background mark completion
+		// point, signal the main GC goroutine.
+		if done {
+			gcBgMarkDone()
+		}
+
+		duration := nanotime() - startTime
+		switch p.gcMarkWorkerMode {
+		case gcMarkWorkerDedicatedMode:
+			xaddint64(&gcController.dedicatedMarkTime, duration)
+		case gcMarkWorkerFractionalMode:
+			xaddint64(&gcController.fractionalMarkTime, duration)
+			xaddint64(&gcController.fractionalMarkWorkersNeeded, 1)
+		case gcMarkWorkerIdleMode:
+			xaddint64(&gcController.idleMarkTime, duration)
+		}
+	}
+}
+
+// gcBgMarkDone signals the completion of background marking. This can
+// be called multiple times during a cycle; only the first call has
+// any effect.
+func gcBgMarkDone() {
+	if cas(&work.bgMarkDone, 0, 1) {
+		// This is the first worker to reach completion.
+		// Signal the main GC goroutine.
+		lock(&work.bgMarkWake.lock)
+		if work.bgMarkWake.g == nil {
+			// It hasn't parked yet.
+			work.bgMarkWake.wake = true
+		} else {
+			ready(work.bgMarkWake.g, 0)
+		}
+		unlock(&work.bgMarkWake.lock)
+	}
+}
+
+// gcFlushGCWork disposes the gcWork caches of all Ps. The world must
+// be stopped.
+//go:nowritebarrier
+func gcFlushGCWork() {
+	// Gather all cached GC work. All other Ps are stopped, so
+	// it's safe to manipulate their GC work caches.
+	for i := 0; i < int(gomaxprocs); i++ {
+		allp[i].gcw.dispose()
+	}
+}
+
 // gcMark runs the mark (or, for concurrent GC, mark termination)
 // STW is in effect at this point.
 //TODO go:nowritebarrier
@@ -457,13 +1184,14 @@
 	}
 	t0 := start_time
 	work.tstart = start_time
-	var t1 int64
-	if debug.gctrace > 0 {
-		t1 = nanotime()
-	}
 
 	gcCopySpans() // TODO(rlh): should this be hoisted and done only once? Right now it is done for normal marking and also for checkmarking.
 
+	// Make sure the per-P gcWork caches are empty. During mark
+	// termination, these caches can still be used temporarily,
+	// but must be disposed to the global lists immediately.
+	gcFlushGCWork()
+
 	work.nwait = 0
 	work.ndone = 0
 	work.nproc = uint32(gcprocs())
@@ -478,16 +1206,11 @@
 		helpgc(int32(work.nproc))
 	}
 
-	var t2 int64
-	if debug.gctrace > 0 {
-		t2 = nanotime()
-	}
-
-	harvestwbufs() // move local workbufs onto global queues where the GC can find them
 	gchelperstart()
 	parfordo(work.markfor)
+
 	var gcw gcWork
-	gcDrain(&gcw)
+	gcDrain(&gcw, -1)
 	gcw.dispose()
 
 	if work.full != 0 {
@@ -497,15 +1220,16 @@
 		throw("work.partial != 0")
 	}
 
-	var t3 int64
-	if debug.gctrace > 0 {
-		t3 = nanotime()
-	}
-
 	if work.nproc > 1 {
 		notesleep(&work.alldone)
 	}
 
+	for i := 0; i < int(gomaxprocs); i++ {
+		if allp[i].gcw.wbuf != 0 {
+			throw("P has cached GC work at end of mark termination")
+		}
+	}
+
 	if trace.enabled {
 		traceGCScanDone()
 	}
@@ -513,17 +1237,44 @@
 	shrinkfinish()
 
 	cachestats()
-	// next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
-	// estimate what was live heap size after previous GC (for printing only)
-	heap0 := memstats.next_gc * 100 / (uint64(gcpercent) + 100)
-	// conservatively set next_gc to high value assuming that everything is live
-	// concurrent/lazy sweep will reduce this number while discovering new garbage
-	memstats.next_gc = memstats.heap_alloc + memstats.heap_alloc*uint64(gcpercent)/100
+
+	// Compute the reachable heap size at the beginning of the
+	// cycle. This is approximately the marked heap size at the
+	// end (which we know) minus the amount of marked heap that
+	// was allocated after marking began (which we don't know, but
+	// is approximately the amount of heap that was allocated
+	// since marking began).
+	allocatedDuringCycle := memstats.heap_live - work.initialHeapLive
+	if work.bytesMarked >= allocatedDuringCycle {
+		memstats.heap_reachable = work.bytesMarked - allocatedDuringCycle
+	} else {
+		// This can happen if most of the allocation during
+		// the cycle never became reachable from the heap.
+		// Just set the reachable heap appropriation to 0 and
+		// let the heapminimum kick in below.
+		memstats.heap_reachable = 0
+	}
+
+	// Trigger the next GC cycle when the allocated heap has grown
+	// by triggerRatio over the reachable heap size. Assume that
+	// we're in steady state, so the reachable heap size is the
+	// same now as it was at the beginning of the GC cycle.
+	memstats.next_gc = uint64(float64(memstats.heap_reachable) * (1 + gcController.triggerRatio))
 	if memstats.next_gc < heapminimum {
 		memstats.next_gc = heapminimum
 	}
+	if int64(memstats.next_gc) < 0 {
+		print("next_gc=", memstats.next_gc, " bytesMarked=", work.bytesMarked, " heap_live=", memstats.heap_live, " initialHeapLive=", work.initialHeapLive, "\n")
+		throw("next_gc underflow")
+	}
+
+	// Update other GC heap size stats.
+	memstats.heap_live = work.bytesMarked
+	memstats.heap_marked = work.bytesMarked
+	memstats.heap_scan = uint64(gcController.scanWork)
 
 	if trace.enabled {
+		traceHeapAlloc()
 		traceNextGC()
 	}
 
@@ -532,37 +1283,6 @@
 	memstats.pause_ns[memstats.numgc%uint32(len(memstats.pause_ns))] = uint64(t4 - t0)
 	memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(t4)
 	memstats.pause_total_ns += uint64(t4 - t0)
-	memstats.numgc++
-	if memstats.debuggc {
-		print("pause ", t4-t0, "\n")
-	}
-
-	if debug.gctrace > 0 {
-		heap1 := memstats.heap_alloc
-		var stats gcstats
-		updatememstats(&stats)
-		if heap1 != memstats.heap_alloc {
-			print("runtime: mstats skew: heap=", heap1, "/", memstats.heap_alloc, "\n")
-			throw("mstats skew")
-		}
-		obj := memstats.nmalloc - memstats.nfree
-
-		stats.nprocyield += work.markfor.nprocyield
-		stats.nosyield += work.markfor.nosyield
-		stats.nsleep += work.markfor.nsleep
-
-		print("gc", memstats.numgc, "(", work.nproc, "): ",
-			(t1-t0)/1000, "+", (t2-t1)/1000, "+", (t3-t2)/1000, "+", (t4-t3)/1000, " us, ",
-			heap0>>20, " -> ", heap1>>20, " MB, ",
-			obj, " (", memstats.nmalloc, "-", memstats.nfree, ") objects, ",
-			gcount(), " goroutines, ",
-			len(work.spans), "/", sweep.nbgsweep, "/", sweep.npausesweep, " sweeps, ",
-			stats.nhandoff, "(", stats.nhandoffcnt, ") handoff, ",
-			work.markfor.nsteal, "(", work.markfor.nstealcnt, ") steal, ",
-			stats.nprocyield, "/", stats.nosyield, "/", stats.nsleep, " yields\n")
-		sweep.nbgsweep = 0
-		sweep.npausesweep = 0
-	}
 }
 
 func gcSweep(mode int) {
@@ -579,6 +1299,11 @@
 
 	if !_ConcurrentSweep || mode == gcForceBlockMode {
 		// Special case synchronous sweep.
+		// Record that no proportional sweeping has to happen.
+		lock(&mheap_.lock)
+		mheap_.sweepPagesPerByte = 0
+		mheap_.pagesSwept = 0
+		unlock(&mheap_.lock)
 		// Sweep all spans eagerly.
 		for sweepone() != ^uintptr(0) {
 			sweep.npausesweep++
@@ -589,6 +1314,27 @@
 		return
 	}
 
+	// Account how much sweeping needs to be done before the next
+	// GC cycle and set up proportional sweep statistics.
+	var pagesToSweep uintptr
+	for _, s := range work.spans {
+		if s.state == mSpanInUse {
+			pagesToSweep += s.npages
+		}
+	}
+	heapDistance := int64(memstats.next_gc) - int64(memstats.heap_live)
+	// Add a little margin so rounding errors and concurrent
+	// sweep are less likely to leave pages unswept when GC starts.
+	heapDistance -= 1024 * 1024
+	if heapDistance < _PageSize {
+		// Avoid setting the sweep ratio extremely high
+		heapDistance = _PageSize
+	}
+	lock(&mheap_.lock)
+	mheap_.sweepPagesPerByte = float64(pagesToSweep) / float64(heapDistance)
+	mheap_.pagesSwept = 0
+	unlock(&mheap_.lock)
+
 	// Background sweep.
 	lock(&sweep.lock)
 	if sweep.parked {
@@ -627,6 +1373,8 @@
 	for _, gp := range allgs {
 		gp.gcworkdone = false  // set to true in gcphasework
 		gp.gcscanvalid = false // stack has not been scanned
+		gp.gcalloc = 0
+		gp.gcscanwork = 0
 	}
 	numgs = len(allgs)
 	unlock(&allglock)
@@ -704,7 +1452,7 @@
 	parfordo(work.markfor)
 	if gcphase != _GCscan {
 		var gcw gcWork
-		gcDrain(&gcw) // blocks in getfull
+		gcDrain(&gcw, -1) // blocks in getfull
 		gcw.dispose()
 	}
 
@@ -730,106 +1478,19 @@
 	}
 }
 
-// gcchronograph holds timer information related to GC phases
-// max records the maximum time spent in each GC phase since GCstarttimes.
-// total records the total time spent in each GC phase since GCstarttimes.
-// cycle records the absolute time (as returned by nanoseconds()) that each GC phase last started at.
-type gcchronograph struct {
-	count    int64
-	verbose  int64
-	maxpause int64
-	max      gctimes
-	total    gctimes
-	cycle    gctimes
-}
-
-// gctimes records the time in nanoseconds of each phase of the concurrent GC.
-type gctimes struct {
-	sweepterm     int64 // stw
-	scan          int64
-	installmarkwb int64 // stw
-	mark          int64
-	markterm      int64 // stw
-	sweep         int64
-}
-
-var gctimer gcchronograph
-
-// GCstarttimes initializes the gc times. All previous times are lost.
-func GCstarttimes(verbose int64) {
-	gctimer = gcchronograph{verbose: verbose}
-}
-
-// GCendtimes stops the gc timers.
-func GCendtimes() {
-	gctimer.verbose = 0
-}
-
-// calctimes converts gctimer.cycle into the elapsed times, updates gctimer.total
-// and updates gctimer.max with the max pause time.
-func calctimes() gctimes {
-	var times gctimes
-
-	var max = func(a, b int64) int64 {
-		if a > b {
-			return a
+// itoaDiv formats val/(10**dec) into buf.
+func itoaDiv(buf []byte, val uint64, dec int) []byte {
+	i := len(buf) - 1
+	idec := i - dec
+	for val >= 10 || i >= idec {
+		buf[i] = byte(val%10 + '0')
+		i--
+		if i == idec {
+			buf[i] = '.'
+			i--
 		}
-		return b
+		val /= 10
 	}
-
-	times.sweepterm = gctimer.cycle.scan - gctimer.cycle.sweepterm
-	gctimer.total.sweepterm += times.sweepterm
-	gctimer.max.sweepterm = max(gctimer.max.sweepterm, times.sweepterm)
-	gctimer.maxpause = max(gctimer.maxpause, gctimer.max.sweepterm)
-
-	times.scan = gctimer.cycle.installmarkwb - gctimer.cycle.scan
-	gctimer.total.scan += times.scan
-	gctimer.max.scan = max(gctimer.max.scan, times.scan)
-
-	times.installmarkwb = gctimer.cycle.mark - gctimer.cycle.installmarkwb
-	gctimer.total.installmarkwb += times.installmarkwb
-	gctimer.max.installmarkwb = max(gctimer.max.installmarkwb, times.installmarkwb)
-	gctimer.maxpause = max(gctimer.maxpause, gctimer.max.installmarkwb)
-
-	times.mark = gctimer.cycle.markterm - gctimer.cycle.mark
-	gctimer.total.mark += times.mark
-	gctimer.max.mark = max(gctimer.max.mark, times.mark)
-
-	times.markterm = gctimer.cycle.sweep - gctimer.cycle.markterm
-	gctimer.total.markterm += times.markterm
-	gctimer.max.markterm = max(gctimer.max.markterm, times.markterm)
-	gctimer.maxpause = max(gctimer.maxpause, gctimer.max.markterm)
-
-	return times
-}
-
-// GCprinttimes prints latency information in nanoseconds about various
-// phases in the GC. The information for each phase includes the maximum pause
-// and total time since the most recent call to GCstarttimes as well as
-// the information from the most recent Concurent GC cycle. Calls from the
-// application to runtime.GC() are ignored.
-func GCprinttimes() {
-	if gctimer.verbose == 0 {
-		println("GC timers not enabled")
-		return
-	}
-
-	// Explicitly put times on the heap so printPhase can use it.
-	times := new(gctimes)
-	*times = calctimes()
-	cycletime := gctimer.cycle.sweep - gctimer.cycle.sweepterm
-	pause := times.sweepterm + times.installmarkwb + times.markterm
-	gomaxprocs := GOMAXPROCS(-1)
-
-	printlock()
-	print("GC: #", gctimer.count, " ", cycletime, "ns @", gctimer.cycle.sweepterm, " pause=", pause, " maxpause=", gctimer.maxpause, " goroutines=", allglen, " gomaxprocs=", gomaxprocs, "\n")
-	printPhase := func(label string, get func(*gctimes) int64, procs int) {
-		print("GC:     ", label, " ", get(times), "ns\tmax=", get(&gctimer.max), "\ttotal=", get(&gctimer.total), "\tprocs=", procs, "\n")
-	}
-	printPhase("sweep term:", func(t *gctimes) int64 { return t.sweepterm }, gomaxprocs)
-	printPhase("scan:      ", func(t *gctimes) int64 { return t.scan }, 1)
-	printPhase("install wb:", func(t *gctimes) int64 { return t.installmarkwb }, gomaxprocs)
-	printPhase("mark:      ", func(t *gctimes) int64 { return t.mark }, 1)
-	printPhase("mark term: ", func(t *gctimes) int64 { return t.markterm }, gomaxprocs)
-	printunlock()
+	buf[i] = byte(val + '0')
+	return buf[i:]
 }
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 3a9679e..9d78dde 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -51,19 +51,24 @@
 }
 
 // ptrmask for an allocation containing a single pointer.
-var oneptr = [...]uint8{typePointer}
+var oneptrmask = [...]uint8{1}
 
 //go:nowritebarrier
 func markroot(desc *parfor, i uint32) {
+	// TODO: Consider using getg().m.p.ptr().gcw.
 	var gcw gcWork
 
 	// Note: if you add a case here, please also update heapdump.go:dumproots.
 	switch i {
 	case _RootData:
-		scanblock(themoduledata.data, themoduledata.edata-themoduledata.data, gcdatamask.bytedata, &gcw)
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			scanblock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, &gcw)
+		}
 
 	case _RootBss:
-		scanblock(themoduledata.bss, themoduledata.ebss-themoduledata.bss, gcbssmask.bytedata, &gcw)
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			scanblock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, &gcw)
+		}
 
 	case _RootFinalizers:
 		for fb := allfin; fb != nil; fb = fb.alllink {
@@ -93,9 +98,9 @@
 				// A finalizer can be set for an inner byte of an object, find object beginning.
 				p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize
 				if gcphase != _GCscan {
-					scanblock(p, s.elemsize, nil, &gcw) // scanned during mark phase
+					scanobject(p, &gcw) // scanned during mark termination
 				}
-				scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0], &gcw)
+				scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptrmask[0], &gcw)
 			}
 		}
 
@@ -155,40 +160,98 @@
 			restartg(gp)
 		}
 	}
+
 	gcw.dispose()
 }
 
-// gchelpwork does a small bounded amount of gc work. The purpose is to
-// shorten the time (as measured by allocations) spent doing a concurrent GC.
-// The number of mutator calls is roughly propotional to the number of allocations
-// made by that mutator. This slows down the allocation while speeding up the GC.
+// gcAssistAlloc records and allocation of size bytes and, if
+// allowAssist is true, may assist GC scanning in proportion to the
+// allocations performed by this mutator since the last assist.
+//
+// It should only be called if gcAssistAlloc != 0.
+//
+// This must be called with preemption disabled.
 //go:nowritebarrier
-func gchelpwork() {
-	switch gcphase {
-	default:
-		throw("gcphasework in bad gcphase")
-	case _GCoff, _GCquiesce, _GCstw:
-		// No work.
-	case _GCsweep:
-		// We could help by calling sweepone to sweep a single span.
-		// _ = sweepone()
-	case _GCscan:
-		// scan the stack, mark the objects, put pointers in work buffers
-		// hanging off the P where this is being run.
-		// scanstack(gp)
-	case _GCmark:
-		// drain your own currentwbuf first in the hopes that it will
-		// be more cache friendly.
-		var gcw gcWork
-		gcw.initFromCache()
-		const n = len(workbuf{}.obj)
-		gcDrainN(&gcw, n) // drain upto one buffer's worth of objects
-		gcw.dispose()
-	case _GCmarktermination:
-		// We should never be here since the world is stopped.
-		// All available mark work will be emptied before returning.
-		throw("gcphasework in bad gcphase")
+func gcAssistAlloc(size uintptr, allowAssist bool) {
+	// Find the G responsible for this assist.
+	gp := getg()
+	if gp.m.curg != nil {
+		gp = gp.m.curg
 	}
+
+	// Record allocation.
+	gp.gcalloc += size
+
+	if !allowAssist {
+		return
+	}
+
+	// Compute the amount of assist scan work we need to do.
+	scanWork := int64(gcController.assistRatio*float64(gp.gcalloc)) - gp.gcscanwork
+	// scanWork can be negative if the last assist scanned a large
+	// object and we're still ahead of our assist goal.
+	if scanWork <= 0 {
+		return
+	}
+
+	// Steal as much credit as we can from the background GC's
+	// scan credit. This is racy and may drop the background
+	// credit below 0 if two mutators steal at the same time. This
+	// will just cause steals to fail until credit is accumulated
+	// again, so in the long run it doesn't really matter, but we
+	// do have to handle the negative credit case.
+	bgScanCredit := atomicloadint64(&gcController.bgScanCredit)
+	stolen := int64(0)
+	if bgScanCredit > 0 {
+		if bgScanCredit < scanWork {
+			stolen = bgScanCredit
+		} else {
+			stolen = scanWork
+		}
+		xaddint64(&gcController.bgScanCredit, -scanWork)
+
+		scanWork -= stolen
+		gp.gcscanwork += stolen
+
+		if scanWork == 0 {
+			return
+		}
+	}
+
+	// Perform assist work
+	systemstack(func() {
+		// Track time spent in this assist. Since we're on the
+		// system stack, this is non-preemptible, so we can
+		// just measure start and end time.
+		startTime := nanotime()
+
+		xadd(&work.nwait, -1)
+
+		// drain own cached work first in the hopes that it
+		// will be more cache friendly.
+		gcw := &getg().m.p.ptr().gcw
+		startScanWork := gcw.scanWork
+		gcDrainN(gcw, scanWork)
+		// Record that we did this much scan work.
+		gp.gcscanwork += gcw.scanWork - startScanWork
+		// No need to dispose since we're not in mark termination.
+
+		// If this is the last worker and we ran out of work,
+		// signal a completion point.
+		if xadd(&work.nwait, +1) == work.nproc && work.full == 0 && work.partial == 0 {
+			// This has reached a background completion
+			// point.
+			gcBgMarkDone()
+		}
+
+		duration := nanotime() - startTime
+		_p_ := gp.m.p.ptr()
+		_p_.gcAssistTime += duration
+		if _p_.gcAssistTime > gcAssistTimeSlack {
+			xaddint64(&gcController.assistTime, _p_.gcAssistTime)
+			_p_.gcAssistTime = 0
+		}
+	})
 }
 
 // The gp has been moved to a GC safepoint. GC phase specific
@@ -246,17 +309,18 @@
 		throw("can't scan gchelper stack")
 	}
 
-	var gcw gcWork
-	gcw.initFromCache()
+	gcw := &getg().m.p.ptr().gcw
 	scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
 		// Pick up gcw as free variable so gentraceback and friends can
 		// keep the same signature.
-		scanframeworker(frame, unused, &gcw)
+		scanframeworker(frame, unused, gcw)
 		return true
 	}
 	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
 	tracebackdefers(gp, scanframe, nil)
-	gcw.disposeToCache()
+	if gcphase == _GCmarktermination {
+		gcw.dispose()
+	}
 	gp.gcscanvalid = true
 }
 
@@ -309,7 +373,7 @@
 			throw("scanframe: bad symbol table")
 		}
 		bv := stackmapdata(stkmap, pcdata)
-		size = (uintptr(bv.n) / typeBitsWidth) * ptrSize
+		size = uintptr(bv.n) * ptrSize
 		scanblock(frame.varp-size, size, bv.bytedata, gcw)
 	}
 
@@ -331,18 +395,31 @@
 			}
 			bv = stackmapdata(stkmap, pcdata)
 		}
-		scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata, gcw)
+		scanblock(frame.argp, uintptr(bv.n)*ptrSize, bv.bytedata, gcw)
 	}
 }
 
+// TODO(austin): Can we consolidate the gcDrain* functions?
+
 // gcDrain scans objects in work buffers, blackening grey
 // objects until all work buffers have been drained.
+// If flushScanCredit != -1, gcDrain flushes accumulated scan work
+// credit to gcController.bgScanCredit whenever gcw's local scan work
+// credit exceeds flushScanCredit.
 //go:nowritebarrier
-func gcDrain(gcw *gcWork) {
+func gcDrain(gcw *gcWork, flushScanCredit int64) {
 	if gcphase != _GCmark && gcphase != _GCmarktermination {
 		throw("scanblock phase incorrect")
 	}
 
+	var lastScanFlush, nextScanFlush int64
+	if flushScanCredit != -1 {
+		lastScanFlush = gcw.scanWork
+		nextScanFlush = lastScanFlush + flushScanCredit
+	} else {
+		nextScanFlush = int64(^uint64(0) >> 1)
+	}
+
 	for {
 		// If another proc wants a pointer, give it some.
 		if work.nwait > 0 && work.full == 0 {
@@ -360,16 +437,85 @@
 		// out of the wbuf passed in + a single object placed
 		// into an empty wbuf in scanobject so there could be
 		// a performance hit as we keep fetching fresh wbufs.
-		scanobject(b, 0, nil, gcw)
+		scanobject(b, gcw)
+
+		// Flush background scan work credit to the global
+		// account if we've accumulated enough locally so
+		// mutator assists can draw on it.
+		if gcw.scanWork >= nextScanFlush {
+			credit := gcw.scanWork - lastScanFlush
+			xaddint64(&gcController.bgScanCredit, credit)
+			lastScanFlush = gcw.scanWork
+			nextScanFlush = lastScanFlush + flushScanCredit
+		}
 	}
-	checknocurrentwbuf()
+	if flushScanCredit != -1 {
+		credit := gcw.scanWork - lastScanFlush
+		xaddint64(&gcController.bgScanCredit, credit)
+	}
 }
 
-// gcDrainN scans n objects, blackening grey objects.
+// gcDrainUntilPreempt blackens grey objects until g.preempt is set.
+// This is best-effort, so it will return as soon as it is unable to
+// get work, even though there may be more work in the system.
 //go:nowritebarrier
-func gcDrainN(gcw *gcWork, n int) {
-	checknocurrentwbuf()
-	for i := 0; i < n; i++ {
+func gcDrainUntilPreempt(gcw *gcWork, flushScanCredit int64) {
+	if gcphase != _GCmark {
+		println("gcphase =", gcphase)
+		throw("gcDrainUntilPreempt phase incorrect")
+	}
+
+	var lastScanFlush, nextScanFlush int64
+	if flushScanCredit != -1 {
+		lastScanFlush = gcw.scanWork
+		nextScanFlush = lastScanFlush + flushScanCredit
+	} else {
+		nextScanFlush = int64(^uint64(0) >> 1)
+	}
+
+	gp := getg()
+	for !gp.preempt {
+		// If the work queue is empty, balance. During
+		// concurrent mark we don't really know if anyone else
+		// can make use of this work, but even if we're the
+		// only worker, the total cost of this per cycle is
+		// only O(_WorkbufSize) pointer copies.
+		if work.full == 0 && work.partial == 0 {
+			gcw.balance()
+		}
+
+		b := gcw.tryGet()
+		if b == 0 {
+			// No more work
+			break
+		}
+		scanobject(b, gcw)
+
+		// Flush background scan work credit to the global
+		// account if we've accumulated enough locally so
+		// mutator assists can draw on it.
+		if gcw.scanWork >= nextScanFlush {
+			credit := gcw.scanWork - lastScanFlush
+			xaddint64(&gcController.bgScanCredit, credit)
+			lastScanFlush = gcw.scanWork
+			nextScanFlush = lastScanFlush + flushScanCredit
+		}
+	}
+	if flushScanCredit != -1 {
+		credit := gcw.scanWork - lastScanFlush
+		xaddint64(&gcController.bgScanCredit, credit)
+	}
+}
+
+// gcDrainN blackens grey objects until it has performed roughly
+// scanWork units of scan work. This is best-effort, so it may perform
+// less work if it fails to get a work buffer. Otherwise, it will
+// perform at least n units of work, but may perform more because
+// scanning is always done in whole object increments.
+//go:nowritebarrier
+func gcDrainN(gcw *gcWork, scanWork int64) {
+	targetScanWork := gcw.scanWork + scanWork
+	for gcw.scanWork < targetScanWork {
 		// This might be a good place to add prefetch code...
 		// if(wbuf.nobj > 4) {
 		//         PREFETCH(wbuf->obj[wbuf.nobj - 3];
@@ -378,12 +524,16 @@
 		if b == 0 {
 			return
 		}
-		scanobject(b, 0, nil, gcw)
+		scanobject(b, gcw)
 	}
 }
 
-// scanblock scans b as scanobject would.
-// If the gcphase is GCscan, scanblock performs additional checks.
+// scanblock scans b as scanobject would, but using an explicit
+// pointer bitmap instead of the heap bitmap.
+//
+// This is used to scan non-heap roots, so it does not update
+// gcw.bytesMarked or gcw.scanWork.
+//
 //go:nowritebarrier
 func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
 	// Use local copies of original parameters, so that a stack trace
@@ -392,127 +542,118 @@
 	b := b0
 	n := n0
 
-	// ptrmask can have 2 possible values:
-	// 1. nil - obtain pointer mask from GC bitmap.
-	// 2. pointer to a compact mask (for stacks and data).
+	arena_start := mheap_.arena_start
+	arena_used := mheap_.arena_used
 
-	scanobject(b, n, ptrmask, gcw)
-	if gcphase == _GCscan {
-		if inheap(b) && ptrmask == nil {
-			// b is in heap, we are in GCscan so there should be a ptrmask.
-			throw("scanblock: In GCscan phase and inheap is true.")
+	for i := uintptr(0); i < n; {
+		// Find bits for the next word.
+		bits := uint32(*addb(ptrmask, i/(ptrSize*8)))
+		if bits == 0 {
+			i += ptrSize * 8
+			continue
+		}
+		for j := 0; j < 8 && i < n; j++ {
+			if bits&1 != 0 {
+				// 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)
+					}
+				}
+			}
+			bits >>= 1
+			i += ptrSize
 		}
 	}
 }
 
-// Scan the object b of size n bytes, adding pointers to wbuf.
-// If ptrmask != nil, it specifies where pointers are in b.
-// If ptrmask == nil, the GC bitmap should be consulted.
-// In this case, n may be an overestimate of the size; the GC bitmap
-// must also be used to make sure the scan stops at the end of b.
+// scanobject scans the object starting at b, adding pointers to gcw.
+// b must point to the beginning of a heap object; scanobject consults
+// the GC bitmap for the pointer mask and the spans for the size of the
+// object (it ignores n).
 //go:nowritebarrier
-func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWork) {
+func scanobject(b uintptr, gcw *gcWork) {
 	arena_start := mheap_.arena_start
 	arena_used := mheap_.arena_used
 
 	// Find bits of the beginning of the object.
-	var hbits heapBits
-
-	if ptrmask == nil {
-		var s *mspan
-		b, hbits, s = heapBitsForObject(b)
-		if b == 0 {
-			return
-		}
-		n = s.elemsize
-		if n == 0 {
-			throw("scanobject n == 0")
-		}
+	// b must point to the beginning of a heap object, so
+	// we can get its bits and span directly.
+	hbits := heapBitsForAddr(b)
+	s := spanOfUnchecked(b)
+	n := s.elemsize
+	if n == 0 {
+		throw("scanobject n == 0")
 	}
-	for i := uintptr(0); i < n; i += ptrSize {
+
+	var i uintptr
+	for i = 0; i < n; i += ptrSize {
 		// Find bits for this word.
-		var bits uintptr
-		if ptrmask != nil {
-			// dense mask (stack or data)
-			bits = (uintptr(*(*byte)(add(unsafe.Pointer(ptrmask), (i/ptrSize)/4))) >> (((i / ptrSize) % 4) * typeBitsWidth)) & typeMask
-		} else {
-			bits = uintptr(hbits.typeBits())
-			if bits == typeDead {
-				break // no more pointers in this object
-			}
+		if i != 0 {
+			// Avoid needless hbits.next() on last iteration.
 			hbits = hbits.next()
 		}
+		bits := uintptr(hbits.typeBits())
+		if bits == typeDead {
+			break // no more pointers in this object
+		}
 
 		if bits <= typeScalar { // typeScalar, typeDead, typeScalarMarked
 			continue
 		}
 
 		if bits&typePointer != typePointer {
-			print("gc useCheckmark=", useCheckmark, " b=", hex(b), " ptrmask=", ptrmask, "\n")
+			print("gc useCheckmark=", useCheckmark, " b=", hex(b), "\n")
 			throw("unexpected garbage collection bits")
 		}
 
+		// Work here is duplicated in scanblock.
+		// 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 || obj < arena_start || obj >= arena_used {
-			continue
-		}
+		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 mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && useCheckmark {
-			checkwbshadow((*uintptr)(unsafe.Pointer(b + i)))
-		}
-
-		// Mark the object.
-		if obj, hbits, _ := heapBitsForObject(obj); obj != 0 {
-			greyobject(obj, b, i, hbits, gcw)
+			// Mark the object.
+			if obj, hbits, span := heapBitsForObject(obj); obj != 0 {
+				greyobject(obj, b, i, hbits, span, gcw)
+			}
 		}
 	}
+	gcw.bytesMarked += uint64(n)
+	gcw.scanWork += int64(i)
 }
 
 // Shade the object if it isn't already.
 // The object is not nil and known to be in the heap.
+// Preemption must be disabled.
 //go:nowritebarrier
 func shade(b uintptr) {
-	if !inheap(b) {
-		throw("shade: passed an address not in the heap")
-	}
-	if obj, hbits, _ := heapBitsForObject(b); obj != 0 {
-		// TODO: this would be a great place to put a check to see
-		// if we are harvesting and if we are then we should
-		// figure out why there is a call to shade when the
-		// harvester thinks we are in a STW.
-		// if atomicload(&harvestingwbufs) == uint32(1) {
-		//	// Throw here to discover write barriers
-		//	// being executed during a STW.
-		//	throw("shade during harvest")
-		// }
-
-		var gcw gcWork
-		greyobject(obj, 0, 0, hbits, &gcw)
-		// This is part of the write barrier so put the wbuf back.
+	if obj, hbits, span := heapBitsForObject(b); obj != 0 {
+		gcw := &getg().m.p.ptr().gcw
+		greyobject(obj, 0, 0, hbits, span, gcw)
 		if gcphase == _GCmarktermination {
+			// Ps aren't allowed to cache work during mark
+			// termination.
 			gcw.dispose()
-		} else {
-			// If we added any pointers to the gcw, then
-			// currentwbuf must be nil because 1)
-			// greyobject got its wbuf from currentwbuf
-			// and 2) shade runs on the systemstack, so
-			// we're still on the same M.  If either of
-			// these becomes no longer true, we need to
-			// rethink this.
-			gcw.disposeToCache()
 		}
 	}
 }
 
 // obj is the start of an object with mark mbits.
-// If it isn't already marked, mark it and enqueue into workbuf.
-// Return possibly new workbuf to use.
+// If it isn't already marked, mark it and enqueue into gcw.
 // base and off are for debugging only and could be removed.
 //go:nowritebarrier
-func greyobject(obj, base, off uintptr, hbits heapBits, gcw *gcWork) {
+func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork) {
 	// obj should be start of allocation, and so must be at least pointer-aligned.
 	if obj&(ptrSize-1) != 0 {
 		throw("greyobject: obj not pointer-aligned")
@@ -532,7 +673,7 @@
 
 			throw("checkmark found unmarked object")
 		}
-		if !hbits.isCheckmarked() {
+		if hbits.isCheckmarked() {
 			return
 		}
 		hbits.setCheckmarked()
@@ -550,6 +691,7 @@
 		// If this is a noscan object, fast-track it to black
 		// instead of greying it.
 		if hbits.typeBits() == typeDead {
+			gcw.bytesMarked += uint64(span.elemsize)
 			return
 		}
 	}
@@ -567,6 +709,10 @@
 // gcDumpObject dumps the contents of obj for debugging and marks the
 // field at byte offset off in obj.
 func gcDumpObject(label string, obj, off uintptr) {
+	if obj < mheap_.arena_start || obj >= mheap_.arena_used {
+		print(label, "=", hex(obj), " is not a heap object\n")
+		return
+	}
 	k := obj >> _PageShift
 	x := k
 	x -= mheap_.arena_start >> _PageShift
@@ -588,7 +734,7 @@
 
 // When in GCmarkterminate phase we allocate black.
 //go:nowritebarrier
-func gcmarknewobject_m(obj uintptr) {
+func gcmarknewobject_m(obj, size uintptr) {
 	if gcphase != _GCmarktermination {
 		throw("marking new object while not in mark termination phase")
 	}
@@ -597,6 +743,7 @@
 	}
 
 	heapBitsForAddr(obj).setMarked()
+	xadd64(&work.bytesMarked, int64(size))
 }
 
 // Checkmarking
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index d72ef3a..02e0ece 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -165,6 +165,8 @@
 		traceGCSweepStart()
 	}
 
+	xadd64(&mheap_.pagesSwept, int64(s.npages))
+
 	cl := s.sizeclass
 	size := s.elemsize
 	res := false
@@ -253,12 +255,6 @@
 			}
 			c.local_nlargefree++
 			c.local_largefree += size
-			reduction := int64(size) * int64(gcpercent+100) / 100
-			if int64(memstats.next_gc)-reduction > int64(heapminimum) {
-				xadd64(&memstats.next_gc, -reduction)
-			} else {
-				atomicstore64(&memstats.next_gc, heapminimum)
-			}
 			res = true
 		} else {
 			// Free small object.
@@ -294,19 +290,11 @@
 	}
 	if nfree > 0 {
 		c.local_nsmallfree[cl] += uintptr(nfree)
-		c.local_cachealloc -= intptr(uintptr(nfree) * size)
-		reduction := int64(nfree) * int64(size) * int64(gcpercent+100) / 100
-		if int64(memstats.next_gc)-reduction > int64(heapminimum) {
-			xadd64(&memstats.next_gc, -reduction)
-		} else {
-			atomicstore64(&memstats.next_gc, heapminimum)
-		}
 		res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head, end, preserve)
 		// MCentral_FreeSpan updates sweepgen
 	}
 	if trace.enabled {
 		traceGCSweepDone()
-		traceNextGC()
 	}
 	return res
 }
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
index f69d6bb6..9c32ae8 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -38,7 +38,7 @@
 // A gcWork provides the interface to produce and consume work for the
 // garbage collector.
 //
-// The usual pattern for using gcWork is:
+// A gcWork can be used on the stack as follows:
 //
 //     var gcw gcWork
 //     disable preemption
@@ -46,6 +46,15 @@
 //     gcw.dispose()
 //     enable preemption
 //
+// Or from the per-P gcWork cache:
+//
+//     (preemption must be disabled)
+//     gcw := &getg().m.p.ptr().gcw
+//     .. call gcw.put() to produce and gcw.get() to consume ..
+//     if gcphase == _GCmarktermination {
+//         gcw.dispose()
+//     }
+//
 // It's important that any use of gcWork during the mark phase prevent
 // the garbage collector from transitioning to mark termination since
 // gcWork may locally hold GC work buffers. This can be done by
@@ -53,20 +62,18 @@
 type gcWork struct {
 	// Invariant: wbuf is never full or empty
 	wbuf wbufptr
-}
 
-// initFromCache fetches work from this M's currentwbuf cache.
-//go:nowritebarrier
-func (w *gcWork) initFromCache() {
-	// TODO: Instead of making gcWork pull from the currentwbuf
-	// cache, use a gcWork as the cache and make shade pass around
-	// that gcWork.
-	if w.wbuf == 0 {
-		w.wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, 0))
-	}
+	// Bytes marked (blackened) on this gcWork. This is aggregated
+	// into work.bytesMarked by dispose.
+	bytesMarked uint64
+
+	// Scan work performed on this gcWork. This is aggregated into
+	// gcController by dispose.
+	scanWork int64
 }
 
 // put enqueues a pointer for the garbage collector to trace.
+// obj must point to the beginning of a heap object.
 //go:nowritebarrier
 func (ww *gcWork) put(obj uintptr) {
 	w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
@@ -152,18 +159,17 @@
 		putpartial(wbuf.ptr(), 167)
 		w.wbuf = 0
 	}
-}
-
-// disposeToCache returns any cached pointers to this M's currentwbuf.
-// It calls throw if currentwbuf is non-nil.
-//go:nowritebarrier
-func (w *gcWork) disposeToCache() {
-	if wbuf := w.wbuf; wbuf != 0 {
-		wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, uintptr(wbuf)))
-		if wbuf != 0 {
-			throw("m.currentwbuf non-nil in disposeToCache")
-		}
-		w.wbuf = 0
+	if w.bytesMarked != 0 {
+		// dispose happens relatively infrequently. If this
+		// atomic becomes a problem, we should first try to
+		// dispose less and if necessary aggregate in a per-P
+		// counter.
+		xadd64(&work.bytesMarked, int64(w.bytesMarked))
+		w.bytesMarked = 0
+	}
+	if w.scanWork != 0 {
+		xaddint64(&gcController.scanWork, w.scanWork)
+		w.scanWork = 0
 	}
 }
 
@@ -194,7 +200,7 @@
 }
 
 // workbuf factory routines. These funcs are used to manage the
-// workbufs. They cache workbuf in the m struct field currentwbuf.
+// workbufs.
 // If the GC asks for some work these are the only routines that
 // make partially full wbufs available to the GC.
 // Each of the gets and puts also take an distinct integer that is used
@@ -255,13 +261,6 @@
 	}
 }
 
-// checknocurrentwbuf checks that the m's currentwbuf field is empty
-func checknocurrentwbuf() {
-	if getg().m.currentwbuf != 0 {
-		throw("unexpected currentwbuf")
-	}
-}
-
 // getempty pops an empty work buffer off the work.empty list,
 // allocating new buffers if none are available.
 // entry is used to record a brief history of ownership.
@@ -307,21 +306,7 @@
 // indicating that two line numbers in the call chain.
 //go:nowritebarrier
 func getpartialorempty(entry int) *workbuf {
-	var b *workbuf
-	// If this m has a buf in currentwbuf then as an optimization
-	// simply return that buffer. If it turns out currentwbuf
-	// is full, put it on the work.full queue and get another
-	// workbuf off the partial or empty queue.
-	if getg().m.currentwbuf != 0 {
-		b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
-		if b != nil {
-			if b.nobj <= len(b.obj) {
-				return b
-			}
-			putfull(b, entry+80100000)
-		}
-	}
-	b = (*workbuf)(lfstackpop(&work.partial))
+	b := (*workbuf)(lfstackpop(&work.partial))
 	if b != nil {
 		b.logget(entry)
 		return b
@@ -367,21 +352,6 @@
 		b.checknonempty()
 		return b
 	}
-	// full and partial are both empty so see if there
-	// is an work available on currentwbuf.
-	// This is an optimization to shift
-	// processing from the STW marktermination phase into
-	// the concurrent mark phase.
-	if getg().m.currentwbuf != 0 {
-		b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
-		if b != nil {
-			if b.nobj != 0 {
-				return b
-			}
-			putempty(b, 839)
-			b = nil
-		}
-	}
 	return b
 }
 
@@ -410,19 +380,6 @@
 		b.logget(entry)
 		return b
 	}
-	// Make sure that currentwbuf is also not a source for pointers to be
-	// processed. This is an optimization that shifts processing
-	// from the mark termination STW phase to the concurrent mark phase.
-	if getg().m.currentwbuf != 0 {
-		b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
-		if b != nil {
-			if b.nobj != 0 {
-				return b
-			}
-			putempty(b, 877)
-			b = nil
-		}
-	}
 
 	xadd(&work.nwait, +1)
 	for i := 0; ; i++ {
@@ -472,35 +429,3 @@
 	putfull(b, 942)
 	return b1
 }
-
-// 1 when you are harvesting so that the write buffer code shade can
-// detect calls during a presumable STW write barrier.
-var harvestingwbufs uint32
-
-// harvestwbufs moves non-empty workbufs to work.full from  m.currentwuf
-// Must be in a STW phase.
-// xchguintptr is used since there are write barrier calls from the GC helper
-// routines even during a STW phase.
-// TODO: chase down write barrier calls in STW phase and understand and eliminate
-// them.
-//go:nowritebarrier
-func harvestwbufs() {
-	// announce to write buffer that you are harvesting the currentwbufs
-	atomicstore(&harvestingwbufs, 1)
-
-	for mp := allm; mp != nil; mp = mp.alllink {
-		wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&mp.currentwbuf, 0)))
-		// TODO: beat write barriers out of the mark termination and eliminate xchg
-		//		tempwbuf := (*workbuf)(unsafe.Pointer(tempm.currentwbuf))
-		//		tempm.currentwbuf = 0
-		if wbuf != nil {
-			if wbuf.nobj == 0 {
-				putempty(wbuf, 945)
-			} else {
-				putfull(wbuf, 947) //use full instead of partial so GC doesn't compete to get wbuf
-			}
-		}
-	}
-
-	atomicstore(&harvestingwbufs, 0)
-}
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index e94b79fb..10878ee 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -24,7 +24,6 @@
 	nspan     uint32
 	sweepgen  uint32 // sweep generation, see comment in mspan
 	sweepdone uint32 // all spans are swept
-
 	// span lookup
 	spans        **mspan
 	spans_mapped uintptr
@@ -37,14 +36,13 @@
 	arena_end      uintptr
 	arena_reserved bool
 
-	// write barrier shadow data+heap.
+	// 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
-	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
 
 	// central free lists for small size classes.
 	// the padding makes sure that the MCentrals are
@@ -61,6 +59,10 @@
 	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)
@@ -100,6 +102,7 @@
 	// if sweepgen == h->sweepgen - 1, the span is currently being swept
 	// if sweepgen == h->sweepgen, the span is swept and ready to use
 	// h->sweepgen is incremented by 2 after every GC
+
 	sweepgen    uint32
 	divMul      uint32   // for divide by elemsize - divMagic.mul
 	ref         uint16   // capacity - number of objects in freelist
@@ -115,6 +118,7 @@
 	limit       uintptr  // end of data in span
 	speciallock mutex    // guards specials list
 	specials    *special // linked list of special records sorted by offset.
+	baseMask    uintptr  // if non-0, elemsize is a power of 2, & this will get object allocation base
 }
 
 func (s *mspan) base() uintptr {
@@ -149,12 +153,12 @@
 		}
 		var new []*mspan
 		sp := (*slice)(unsafe.Pointer(&new))
-		sp.array = (*byte)(sysAlloc(uintptr(n)*ptrSize, &memstats.other_sys))
+		sp.array = sysAlloc(uintptr(n)*ptrSize, &memstats.other_sys)
 		if sp.array == nil {
 			throw("runtime: cannot allocate memory")
 		}
-		sp.len = uint(len(h_allspans))
-		sp.cap = uint(n)
+		sp.len = len(h_allspans)
+		sp.cap = n
 		if len(h_allspans) > 0 {
 			copy(new, h_allspans)
 			// Don't free the old array if it's referenced by sweep.
@@ -188,6 +192,25 @@
 	return true
 }
 
+// TODO: spanOf and spanOfUnchecked are open-coded in a lot of places.
+// Use the functions instead.
+
+// spanOf returns the span of p. If p does not point into the heap or
+// no span contains p, spanOf returns nil.
+func spanOf(p uintptr) *mspan {
+	if p == 0 || p < mheap_.arena_start || p >= mheap_.arena_used {
+		return nil
+	}
+	return spanOfUnchecked(p)
+}
+
+// spanOfUnchecked is equivalent to spanOf, but the caller must ensure
+// that p points into the heap (that is, mheap_.arena_start <= p <
+// mheap_.arena_used).
+func spanOfUnchecked(p uintptr) *mspan {
+	return h_spans[(p-mheap_.arena_start)>>_PageShift]
+}
+
 func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
 	_g_ := getg()
 
@@ -257,9 +280,9 @@
 	}
 
 	sp := (*slice)(unsafe.Pointer(&h_spans))
-	sp.array = (*byte)(unsafe.Pointer(h.spans))
-	sp.len = uint(spans_size / ptrSize)
-	sp.cap = uint(spans_size / ptrSize)
+	sp.array = unsafe.Pointer(h.spans)
+	sp.len = int(spans_size / ptrSize)
+	sp.cap = int(spans_size / ptrSize)
 }
 
 func mHeap_MapSpans(h *mheap) {
@@ -287,15 +310,9 @@
 			// swept spans are at the end of the list
 			mSpanList_InsertBack(list, s)
 			unlock(&h.lock)
+			snpages := s.npages
 			if mSpan_Sweep(s, false) {
-				// TODO(rsc,dvyukov): This is probably wrong.
-				// It is undercounting the number of pages reclaimed.
-				// See golang.org/issue/9048.
-				// Note that if we want to add the true count of s's pages,
-				// we must record that before calling mSpan_Sweep,
-				// because if mSpan_Sweep returns true the span has
-				// been
-				n++
+				n += snpages
 			}
 			lock(&h.lock)
 			if n >= npages {
@@ -368,12 +385,21 @@
 	// To prevent excessive heap growth, before allocating n pages
 	// we need to sweep and reclaim at least n pages.
 	if h.sweepdone == 0 {
+		// TODO(austin): This tends to sweep a large number of
+		// spans in order to find a few completely free spans
+		// (for example, in the garbage benchmark, this sweeps
+		// ~30x the number of pages its trying to allocate).
+		// If GC kept a bit for whether there were any marks
+		// in a span, we could release these free spans
+		// at the end of GC and eliminate this entirely.
 		mHeap_Reclaim(h, npage)
 	}
 
 	// transfer stats from cache to global
-	memstats.heap_alloc += uint64(_g_.m.mcache.local_cachealloc)
+	memstats.heap_live += uint64(_g_.m.mcache.local_cachealloc)
 	_g_.m.mcache.local_cachealloc = 0
+	memstats.heap_scan += uint64(_g_.m.mcache.local_scan)
+	_g_.m.mcache.local_scan = 0
 	memstats.tinyallocs += uint64(_g_.m.mcache.local_tinyallocs)
 	_g_.m.mcache.local_tinyallocs = 0
 
@@ -391,18 +417,20 @@
 			s.divShift = 0
 			s.divMul = 0
 			s.divShift2 = 0
+			s.baseMask = 0
 		} else {
 			s.elemsize = uintptr(class_to_size[sizeclass])
 			m := &class_to_divmagic[sizeclass]
 			s.divShift = m.shift
 			s.divMul = m.mul
 			s.divShift2 = m.shift2
+			s.baseMask = m.baseMask
 		}
 
 		// update stats, sweep lists
 		if large {
 			memstats.heap_objects++
-			memstats.heap_alloc += uint64(npage << _PageShift)
+			memstats.heap_live += uint64(npage << _PageShift)
 			// Swept spans are at the end of lists.
 			if s.npages < uintptr(len(h.free)) {
 				mSpanList_InsertBack(&h.busy[s.npages], s)
@@ -628,12 +656,13 @@
 	systemstack(func() {
 		mp := getg().m
 		lock(&h.lock)
-		memstats.heap_alloc += uint64(mp.mcache.local_cachealloc)
+		memstats.heap_live += uint64(mp.mcache.local_cachealloc)
 		mp.mcache.local_cachealloc = 0
+		memstats.heap_scan += uint64(mp.mcache.local_scan)
+		mp.mcache.local_scan = 0
 		memstats.tinyallocs += uint64(mp.mcache.local_tinyallocs)
 		mp.mcache.local_tinyallocs = 0
 		if acct != 0 {
-			memstats.heap_alloc -= uint64(s.npages << _PageShift)
 			memstats.heap_objects--
 		}
 		mHeap_FreeSpanLocked(h, s, true, true, 0)
diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go
new file mode 100644
index 0000000..dc94cee
--- /dev/null
+++ b/src/runtime/mkduff.go
@@ -0,0 +1,188 @@
+// 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 ignore
+
+// runtime·duffzero is a Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// the routine to zero chunks of memory.
+// Do not change duffzero without also
+// changing clearfat in cmd/?g/ggen.go.
+
+// runtime·duffcopy is a Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// the routine to copy chunks of memory.
+// Source and destination must not overlap.
+// Do not change duffcopy without also
+// changing blockcopy in cmd/?g/cgen.go.
+
+// See the zero* and copy* generators below
+// for architecture-specific comments.
+
+// mkduff generates duff_*.s.
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+)
+
+func main() {
+	gen("amd64", notags, zeroAMD64, copyAMD64)
+	gen("386", notags, zero386, copy386)
+	gen("arm", notags, zeroARM, copyARM)
+	gen("arm64", notags, zeroARM64, copyARM64)
+	gen("ppc64x", tagsPPC64x, zeroPPC64x, copyPPC64x)
+}
+
+func gen(arch string, tags, zero, copy func(io.Writer)) {
+	var buf bytes.Buffer
+
+	fmt.Fprintln(&buf, "// AUTO-GENERATED by mkduff.go")
+	fmt.Fprintln(&buf, "// Run go generate from src/runtime to update.")
+	fmt.Fprintln(&buf, "// See mkduff.go for comments.")
+	tags(&buf)
+	fmt.Fprintln(&buf, "#include \"textflag.h\"")
+	fmt.Fprintln(&buf)
+	zero(&buf)
+	fmt.Fprintln(&buf)
+	copy(&buf)
+
+	if err := ioutil.WriteFile("duff_"+arch+".s", buf.Bytes(), 0644); err != nil {
+		log.Fatalln(err)
+	}
+}
+
+func notags(w io.Writer) { fmt.Fprintln(w) }
+
+func zeroAMD64(w io.Writer) {
+	// AX: zero
+	// DI: ptr to memory to be zeroed
+	// DI is updated as a side effect.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $0-0")
+	for i := 0; i < 31; i++ {
+		fmt.Fprintln(w, "\tMOVQ\tAX,(DI)")
+		fmt.Fprintln(w, "\tMOVQ\tAX,8(DI)")
+		fmt.Fprintln(w, "\tMOVQ\tAX,16(DI)")
+		fmt.Fprintln(w, "\tMOVQ\tAX,24(DI)")
+		fmt.Fprintln(w, "\tADDQ\t$32,DI")
+		fmt.Fprintln(w)
+	}
+	for i := 0; i < 4; i++ {
+		fmt.Fprintln(w, "\tSTOSQ")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copyAMD64(w io.Writer) {
+	// SI: ptr to source memory
+	// DI: ptr to destination memory
+	// SI and DI are updated as a side effect.
+	//
+	// This is equivalent to a sequence of MOVSQ but
+	// for some reason that is 3.5x slower than this code.
+	// The STOSQ in duffzero seem fine, though.
+	fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVQ\t(SI), CX")
+		fmt.Fprintln(w, "\tADDQ\t$8, SI")
+		fmt.Fprintln(w, "\tMOVQ\tCX, (DI)")
+		fmt.Fprintln(w, "\tADDQ\t$8, DI")
+		fmt.Fprintln(w)
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func zero386(w io.Writer) {
+	// AX: zero
+	// DI: ptr to memory to be zeroed
+	// DI is updated as a side effect.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tSTOSL")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copy386(w io.Writer) {
+	// SI: ptr to source memory
+	// DI: ptr to destination memory
+	// SI and DI are updated as a side effect.
+	//
+	// This is equivalent to a sequence of MOVSL but
+	// for some reason MOVSL is really slow.
+	fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVL\t(SI), CX")
+		fmt.Fprintln(w, "\tADDL\t$4, SI")
+		fmt.Fprintln(w, "\tMOVL\tCX, (DI)")
+		fmt.Fprintln(w, "\tADDL\t$4, DI")
+		fmt.Fprintln(w)
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func zeroARM(w io.Writer) {
+	// R0: zero
+	// R1: ptr to memory to be zeroed
+	// R1 is updated as a side effect.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVW.P\tR0, 4(R1)")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copyARM(w io.Writer) {
+	// R0: scratch space
+	// R1: ptr to source memory
+	// R2: ptr to destination memory
+	// R1 and R2 are updated as a side effect
+	fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVW.P\t4(R1), R0")
+		fmt.Fprintln(w, "\tMOVW.P\tR0, 4(R2)")
+		fmt.Fprintln(w)
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func zeroARM64(w io.Writer) {
+	// ZR: always zero
+	// R16 (aka REGRT1): ptr to memory to be zeroed - 8
+	// On return, R16 points to the last zeroed dword.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $-8-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVD.W\tZR, 8(R16)")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copyARM64(w io.Writer) {
+	fmt.Fprintln(w, "// TODO: Implement runtime·duffcopy.")
+}
+
+func tagsPPC64x(w io.Writer) {
+	fmt.Fprintln(w)
+	fmt.Fprintln(w, "// +build ppc64 ppc64le")
+	fmt.Fprintln(w)
+}
+
+func zeroPPC64x(w io.Writer) {
+	// R0: always zero
+	// R3 (aka REGRT1): ptr to memory to be zeroed - 8
+	// On return, R3 points to the last zeroed dword.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $-8-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVDU\tR0, 8(R3)")
+	}
+	fmt.Fprintln(w, "\tRETURN")
+}
+
+func copyPPC64x(w io.Writer) {
+	fmt.Fprintln(w, "// TODO: Implement runtime·duffcopy.")
+}
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
index 9ba145d..bc735be 100644
--- a/src/runtime/msize.go
+++ b/src/runtime/msize.go
@@ -215,14 +215,24 @@
 // http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html
 // http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html
 type divMagic struct {
-	shift  uint8
-	mul    uint32
-	shift2 uint8
+	shift    uint8
+	mul      uint32
+	shift2   uint8
+	baseMask uintptr
 }
 
 func computeDivMagic(d uint32) divMagic {
 	var m divMagic
 
+	// If the size is a power of two, heapBitsForObject can divide even faster by masking.
+	// Compute this mask.
+	if d&(d-1) == 0 {
+		// It is a power of 2 (assuming dinptr != 1)
+		m.baseMask = ^(uintptr(d) - 1)
+	} else {
+		m.baseMask = 0
+	}
+
 	// Compute pre-shift by factoring power of 2 out of d.
 	for d&1 == 0 {
 		m.shift++
@@ -239,5 +249,6 @@
 	}
 	m.mul = uint32(((1 << k) + d64 - 1) / d64) //  ⌈2^k / d⌉
 	m.shift2 = k
+
 	return m
 }
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index 88cf42f..c8e5249 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -12,7 +12,7 @@
 // Shared with Go: if you edit this structure, also edit type MemStats in mem.go.
 type mstats struct {
 	// General statistics.
-	alloc       uint64 // bytes allocated and still in use
+	alloc       uint64 // bytes allocated and not yet freed
 	total_alloc uint64 // bytes allocated (even if freed)
 	sys         uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
 	nlookup     uint64 // number of pointer lookups
@@ -21,7 +21,7 @@
 
 	// Statistics about malloc heap.
 	// protected by mheap.lock
-	heap_alloc    uint64 // bytes allocated and still in use
+	heap_alloc    uint64 // bytes allocated and not yet freed (same as alloc above)
 	heap_sys      uint64 // bytes obtained from system
 	heap_idle     uint64 // bytes in idle spans
 	heap_inuse    uint64 // bytes in non-idle spans
@@ -59,7 +59,30 @@
 		nfree   uint64
 	}
 
+	// Statistics below here are not exported to Go directly.
+
 	tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
+
+	// heap_live is the number of bytes considered live by the GC.
+	// That is: retained by the most recent GC plus allocated
+	// since then. heap_live <= heap_alloc, since heap_live
+	// excludes unmarked objects that have not yet been swept.
+	heap_live uint64
+
+	// heap_scan is the number of bytes of "scannable" heap. This
+	// is the live heap (as counted by heap_live), but omitting
+	// no-scan objects and no-scan tails of objects.
+	heap_scan uint64
+
+	// heap_marked is the number of bytes marked by the previous
+	// GC. After mark termination, heap_live == heap_marked, but
+	// unlike heap_live, heap_marked does not change until the
+	// next mark termination.
+	heap_marked uint64
+
+	// heap_reachable is an estimate of the reachable heap bytes
+	// at the end of the previous GC.
+	heap_reachable uint64
 }
 
 var memstats mstats
@@ -67,7 +90,7 @@
 // A MemStats records statistics about the memory allocator.
 type MemStats struct {
 	// General statistics.
-	Alloc      uint64 // bytes allocated and still in use
+	Alloc      uint64 // bytes allocated and not yet freed
 	TotalAlloc uint64 // bytes allocated (even if freed)
 	Sys        uint64 // bytes obtained from system (sum of XxxSys below)
 	Lookups    uint64 // number of pointer lookups
@@ -75,7 +98,7 @@
 	Frees      uint64 // number of frees
 
 	// Main allocation heap statistics.
-	HeapAlloc    uint64 // bytes allocated and still in use
+	HeapAlloc    uint64 // bytes allocated and not yet freed (same as Alloc above)
 	HeapSys      uint64 // bytes obtained from system
 	HeapIdle     uint64 // bytes in idle spans
 	HeapInuse    uint64 // bytes in non-idle span
@@ -158,7 +181,7 @@
 	memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
 
 	// Stack numbers are part of the heap numbers, separate those out for user consumption
-	stats.StackSys = stats.StackInuse
+	stats.StackSys += stats.StackInuse
 	stats.HeapInuse -= stats.StackInuse
 	stats.HeapSys -= stats.StackInuse
 }
@@ -317,11 +340,13 @@
 func purgecachedstats(c *mcache) {
 	// Protected by either heap or GC lock.
 	h := &mheap_
-	memstats.heap_alloc += uint64(c.local_cachealloc)
+	memstats.heap_live += uint64(c.local_cachealloc)
 	c.local_cachealloc = 0
 	if trace.enabled {
 		traceHeapAlloc()
 	}
+	memstats.heap_scan += uint64(c.local_scan)
+	c.local_scan = 0
 	memstats.tinyallocs += uint64(c.local_tinyallocs)
 	c.local_tinyallocs = 0
 	memstats.nlookup += uint64(c.local_nlookup)
@@ -335,3 +360,41 @@
 		c.local_nsmallfree[i] = 0
 	}
 }
+
+// Atomically increases a given *system* memory stat.  We are counting on this
+// stat never overflowing a uintptr, so this function must only be used for
+// system memory stats.
+//
+// The current implementation for little endian architectures is based on
+// xadduintptr(), which is less than ideal: xadd64() should really be used.
+// Using xadduintptr() is a stop-gap solution until arm supports xadd64() that
+// doesn't use locks.  (Locks are a problem as they require a valid G, which
+// restricts their useability.)
+//
+// A side-effect of using xadduintptr() is that we need to check for
+// overflow errors.
+//go:nosplit
+func mSysStatInc(sysStat *uint64, n uintptr) {
+	if _BigEndian != 0 {
+		xadd64(sysStat, int64(n))
+		return
+	}
+	if val := xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), n); val < n {
+		print("runtime: stat overflow: val ", val, ", n ", n, "\n")
+		exit(2)
+	}
+}
+
+// Atomically decreases a given *system* memory stat.  Same comments as
+// mSysStatInc apply.
+//go:nosplit
+func mSysStatDec(sysStat *uint64, n uintptr) {
+	if _BigEndian != 0 {
+		xadd64(sysStat, -int64(n))
+		return
+	}
+	if val := xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), uintptr(-int64(n))); val+n < n {
+		print("runtime: stat underflow: val ", val, ", n ", n, "\n")
+		exit(2)
+	}
+}
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 4791e5e..c06722f 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -275,24 +275,22 @@
 
 // make pd ready, newly runnable goroutines (if any) are returned in rg/wg
 // May run during STW, so write barriers are not allowed.
-// Eliminating WB calls using setGNoWriteBarrier are safe since the gs are
-// reachable through allg.
 //go:nowritebarrier
-func netpollready(gpp **g, pd *pollDesc, mode int32) {
-	var rg, wg *g
+func netpollready(gpp *guintptr, pd *pollDesc, mode int32) {
+	var rg, wg guintptr
 	if mode == 'r' || mode == 'r'+'w' {
-		setGNoWriteBarrier(&rg, netpollunblock(pd, 'r', true))
+		rg.set(netpollunblock(pd, 'r', true))
 	}
 	if mode == 'w' || mode == 'r'+'w' {
-		setGNoWriteBarrier(&wg, netpollunblock(pd, 'w', true))
+		wg.set(netpollunblock(pd, 'w', true))
 	}
-	if rg != nil {
-		setGNoWriteBarrier(&rg.schedlink, *gpp)
-		setGNoWriteBarrier(gpp, rg)
+	if rg != 0 {
+		rg.ptr().schedlink = *gpp
+		*gpp = rg
 	}
-	if wg != nil {
-		setGNoWriteBarrier(&wg.schedlink, *gpp)
-		setGNoWriteBarrier(gpp, wg)
+	if wg != 0 {
+		wg.ptr().schedlink = *gpp
+		*gpp = wg
 	}
 }
 
diff --git a/src/runtime/netpoll_epoll.go b/src/runtime/netpoll_epoll.go
index 4f9ccaf..7b4052a 100644
--- a/src/runtime/netpoll_epoll.go
+++ b/src/runtime/netpoll_epoll.go
@@ -55,9 +55,9 @@
 
 // polls for ready network connections
 // returns list of goroutines that become runnable
-func netpoll(block bool) (gp *g) {
+func netpoll(block bool) *g {
 	if epfd == -1 {
-		return
+		return nil
 	}
 	waitms := int32(-1)
 	if !block {
@@ -73,6 +73,7 @@
 		}
 		goto retry
 	}
+	var gp guintptr
 	for i := int32(0); i < n; i++ {
 		ev := &events[i]
 		if ev.events == 0 {
@@ -87,11 +88,12 @@
 		}
 		if mode != 0 {
 			pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
-			netpollready((**g)(noescape(unsafe.Pointer(&gp))), pd, mode)
+
+			netpollready(&gp, pd, mode)
 		}
 	}
-	if block && gp == nil {
+	if block && gp == 0 {
 		goto retry
 	}
-	return gp
+	return gp.ptr()
 }
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index 080964b..01445dc 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -62,9 +62,9 @@
 
 // Polls for ready network connections.
 // Returns list of goroutines that become runnable.
-func netpoll(block bool) (gp *g) {
+func netpoll(block bool) *g {
 	if kq == -1 {
-		return
+		return nil
 	}
 	var tp *timespec
 	var ts timespec
@@ -81,6 +81,7 @@
 		}
 		goto retry
 	}
+	var gp guintptr
 	for i := 0; i < int(n); i++ {
 		ev := &events[i]
 		var mode int32
@@ -91,11 +92,11 @@
 			mode += 'w'
 		}
 		if mode != 0 {
-			netpollready((**g)(noescape(unsafe.Pointer(&gp))), (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
+			netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
 		}
 	}
-	if block && gp == nil {
+	if block && gp == 0 {
 		goto retry
 	}
-	return gp
+	return gp.ptr()
 }
diff --git a/src/runtime/netpoll_solaris.go b/src/runtime/netpoll_solaris.go
index d8f050e..359fd47 100644
--- a/src/runtime/netpoll_solaris.go
+++ b/src/runtime/netpoll_solaris.go
@@ -89,23 +89,23 @@
 }
 
 func fcntl(fd, cmd int32, arg uintptr) int32 {
-	return int32(sysvicall3(libc_fcntl, uintptr(fd), uintptr(cmd), arg))
+	return int32(sysvicall3(&libc_fcntl, uintptr(fd), uintptr(cmd), arg))
 }
 
 func port_create() int32 {
-	return int32(sysvicall0(libc_port_create))
+	return int32(sysvicall0(&libc_port_create))
 }
 
 func port_associate(port, source int32, object uintptr, events uint32, user uintptr) int32 {
-	return int32(sysvicall5(libc_port_associate, uintptr(port), uintptr(source), object, uintptr(events), user))
+	return int32(sysvicall5(&libc_port_associate, uintptr(port), uintptr(source), object, uintptr(events), user))
 }
 
 func port_dissociate(port, source int32, object uintptr) int32 {
-	return int32(sysvicall3(libc_port_dissociate, uintptr(port), uintptr(source), object))
+	return int32(sysvicall3(&libc_port_dissociate, uintptr(port), uintptr(source), object))
 }
 
 func port_getn(port int32, evs *portevent, max uint32, nget *uint32, timeout *timespec) int32 {
-	return int32(sysvicall5(libc_port_getn, uintptr(port), uintptr(unsafe.Pointer(evs)), uintptr(max), uintptr(unsafe.Pointer(nget)), uintptr(unsafe.Pointer(timeout))))
+	return int32(sysvicall5(&libc_port_getn, uintptr(port), uintptr(unsafe.Pointer(evs)), uintptr(max), uintptr(unsafe.Pointer(nget)), uintptr(unsafe.Pointer(timeout))))
 }
 
 var portfd int32 = -1
@@ -179,9 +179,9 @@
 
 // polls for ready network connections
 // returns list of goroutines that become runnable
-func netpoll(block bool) (gp *g) {
+func netpoll(block bool) *g {
 	if portfd == -1 {
-		return
+		return nil
 	}
 
 	var wait *timespec
@@ -201,7 +201,7 @@
 		goto retry
 	}
 
-	gp = nil
+	var gp guintptr
 	for i := 0; i < int(n); i++ {
 		ev := &events[i]
 
@@ -232,12 +232,12 @@
 		}
 
 		if mode != 0 {
-			netpollready((**g)(noescape(unsafe.Pointer(&gp))), pd, mode)
+			netpollready(&gp, pd, mode)
 		}
 	}
 
-	if block && gp == nil {
+	if block && gp == 0 {
 		goto retry
 	}
-	return gp
+	return gp.ptr()
 }
diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go
index 0861e20..7e15cd2 100644
--- a/src/runtime/netpoll_windows.go
+++ b/src/runtime/netpoll_windows.go
@@ -63,14 +63,13 @@
 	var wait, qty, key, flags, n, i uint32
 	var errno int32
 	var op *net_op
-	var gp *g
+	var gp guintptr
 
 	mp := getg().m
 
 	if iocphandle == _INVALID_HANDLE_VALUE {
 		return nil
 	}
-	gp = nil
 	wait = 0
 	if block {
 		wait = _INFINITE
@@ -125,13 +124,13 @@
 		mp.blocked = false
 		handlecompletion(&gp, op, errno, qty)
 	}
-	if block && gp == nil {
+	if block && gp == 0 {
 		goto retry
 	}
-	return gp
+	return gp.ptr()
 }
 
-func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) {
+func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
 	if op == nil {
 		throw("netpoll: GetQueuedCompletionStatus returned op == nil")
 	}
@@ -142,5 +141,5 @@
 	}
 	op.errno = errno
 	op.qty = qty
-	netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode)
+	netpollready(gpp, op.pd, mode)
 }
diff --git a/src/runtime/noasm.go b/src/runtime/noasm.go
index ab9c744..9a6dbee 100644
--- a/src/runtime/noasm.go
+++ b/src/runtime/noasm.go
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routines that are implemented in assembly in asm_{amd64,386,arm}.s
+// Routines that are implemented in assembly in asm_{amd64,386,arm,arm64}.s
 
-// +build arm64 ppc64 ppc64le
+// +build ppc64 ppc64le
 
 package runtime
 
diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go
new file mode 100644
index 0000000..bbf9d0b
--- /dev/null
+++ b/src/runtime/norace_linux_test.go
@@ -0,0 +1,41 @@
+// 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.
+
+// The file contains tests that can not run under race detector for some reason.
+// +build !race
+
+package runtime_test
+
+import (
+	"runtime"
+	"testing"
+	"time"
+	"unsafe"
+)
+
+var newOSProcDone bool
+
+//go:nosplit
+func newOSProcCreated() {
+	newOSProcDone = true
+}
+
+// Can't be run with -race because it inserts calls into newOSProcCreated()
+// that require a valid G/M.
+func TestNewOSProc0(t *testing.T) {
+	runtime.NewOSProc0(0x800000, unsafe.Pointer(runtime.FuncPC(newOSProcCreated)))
+	check := time.NewTicker(100 * time.Millisecond)
+	defer check.Stop()
+	end := time.After(5 * time.Second)
+	for {
+		select {
+		case <-check.C:
+			if newOSProcDone {
+				return
+			}
+		case <-end:
+			t.Fatalf("couldn't create new OS process")
+		}
+	}
+}
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
index 6c79bbb..10cf460 100644
--- a/src/runtime/os1_darwin.go
+++ b/src/runtime/os1_darwin.go
@@ -51,7 +51,7 @@
 func getRandomData(r []byte) {
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
@@ -81,7 +81,7 @@
 
 	var oset uint32
 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
-	errno := bsdthread_create(stk, mp, mp.g0, funcPC(mstart))
+	errno := bsdthread_create(stk, unsafe.Pointer(mp), funcPC(mstart))
 	sigprocmask(_SIG_SETMASK, &oset, nil)
 
 	if errno < 0 {
@@ -90,6 +90,35 @@
 	}
 }
 
+// newosproc0 is a version of newosproc that can be called before the runtime
+// is initialized.
+//
+// As Go uses bsdthread_register when running without cgo, this function is
+// not safe to use after initialization as it does not pass an M as fnarg.
+//
+//go:nosplit
+func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg uintptr) {
+	stack := sysAlloc(stacksize, &memstats.stacks_sys)
+	if stack == nil {
+		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
+		exit(1)
+	}
+	stk := unsafe.Pointer(uintptr(stack) + stacksize)
+
+	var oset uint32
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+	errno := bsdthread_create(stk, fn, fnarg)
+	sigprocmask(_SIG_SETMASK, &oset, nil)
+
+	if errno < 0 {
+		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+		exit(1)
+	}
+}
+
+var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
+var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
 func mpreinit(mp *m) {
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
index 54f19ef..a590aea 100644
--- a/src/runtime/os1_dragonfly.go
+++ b/src/runtime/os1_dragonfly.go
@@ -105,7 +105,7 @@
 func getRandomData(r []byte) {
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
index ceaa916..8719a49 100644
--- a/src/runtime/os1_freebsd.go
+++ b/src/runtime/os1_freebsd.go
@@ -104,7 +104,7 @@
 func getRandomData(r []byte) {
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go
index 735f595..e4b18c7 100644
--- a/src/runtime/os1_linux.go
+++ b/src/runtime/os1_linux.go
@@ -111,6 +111,12 @@
 	_CLONE_STOPPED        = 0x2000000
 	_CLONE_NEWUTS         = 0x4000000
 	_CLONE_NEWIPC         = 0x8000000
+
+	cloneFlags = _CLONE_VM | /* share memory */
+		_CLONE_FS | /* share cwd, etc */
+		_CLONE_FILES | /* share fd table */
+		_CLONE_SIGHAND | /* share sig handler table */
+		_CLONE_THREAD /* revisit - okay for now */
 )
 
 // May run with m.p==nil, so write barriers are not allowed.
@@ -119,12 +125,6 @@
 	/*
 	 * note: strace gets confused if we use CLONE_PTRACE here.
 	 */
-	var flags int32 = _CLONE_VM | /* share memory */
-		_CLONE_FS | /* share cwd, etc */
-		_CLONE_FILES | /* share fd table */
-		_CLONE_SIGHAND | /* share sig handler table */
-		_CLONE_THREAD /* revisit - okay for now */
-
 	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
 	if false {
 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
@@ -134,7 +134,7 @@
 	// with signals disabled.  It will enable them in minit.
 	var oset sigset
 	rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
-	ret := clone(flags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
+	ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
 	rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))
 
 	if ret < 0 {
@@ -143,6 +143,24 @@
 	}
 }
 
+// Version of newosproc that doesn't require a valid G.
+//go:nosplit
+func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
+	stack := sysAlloc(stacksize, &memstats.stacks_sys)
+	if stack == nil {
+		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
+		exit(1)
+	}
+	ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn)
+	if ret < 0 {
+		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+		exit(1)
+	}
+}
+
+var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
+var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+
 func osinit() {
 	ncpu = getproccount()
 }
@@ -157,7 +175,7 @@
 	}
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go
index 85b3df3..8df74b5 100644
--- a/src/runtime/os1_netbsd.go
+++ b/src/runtime/os1_netbsd.go
@@ -124,7 +124,7 @@
 func getRandomData(r []byte) {
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go
index 4f41864..95729a5 100644
--- a/src/runtime/os1_openbsd.go
+++ b/src/runtime/os1_openbsd.go
@@ -133,7 +133,7 @@
 func getRandomData(r []byte) {
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
index 284f338..c026218 100644
--- a/src/runtime/os1_plan9.go
+++ b/src/runtime/os1_plan9.go
@@ -50,7 +50,7 @@
 			}
 		}
 	}
-	close(fd)
+	closefd(fd)
 	if ncpu == 0 {
 		ncpu = 1
 	}
@@ -64,7 +64,7 @@
 	fd := open(&pid[0], 0, 0)
 	if fd >= 0 {
 		read(fd, unsafe.Pointer(&b), int32(len(b)))
-		close(fd)
+		closefd(fd)
 	}
 	c := b[:]
 	for c[0] == ' ' || c[0] == '\t' {
@@ -162,10 +162,10 @@
 	}
 	len := findnull(&msg[0])
 	if write(uintptr(fd), (unsafe.Pointer)(&msg[0]), int32(len)) != int64(len) {
-		close(fd)
+		closefd(fd)
 		return -1
 	}
-	close(fd)
+	closefd(fd)
 	return 0
 }
 
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
index 9a077af..5719b32 100644
--- a/src/runtime/os1_windows.go
+++ b/src/runtime/os1_windows.go
@@ -94,6 +94,12 @@
 	_GetQueuedCompletionStatusEx stdFunction
 )
 
+// Call a Windows function with stdcall conventions,
+// and switch to os stack during the call.
+func asmstdcall(fn unsafe.Pointer)
+
+var asmstdcallAddr unsafe.Pointer
+
 func loadOptionalSyscalls() {
 	var buf [50]byte // large enough for longest string
 	strtoptr := func(s string) uintptr {
@@ -111,12 +117,6 @@
 	}
 }
 
-// in sys_windows_386.s and sys_windows_amd64.s
-func externalthreadhandler()
-func exceptiontramp()
-func firstcontinuetramp()
-func lastcontinuetramp()
-
 //go:nosplit
 func getLoadLibrary() uintptr {
 	return uintptr(unsafe.Pointer(_LoadLibraryW))
@@ -138,25 +138,18 @@
 	currentThread  = ^uintptr(1) // -2 = current thread
 )
 
-func disableWER() {
-	// do not display Windows Error Reporting dialogue
-	const (
-		SEM_FAILCRITICALERRORS     = 0x0001
-		SEM_NOGPFAULTERRORBOX      = 0x0002
-		SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
-		SEM_NOOPENFILEERRORBOX     = 0x8000
-	)
-	errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
-	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
-}
-
 func getVersion() (major, minor byte) {
 	v := uint32(stdcall0(_GetVersion))
 	low := uint16(v)
 	return byte(low), byte(low >> 8)
 }
 
+// in sys_windows_386.s and sys_windows_amd64.s
+func externalthreadhandler()
+
 func osinit() {
+	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
+
 	setBadSignalMsg()
 
 	loadOptionalSyscalls()
@@ -165,21 +158,7 @@
 
 	externalthreadhandlerp = funcPC(externalthreadhandler)
 
-	major, _ := getVersion()
-
-	stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
-	if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 || major < 6 {
-		// use SetUnhandledExceptionFilter for windows-386 or
-		// if VectoredContinueHandler is unavailable or
-		// if running windows-amd64 v5. V5 appears to fail to
-		// call the continue handlers if windows error reporting dialog
-		// is disabled.
-		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
-		stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
-	} else {
-		stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
-		stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
-	}
+	initExceptionHandler()
 
 	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
 
@@ -303,7 +282,7 @@
 		funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
 		_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
 	if thandle == 0 {
-		println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")")
+		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
 		throw("runtime.newosproc")
 	}
 }
@@ -384,14 +363,13 @@
 
 	if mp.profilehz != 0 {
 		// leave pc/sp for cpu profiler
-		// gp is on allg, so this WB can be eliminated.
-		setGNoWriteBarrier(&mp.libcallg, gp)
+		mp.libcallg.set(gp)
 		mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
 		// sp must be the last, because once async cpu profiler finds
 		// all three values to be non-zero, it will use them
 		mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
 	}
-	asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall))
+	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
 	mp.libcallsp = 0
 	return mp.libcall.r1
 }
@@ -474,37 +452,6 @@
 	usleep1(10 * us)
 }
 
-func issigpanic(code uint32) uint32 {
-	switch code {
-	default:
-		return 0
-	case _EXCEPTION_ACCESS_VIOLATION:
-	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
-	case _EXCEPTION_INT_OVERFLOW:
-	case _EXCEPTION_FLT_DENORMAL_OPERAND:
-	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
-	case _EXCEPTION_FLT_INEXACT_RESULT:
-	case _EXCEPTION_FLT_OVERFLOW:
-	case _EXCEPTION_FLT_UNDERFLOW:
-	case _EXCEPTION_BREAKPOINT:
-	}
-	return 1
-}
-
-func initsig() {
-	/*
-		// TODO(brainman): I don't think we need that bit of code
-		// following line keeps these functions alive at link stage
-		// if there's a better way please write it here
-		void *e = runtime·exceptiontramp;
-		void *f = runtime·firstcontinuetramp;
-		void *l = runtime·lastcontinuetramp;
-		USED(e);
-		USED(f);
-		USED(l);
-	*/
-}
-
 func ctrlhandler1(_type uint32) uint32 {
 	var s uint32
 
@@ -544,7 +491,7 @@
 	sigprof(r.ip(), r.sp(), 0, gp, mp)
 }
 
-func profileloop1() {
+func profileloop1(param uintptr) uint32 {
 	stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
 
 	for {
@@ -596,35 +543,3 @@
 func memlimit() uintptr {
 	return 0
 }
-
-var (
-	badsignalmsg [100]byte
-	badsignallen int32
-)
-
-func setBadSignalMsg() {
-	const msg = "runtime: signal received on thread not created by Go.\n"
-	for i, c := range msg {
-		badsignalmsg[i] = byte(c)
-		badsignallen++
-	}
-}
-
-const (
-	_SIGPROF = 0 // dummy value for badsignal
-	_SIGQUIT = 0 // dummy value for sighandler
-)
-
-func raiseproc(sig int32) {
-}
-
-func crash() {
-	// TODO: This routine should do whatever is needed
-	// to make the Windows program abort/crash as it
-	// would if Go was not intercepting signals.
-	// On Unix the routine would remove the custom signal
-	// handler and then raise a signal (like SIGABRT).
-	// Something like that should happen here.
-	// It's okay to leave this empty for now: if crash returns
-	// the ordinary exit-after-panic happens.
-}
diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go
deleted file mode 100644
index e5fe748..0000000
--- a/src/runtime/os1_windows_386.go
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import (
-	"unsafe"
-)
-
-func dumpregs(r *context) {
-	print("eax     ", hex(r.eax), "\n")
-	print("ebx     ", hex(r.ebx), "\n")
-	print("ecx     ", hex(r.ecx), "\n")
-	print("edx     ", hex(r.edx), "\n")
-	print("edi     ", hex(r.edi), "\n")
-	print("esi     ", hex(r.esi), "\n")
-	print("ebp     ", hex(r.ebp), "\n")
-	print("esp     ", hex(r.esp), "\n")
-	print("eip     ", hex(r.eip), "\n")
-	print("eflags  ", hex(r.eflags), "\n")
-	print("cs      ", hex(r.segcs), "\n")
-	print("fs      ", hex(r.segfs), "\n")
-	print("gs      ", hex(r.seggs), "\n")
-}
-
-func isgoexception(info *exceptionrecord, r *context) bool {
-	// Only handle exception if executing instructions in Go binary
-	// (not Windows library code).
-	if r.eip < uint32(themoduledata.text) || uint32(themoduledata.etext) < r.eip {
-		return false
-	}
-
-	if issigpanic(info.exceptioncode) == 0 {
-		return false
-	}
-
-	return true
-}
-
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
-// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
-func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
-	if !isgoexception(info, r) {
-		return _EXCEPTION_CONTINUE_SEARCH
-	}
-
-	// Make it look like a call to the signal func.
-	// Have to pass arguments out of band since
-	// augmenting the stack frame would break
-	// the unwinding code.
-	gp.sig = info.exceptioncode
-	gp.sigcode0 = uintptr(info.exceptioninformation[0])
-	gp.sigcode1 = uintptr(info.exceptioninformation[1])
-	gp.sigpc = uintptr(r.eip)
-
-	// Only push runtime·sigpanic if r->eip != 0.
-	// If r->eip == 0, probably panicked because of a
-	// call to a nil func.  Not pushing that onto sp will
-	// make the trace look like a call to runtime·sigpanic instead.
-	// (Otherwise the trace will end at runtime·sigpanic and we
-	// won't get to see who faulted.)
-	if r.eip != 0 {
-		sp := unsafe.Pointer(uintptr(r.esp))
-		sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
-		*((*uintptr)(sp)) = uintptr(r.eip)
-		r.esp = uint32(uintptr(sp))
-	}
-	r.eip = uint32(funcPC(sigpanic))
-	return _EXCEPTION_CONTINUE_EXECUTION
-}
-
-var testingWER bool
-
-// lastcontinuehandler is reached, because runtime cannot handle
-// current exception. lastcontinuehandler will print crash info and exit.
-func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
-	if testingWER {
-		return _EXCEPTION_CONTINUE_SEARCH
-	}
-
-	_g_ := getg()
-
-	if panicking != 0 { // traceback already printed
-		exit(2)
-	}
-	panicking = 1
-
-	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.eip), "\n")
-
-	print("PC=", hex(r.eip), "\n")
-	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
-		print("signal arrived during cgo execution\n")
-		gp = _g_.m.lockedg
-	}
-	print("\n")
-
-	var docrash bool
-	if gotraceback(&docrash) > 0 {
-		tracebacktrap(uintptr(r.eip), uintptr(r.esp), 0, gp)
-		tracebackothers(gp)
-		dumpregs(r)
-	}
-
-	if docrash {
-		crash()
-	}
-
-	exit(2)
-	return 0 // not reached
-}
-
-func sigenable(sig uint32) {
-}
-
-func sigdisable(sig uint32) {
-}
-
-func sigignore(sig uint32) {
-}
diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go
deleted file mode 100644
index 37a97b7..0000000
--- a/src/runtime/os1_windows_amd64.go
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import (
-	"unsafe"
-)
-
-func dumpregs(r *context) {
-	print("rax     ", hex(r.rax), "\n")
-	print("rbx     ", hex(r.rbx), "\n")
-	print("rcx     ", hex(r.rcx), "\n")
-	print("rdi     ", hex(r.rdi), "\n")
-	print("rsi     ", hex(r.rsi), "\n")
-	print("rbp     ", hex(r.rbp), "\n")
-	print("rsp     ", hex(r.rsp), "\n")
-	print("r8      ", hex(r.r8), "\n")
-	print("r9      ", hex(r.r9), "\n")
-	print("r10     ", hex(r.r10), "\n")
-	print("r11     ", hex(r.r11), "\n")
-	print("r12     ", hex(r.r12), "\n")
-	print("r13     ", hex(r.r13), "\n")
-	print("r14     ", hex(r.r14), "\n")
-	print("r15     ", hex(r.r15), "\n")
-	print("rip     ", hex(r.rip), "\n")
-	print("rflags  ", hex(r.eflags), "\n")
-	print("cs      ", hex(r.segcs), "\n")
-	print("fs      ", hex(r.segfs), "\n")
-	print("gs      ", hex(r.seggs), "\n")
-}
-
-func isgoexception(info *exceptionrecord, r *context) bool {
-	// Only handle exception if executing instructions in Go binary
-	// (not Windows library code).
-	if r.rip < uint64(themoduledata.text) || uint64(themoduledata.etext) < r.rip {
-		return false
-	}
-
-	if issigpanic(info.exceptioncode) == 0 {
-		return false
-	}
-
-	return true
-}
-
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
-// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
-
-func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
-	if !isgoexception(info, r) {
-		return _EXCEPTION_CONTINUE_SEARCH
-	}
-
-	// Make it look like a call to the signal func.
-	// Have to pass arguments out of band since
-	// augmenting the stack frame would break
-	// the unwinding code.
-	gp.sig = info.exceptioncode
-	gp.sigcode0 = uintptr(info.exceptioninformation[0])
-	gp.sigcode1 = uintptr(info.exceptioninformation[1])
-	gp.sigpc = uintptr(r.rip)
-
-	// Only push runtime·sigpanic if r->rip != 0.
-	// If r->rip == 0, probably panicked because of a
-	// call to a nil func.  Not pushing that onto sp will
-	// make the trace look like a call to runtime·sigpanic instead.
-	// (Otherwise the trace will end at runtime·sigpanic and we
-	// won't get to see who faulted.)
-	if r.rip != 0 {
-		sp := unsafe.Pointer(uintptr(r.rsp))
-		sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
-		*((*uintptr)(sp)) = uintptr(r.rip)
-		r.rsp = uint64(uintptr(sp))
-	}
-	r.rip = uint64(funcPC(sigpanic))
-	return _EXCEPTION_CONTINUE_EXECUTION
-}
-
-// It seems Windows searches ContinueHandler's list even
-// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
-// firstcontinuehandler will stop that search,
-// if exceptionhandler did the same earlier.
-func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
-	if !isgoexception(info, r) {
-		return _EXCEPTION_CONTINUE_SEARCH
-	}
-	return _EXCEPTION_CONTINUE_EXECUTION
-}
-
-var testingWER bool
-
-// lastcontinuehandler is reached, because runtime cannot handle
-// current exception. lastcontinuehandler will print crash info and exit.
-func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
-	if testingWER {
-		return _EXCEPTION_CONTINUE_SEARCH
-	}
-
-	_g_ := getg()
-
-	if panicking != 0 { // traceback already printed
-		exit(2)
-	}
-	panicking = 1
-
-	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.rip), "\n")
-
-	print("PC=", hex(r.rip), "\n")
-	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
-		print("signal arrived during cgo execution\n")
-		gp = _g_.m.lockedg
-	}
-	print("\n")
-
-	var docrash bool
-	if gotraceback(&docrash) > 0 {
-		tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp)
-		tracebackothers(gp)
-		dumpregs(r)
-	}
-
-	if docrash {
-		crash()
-	}
-
-	exit(2)
-	return 0 // not reached
-}
-
-func sigenable(sig uint32) {
-}
-
-func sigdisable(sig uint32) {
-}
-
-func sigignore(sig uint32) {
-}
diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go
index d5b1f47..a867dfe 100644
--- a/src/runtime/os2_windows.go
+++ b/src/runtime/os2_windows.go
@@ -4,12 +4,6 @@
 
 package runtime
 
-import "unsafe"
-
-// Call a Windows function with stdcall conventions,
-// and switch to os stack during the call.
-func asmstdcall(fn unsafe.Pointer)
-
 func getlasterror() uint32
 func setlasterror(err uint32)
 
diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go
index fa49ad6..248576a 100644
--- a/src/runtime/os3_plan9.go
+++ b/src/runtime/os3_plan9.go
@@ -81,7 +81,7 @@
 	}
 Throw:
 	_g_.m.throwing = 1
-	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	_g_.m.caughtsig.set(gp)
 	startpanic()
 	print(notestr, "\n")
 	print("PC=", hex(c.pc()), "\n")
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 7a4d27e..69ac5b4 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -173,7 +173,7 @@
 func getRandomData(r []byte) {
 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
-	close(fd)
+	closefd(fd)
 	extendRandom(r, int(n))
 }
 
@@ -194,7 +194,7 @@
 // Called on the new thread, can not allocate memory.
 func minit() {
 	_g_ := getg()
-	asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(libc____errno))
+	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)
@@ -290,7 +290,7 @@
 	// Call libc's malloc rather than malloc.  This will
 	// allocate space on the C heap.  We can't call malloc
 	// here because it could cause a deadlock.
-	_g_.m.libcall.fn = uintptr(libc_malloc)
+	_g_.m.libcall.fn = uintptr(unsafe.Pointer(&libc_malloc))
 	_g_.m.libcall.n = 1
 	memclr(unsafe.Pointer(&_g_.m.scratch), uintptr(len(_g_.m.scratch.v)))
 	_g_.m.scratch.v[0] = unsafe.Sizeof(*sem)
@@ -310,7 +310,7 @@
 		_m_.ts.tv_sec = ns / 1000000000
 		_m_.ts.tv_nsec = ns % 1000000000
 
-		_m_.libcall.fn = uintptr(unsafe.Pointer(libc_sem_reltimedwait_np))
+		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
 		_m_.libcall.n = 2
 		memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
 		_m_.scratch.v[0] = _m_.waitsema
@@ -326,7 +326,7 @@
 		return 0
 	}
 	for {
-		_m_.libcall.fn = uintptr(unsafe.Pointer(libc_sem_wait))
+		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
 		_m_.libcall.n = 1
 		memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
 		_m_.scratch.v[0] = _m_.waitsema
@@ -351,122 +351,122 @@
 }
 
 //go:nosplit
-func close(fd int32) int32 {
-	return int32(sysvicall1(libc_close, uintptr(fd)))
+func closefd(fd int32) int32 {
+	return int32(sysvicall1(&libc_close, uintptr(fd)))
 }
 
 //go:nosplit
 func exit(r int32) {
-	sysvicall1(libc_exit, uintptr(r))
+	sysvicall1(&libc_exit, uintptr(r))
 }
 
 //go:nosplit
 func getcontext(context *ucontext) /* int32 */ {
-	sysvicall1(libc_getcontext, uintptr(unsafe.Pointer(context)))
+	sysvicall1(&libc_getcontext, uintptr(unsafe.Pointer(context)))
 }
 
 //go:nosplit
 func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
-	sysvicall3(libc_madvise, uintptr(addr), uintptr(n), uintptr(flags))
+	sysvicall3(&libc_madvise, uintptr(addr), uintptr(n), uintptr(flags))
 }
 
 //go:nosplit
 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
-	return unsafe.Pointer(sysvicall6(libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)))
+	return unsafe.Pointer(sysvicall6(&libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)))
 }
 
 //go:nosplit
 func munmap(addr unsafe.Pointer, n uintptr) {
-	sysvicall2(libc_munmap, uintptr(addr), uintptr(n))
+	sysvicall2(&libc_munmap, uintptr(addr), uintptr(n))
 }
 
 func nanotime1()
 
 //go:nosplit
 func nanotime() int64 {
-	return int64(sysvicall0(libcFunc(funcPC(nanotime1))))
+	return int64(sysvicall0((*libcFunc)(unsafe.Pointer(funcPC(nanotime1)))))
 }
 
 //go:nosplit
 func open(path *byte, mode, perm int32) int32 {
-	return int32(sysvicall3(libc_open, uintptr(unsafe.Pointer(path)), uintptr(mode), uintptr(perm)))
+	return int32(sysvicall3(&libc_open, uintptr(unsafe.Pointer(path)), uintptr(mode), uintptr(perm)))
 }
 
 func pthread_attr_destroy(attr *pthreadattr) int32 {
-	return int32(sysvicall1(libc_pthread_attr_destroy, uintptr(unsafe.Pointer(attr))))
+	return int32(sysvicall1(&libc_pthread_attr_destroy, uintptr(unsafe.Pointer(attr))))
 }
 
 func pthread_attr_getstack(attr *pthreadattr, addr unsafe.Pointer, size *uint64) int32 {
-	return int32(sysvicall3(libc_pthread_attr_getstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(unsafe.Pointer(size))))
+	return int32(sysvicall3(&libc_pthread_attr_getstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(unsafe.Pointer(size))))
 }
 
 func pthread_attr_init(attr *pthreadattr) int32 {
-	return int32(sysvicall1(libc_pthread_attr_init, uintptr(unsafe.Pointer(attr))))
+	return int32(sysvicall1(&libc_pthread_attr_init, uintptr(unsafe.Pointer(attr))))
 }
 
 func pthread_attr_setdetachstate(attr *pthreadattr, state int32) int32 {
-	return int32(sysvicall2(libc_pthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state)))
+	return int32(sysvicall2(&libc_pthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state)))
 }
 
 func pthread_attr_setstack(attr *pthreadattr, addr uintptr, size uint64) int32 {
-	return int32(sysvicall3(libc_pthread_attr_setstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(size)))
+	return int32(sysvicall3(&libc_pthread_attr_setstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(size)))
 }
 
 func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.Pointer) int32 {
-	return int32(sysvicall4(libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
+	return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
 }
 
 func raise(sig int32) /* int32 */ {
-	sysvicall1(libc_raise, uintptr(sig))
+	sysvicall1(&libc_raise, uintptr(sig))
 }
 
 func raiseproc(sig int32) /* int32 */ {
-	sysvicall1(libc_raise, uintptr(sig))
+	sysvicall1(&libc_raise, uintptr(sig))
 }
 
 //go:nosplit
 func read(fd int32, buf unsafe.Pointer, nbyte int32) int32 {
-	return int32(sysvicall3(libc_read, uintptr(fd), uintptr(buf), uintptr(nbyte)))
+	return int32(sysvicall3(&libc_read, uintptr(fd), uintptr(buf), uintptr(nbyte)))
 }
 
 //go:nosplit
 func sem_init(sem *semt, pshared int32, value uint32) int32 {
-	return int32(sysvicall3(libc_sem_init, uintptr(unsafe.Pointer(sem)), uintptr(pshared), uintptr(value)))
+	return int32(sysvicall3(&libc_sem_init, uintptr(unsafe.Pointer(sem)), uintptr(pshared), uintptr(value)))
 }
 
 //go:nosplit
 func sem_post(sem *semt) int32 {
-	return int32(sysvicall1(libc_sem_post, uintptr(unsafe.Pointer(sem))))
+	return int32(sysvicall1(&libc_sem_post, uintptr(unsafe.Pointer(sem))))
 }
 
 //go:nosplit
 func sem_reltimedwait_np(sem *semt, timeout *timespec) int32 {
-	return int32(sysvicall2(libc_sem_reltimedwait_np, uintptr(unsafe.Pointer(sem)), uintptr(unsafe.Pointer(timeout))))
+	return int32(sysvicall2(&libc_sem_reltimedwait_np, uintptr(unsafe.Pointer(sem)), uintptr(unsafe.Pointer(timeout))))
 }
 
 //go:nosplit
 func sem_wait(sem *semt) int32 {
-	return int32(sysvicall1(libc_sem_wait, uintptr(unsafe.Pointer(sem))))
+	return int32(sysvicall1(&libc_sem_wait, uintptr(unsafe.Pointer(sem))))
 }
 
 func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
-	sysvicall3(libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
+	sysvicall3(&libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
 }
 
 func sigaction(sig int32, act *sigactiont, oact *sigactiont) /* int32 */ {
-	sysvicall3(libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
+	sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
 }
 
 func sigaltstack(ss *sigaltstackt, oss *sigaltstackt) /* int32 */ {
-	sysvicall2(libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
+	sysvicall2(&libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
 }
 
 func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
-	sysvicall3(libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
+	sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
 }
 
 func sysconf(name int32) int64 {
-	return int64(sysvicall1(libc_sysconf, uintptr(name)))
+	return int64(sysvicall1(&libc_sysconf, uintptr(name)))
 }
 
 func usleep1(uint32)
@@ -478,7 +478,7 @@
 
 //go:nosplit
 func write(fd uintptr, buf unsafe.Pointer, nbyte int32) int32 {
-	return int32(sysvicall3(libc_write, uintptr(fd), uintptr(buf), uintptr(nbyte)))
+	return int32(sysvicall3(&libc_write, uintptr(fd), uintptr(buf), uintptr(nbyte)))
 }
 
 func osyield1()
@@ -490,7 +490,7 @@
 	// Check the validity of m because we might be called in cgo callback
 	// path early enough where there isn't a m available yet.
 	if _g_ != nil && _g_.m != nil {
-		sysvicall0(libc_sched_yield)
+		sysvicall0(&libc_sched_yield)
 		return
 	}
 	osyield1()
diff --git a/src/runtime/os_android_arm.go b/src/runtime/os_android_arm.go
index be7c3c0..52c8c86 100644
--- a/src/runtime/os_android_arm.go
+++ b/src/runtime/os_android_arm.go
@@ -6,10 +6,10 @@
 
 import _ "unsafe" // for go:cgo_export_static and go:cgo_export_dynamic
 
-// Export the runtime entry point symbol.
+// Export the main function.
 //
-// Used by the app package to start the Go runtime after loading
-// a shared library via JNI. See golang.org/x/mobile/app.
+// Used by the app package to start all-Go Android apps that are
+// loaded via JNI. See golang.org/x/mobile/app.
 
-//go:cgo_export_static _rt0_arm_linux1
-//go:cgo_export_dynamic _rt0_arm_linux1
+//go:cgo_export_static main.main
+//go:cgo_export_dynamic main.main
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 15f8f44..c432c99 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -6,7 +6,7 @@
 
 import "unsafe"
 
-func bsdthread_create(stk unsafe.Pointer, mm *m, gg *g, fn uintptr) int32
+func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 func bsdthread_register() int32
 
 //go:noescape
@@ -33,5 +33,5 @@
 //go:noescape
 func setitimer(mode int32, new, old *itimerval)
 
-func raise(int32)
+func raise(sig int32)
 func raiseproc(int32)
diff --git a/src/runtime/os_darwin_arm64.go b/src/runtime/os_darwin_arm64.go
new file mode 100644
index 0000000..4d35af9
--- /dev/null
+++ b/src/runtime/os_darwin_arm64.go
@@ -0,0 +1,13 @@
+// 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.
+
+package runtime
+
+//go:nosplit
+func cputicks() int64 {
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// TODO: need more entropy to better seed fastrand1.
+	return nanotime()
+}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index 8cffd2b..60234bb 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -13,6 +13,9 @@
 func sigaltstack(new, old *sigaltstackt)
 
 //go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
 func sigaction(sig int32, new, old *sigactiont)
 
 //go:noescape
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index c274b39..b2b5cd1 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -13,6 +13,9 @@
 func sigaltstack(new, old *stackt)
 
 //go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
 func sigaction(sig int32, new, old *sigactiont)
 
 //go:noescape
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index abea5d6..523d28b 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -19,6 +19,9 @@
 func sigaltstack(new, old *sigaltstackt)
 
 //go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
 func setitimer(mode int32, new, old *itimerval)
 
 //go:noescape
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
index d88bf78..c5abedb 100644
--- a/src/runtime/os_linux_arm.go
+++ b/src/runtime/os_linux_arm.go
@@ -64,6 +64,7 @@
 	}
 }
 
+//go:nosplit
 func cputicks() int64 {
 	// Currently cputicks() is used in blocking profiler and to seed fastrand1().
 	// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go
index c3ad871..3f994f1 100644
--- a/src/runtime/os_linux_arm64.go
+++ b/src/runtime/os_linux_arm64.go
@@ -11,6 +11,7 @@
 
 var randomNumber uint32
 
+//go:nosplit
 func cputicks() int64 {
 	// Currently cputicks() is used in blocking profiler and to seed fastrand1().
 	// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index a6a796c..3b4c136 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -50,10 +50,14 @@
 	panicmem()
 }
 
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	throw("sigfwd not implemented")
+}
+
 func raiseproc(sig int32) {
 }
 
 // Stubs so tests can link correctly.  These should never be called.
 func open(name *byte, mode, perm int32) int32
-func close(fd int32) int32
+func closefd(fd int32) int32
 func read(fd int32, p unsafe.Pointer, n int32) int32
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index 4fa4a41..af52099 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -15,6 +15,10 @@
 //go:noescape
 func sigaltstack(new, old *sigaltstackt)
 
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	throw("sigfwd not implemented")
+}
+
 //go:noescape
 func sigprocmask(mode int32, new, old *sigset)
 
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index 8a97a73..f94b490 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 //go:noescape
 func setitimer(mode int32, new, old *itimerval)
 
@@ -14,6 +16,9 @@
 func sigaltstack(new, old *stackt)
 
 //go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
 func sigprocmask(mode int32, new uint32) uint32
 
 //go:noescape
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 870404b..6def35c 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -6,7 +6,7 @@
 
 import "unsafe"
 
-func close(fd int32) int32
+func closefd(fd int32) int32
 
 //go:noescape
 func open(name *byte, mode, perm int32) int32
diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go
index 6864ef9..fd20a5c 100644
--- a/src/runtime/os_solaris.go
+++ b/src/runtime/os_solaris.go
@@ -10,20 +10,23 @@
 
 var asmsysvicall6 libcFunc
 
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
 //go:nosplit
-func sysvicall0(fn libcFunc) uintptr {
+func sysvicall0(fn *libcFunc) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 0
-	libcall.args = uintptr(fn) // it's unused but must be non-nil, otherwise crashes
+	libcall.args = uintptr(unsafe.Pointer(fn)) // it's unused but must be non-nil, otherwise crashes
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
 	return libcall.r1
 }
 
 //go:nosplit
-func sysvicall1(fn libcFunc, a1 uintptr) uintptr {
+func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 1
 	// TODO(rsc): Why is noescape necessary here and below?
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
@@ -32,9 +35,9 @@
 }
 
 //go:nosplit
-func sysvicall2(fn libcFunc, a1, a2 uintptr) uintptr {
+func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 2
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -42,9 +45,9 @@
 }
 
 //go:nosplit
-func sysvicall3(fn libcFunc, a1, a2, a3 uintptr) uintptr {
+func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 3
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -52,9 +55,9 @@
 }
 
 //go:nosplit
-func sysvicall4(fn libcFunc, a1, a2, a3, a4 uintptr) uintptr {
+func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 4
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -62,9 +65,9 @@
 }
 
 //go:nosplit
-func sysvicall5(fn libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
+func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 5
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
@@ -72,9 +75,9 @@
 }
 
 //go:nosplit
-func sysvicall6(fn libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
+func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
 	libcall := &getg().m.libcall
-	libcall.fn = uintptr(fn)
+	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 6
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 744dc66..545b416 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -13,39 +13,12 @@
 	throw("too many writes on closed pipe")
 }
 
-func sigpanic() {
-	g := getg()
-	if !canpanic(g) {
-		throw("unexpected signal during runtime execution")
-	}
-
-	switch uint32(g.sig) {
-	case _EXCEPTION_ACCESS_VIOLATION:
-		if g.sigcode1 < 0x1000 || g.paniconfault {
-			panicmem()
-		}
-		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		throw("fault")
-	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
-		panicdivide()
-	case _EXCEPTION_INT_OVERFLOW:
-		panicoverflow()
-	case _EXCEPTION_FLT_DENORMAL_OPERAND,
-		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
-		_EXCEPTION_FLT_INEXACT_RESULT,
-		_EXCEPTION_FLT_OVERFLOW,
-		_EXCEPTION_FLT_UNDERFLOW:
-		panicfloat()
-	}
-	throw("fault")
-}
-
 // Stubs so tests can link correctly.  These should never be called.
 func open(name *byte, mode, perm int32) int32 {
 	throw("unimplemented")
 	return -1
 }
-func close(fd int32) int32 {
+func closefd(fd int32) int32 {
 	throw("unimplemented")
 	return -1
 }
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 9b937f5..0e4086c 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -165,7 +165,7 @@
 	sc := deferclass(uintptr(siz))
 	mp := acquirem()
 	if sc < uintptr(len(p{}.deferpool)) {
-		pp := mp.p
+		pp := mp.p.ptr()
 		if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
 			lock(&sched.deferlock)
 			for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
@@ -223,7 +223,7 @@
 	sc := deferclass(uintptr(d.siz))
 	if sc < uintptr(len(p{}.deferpool)) {
 		mp := acquirem()
-		pp := mp.p
+		pp := mp.p.ptr()
 		if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
 			// Transfer half of local cache to the central cache.
 			var first, last *_defer
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 65d0a0a..0189f45 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -122,7 +122,10 @@
 func testCPUProfile(t *testing.T, need []string, f func()) {
 	switch runtime.GOOS {
 	case "darwin":
-		if runtime.GOARCH != "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			// nothing
+		default:
 			out, err := exec.Command("uname", "-a").CombinedOutput()
 			if err != nil {
 				t.Fatal(err)
@@ -207,8 +210,9 @@
 // Ensure that we do not do this.
 func TestCPUProfileWithFork(t *testing.T) {
 	if runtime.GOOS == "darwin" {
-		if runtime.GOARCH == "arm" {
-			t.Skipf("skipping on darwin/arm")
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
 
diff --git a/src/runtime/pprof/trace_test.go b/src/runtime/pprof/trace_test.go
index 2b85e47..a333a3f 100644
--- a/src/runtime/pprof/trace_test.go
+++ b/src/runtime/pprof/trace_test.go
@@ -21,6 +21,11 @@
 	switch runtime.GOOS {
 	case "solaris":
 		t.Skip("skipping: solaris timer can go backwards (http://golang.org/issue/8976)")
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
+		}
 	}
 
 	switch runtime.GOARCH {
@@ -224,6 +229,7 @@
 // And concurrently with all that start/stop trace 3 times.
 func TestTraceStressStartStop(t *testing.T) {
 	skipTraceTestsIfNeeded(t)
+	t.Skip("test is unreliable; issue #10476")
 
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
 	outerDone := make(chan bool)
@@ -365,6 +371,10 @@
 	// The test generates a full-load of futile wakeups on channels,
 	// and ensures that the trace is consistent after their removal.
 	skipTraceTestsIfNeeded(t)
+	if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
+		t.Skip("test is unreliable; issue #10512")
+	}
+
 	buf := new(bytes.Buffer)
 	if err := StartTrace(buf); err != nil {
 		t.Fatalf("failed to start tracing: %v", err)
diff --git a/src/runtime/print1.go b/src/runtime/print1.go
index ba57991..6eff381 100644
--- a/src/runtime/print1.go
+++ b/src/runtime/print1.go
@@ -13,9 +13,9 @@
 func bytes(s string) (ret []byte) {
 	rp := (*slice)(unsafe.Pointer(&ret))
 	sp := (*_string)(noescape(unsafe.Pointer(&s)))
-	rp.array = sp.str
-	rp.len = uint(sp.len)
-	rp.cap = uint(sp.len)
+	rp.array = unsafe.Pointer(sp.str)
+	rp.len = sp.len
+	rp.cap = sp.len
 	return
 }
 
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index edab9bf..f725fc8 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -12,9 +12,18 @@
 //go:linkname main_init main.init
 func main_init()
 
+// main_init_done is a signal used by cgocallbackg that initialization
+// has been completed. It is made before _cgo_notify_runtime_init_done,
+// so all cgo calls can rely on it existing. When main_init is complete,
+// it is closed, meaning cgocallbackg can reliably receive from it.
+var main_init_done chan bool
+
 //go:linkname main_main main.main
 func main_main()
 
+// runtimeInitTime is the nanotime() at which the runtime started.
+var runtimeInitTime int64
+
 // The main goroutine.
 func main() {
 	g := getg()
@@ -32,6 +41,9 @@
 		maxstacksize = 250000000
 	}
 
+	// Record when the world started.
+	runtimeInitTime = nanotime()
+
 	systemstack(func() {
 		newm(sysmon, nil)
 	})
@@ -60,6 +72,7 @@
 
 	gcenable()
 
+	main_init_done = make(chan bool)
 	if iscgo {
 		if _cgo_thread_start == nil {
 			throw("_cgo_thread_start missing")
@@ -78,13 +91,23 @@
 				throw("_cgo_unsetenv missing")
 			}
 		}
+		if _cgo_notify_runtime_init_done == nil {
+			throw("_cgo_notify_runtime_init_done missing")
+		}
+		cgocall(_cgo_notify_runtime_init_done, nil)
 	}
 
 	main_init()
+	close(main_init_done)
 
 	needUnlock = false
 	unlockOSThread()
 
+	if isarchive || islibrary {
+		// A program compiled with -buildmode=c-archive or c-shared
+		// has a main, but it is not executed.
+		return
+	}
 	main_main()
 	if raceenabled {
 		racefini()
@@ -185,7 +208,7 @@
 	// The acquirem/releasem increments m.locks during new(sudog),
 	// which keeps the garbage collector from being invoked.
 	mp := acquirem()
-	pp := mp.p
+	pp := mp.p.ptr()
 	if len(pp.sudogcache) == 0 {
 		lock(&sched.sudoglock)
 		// First, try to grab a batch from central cache.
@@ -234,7 +257,7 @@
 		throw("runtime: releaseSudog with non-nil gp.param")
 	}
 	mp := acquirem() // avoid rescheduling to another P
-	pp := mp.p
+	pp := mp.p.ptr()
 	if len(pp.sudogcache) == cap(pp.sudogcache) {
 		// Transfer half of local cache to the central cache.
 		var first, last *sudog
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 7fa519d..00535da 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -51,7 +51,7 @@
 	framepointer_enabled = haveexperiment("framepointer")
 
 	tracebackinit()
-	symtabinit()
+	moduledataverify()
 	stackinit()
 	mallocinit()
 	mcommoninit(_g_.m)
@@ -145,7 +145,7 @@
 
 	// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
 	casgstatus(gp, _Gwaiting, _Grunnable)
-	runqput(_g_.m.p, gp)
+	runqput(_g_.m.p.ptr(), gp, true)
 	if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 { // TODO: fast atomic
 		wakep()
 	}
@@ -200,7 +200,7 @@
 			throw("gcprocs inconsistency")
 		}
 		mp.helpgc = n
-		mp.p = allp[pos]
+		mp.p.set(allp[pos])
 		mp.mcache = allp[pos].mcache
 		pos++
 		notewakeup(&mp.park)
@@ -208,19 +208,20 @@
 	unlock(&sched.lock)
 }
 
+// freezeStopWait is a large value that freezetheworld sets
+// 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.
 // There is no reverse operation, used during crashing.
 // This function must not lock any mutexes.
 func freezetheworld() {
-	if gomaxprocs == 1 {
-		return
-	}
 	// stopwait and preemption requests can be lost
 	// due to races with concurrently executing threads,
 	// so try several times
 	for i := 0; i < 5; i++ {
 		// this should tell the scheduler to not start any new goroutines
-		sched.stopwait = 0x7fffffff
+		sched.stopwait = freezeStopWait
 		atomicstore(&sched.gcwaiting, 1)
 		// this should stop running goroutines
 		if !preemptall() {
@@ -560,7 +561,7 @@
 	atomicstore(&sched.gcwaiting, 1)
 	preemptall()
 	// stop current P
-	_g_.m.p.status = _Pgcstop // Pgcstop is only diagnostic.
+	_g_.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic.
 	sched.stopwait--
 	// try to retake all P's in Psyscall status
 	for i := 0; i < int(gomaxprocs); i++ {
@@ -638,14 +639,14 @@
 
 	for p1 != nil {
 		p := p1
-		p1 = p1.link
-		if p.m != nil {
-			mp := p.m
-			p.m = nil
-			if mp.nextp != nil {
+		p1 = p1.link.ptr()
+		if p.m != 0 {
+			mp := p.m.ptr()
+			p.m = 0
+			if mp.nextp != 0 {
 				throw("starttheworld: inconsistent mp->nextp")
 			}
-			mp.nextp = p
+			mp.nextp.set(p)
 			notewakeup(&mp.park)
 		} else {
 			// Start M to run P.  Do not start another M below.
@@ -687,7 +688,7 @@
 		// Cgo may have left stack size in stack.hi.
 		size := _g_.stack.hi
 		if size == 0 {
-			size = 8192
+			size = 8192 * stackGuardMultiplier
 		}
 		_g_.stack.hi = uintptr(noescape(unsafe.Pointer(&size)))
 		_g_.stack.lo = _g_.stack.hi - size + 1024
@@ -725,8 +726,7 @@
 		initsig()
 	}
 
-	if _g_.m.mstartfn != 0 {
-		fn := *(*func())(unsafe.Pointer(&_g_.m.mstartfn))
+	if fn := _g_.m.mstartfn; fn != nil {
 		fn()
 	}
 
@@ -734,32 +734,152 @@
 		_g_.m.helpgc = 0
 		stopm()
 	} else if _g_.m != &m0 {
-		acquirep(_g_.m.nextp)
-		_g_.m.nextp = nil
+		acquirep(_g_.m.nextp.ptr())
+		_g_.m.nextp = 0
 	}
 	schedule()
 }
 
+// forEachP calls fn(p) for every P p when p reaches a GC safe point.
+// If a P is currently executing code, this will bring the P to a GC
+// safe point and execute fn on that P. If the P is not executing code
+// (it is idle or in a syscall), this will call fn(p) directly while
+// preventing the P from exiting its state. This does not ensure that
+// fn will run on every CPU executing Go code, but it acts as a global
+// memory barrier. GC uses this as a "ragged barrier."
+//
+// The caller must hold worldsema.
+func forEachP(fn func(*p)) {
+	mp := acquirem()
+	_p_ := getg().m.p.ptr()
+
+	lock(&sched.lock)
+	if sched.stopwait != 0 {
+		throw("forEachP: sched.stopwait != 0")
+	}
+	sched.stopwait = gomaxprocs - 1
+	sched.safePointFn = fn
+
+	// Ask all Ps to run the safe point function.
+	for _, p := range allp[:gomaxprocs] {
+		if p != _p_ {
+			atomicstore(&p.runSafePointFn, 1)
+		}
+	}
+	preemptall()
+
+	// Any P entering _Pidle or _Psyscall from now on will observe
+	// p.runSafePointFn == 1 and will call runSafePointFn when
+	// changing its status to _Pidle/_Psyscall.
+
+	// Run safe point function for all idle Ps. sched.pidle will
+	// not change because we hold sched.lock.
+	for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() {
+		if cas(&p.runSafePointFn, 1, 0) {
+			fn(p)
+			sched.stopwait--
+		}
+	}
+
+	wait := sched.stopwait > 0
+	unlock(&sched.lock)
+
+	// Run fn for the current P.
+	fn(_p_)
+
+	// Force Ps currently in _Psyscall into _Pidle and hand them
+	// off to induce safe point function execution.
+	for i := 0; i < int(gomaxprocs); i++ {
+		p := allp[i]
+		s := p.status
+		if s == _Psyscall && p.runSafePointFn == 1 && cas(&p.status, s, _Pidle) {
+			if trace.enabled {
+				traceGoSysBlock(p)
+				traceProcStop(p)
+			}
+			p.syscalltick++
+			handoffp(p)
+		}
+	}
+
+	// Wait for remaining Ps to run fn.
+	if wait {
+		for {
+			// Wait for 100us, then try to re-preempt in
+			// case of any races.
+			if notetsleep(&sched.stopnote, 100*1000) {
+				noteclear(&sched.stopnote)
+				break
+			}
+			preemptall()
+		}
+	}
+	if sched.stopwait != 0 {
+		throw("forEachP: not stopped")
+	}
+	for i := 0; i < int(gomaxprocs); i++ {
+		p := allp[i]
+		if p.runSafePointFn != 0 {
+			throw("forEachP: P did not run fn")
+		}
+	}
+
+	lock(&sched.lock)
+	sched.safePointFn = nil
+	unlock(&sched.lock)
+	releasem(mp)
+}
+
+// runSafePointFn runs the safe point function, if any, for this P.
+// This should be called like
+//
+//     if getg().m.p.runSafePointFn != 0 {
+//         runSafePointFn()
+//     }
+//
+// runSafePointFn must be checked on any transition in to _Pidle or
+// _Psyscall to avoid a race where forEachP sees that the P is running
+// just before the P goes into _Pidle/_Psyscall and neither forEachP
+// nor the P run the safe-point function.
+func runSafePointFn() {
+	p := getg().m.p.ptr()
+	// Resolve the race between forEachP running the safe-point
+	// function on this P's behalf and this P running the
+	// safe-point function directly.
+	if !cas(&p.runSafePointFn, 1, 0) {
+		return
+	}
+	sched.safePointFn(p)
+	lock(&sched.lock)
+	sched.stopwait--
+	if sched.stopwait == 0 {
+		notewakeup(&sched.stopnote)
+	}
+	unlock(&sched.lock)
+}
+
 // When running with cgo, we call _cgo_thread_start
 // to start threads for us so that we can play nicely with
 // foreign code.
 var cgoThreadStart unsafe.Pointer
 
 type cgothreadstart struct {
-	g   *g
+	g   guintptr
 	tls *uint64
 	fn  unsafe.Pointer
 }
 
 // Allocate a new m unassociated with any thread.
 // Can use p for allocation context if needed.
-func allocm(_p_ *p) *m {
+// fn is recorded as the new m's m.mstartfn.
+func allocm(_p_ *p, fn func()) *m {
 	_g_ := getg()
 	_g_.m.locks++ // disable GC because it can be called from sysmon
-	if _g_.m.p == nil {
+	if _g_.m.p == 0 {
 		acquirep(_p_) // temporarily borrow p for mallocs in this function
 	}
 	mp := new(m)
+	mp.mstartfn = fn
 	mcommoninit(mp)
 
 	// In case of cgo or Solaris, pthread_create will make us a stack.
@@ -767,11 +887,11 @@
 	if iscgo || GOOS == "solaris" || GOOS == "windows" || GOOS == "plan9" {
 		mp.g0 = malg(-1)
 	} else {
-		mp.g0 = malg(8192)
+		mp.g0 = malg(8192 * stackGuardMultiplier)
 	}
 	mp.g0.m = mp
 
-	if _p_ == _g_.m.p {
+	if _p_ == _g_.m.p.ptr() {
 		releasep()
 	}
 	_g_.m.locks--
@@ -837,8 +957,8 @@
 	// after exitsyscall makes sure it is okay to be
 	// running at all (that is, there's no garbage collection
 	// running right now).
-	mp.needextram = mp.schedlink == nil
-	unlockextra(mp.schedlink)
+	mp.needextram = mp.schedlink == 0
+	unlockextra(mp.schedlink.ptr())
 
 	// Install g (= m->g0) and set the stack bounds
 	// to match the current stack. We don't actually know
@@ -867,7 +987,7 @@
 	// The sched.pc will never be returned to, but setting it to
 	// goexit makes clear to the traceback routines where
 	// the goroutine stack ends.
-	mp := allocm(nil)
+	mp := allocm(nil, nil)
 	gp := malg(4096)
 	gp.sched.pc = funcPC(goexit) + _PCQuantum
 	gp.sched.sp = gp.stack.hi
@@ -893,7 +1013,7 @@
 
 	// Add m to the extra list.
 	mnext := lockextra(true)
-	mp.schedlink = mnext
+	mp.schedlink.set(mnext)
 	unlockextra(mp)
 }
 
@@ -929,7 +1049,7 @@
 	// with no pointer manipulation.
 	mp := getg().m
 	mnext := lockextra(true)
-	mp.schedlink = mnext
+	mp.schedlink.set(mnext)
 
 	setg(nil)
 	unlockextra(mp)
@@ -976,18 +1096,14 @@
 // May run with m.p==nil, so write barriers are not allowed.
 //go:nowritebarrier
 func newm(fn func(), _p_ *p) {
-	mp := allocm(_p_)
-	// procresize made _p_ reachable through allp, which doesn't change during GC, so WB can be eliminated
-	setPNoWriteBarrier(&mp.nextp, _p_)
-	// Store &fn as a uintptr since it is not heap allocated so the WB can be eliminated
-	mp.mstartfn = *(*uintptr)(unsafe.Pointer(&fn))
+	mp := allocm(_p_, fn)
+	mp.nextp.set(_p_)
 	if iscgo {
 		var ts cgothreadstart
 		if _cgo_thread_start == nil {
 			throw("_cgo_thread_start missing")
 		}
-		// mp is reachable via allm and mp.g0 never changes, so WB can be eliminated.
-		setGNoWriteBarrier(&ts.g, mp.g0)
+		ts.g.set(mp.g0)
 		ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0]))
 		ts.fn = unsafe.Pointer(funcPC(mstart))
 		asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
@@ -1004,7 +1120,7 @@
 	if _g_.m.locks != 0 {
 		throw("stopm holding locks")
 	}
-	if _g_.m.p != nil {
+	if _g_.m.p != 0 {
 		throw("stopm holding p")
 	}
 	if _g_.m.spinning {
@@ -1022,15 +1138,25 @@
 		gchelper()
 		_g_.m.helpgc = 0
 		_g_.m.mcache = nil
-		_g_.m.p = nil
+		_g_.m.p = 0
 		goto retry
 	}
-	acquirep(_g_.m.nextp)
-	_g_.m.nextp = nil
+	acquirep(_g_.m.nextp.ptr())
+	_g_.m.nextp = 0
 }
 
 func mspinning() {
-	getg().m.spinning = true
+	gp := getg()
+	if !runqempty(gp.m.nextp.ptr()) {
+		// Something (presumably the GC) was readied while the
+		// runtime was starting up this M, so the M is no
+		// longer spinning.
+		if int32(xadd(&sched.nmspinning, -1)) < 0 {
+			throw("mspinning: nmspinning underflowed")
+		}
+	} else {
+		gp.m.spinning = true
+	}
 }
 
 // Schedules some M to run the p (creates an M if necessary).
@@ -1062,12 +1188,14 @@
 	if mp.spinning {
 		throw("startm: m is spinning")
 	}
-	if mp.nextp != nil {
+	if mp.nextp != 0 {
 		throw("startm: m has p")
 	}
+	if spinning && !runqempty(_p_) {
+		throw("startm: p has runnable gs")
+	}
 	mp.spinning = spinning
-	// procresize made _p_ reachable through allp, which doesn't change during GC, so WB can be eliminated
-	setPNoWriteBarrier(&mp.nextp, _p_)
+	mp.nextp.set(_p_)
 	notewakeup(&mp.park)
 }
 
@@ -1076,7 +1204,7 @@
 //go:nowritebarrier
 func handoffp(_p_ *p) {
 	// if it has local work, start it straight away
-	if _p_.runqhead != _p_.runqtail || sched.runqsize != 0 {
+	if !runqempty(_p_) || sched.runqsize != 0 {
 		startm(_p_, false)
 		return
 	}
@@ -1096,6 +1224,13 @@
 		unlock(&sched.lock)
 		return
 	}
+	if _p_.runSafePointFn != 0 && cas(&_p_.runSafePointFn, 1, 0) {
+		sched.safePointFn(_p_)
+		sched.stopwait--
+		if sched.stopwait == 0 {
+			notewakeup(&sched.stopnote)
+		}
+	}
 	if sched.runqsize != 0 {
 		unlock(&sched.lock)
 		startm(_p_, false)
@@ -1130,7 +1265,7 @@
 	if _g_.m.lockedg == nil || _g_.m.lockedg.lockedm != _g_.m {
 		throw("stoplockedm: inconsistent locking")
 	}
-	if _g_.m.p != nil {
+	if _g_.m.p != 0 {
 		// Schedule another M to run this p.
 		_p_ := releasep()
 		handoffp(_p_)
@@ -1145,8 +1280,8 @@
 		dumpgstatus(_g_)
 		throw("stoplockedm: not runnable")
 	}
-	acquirep(_g_.m.nextp)
-	_g_.m.nextp = nil
+	acquirep(_g_.m.nextp.ptr())
+	_g_.m.nextp = 0
 }
 
 // Schedules the locked m to run the locked gp.
@@ -1159,14 +1294,13 @@
 	if mp == _g_.m {
 		throw("startlockedm: locked to me")
 	}
-	if mp.nextp != nil {
+	if mp.nextp != 0 {
 		throw("startlockedm: m has p")
 	}
 	// directly handoff current P to the locked m
 	incidlelocked(-1)
 	_p_ := releasep()
-	// procresize made _p_ reachable through allp, which doesn't change during GC, so WB can be eliminated
-	setPNoWriteBarrier(&mp.nextp, _p_)
+	mp.nextp.set(_p_)
 	notewakeup(&mp.park)
 	stopm()
 }
@@ -1195,15 +1329,19 @@
 }
 
 // Schedules gp to run on the current M.
+// If inheritTime is true, gp inherits the remaining time in the
+// current time slice. Otherwise, it starts a new time slice.
 // Never returns.
-func execute(gp *g) {
+func execute(gp *g, inheritTime bool) {
 	_g_ := getg()
 
 	casgstatus(gp, _Grunnable, _Grunning)
 	gp.waitsince = 0
 	gp.preempt = false
 	gp.stackguard0 = gp.stack.lo + _StackGuard
-	_g_.m.p.schedtick++
+	if !inheritTime {
+		_g_.m.p.ptr().schedtick++
+	}
 	_g_.m.curg = gp
 	gp.m = _g_.m
 
@@ -1222,7 +1360,7 @@
 
 // Finds a runnable goroutine to execute.
 // Tries to steal from other P's, get g from global queue, poll network.
-func findrunnable() *g {
+func findrunnable() (gp *g, inheritTime bool) {
 	_g_ := getg()
 
 top:
@@ -1230,6 +1368,9 @@
 		gcstopm()
 		goto top
 	}
+	if _g_.m.p.ptr().runSafePointFn != 0 {
+		runSafePointFn()
+	}
 	if fingwait && fingwake {
 		if gp := wakefing(); gp != nil {
 			ready(gp, 0)
@@ -1237,17 +1378,17 @@
 	}
 
 	// local runq
-	if gp := runqget(_g_.m.p); gp != nil {
-		return gp
+	if gp, inheritTime := runqget(_g_.m.p.ptr()); gp != nil {
+		return gp, inheritTime
 	}
 
 	// global runq
 	if sched.runqsize != 0 {
 		lock(&sched.lock)
-		gp := globrunqget(_g_.m.p, 0)
+		gp := globrunqget(_g_.m.p.ptr(), 0)
 		unlock(&sched.lock)
 		if gp != nil {
-			return gp
+			return gp, false
 		}
 	}
 
@@ -1260,12 +1401,12 @@
 	if netpollinited() && sched.lastpoll != 0 {
 		if gp := netpoll(false); gp != nil { // non-blocking
 			// netpoll returns list of goroutines linked by schedlink.
-			injectglist(gp.schedlink)
+			injectglist(gp.schedlink.ptr())
 			casgstatus(gp, _Gwaiting, _Grunnable)
 			if trace.enabled {
 				traceGoUnpark(gp, 0)
 			}
-			return gp
+			return gp, false
 		}
 	}
 
@@ -1286,27 +1427,40 @@
 		}
 		_p_ := allp[fastrand1()%uint32(gomaxprocs)]
 		var gp *g
-		if _p_ == _g_.m.p {
-			gp = runqget(_p_)
+		if _p_ == _g_.m.p.ptr() {
+			gp, _ = runqget(_p_)
 		} else {
-			gp = runqsteal(_g_.m.p, _p_)
+			gp = runqsteal(_g_.m.p.ptr(), _p_)
 		}
 		if gp != nil {
-			return gp
+			return gp, false
 		}
 	}
 stop:
 
+	// We have nothing to do. If we're in the GC mark phaseand 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 {
+		_p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
+		gp := _p_.gcBgMarkWorker
+		casgstatus(gp, _Gwaiting, _Grunnable)
+		if trace.enabled {
+			traceGoUnpark(gp, 0)
+		}
+		return gp, false
+	}
+
 	// return P and block
 	lock(&sched.lock)
-	if sched.gcwaiting != 0 {
+	if sched.gcwaiting != 0 || _g_.m.p.ptr().runSafePointFn != 0 {
 		unlock(&sched.lock)
 		goto top
 	}
 	if sched.runqsize != 0 {
-		gp := globrunqget(_g_.m.p, 0)
+		gp := globrunqget(_g_.m.p.ptr(), 0)
 		unlock(&sched.lock)
-		return gp
+		return gp, false
 	}
 	_p_ := releasep()
 	pidleput(_p_)
@@ -1319,7 +1473,7 @@
 	// check all runqueues once again
 	for i := 0; i < int(gomaxprocs); i++ {
 		_p_ := allp[i]
-		if _p_ != nil && _p_.runqhead != _p_.runqtail {
+		if _p_ != nil && !runqempty(_p_) {
 			lock(&sched.lock)
 			_p_ = pidleget()
 			unlock(&sched.lock)
@@ -1333,7 +1487,7 @@
 
 	// poll network
 	if netpollinited() && xchg64(&sched.lastpoll, 0) != 0 {
-		if _g_.m.p != nil {
+		if _g_.m.p != 0 {
 			throw("findrunnable: netpoll with p")
 		}
 		if _g_.m.spinning {
@@ -1347,12 +1501,12 @@
 			unlock(&sched.lock)
 			if _p_ != nil {
 				acquirep(_p_)
-				injectglist(gp.schedlink)
+				injectglist(gp.schedlink.ptr())
 				casgstatus(gp, _Gwaiting, _Grunnable)
 				if trace.enabled {
 					traceGoUnpark(gp, 0)
 				}
-				return gp
+				return gp, false
 			}
 			injectglist(gp)
 		}
@@ -1389,7 +1543,7 @@
 		return
 	}
 	if trace.enabled {
-		for gp := glist; gp != nil; gp = gp.schedlink {
+		for gp := glist; gp != nil; gp = gp.schedlink.ptr() {
 			traceGoUnpark(gp, 0)
 		}
 	}
@@ -1397,7 +1551,7 @@
 	var n int
 	for n = 0; glist != nil; n++ {
 		gp := glist
-		glist = gp.schedlink
+		glist = gp.schedlink.ptr()
 		casgstatus(gp, _Gwaiting, _Grunnable)
 		globrunqput(gp)
 	}
@@ -1418,7 +1572,7 @@
 
 	if _g_.m.lockedg != nil {
 		stoplockedm()
-		execute(_g_.m.lockedg) // Never returns.
+		execute(_g_.m.lockedg, false) // Never returns.
 	}
 
 top:
@@ -1426,8 +1580,12 @@
 		gcstopm()
 		goto top
 	}
+	if _g_.m.p.ptr().runSafePointFn != 0 {
+		runSafePointFn()
+	}
 
 	var gp *g
+	var inheritTime bool
 	if trace.enabled || trace.shutdown {
 		gp = traceReader()
 		if gp != nil {
@@ -1436,13 +1594,19 @@
 			resetspinning()
 		}
 	}
+	if gp == nil && gcBlackenEnabled != 0 {
+		gp = gcController.findRunnableGCWorker(_g_.m.p.ptr())
+		if gp != nil {
+			resetspinning()
+		}
+	}
 	if gp == nil {
 		// Check the global runnable queue once in a while to ensure fairness.
 		// Otherwise two goroutines can completely occupy the local runqueue
 		// by constantly respawning each other.
-		if _g_.m.p.schedtick%61 == 0 && sched.runqsize > 0 {
+		if _g_.m.p.ptr().schedtick%61 == 0 && sched.runqsize > 0 {
 			lock(&sched.lock)
-			gp = globrunqget(_g_.m.p, 1)
+			gp = globrunqget(_g_.m.p.ptr(), 1)
 			unlock(&sched.lock)
 			if gp != nil {
 				resetspinning()
@@ -1450,13 +1614,13 @@
 		}
 	}
 	if gp == nil {
-		gp = runqget(_g_.m.p)
+		gp, inheritTime = runqget(_g_.m.p.ptr())
 		if gp != nil && _g_.m.spinning {
 			throw("schedule: spinning with local work")
 		}
 	}
 	if gp == nil {
-		gp = findrunnable() // blocks until work is available
+		gp, inheritTime = findrunnable() // blocks until work is available
 		resetspinning()
 	}
 
@@ -1467,7 +1631,7 @@
 		goto top
 	}
 
-	execute(gp)
+	execute(gp, inheritTime)
 }
 
 // dropg removes the association between m and the current goroutine m->curg (gp for short).
@@ -1512,7 +1676,7 @@
 				traceGoUnpark(gp, 2)
 			}
 			casgstatus(gp, _Gwaiting, _Grunnable)
-			execute(gp) // Schedule it back, never returns.
+			execute(gp, true) // Schedule it back, never returns.
 		}
 	}
 	schedule()
@@ -1581,7 +1745,7 @@
 		throw("internal lockOSThread error")
 	}
 	_g_.m.locked = 0
-	gfput(_g_.m.p, gp)
+	gfput(_g_.m.p.ptr(), gp)
 	schedule()
 }
 
@@ -1628,7 +1792,7 @@
 // when syscall returns we emit traceGoSysExit and when the goroutine starts running
 // (potentially instantly, if exitsyscallfast returns true) we emit traceGoStart.
 // To ensure that traceGoSysExit is emitted strictly after traceGoSysBlock,
-// we remember current value of syscalltick in m (_g_.m.syscalltick = _g_.m.p.syscalltick),
+// we remember current value of syscalltick in m (_g_.m.syscalltick = _g_.m.p.ptr().syscalltick),
 // whoever emits traceGoSysBlock increments p.syscalltick afterwards;
 // and we wait for the increment before emitting traceGoSysExit.
 // Note that the increment is done even if tracing is not enabled,
@@ -1670,10 +1834,14 @@
 		save(pc, sp)
 	}
 
-	_g_.m.syscalltick = _g_.m.p.syscalltick
+	_g_.m.syscalltick = _g_.m.p.ptr().syscalltick
 	_g_.m.mcache = nil
-	_g_.m.p.m = nil
-	atomicstore(&_g_.m.p.status, _Psyscall)
+	_g_.m.p.ptr().m = 0
+	atomicstore(&_g_.m.p.ptr().status, _Psyscall)
+	if _g_.m.p.ptr().runSafePointFn != 0 {
+		// runSafePointFn may stack split if run on this stack
+		systemstack(runSafePointFn)
+	}
 	if sched.gcwaiting != 0 {
 		systemstack(entersyscall_gcwait)
 		save(pc, sp)
@@ -1703,7 +1871,7 @@
 
 func entersyscall_gcwait() {
 	_g_ := getg()
-	_p_ := _g_.m.p
+	_p_ := _g_.m.p.ptr()
 
 	lock(&sched.lock)
 	if sched.stopwait > 0 && cas(&_p_.status, _Psyscall, _Pgcstop) {
@@ -1727,8 +1895,8 @@
 	_g_.m.locks++ // see comment in entersyscall
 	_g_.throwsplit = true
 	_g_.stackguard0 = stackPreempt // see comment in entersyscall
-	_g_.m.syscalltick = _g_.m.p.syscalltick
-	_g_.m.p.syscalltick++
+	_g_.m.syscalltick = _g_.m.p.ptr().syscalltick
+	_g_.m.p.ptr().syscalltick++
 
 	// Leave SP around for GC and traceback.
 	pc := getcallerpc(unsafe.Pointer(&dummy))
@@ -1764,7 +1932,7 @@
 func entersyscallblock_handoff() {
 	if trace.enabled {
 		traceGoSysCall()
-		traceGoSysBlock(getg().m.p)
+		traceGoSysBlock(getg().m.p.ptr())
 	}
 	handoffp(releasep())
 }
@@ -1783,18 +1951,18 @@
 	}
 
 	_g_.waitsince = 0
-	oldp := _g_.m.p
+	oldp := _g_.m.p.ptr()
 	if exitsyscallfast() {
 		if _g_.m.mcache == nil {
 			throw("lost mcache")
 		}
 		if trace.enabled {
-			if oldp != _g_.m.p || _g_.m.syscalltick != _g_.m.p.syscalltick {
+			if oldp != _g_.m.p.ptr() || _g_.m.syscalltick != _g_.m.p.ptr().syscalltick {
 				systemstack(traceGoStart)
 			}
 		}
 		// There's a cpu for us, so we can run.
-		_g_.m.p.syscalltick++
+		_g_.m.p.ptr().syscalltick++
 		// We need to cas the status and scan before resuming...
 		casgstatus(_g_, _Gsyscall, _Grunning)
 
@@ -1813,17 +1981,18 @@
 		return
 	}
 
+	var exitTicks int64
 	if trace.enabled {
 		// Wait till traceGoSysBlock event is emited.
 		// This ensures consistency of the trace (the goroutine is started after it is blocked).
 		for oldp != nil && oldp.syscalltick == _g_.m.syscalltick {
 			osyield()
 		}
-		// This can't be done since the GC may be running and this code
-		// will invoke write barriers.
-		// TODO: Figure out how to get traceGoSysExit into the trace log or
-		// it is likely not to work as expected.
-		//		systemstack(traceGoSysExit)
+		// We can't trace syscall exit right now because we don't have a P.
+		// Tracing code can invoke write barriers that cannot run without a P.
+		// So instead we remember the syscall exit time and emit the event
+		// below when we have a P.
+		exitTicks = cputicks()
 	}
 
 	_g_.m.locks--
@@ -1831,6 +2000,11 @@
 	// Call the scheduler.
 	mcall(exitsyscall0)
 
+	// The goroutine must not be re-scheduled up to traceGoSysExit.
+	// Otherwise we can emit GoStart but not GoSysExit, that would lead
+	// no an inconsistent trace.
+	_g_.m.locks++
+
 	if _g_.m.mcache == nil {
 		throw("lost mcache")
 	}
@@ -1842,8 +2016,15 @@
 	// we don't know for sure that the garbage collector
 	// is not running.
 	_g_.syscallsp = 0
-	_g_.m.p.syscalltick++
+	_g_.m.p.ptr().syscalltick++
 	_g_.throwsplit = false
+
+	if exitTicks != 0 {
+		systemstack(func() {
+			traceGoSysExit(exitTicks)
+		})
+	}
+	_g_.m.locks--
 }
 
 //go:nosplit
@@ -1851,39 +2032,39 @@
 	_g_ := getg()
 
 	// Freezetheworld sets stopwait but does not retake P's.
-	if sched.stopwait != 0 {
+	if sched.stopwait == freezeStopWait {
 		_g_.m.mcache = nil
-		_g_.m.p = nil
+		_g_.m.p = 0
 		return false
 	}
 
 	// Try to re-acquire the last P.
-	if _g_.m.p != nil && _g_.m.p.status == _Psyscall && cas(&_g_.m.p.status, _Psyscall, _Prunning) {
+	if _g_.m.p != 0 && _g_.m.p.ptr().status == _Psyscall && cas(&_g_.m.p.ptr().status, _Psyscall, _Prunning) {
 		// There's a cpu for us, so we can run.
-		_g_.m.mcache = _g_.m.p.mcache
-		_g_.m.p.m = _g_.m
-		if _g_.m.syscalltick != _g_.m.p.syscalltick {
+		_g_.m.mcache = _g_.m.p.ptr().mcache
+		_g_.m.p.ptr().m.set(_g_.m)
+		if _g_.m.syscalltick != _g_.m.p.ptr().syscalltick {
 			if trace.enabled {
 				// The p was retaken and then enter into syscall again (since _g_.m.syscalltick has changed).
 				// traceGoSysBlock for this syscall was already emitted,
 				// but here we effectively retake the p from the new syscall running on the same p.
 				systemstack(func() {
 					// Denote blocking of the new syscall.
-					traceGoSysBlock(_g_.m.p)
+					traceGoSysBlock(_g_.m.p.ptr())
 					// Denote completion of the current syscall.
-					traceGoSysExit()
+					traceGoSysExit(0)
 				})
 			}
-			_g_.m.p.syscalltick++
+			_g_.m.p.ptr().syscalltick++
 		}
 		return true
 	}
 
 	// Try to get any other idle P.
-	oldp := _g_.m.p
+	oldp := _g_.m.p.ptr()
 	_g_.m.mcache = nil
-	_g_.m.p = nil
-	if sched.pidle != nil {
+	_g_.m.p = 0
+	if sched.pidle != 0 {
 		var ok bool
 		systemstack(func() {
 			ok = exitsyscallfast_pidle()
@@ -1895,7 +2076,7 @@
 						osyield()
 					}
 				}
-				traceGoSysExit()
+				traceGoSysExit(0)
 			}
 		})
 		if ok {
@@ -1938,12 +2119,12 @@
 	unlock(&sched.lock)
 	if _p_ != nil {
 		acquirep(_p_)
-		execute(gp) // Never returns.
+		execute(gp, false) // Never returns.
 	}
 	if _g_.m.lockedg != nil {
 		// Wait until another thread schedules gp and so m again.
 		stoplockedm()
-		execute(gp) // Never returns.
+		execute(gp, false) // Never returns.
 	}
 	stopm()
 	schedule() // Never returns.
@@ -2045,7 +2226,7 @@
 		throw("newproc: function arguments too large for new goroutine")
 	}
 
-	_p_ := _g_.m.p
+	_p_ := _g_.m.p.ptr()
 	newg := gfget(_p_)
 	if newg == nil {
 		newg = malg(_StackMin)
@@ -2099,7 +2280,7 @@
 	if trace.enabled {
 		traceGoCreate(newg, newg.startpc)
 	}
-	runqput(_p_, newg)
+	runqput(_p_, newg, true)
 
 	if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 && unsafe.Pointer(fn.fn) != unsafe.Pointer(funcPC(main)) { // TODO: fast atomic
 		wakep()
@@ -2128,7 +2309,7 @@
 		gp.stackguard0 = 0
 	}
 
-	gp.schedlink = _p_.gfree
+	gp.schedlink.set(_p_.gfree)
 	_p_.gfree = gp
 	_p_.gfreecnt++
 	if _p_.gfreecnt >= 64 {
@@ -2136,8 +2317,8 @@
 		for _p_.gfreecnt >= 32 {
 			_p_.gfreecnt--
 			gp = _p_.gfree
-			_p_.gfree = gp.schedlink
-			gp.schedlink = sched.gfree
+			_p_.gfree = gp.schedlink.ptr()
+			gp.schedlink.set(sched.gfree)
 			sched.gfree = gp
 			sched.ngfree++
 		}
@@ -2155,16 +2336,16 @@
 		for _p_.gfreecnt < 32 && sched.gfree != nil {
 			_p_.gfreecnt++
 			gp = sched.gfree
-			sched.gfree = gp.schedlink
+			sched.gfree = gp.schedlink.ptr()
 			sched.ngfree--
-			gp.schedlink = _p_.gfree
+			gp.schedlink.set(_p_.gfree)
 			_p_.gfree = gp
 		}
 		unlock(&sched.gflock)
 		goto retry
 	}
 	if gp != nil {
-		_p_.gfree = gp.schedlink
+		_p_.gfree = gp.schedlink.ptr()
 		_p_.gfreecnt--
 		if gp.stack.lo == 0 {
 			// Stack was deallocated in gfput.  Allocate a new one.
@@ -2187,8 +2368,8 @@
 	for _p_.gfreecnt != 0 {
 		_p_.gfreecnt--
 		gp := _p_.gfree
-		_p_.gfree = gp.schedlink
-		gp.schedlink = sched.gfree
+		_p_.gfree = gp.schedlink.ptr()
+		gp.schedlink.set(sched.gfree)
 		sched.gfree = gp
 		sched.ngfree++
 	}
@@ -2397,16 +2578,16 @@
 			// 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 != nil && mp.libcallpc != 0 && mp.libcallsp != 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.
-			n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg, 0, &stk[0], len(stk), nil, nil, 0)
+			n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, 0)
 		}
 		if n == 0 {
 			// If all of the above has failed, account it against abstract "System" or "GC".
 			n = 2
 			// "ExternalCode" is better than "etext".
-			if pc > themoduledata.etext {
+			if pc > firstmoduledata.etext {
 				pc = funcPC(_ExternalCode) + _PCQuantum
 			}
 			stk[0] = pc
@@ -2478,6 +2659,13 @@
 		traceGomaxprocs(nprocs)
 	}
 
+	// update statistics
+	now := nanotime()
+	if sched.procresizetime != 0 {
+		sched.totaltime += int64(old) * (now - sched.procresizetime)
+	}
+	sched.procresizetime = now
+
 	// initialize new P's
 	for i := int32(0); i < nprocs; i++ {
 		pp := allp[i]
@@ -2507,7 +2695,7 @@
 	for i := nprocs; i < old; i++ {
 		p := allp[i]
 		if trace.enabled {
-			if p == getg().m.p {
+			if p == getg().m.p.ptr() {
 				// moving to p[0], pretend that we were descheduled
 				// and then scheduled again to keep the trace sane.
 				traceGoSched()
@@ -2520,12 +2708,21 @@
 			p.runqtail--
 			gp := p.runq[p.runqtail%uint32(len(p.runq))]
 			// push onto head of global queue
-			gp.schedlink = sched.runqhead
-			sched.runqhead = gp
-			if sched.runqtail == nil {
-				sched.runqtail = gp
+			globrunqputhead(gp)
+		}
+		if p.runnext != 0 {
+			globrunqputhead(p.runnext.ptr())
+			p.runnext = 0
+		}
+		// if there's a background worker, make it runnable and put
+		// it on the global queue so it can clean itself up
+		if p.gcBgMarkWorker != nil {
+			casgstatus(p.gcBgMarkWorker, _Gwaiting, _Grunnable)
+			if trace.enabled {
+				traceGoUnpark(p.gcBgMarkWorker, 0)
 			}
-			sched.runqsize++
+			globrunqput(p.gcBgMarkWorker)
+			p.gcBgMarkWorker = nil
 		}
 		for i := range p.sudogbuf {
 			p.sudogbuf[i] = nil
@@ -2546,18 +2743,18 @@
 	}
 
 	_g_ := getg()
-	if _g_.m.p != nil && _g_.m.p.id < nprocs {
+	if _g_.m.p != 0 && _g_.m.p.ptr().id < nprocs {
 		// continue to use the current P
-		_g_.m.p.status = _Prunning
+		_g_.m.p.ptr().status = _Prunning
 	} else {
 		// release the current P and acquire allp[0]
-		if _g_.m.p != nil {
-			_g_.m.p.m = nil
+		if _g_.m.p != 0 {
+			_g_.m.p.ptr().m = 0
 		}
-		_g_.m.p = nil
+		_g_.m.p = 0
 		_g_.m.mcache = nil
 		p := allp[0]
-		p.m = nil
+		p.m = 0
 		p.status = _Pidle
 		acquirep(p)
 		if trace.enabled {
@@ -2567,15 +2764,15 @@
 	var runnablePs *p
 	for i := nprocs - 1; i >= 0; i-- {
 		p := allp[i]
-		if _g_.m.p == p {
+		if _g_.m.p.ptr() == p {
 			continue
 		}
 		p.status = _Pidle
-		if p.runqhead == p.runqtail {
+		if runqempty(p) {
 			pidleput(p)
 		} else {
-			p.m = mget()
-			p.link = runnablePs
+			p.m.set(mget())
+			p.link.set(runnablePs)
 			runnablePs = p
 		}
 	}
@@ -2585,53 +2782,57 @@
 }
 
 // Associate p and the current m.
-// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
 func acquirep(_p_ *p) {
-	_g_ := getg()
+	acquirep1(_p_)
 
-	if _g_.m.p != nil || _g_.m.mcache != nil {
-		throw("acquirep: already in go")
-	}
-	if _p_.m != nil || _p_.status != _Pidle {
-		id := int32(0)
-		if _p_.m != nil {
-			id = _p_.m.id
-		}
-		print("acquirep: p->m=", _p_.m, "(", id, ") p->status=", _p_.status, "\n")
-		throw("acquirep: invalid p state")
-	}
-	// _p_.mcache holds the mcache and _p_ is in allp, so WB can be eliminated
-	setMcacheNoWriteBarrier(&_g_.m.mcache, _p_.mcache)
-	// _p_ is in allp so WB can be eliminated
-	setPNoWriteBarrier(&_g_.m.p, _p_)
-	// m is in _g_.m and is reachable through allg, so WB can be eliminated
-	setMNoWriteBarrier(&_p_.m, _g_.m)
-	_p_.status = _Prunning
+	// have p; write barriers now allowed
+	_g_ := getg()
+	_g_.m.mcache = _p_.mcache
 
 	if trace.enabled {
 		traceProcStart()
 	}
 }
 
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func acquirep1(_p_ *p) {
+	_g_ := getg()
+
+	if _g_.m.p != 0 || _g_.m.mcache != nil {
+		throw("acquirep: already in go")
+	}
+	if _p_.m != 0 || _p_.status != _Pidle {
+		id := int32(0)
+		if _p_.m != 0 {
+			id = _p_.m.ptr().id
+		}
+		print("acquirep: p->m=", _p_.m, "(", id, ") p->status=", _p_.status, "\n")
+		throw("acquirep: invalid p state")
+	}
+	_g_.m.p.set(_p_)
+	_p_.m.set(_g_.m)
+	_p_.status = _Prunning
+}
+
 // Disassociate p and the current m.
 func releasep() *p {
 	_g_ := getg()
 
-	if _g_.m.p == nil || _g_.m.mcache == nil {
+	if _g_.m.p == 0 || _g_.m.mcache == nil {
 		throw("releasep: invalid arg")
 	}
-	_p_ := _g_.m.p
-	if _p_.m != _g_.m || _p_.mcache != _g_.m.mcache || _p_.status != _Prunning {
-		print("releasep: m=", _g_.m, " m->p=", _g_.m.p, " p->m=", _p_.m, " m->mcache=", _g_.m.mcache, " p->mcache=", _p_.mcache, " p->status=", _p_.status, "\n")
+	_p_ := _g_.m.p.ptr()
+	if _p_.m.ptr() != _g_.m || _p_.mcache != _g_.m.mcache || _p_.status != _Prunning {
+		print("releasep: m=", _g_.m, " m->p=", _g_.m.p.ptr(), " p->m=", _p_.m, " m->mcache=", _g_.m.mcache, " p->mcache=", _p_.mcache, " p->status=", _p_.status, "\n")
 		throw("releasep: invalid p state")
 	}
 	if trace.enabled {
-		traceProcStop(_g_.m.p)
+		traceProcStop(_g_.m.p.ptr())
 	}
-	_g_.m.p = nil
+	_g_.m.p = 0
 	_g_.m.mcache = nil
-	_p_.m = nil
+	_p_.m = 0
 	_p_.status = _Pidle
 	return _p_
 }
@@ -2648,6 +2849,13 @@
 // Check for deadlock situation.
 // The check is based on number of running M's, if 0 -> deadlock.
 func checkdead() {
+	// For -buildmode=c-shared or -buildmode=c-archive it's OK if
+	// there are no running goroutines.  The calling program is
+	// assumed to be running.
+	if islibrary || isarchive {
+		return
+	}
+
 	// If we are dying because of a signal caught on an already idle thread,
 	// freezetheworld will cause all running threads to block.
 	// And runtime will essentially enter into deadlock state,
@@ -2703,7 +2911,7 @@
 		if mp == nil {
 			newm(nil, _p_)
 		} else {
-			mp.nextp = _p_
+			mp.nextp.set(_p_)
 			notewakeup(&mp.park)
 		}
 		return
@@ -2795,7 +3003,7 @@
 		if lastgc != 0 && unixnow-lastgc > forcegcperiod && atomicload(&forcegc.idle) != 0 {
 			lock(&forcegc.lock)
 			forcegc.idle = 0
-			forcegc.g.schedlink = nil
+			forcegc.g.schedlink = 0
 			injectglist(forcegc.g)
 			unlock(&forcegc.lock)
 		}
@@ -2819,6 +3027,10 @@
 	syscallwhen int64
 }
 
+// forcePreemptNS is the time slice given to a G before it is
+// preempted.
+const forcePreemptNS = 10 * 1000 * 1000 // 10ms
+
 func retake(now int64) uint32 {
 	n := 0
 	for i := int32(0); i < gomaxprocs; i++ {
@@ -2839,7 +3051,7 @@
 			// On the one hand we don't want to retake Ps if there is no other work to do,
 			// but on the other hand we want to retake them eventually
 			// because they can prevent the sysmon thread from deep sleep.
-			if _p_.runqhead == _p_.runqtail && atomicload(&sched.nmspinning)+atomicload(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now {
+			if runqempty(_p_) && atomicload(&sched.nmspinning)+atomicload(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now {
 				continue
 			}
 			// Need to decrement number of idle locked M's
@@ -2858,14 +3070,14 @@
 			}
 			incidlelocked(1)
 		} else if s == _Prunning {
-			// Preempt G if it's running for more than 10ms.
+			// Preempt G if it's running for too long.
 			t := int64(_p_.schedtick)
 			if int64(pd.schedtick) != t {
 				pd.schedtick = uint32(t)
 				pd.schedwhen = now
 				continue
 			}
-			if pd.schedwhen+10*1000*1000 > now {
+			if pd.schedwhen+forcePreemptNS > now {
 				continue
 			}
 			preemptone(_p_)
@@ -2904,7 +3116,7 @@
 // and will be indicated by the gp->status no longer being
 // Grunning
 func preemptone(_p_ *p) bool {
-	mp := _p_.m
+	mp := _p_.m.ptr()
 	if mp == nil || mp == getg().m {
 		return false
 	}
@@ -2944,7 +3156,7 @@
 		if _p_ == nil {
 			continue
 		}
-		mp := _p_.m
+		mp := _p_.m.ptr()
 		h := atomicload(&_p_.runqhead)
 		t := atomicload(&_p_.runqtail)
 		if detailed {
@@ -2973,7 +3185,7 @@
 	}
 
 	for mp := allm; mp != nil; mp = mp.alllink {
-		_p_ := mp.p
+		_p_ := mp.p.ptr()
 		gp := mp.curg
 		lockedg := mp.lockedg
 		id1 := int32(-1)
@@ -3015,10 +3227,8 @@
 // May run during STW, so write barriers are not allowed.
 //go:nowritebarrier
 func mput(mp *m) {
-	// sched.midle is reachable via allm, so WB can be eliminated.
-	setMNoWriteBarrier(&mp.schedlink, sched.midle)
-	// mp is reachable via allm, so WB can be eliminated.
-	setMNoWriteBarrier(&sched.midle, mp)
+	mp.schedlink = sched.midle
+	sched.midle.set(mp)
 	sched.nmidle++
 	checkdead()
 }
@@ -3028,10 +3238,9 @@
 // May run during STW, so write barriers are not allowed.
 //go:nowritebarrier
 func mget() *m {
-	mp := sched.midle
+	mp := sched.midle.ptr()
 	if mp != nil {
-		// mp.schedlink is reachable via mp, which is on allm, so WB can be eliminated.
-		setMNoWriteBarrier(&sched.midle, mp.schedlink)
+		sched.midle = mp.schedlink
 		sched.nmidle--
 	}
 	return mp
@@ -3042,27 +3251,39 @@
 // May run during STW, so write barriers are not allowed.
 //go:nowritebarrier
 func globrunqput(gp *g) {
-	gp.schedlink = nil
-	if sched.runqtail != nil {
-		// gp is on allg, so these three WBs can be eliminated.
-		setGNoWriteBarrier(&sched.runqtail.schedlink, gp)
+	gp.schedlink = 0
+	if sched.runqtail != 0 {
+		sched.runqtail.ptr().schedlink.set(gp)
 	} else {
-		setGNoWriteBarrier(&sched.runqhead, gp)
+		sched.runqhead.set(gp)
 	}
-	setGNoWriteBarrier(&sched.runqtail, gp)
+	sched.runqtail.set(gp)
+	sched.runqsize++
+}
+
+// Put gp at the head of the global runnable queue.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func globrunqputhead(gp *g) {
+	gp.schedlink = sched.runqhead
+	sched.runqhead.set(gp)
+	if sched.runqtail == 0 {
+		sched.runqtail.set(gp)
+	}
 	sched.runqsize++
 }
 
 // Put a batch of runnable goroutines on the global runnable queue.
 // Sched must be locked.
 func globrunqputbatch(ghead *g, gtail *g, n int32) {
-	gtail.schedlink = nil
-	if sched.runqtail != nil {
-		sched.runqtail.schedlink = ghead
+	gtail.schedlink = 0
+	if sched.runqtail != 0 {
+		sched.runqtail.ptr().schedlink.set(ghead)
 	} else {
-		sched.runqhead = ghead
+		sched.runqhead.set(ghead)
 	}
-	sched.runqtail = gtail
+	sched.runqtail.set(gtail)
 	sched.runqsize += n
 }
 
@@ -3086,16 +3307,16 @@
 
 	sched.runqsize -= n
 	if sched.runqsize == 0 {
-		sched.runqtail = nil
+		sched.runqtail = 0
 	}
 
-	gp := sched.runqhead
+	gp := sched.runqhead.ptr()
 	sched.runqhead = gp.schedlink
 	n--
 	for ; n > 0; n-- {
-		gp1 := sched.runqhead
+		gp1 := sched.runqhead.ptr()
 		sched.runqhead = gp1.schedlink
-		runqput(_p_, gp1)
+		runqput(_p_, gp1, false)
 	}
 	return gp
 }
@@ -3105,9 +3326,11 @@
 // May run during STW, so write barriers are not allowed.
 //go:nowritebarrier
 func pidleput(_p_ *p) {
-	// sched.pidle, _p_.link and _p_ are reachable via allp, so WB can be eliminated.
-	setPNoWriteBarrier(&_p_.link, sched.pidle)
-	setPNoWriteBarrier(&sched.pidle, _p_)
+	if !runqempty(_p_) {
+		throw("pidleput: P has non-empty run queue")
+	}
+	_p_.link = sched.pidle
+	sched.pidle.set(_p_)
 	xadd(&sched.npidle, 1) // TODO: fast atomic
 }
 
@@ -3116,19 +3339,39 @@
 // May run during STW, so write barriers are not allowed.
 //go:nowritebarrier
 func pidleget() *p {
-	_p_ := sched.pidle
+	_p_ := sched.pidle.ptr()
 	if _p_ != nil {
-		// _p_.link is reachable via a _p_ in  allp, so WB can be eliminated.
-		setPNoWriteBarrier(&sched.pidle, _p_.link)
+		sched.pidle = _p_.link
 		xadd(&sched.npidle, -1) // TODO: fast atomic
 	}
 	return _p_
 }
 
-// Try to put g on local runnable queue.
-// If it's full, put onto global queue.
+// runqempty returns true if _p_ has no Gs on its local run queue.
+// Note that this test is generally racy.
+func runqempty(_p_ *p) bool {
+	return _p_.runqhead == _p_.runqtail && _p_.runnext == 0
+}
+
+// runqput tries to put g on the local runnable queue.
+// If next if false, runqput adds g to the tail of the runnable queue.
+// If next is true, runqput puts g in the _p_.runnext slot.
+// If the run queue is full, runnext puts g on the global queue.
 // Executed only by the owner P.
-func runqput(_p_ *p, gp *g) {
+func runqput(_p_ *p, gp *g, next bool) {
+	if next {
+	retryNext:
+		oldnext := _p_.runnext
+		if !_p_.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) {
+			goto retryNext
+		}
+		if oldnext == 0 {
+			return
+		}
+		// Kick the old runnext out to the regular run queue.
+		gp = oldnext.ptr()
+	}
+
 retry:
 	h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers
 	t := _p_.runqtail
@@ -3165,7 +3408,7 @@
 
 	// Link the goroutines.
 	for i := uint32(0); i < n; i++ {
-		batch[i].schedlink = batch[i+1]
+		batch[i].schedlink.set(batch[i+1])
 	}
 
 	// Now put the batch on global queue.
@@ -3176,17 +3419,30 @@
 }
 
 // Get g from local runnable queue.
+// If inheritTime is true, gp should inherit the remaining time in the
+// current time slice. Otherwise, it should start a new time slice.
 // Executed only by the owner P.
-func runqget(_p_ *p) *g {
+func runqget(_p_ *p) (gp *g, inheritTime bool) {
+	// If there's a runnext, it's the next G to run.
+	for {
+		next := _p_.runnext
+		if next == 0 {
+			break
+		}
+		if _p_.runnext.cas(next, 0) {
+			return next.ptr(), true
+		}
+	}
+
 	for {
 		h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers
 		t := _p_.runqtail
 		if t == h {
-			return nil
+			return nil, false
 		}
 		gp := _p_.runq[h%uint32(len(_p_.runq))]
 		if cas(&_p_.runqhead, h, h+1) { // cas-release, commits consume
-			return gp
+			return gp, false
 		}
 	}
 }
@@ -3201,6 +3457,14 @@
 		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
+				}
+				batch[0] = next.ptr()
+				return 1
+			}
 			return 0
 		}
 		if n > uint32(len(_p_.runq)/2) { // read inconsistent h and t
@@ -3246,32 +3510,36 @@
 	_p_ := new(p)
 	gs := make([]g, len(_p_.runq))
 	for i := 0; i < len(_p_.runq); i++ {
-		if runqget(_p_) != nil {
+		if g, _ := runqget(_p_); g != nil {
 			throw("runq is not empty initially")
 		}
 		for j := 0; j < i; j++ {
-			runqput(_p_, &gs[i])
+			runqput(_p_, &gs[i], false)
 		}
 		for j := 0; j < i; j++ {
-			if runqget(_p_) != &gs[i] {
+			if g, _ := runqget(_p_); g != &gs[i] {
 				print("bad element at iter ", i, "/", j, "\n")
 				throw("bad element")
 			}
 		}
-		if runqget(_p_) != nil {
+		if g, _ := runqget(_p_); g != nil {
 			throw("runq is not empty afterwards")
 		}
 	}
 }
 
+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])
+			runqput(p1, &gs[j], false)
 		}
 		gp := runqsteal(p2, p1)
 		s := 0
@@ -3280,7 +3548,7 @@
 			gp.sig++
 		}
 		for {
-			gp = runqget(p2)
+			gp, _ = runqget(p2)
 			if gp == nil {
 				break
 			}
@@ -3288,7 +3556,7 @@
 			gp.sig++
 		}
 		for {
-			gp = runqget(p1)
+			gp, _ = runqget(p1)
 			if gp == nil {
 				break
 			}
@@ -3339,7 +3607,7 @@
 	mp := _g_.m
 
 	mp.locks++
-	return int(mp.p.id)
+	return int(mp.p.ptr().id)
 }
 
 //go:nosplit
@@ -3384,7 +3652,7 @@
 	if i >= active_spin || ncpu <= 1 || gomaxprocs <= int32(sched.npidle+sched.nmspinning)+1 {
 		return false
 	}
-	if p := getg().m.p; p.runqhead != p.runqtail {
+	if p := getg().m.p.ptr(); !runqempty(p) {
 		return false
 	}
 	return true
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 88cd484..4c5712d 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -292,6 +292,98 @@
 }
 `
 
+func TestPingPongHog(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in -short mode")
+	}
+
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	done := make(chan bool)
+	hogChan, lightChan := make(chan bool), make(chan bool)
+	hogCount, lightCount := 0, 0
+
+	run := func(limit int, counter *int, wake chan bool) {
+		for {
+			select {
+			case <-done:
+				return
+
+			case <-wake:
+				for i := 0; i < limit; i++ {
+					*counter++
+				}
+				wake <- true
+			}
+		}
+	}
+
+	// Start two co-scheduled hog goroutines.
+	for i := 0; i < 2; i++ {
+		go run(1e6, &hogCount, hogChan)
+	}
+
+	// Start two co-scheduled light goroutines.
+	for i := 0; i < 2; i++ {
+		go run(1e3, &lightCount, lightChan)
+	}
+
+	// Start goroutine pairs and wait for a few preemption rounds.
+	hogChan <- true
+	lightChan <- true
+	time.Sleep(100 * time.Millisecond)
+	close(done)
+	<-hogChan
+	<-lightChan
+
+	// Check that hogCount and lightCount are within a factor of
+	// 2, which indicates that both pairs of goroutines handed off
+	// the P within a time-slice to their buddy.
+	if hogCount > lightCount*2 || lightCount > hogCount*2 {
+		t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount))
+	}
+}
+
+func BenchmarkPingPongHog(b *testing.B) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
+	// Create a CPU hog
+	stop, done := make(chan bool), make(chan bool)
+	go func() {
+		for {
+			select {
+			case <-stop:
+				done <- true
+				return
+			default:
+			}
+		}
+	}()
+
+	// Ping-pong b.N times
+	ping, pong := make(chan bool), make(chan bool)
+	go func() {
+		for j := 0; j < b.N; j++ {
+			pong <- <-ping
+		}
+		close(stop)
+		done <- true
+	}()
+	go func() {
+		for i := 0; i < b.N; i++ {
+			ping <- <-pong
+		}
+		done <- true
+	}()
+	b.ResetTimer()
+	ping <- true // Start ping-pong
+	<-stop
+	b.StopTimer()
+	<-ping // Let last ponger exit
+	<-done // Make sure goroutines exit
+	<-done
+	<-done
+}
+
 func stackGrowthRecursive(i int) {
 	var pad [128]uint64
 	if i != 0 && pad[0] == 0 {
diff --git a/src/runtime/race/testdata/io_test.go b/src/runtime/race/testdata/io_test.go
index 9eb3552..1b3ee38 100644
--- a/src/runtime/race/testdata/io_test.go
+++ b/src/runtime/race/testdata/io_test.go
@@ -49,7 +49,7 @@
 			fmt.Fprintf(w, "test")
 			x = 42
 		})
-		err := http.ListenAndServe(":23651", nil)
+		err := http.ListenAndServe("127.0.0.1:23651", nil)
 		if err != nil {
 			t.Fatalf("http.ListenAndServe: %v", err)
 		}
diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go
index cb17a27..7f95051 100644
--- a/src/runtime/race/testdata/mop_test.go
+++ b/src/runtime/race/testdata/mop_test.go
@@ -335,6 +335,8 @@
 			}
 			done <- true
 		}(i)
+		// Ensure the goroutine runs before we continue the loop.
+		runtime.Gosched()
 	}
 	for i := 0; i < N; i++ {
 		<-done
@@ -1063,6 +1065,7 @@
 		}()
 		seen[u] = true
 		if d <= 0 {
+			wg.Done()
 			return
 		}
 		urls := [...]string{"a", "b", "c"}
@@ -1726,13 +1729,16 @@
 }
 
 func TestRaceHeapParam(t *testing.T) {
+	done := make(chan bool)
 	x := func() (x int) {
 		go func() {
 			x = 42
+			done <- true
 		}()
 		return
 	}()
 	_ = x
+	<-done
 }
 
 func TestNoRaceEmptyStruct(t *testing.T) {
diff --git a/src/runtime/race/testdata/rwmutex_test.go b/src/runtime/race/testdata/rwmutex_test.go
index 85cb5df..7ac829d 100644
--- a/src/runtime/race/testdata/rwmutex_test.go
+++ b/src/runtime/race/testdata/rwmutex_test.go
@@ -54,13 +54,16 @@
 func TestRaceRWMutexMultipleReaders(t *testing.T) {
 	var mu sync.RWMutex
 	var x, y int64 = 0, 1
-	ch := make(chan bool, 3)
+	ch := make(chan bool, 4)
 	go func() {
 		mu.Lock()
 		defer mu.Unlock()
 		x = 2
 		ch <- true
 	}()
+	// Use three readers so that no matter what order they're
+	// scheduled in, two will be on the same side of the write
+	// lock above.
 	go func() {
 		mu.RLock()
 		y = x + 1
@@ -73,6 +76,13 @@
 		mu.RUnlock()
 		ch <- true
 	}()
+	go func() {
+		mu.RLock()
+		y = x + 3
+		mu.RUnlock()
+		ch <- true
+	}()
+	<-ch
 	<-ch
 	<-ch
 	<-ch
@@ -82,7 +92,7 @@
 func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
 	var mu sync.RWMutex
 	x := int64(0)
-	ch := make(chan bool, 3)
+	ch := make(chan bool, 4)
 	go func() {
 		mu.Lock()
 		defer mu.Unlock()
@@ -103,6 +113,14 @@
 		mu.RUnlock()
 		ch <- true
 	}()
+	go func() {
+		mu.RLock()
+		y := x + 3
+		_ = y
+		mu.RUnlock()
+		ch <- true
+	}()
+	<-ch
 	<-ch
 	<-ch
 	<-ch
diff --git a/src/runtime/race1.go b/src/runtime/race1.go
index 18ecc88..38afca7 100644
--- a/src/runtime/race1.go
+++ b/src/runtime/race1.go
@@ -119,29 +119,29 @@
 	// Round data segment to page boundaries, because it's used in mmap().
 	start := ^uintptr(0)
 	end := uintptr(0)
-	if start > themoduledata.noptrdata {
-		start = themoduledata.noptrdata
+	if start > firstmoduledata.noptrdata {
+		start = firstmoduledata.noptrdata
 	}
-	if start > themoduledata.data {
-		start = themoduledata.data
+	if start > firstmoduledata.data {
+		start = firstmoduledata.data
 	}
-	if start > themoduledata.noptrbss {
-		start = themoduledata.noptrbss
+	if start > firstmoduledata.noptrbss {
+		start = firstmoduledata.noptrbss
 	}
-	if start > themoduledata.bss {
-		start = themoduledata.bss
+	if start > firstmoduledata.bss {
+		start = firstmoduledata.bss
 	}
-	if end < themoduledata.enoptrdata {
-		end = themoduledata.enoptrdata
+	if end < firstmoduledata.enoptrdata {
+		end = firstmoduledata.enoptrdata
 	}
-	if end < themoduledata.edata {
-		end = themoduledata.edata
+	if end < firstmoduledata.edata {
+		end = firstmoduledata.edata
 	}
-	if end < themoduledata.enoptrbss {
-		end = themoduledata.enoptrbss
+	if end < firstmoduledata.enoptrbss {
+		end = firstmoduledata.enoptrbss
 	}
-	if end < themoduledata.ebss {
-		end = themoduledata.ebss
+	if end < firstmoduledata.ebss {
+		end = firstmoduledata.ebss
 	}
 	size := round(end-start, _PageSize)
 	racecall(&__tsan_map_shadow, start, size, 0, 0)
diff --git a/src/runtime/rt0_android_arm.s b/src/runtime/rt0_android_arm.s
index 6b65fb4..8571253 100644
--- a/src/runtime/rt0_android_arm.s
+++ b/src/runtime/rt0_android_arm.s
@@ -9,3 +9,27 @@
 	MOVW		$4(R13), R1    // argv
 	MOVW		$_rt0_arm_linux1(SB), R4
 	B		(R4)
+
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_arm_android_lib(SB),NOSPLIT,$0
+	MOVW	$1, R0                          // argc
+	MOVW	$_rt0_arm_android_argv(SB), R1  // **argv
+	BL _rt0_arm_linux_lib(SB)
+	RET
+
+DATA _rt0_arm_android_argv+0x00(SB)/4,$_rt0_arm_android_argv0(SB)
+DATA _rt0_arm_android_argv+0x04(SB)/4,$0
+DATA _rt0_arm_android_argv+0x08(SB)/4,$0
+DATA _rt0_arm_android_argv+0x0C(SB)/4,$15      // AT_PLATFORM
+DATA _rt0_arm_android_argv+0x10(SB)/4,$_rt0_arm_android_auxv0(SB)
+DATA _rt0_arm_android_argv+0x14(SB)/4,$16      // AT_HWCAP
+DATA _rt0_arm_android_argv+0x18(SB)/4,$0x2040  // HWCAP_VFP | HWCAP_VFPv3
+DATA _rt0_arm_android_argv+0x1C(SB)/4,$0
+GLOBL _rt0_arm_android_argv(SB),NOPTR,$0x20
+
+DATA _rt0_arm_android_argv0(SB)/8, $"gojni"
+GLOBL _rt0_arm_android_argv0(SB),RODATA,$8
+
+DATA _rt0_arm_android_auxv0(SB)/4, $"v7l"
+GLOBL _rt0_arm_android_auxv0(SB),RODATA,$4
diff --git a/src/runtime/rt0_darwin_amd64.s b/src/runtime/rt0_darwin_amd64.s
index 452d854..8d50e96 100644
--- a/src/runtime/rt0_darwin_amd64.s
+++ b/src/runtime/rt0_darwin_amd64.s
@@ -10,6 +10,40 @@
 	MOVQ	$main(SB), AX
 	JMP	AX
 
+// When linking with -shared, this symbol is called when the shared library
+// is loaded.
+TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$40
+	MOVQ	DI, _rt0_amd64_darwin_lib_argc<>(SB)
+	MOVQ	SI, _rt0_amd64_darwin_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVQ	_cgo_sys_thread_create(SB), AX
+	TESTQ	AX, AX
+	JZ	nocgo
+	MOVQ	$_rt0_amd64_darwin_lib_go(SB), DI
+	MOVQ	$0, SI
+	CALL	AX
+	RET
+nocgo:
+	MOVQ	$8388608, 0(SP)                    // stacksize
+	MOVQ	$_rt0_amd64_darwin_lib_go(SB), AX
+	MOVQ	AX, 8(SP)                          // fn
+	MOVQ	$0, 16(SP)                         // fnarg
+	MOVQ	$runtime·newosproc0(SB), AX
+	CALL	AX
+	RET
+
+TEXT _rt0_amd64_darwin_lib_go(SB),NOSPLIT,$0
+	MOVQ	_rt0_amd64_darwin_lib_argc<>(SB), DI
+	MOVQ	_rt0_amd64_darwin_lib_argv<>(SB), SI
+	MOVQ	$runtime·rt0_go(SB), AX
+	JMP	AX
+
+DATA _rt0_amd64_darwin_lib_argc<>(SB)/8, $0
+GLOBL _rt0_amd64_darwin_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_amd64_darwin_lib_argv<>(SB)/8, $0
+GLOBL _rt0_amd64_darwin_lib_argv<>(SB),NOPTR, $8
+
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_darwin_arm.s b/src/runtime/rt0_darwin_arm.s
index 4d31e3a..95a2b17 100644
--- a/src/runtime/rt0_darwin_arm.s
+++ b/src/runtime/rt0_darwin_arm.s
@@ -11,6 +11,47 @@
 	MOVW	$main(SB), R4
 	B		(R4)
 
+// When linking with -buildmode=c-archive or -buildmode=c-shared,
+// this symbol is called from a global initialization function.
+//
+// Note that all currently shipping darwin/arm platforms require
+// cgo and do not support c-shared.
+TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$12
+	MOVW  R0, _rt0_arm_darwin_lib_argc<>(SB)
+	MOVW  R1, _rt0_arm_darwin_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVW  _cgo_sys_thread_create(SB), R4
+	CMP   $0, R4
+	B.EQ  nocgo
+	MOVW  $_rt0_arm_darwin_lib_go(SB), R0
+	MOVW  $0, R1
+	BL    (R4)
+	RET
+nocgo:
+	MOVW  $0x400000, R0
+	MOVW  $_rt0_arm_darwin_lib_go(SB), R1
+	MOVW  $0, R2
+	MOVW  R0,  (R13) // stacksize
+	MOVW  R1, 4(R13) // fn
+	MOVW  R2, 8(R13) // fnarg
+	MOVW  $runtime·newosproc0(SB), R4
+	BL    (R4)
+	RET
+
+TEXT _rt0_arm_darwin_lib_go(SB),NOSPLIT,$0
+	MOVW  _rt0_arm_darwin_lib_argc<>(SB), R0
+	MOVW  _rt0_arm_darwin_lib_argv<>(SB), R1
+	MOVW  R0,  (R13)
+	MOVW  R1, 4(R13)
+	MOVW  $runtime·rt0_go(SB), R4
+	B     (R4)
+
+DATA  _rt0_arm_darwin_lib_argc<>(SB)/4, $0
+GLOBL _rt0_arm_darwin_lib_argc<>(SB),NOPTR, $4
+DATA  _rt0_arm_darwin_lib_argv<>(SB)/4, $0
+GLOBL _rt0_arm_darwin_lib_argv<>(SB),NOPTR, $4
+
 TEXT main(SB),NOSPLIT,$-8
 	// save argc and argv onto stack
 	MOVM.DB.W [R0-R1], (R13)
diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s
new file mode 100644
index 0000000..e4e4a30
--- /dev/null
+++ b/src/runtime/rt0_darwin_arm64.s
@@ -0,0 +1,55 @@
+// 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"
+
+// No need for _rt0_arm64_darwin as darwin/arm64 only
+// supports external linking.
+TEXT _rt0_arm64_darwin(SB),NOSPLIT,$-8
+	MOVD	$42, R0
+	MOVD	$1, R16	// SYS_exit
+	SVC	$0x80
+
+// When linking with -buildmode=c-archive or -buildmode=c-shared,
+// this symbol is called from a global initialization function.
+//
+// Note that all currently shipping darwin/arm64 platforms require
+// cgo and do not support c-shared.
+TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$0
+	// R27 is REGTMP, reserved for liblink. It is used below to
+	// move R0/R1 into globals. However in the standard ARM64 calling
+	// convention, it is a callee-saved register. So we save it to a
+	// temporary register.
+	MOVD  R27, R7
+
+	MOVD  R0, _rt0_arm64_darwin_lib_argc<>(SB)
+	MOVD  R1, _rt0_arm64_darwin_lib_argv<>(SB)
+	// Create a new thread to do the runtime initialization and return.
+	MOVD  _cgo_sys_thread_create(SB), R4
+	MOVD  $_rt0_arm64_darwin_lib_go(SB), R0
+	MOVD  $0, R1
+	BL    (R4)
+
+	MOVD  R7, R27
+	RET
+
+TEXT _rt0_arm64_darwin_lib_go(SB),NOSPLIT,$0
+	MOVD  _rt0_arm64_darwin_lib_argc<>(SB), R0
+	MOVD  _rt0_arm64_darwin_lib_argv<>(SB), R1
+	MOVD  $runtime·rt0_go(SB), R4
+	B     (R4)
+
+DATA  _rt0_arm64_darwin_lib_argc<>(SB)/8, $0
+GLOBL _rt0_arm64_darwin_lib_argc<>(SB),NOPTR, $8
+DATA  _rt0_arm64_darwin_lib_argv<>(SB)/8, $0
+GLOBL _rt0_arm64_darwin_lib_argv<>(SB),NOPTR, $8
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVD	$runtime·rt0_go(SB), R2
+	BL	(R2)
+exit:
+	MOVD	$0, R0
+	MOVD	$1, R16	// sys_exit
+	SVC	$0x80
+	B	exit
diff --git a/src/runtime/rt0_linux_386.s b/src/runtime/rt0_linux_386.s
index 47fd908..633e806 100644
--- a/src/runtime/rt0_linux_386.s
+++ b/src/runtime/rt0_linux_386.s
@@ -12,6 +12,61 @@
 	CALL	main(SB)
 	INT	$3
 
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_386_linux_lib(SB),NOSPLIT,$0
+	PUSHL	BP
+	MOVL	SP, BP
+	PUSHL	BX
+	PUSHL	SI
+	PUSHL	DI
+
+	MOVL	8(BP), AX
+	MOVL	AX, _rt0_386_linux_lib_argc<>(SB)
+	MOVL	12(BP), AX
+	MOVL	AX, _rt0_386_linux_lib_argv<>(SB)
+
+	SUBL	$8, SP
+
+	// Create a new thread to do the runtime initialization.
+	MOVL	_cgo_sys_thread_create(SB), AX
+	TESTL	AX, AX
+	JZ	nocgo
+	MOVL	$_rt0_386_linux_lib_go(SB), BX
+	MOVL	BX, 0(SP)
+	MOVL	$0, 4(SP)
+	CALL	AX
+	JMP	restore
+
+nocgo:
+	MOVL	$0x800000, 0(SP)                    // stacksize = 8192KB
+	MOVL	$_rt0_386_linux_lib_go(SB), AX
+	MOVL	AX, 4(SP)                           // fn
+	MOVL	$runtime·newosproc0(SB), AX
+	CALL	AX
+
+restore:
+	ADDL	$8, SP
+	POPL	DI
+	POPL	SI
+	POPL	BX
+	POPL	BP
+	RET
+
+TEXT _rt0_386_linux_lib_go(SB),NOSPLIT,$12
+	MOVL	_rt0_386_linux_lib_argc<>(SB), AX
+	MOVL	AX, 0(SP)
+	MOVL	_rt0_386_linux_lib_argv<>(SB), AX
+	MOVL	AX, 4(SP)
+	MOVL	$runtime·rt0_go(SB), AX
+	CALL	AX
+	RET
+
+DATA _rt0_386_linux_lib_argc<>(SB)/4, $0
+GLOBL _rt0_386_linux_lib_argc<>(SB),NOPTR, $4
+DATA _rt0_386_linux_lib_argv<>(SB)/4, $0
+GLOBL _rt0_386_linux_lib_argv<>(SB),NOPTR, $4
+
 TEXT main(SB),NOSPLIT,$0
 	JMP	runtime·rt0_go(SB)
 
diff --git a/src/runtime/rt0_linux_amd64.s b/src/runtime/rt0_linux_amd64.s
index 9d9cb34..726b550 100644
--- a/src/runtime/rt0_linux_amd64.s
+++ b/src/runtime/rt0_linux_amd64.s
@@ -10,13 +10,55 @@
 	MOVQ	$main(SB), AX
 	JMP	AX
 
-// When linking with -shared, this symbol is called when the shared library
-// is loaded.
-TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0
-	// TODO(spetrovic): Do something useful, like calling $main.  (Note that
-	// this has to be done in a separate thread, as main is expected to block.)
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x48
+	MOVQ	BX, 0x10(SP)
+	MOVQ	BP, 0x18(SP)
+	MOVQ	R12, 0x20(SP)
+	MOVQ	R13, 0x28(SP)
+	MOVQ	R14, 0x30(SP)
+	MOVQ	R15, 0x38(SP)
+
+	MOVQ	DI, _rt0_amd64_linux_lib_argc<>(SB)
+	MOVQ	SI, _rt0_amd64_linux_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVQ	_cgo_sys_thread_create(SB), AX
+	TESTQ	AX, AX
+	JZ	nocgo
+	MOVQ	$_rt0_amd64_linux_lib_go(SB), DI
+	MOVQ	$0, SI
+	CALL	AX
+	JMP	restore
+
+nocgo:
+	MOVQ	$8388608, 0(SP)                    // stacksize
+	MOVQ	$_rt0_amd64_linux_lib_go(SB), AX
+	MOVQ	AX, 8(SP)                          // fn
+	MOVQ	$runtime·newosproc0(SB), AX
+	CALL	AX
+
+restore:
+	MOVQ	0x10(SP), BX
+	MOVQ	0x18(SP), BP
+	MOVQ	0x20(SP), R12
+	MOVQ	0x28(SP), R13
+	MOVQ	0x30(SP), R14
+	MOVQ	0x38(SP), R15
 	RET
 
+TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,$0
+	MOVQ	_rt0_amd64_linux_lib_argc<>(SB), DI
+	MOVQ	_rt0_amd64_linux_lib_argv<>(SB), SI
+	MOVQ	$runtime·rt0_go(SB), AX
+	JMP	AX
+
+DATA _rt0_amd64_linux_lib_argc<>(SB)/8, $0
+GLOBL _rt0_amd64_linux_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_amd64_linux_lib_argv<>(SB)/8, $0
+GLOBL _rt0_amd64_linux_lib_argv<>(SB),NOPTR, $8
+
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_linux_arm.s b/src/runtime/rt0_linux_arm.s
index 15c1092..b71a3f9 100644
--- a/src/runtime/rt0_linux_arm.s
+++ b/src/runtime/rt0_linux_arm.s
@@ -10,6 +10,58 @@
 	MOVW	$_rt0_arm_linux1(SB), R4
 	B		(R4)
 
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32
+	// Preserve callee-save registers.  Raspberry Pi's dlopen(), for example,
+	// actually cares that R11 is preserved.
+	MOVW	R4, 12(R13)
+	MOVW	R5, 16(R13)
+	MOVW	R6, 20(R13)
+	MOVW	R7, 24(R13)
+	MOVW	R8, 28(R13)
+	MOVW	R11, 32(R13)
+
+	// Save argc/argv.
+	MOVW	R0, _rt0_arm_linux_lib_argc<>(SB)
+	MOVW	R1, _rt0_arm_linux_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization.
+	MOVW	_cgo_sys_thread_create(SB), R2
+	CMP	$0, R2
+	BEQ	nocgo
+	MOVW	$_rt0_arm_linux_lib_go<>(SB), R0
+	MOVW	$0, R1
+	BL	(R2)
+	B	rr
+nocgo:
+	MOVW	$0x800000, R0                     // stacksize = 8192KB
+	MOVW	$_rt0_arm_linux_lib_go<>(SB), R1  // fn
+	MOVW	R0, 4(R13)
+	MOVW	R1, 8(R13)
+	BL	runtime·newosproc0(SB)
+rr:
+	// Restore callee-save registers and return.
+	MOVW	12(R13), R4
+	MOVW	16(R13), R5
+	MOVW	20(R13), R6
+	MOVW	24(R13), R7
+	MOVW	28(R13), R8
+	MOVW	32(R13), R11
+	RET
+
+TEXT _rt0_arm_linux_lib_go<>(SB),NOSPLIT,$8
+	MOVW	_rt0_arm_linux_lib_argc<>(SB), R0
+	MOVW	_rt0_arm_linux_lib_argv<>(SB), R1
+	MOVW	R0, 0(R13)
+	MOVW	R1, 4(R13)
+	B	runtime·rt0_go(SB)
+
+DATA _rt0_arm_linux_lib_argc<>(SB)/4,$0
+GLOBL _rt0_arm_linux_lib_argc<>(SB),NOPTR,$4
+DATA _rt0_arm_linux_lib_argv<>(SB)/4,$0
+GLOBL _rt0_arm_linux_lib_argv<>(SB),NOPTR,$4
+
 TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
 	// We first need to detect the kernel ABI, and warn the user
 	// if the system only supports OABI
diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py
index c70aea7..e57fa00 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -446,7 +446,7 @@
 			#python3 / newer versions of gdb
 			pc = int(pc)
 		except gdb.error:
-			pc = int(str(pc), 16)
+			pc = int(str(pc).split(None, 1)[0], 16)
 		save_frame = gdb.selected_frame()
 		gdb.parse_and_eval('$save_pc = $pc')
 		gdb.parse_and_eval('$save_sp = $sp')
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 7569d07..fe7d38a 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -64,7 +64,7 @@
 		t.Fatalf("building source %v\n%s", err, out)
 	}
 
-	got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex",
+	args := []string{"-nx", "-q", "--batch", "-iex",
 		fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
 		"-ex", "br main.go:10",
 		"-ex", "run",
@@ -79,8 +79,22 @@
 		"-ex", "echo END\n",
 		"-ex", "echo BEGIN print ptrvar\n",
 		"-ex", "print ptrvar",
-		"-ex", "echo END\n",
-		filepath.Join(dir, "a.exe")).CombinedOutput()
+		"-ex", "echo END\n"}
+
+	// without framepointer, gdb cannot backtrace our non-standard
+	// stack frames on RISC architectures.
+	canBackTrace := false
+	switch runtime.GOARCH {
+	case "amd64", "386":
+		canBackTrace = true
+		args = append(args,
+			"-ex", "echo BEGIN goroutine 2 bt\n",
+			"-ex", "goroutine 2 bt",
+			"-ex", "echo END\n")
+	}
+
+	args = append(args, filepath.Join(dir, "a.exe"))
+	got, _ := exec.Command("gdb", args...).CombinedOutput()
 
 	firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
 	if string(firstLine) != "Loading Go Runtime support." {
@@ -112,4 +126,11 @@
 	if bl := blocks["print ptrvar"]; !strVarRe.MatchString(bl) {
 		t.Fatalf("print ptrvar failed: %s", bl)
 	}
+
+	btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`)
+	if bl := blocks["goroutine 2 bt"]; canBackTrace && !btGoroutineRe.MatchString(bl) {
+		t.Fatalf("goroutine 2 bt failed: %s", bl)
+	} else if !canBackTrace {
+		t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH)
+	}
 }
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index 5f0ca02..2387d9a 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -7,6 +7,7 @@
 import _ "unsafe" // for go:linkname
 
 //go:generate go run wincallback.go
+//go:generate go run mkduff.go
 
 var ticks struct {
 	lock mutex
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index 072a585..ea38830 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -317,6 +317,7 @@
 	wbshadow       int32
 	gccheckmark    int32
 	sbrk           int32
+	gcpacertrace   int32
 }
 
 var dbgvars = []dbgVar{
@@ -331,12 +332,10 @@
 	{"wbshadow", &debug.wbshadow},
 	{"gccheckmark", &debug.gccheckmark},
 	{"sbrk", &debug.sbrk},
+	{"gcpacertrace", &debug.gcpacertrace},
 }
 
 func parsedebugvars() {
-	// gccheckmark is enabled by default for the 1.5 dev cycle
-	debug.gccheckmark = 1
-
 	for p := gogetenv("GODEBUG"); p != ""; {
 		field := ""
 		i := index(p, ",")
@@ -426,23 +425,10 @@
 
 //go:linkname reflect_typelinks reflect.typelinks
 //go:nosplit
-func reflect_typelinks() []*_type {
-	var ret []*_type
-	sp := (*slice)(unsafe.Pointer(&ret))
-	sp.array = (*byte)(unsafe.Pointer(themoduledata.typelink))
-	sp.len = uint((themoduledata.etypelink - themoduledata.typelink) / unsafe.Sizeof(ret[0]))
-	sp.cap = sp.len
+func reflect_typelinks() [][]*_type {
+	ret := [][]*_type{firstmoduledata.typelinks}
+	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
+		ret = append(ret, datap.typelinks)
+	}
 	return ret
 }
-
-// TODO: move back into mgc.go
-func readgogc() int32 {
-	p := gogetenv("GOGC")
-	if p == "" {
-		return 100
-	}
-	if p == "off" {
-		return -1
-	}
-	return int32(atoi(p))
-}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 0d3e542..ac539b9 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -29,7 +29,7 @@
 	// _Gscanidle =     _Gscan + _Gidle,      // Not used. Gidle only used with newly malloced gs
 	_Gscanrunnable = _Gscan + _Grunnable //  0x1001 When scanning complets make Grunnable (it is already on run queue)
 	_Gscanrunning  = _Gscan + _Grunning  //  0x1002 Used to tell preemption newstack routine to scan preempted stack.
-	_Gscansyscall  = _Gscan + _Gsyscall  //  0x1003 When scanning completes make is Gsyscall
+	_Gscansyscall  = _Gscan + _Gsyscall  //  0x1003 When scanning completes make it Gsyscall
 	_Gscanwaiting  = _Gscan + _Gwaiting  //  0x1004 When scanning completes make it Gwaiting
 	// _Gscanmoribund_unused,               //  not possible
 	// _Gscandead,                          //  not possible
@@ -38,8 +38,8 @@
 
 const (
 	// P status
-	_Pidle = iota
-	_Prunning
+	_Pidle    = iota
+	_Prunning // Only this P is allowed to change from _Prunning.
 	_Psyscall
 	_Pgcstop
 	_Pdead
@@ -87,14 +87,28 @@
 	data  unsafe.Pointer
 }
 
-type slice struct {
-	array *byte // actual data
-	len   uint  // number of elements
-	cap   uint  // allocated number of elements
-}
+// The guintptr, muintptr, and puintptr are all used to bypass write barriers.
+// It is particularly important to avoid write barriers when the current P has
+// been released, because the GC thinks the world is stopped, and an
+// unexpected write barrier would not be synchronized with the GC,
+// which can lead to a half-executed write barrier that has marked the object
+// but not queued it. If the GC skips the object and completes before the
+// queuing can occur, it will incorrectly free the object.
+//
+// We tried using special assignment functions invoked only when not
+// holding a running P, but then some updates to a particular memory
+// word went through write barriers and some did not. This breaks the
+// write barrier shadow checking mode, and it is also scary: better to have
+// a word that is completely ignored by the GC than to have one for which
+// only a few updates are ignored.
+//
+// Gs, Ms, and Ps are always reachable via true pointers in the
+// allgs, allm, and allp lists or (during allocation before they reach those lists)
+// from stack variables.
 
 // A guintptr holds a goroutine pointer, but typed as a uintptr
-// to bypass write barriers. It is used in the Gobuf goroutine state.
+// to bypass write barriers. It is used in the Gobuf goroutine state
+// and in scheduling lists that are manipulated without a P.
 //
 // The Gobuf.g goroutine pointer is almost always updated by assembly code.
 // In one of the few places it is updated by Go code - func save - it must be
@@ -113,41 +127,21 @@
 // alternate arena. Using guintptr doesn't make that problem any worse.
 type guintptr uintptr
 
-func (gp guintptr) ptr() *g {
-	return (*g)(unsafe.Pointer(gp))
+func (gp guintptr) ptr() *g   { return (*g)(unsafe.Pointer(gp)) }
+func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) }
+func (gp *guintptr) cas(old, new guintptr) bool {
+	return casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new))
 }
 
-// ps, ms, gs, and mcache are structures that must be manipulated at a level
-// lower than that of the normal Go language. For example the routine that
-// stops the world removes the p from the m structure informing the GC that
-// this P is stopped and then it moves the g to the global runnable queue.
-// If write barriers were allowed to happen at this point not only does
-// the GC think the thread is stopped but the underlying structures
-// like a p or m are not in a state that is not coherent enough to
-// support the write barrier actions.
-// This is particularly painful since a partially executed write barrier
-// may mark the object but be delinquent in informing the GC that the
-// object needs to be scanned.
+type puintptr uintptr
 
-// setGNoWriteBarriers does *gdst = gval without a write barrier.
-func setGNoWriteBarrier(gdst **g, gval *g) {
-	*(*uintptr)(unsafe.Pointer(gdst)) = uintptr(unsafe.Pointer(gval))
-}
+func (pp puintptr) ptr() *p   { return (*p)(unsafe.Pointer(pp)) }
+func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }
 
-// setMNoWriteBarriers does *mdst = mval without a write barrier.
-func setMNoWriteBarrier(mdst **m, mval *m) {
-	*(*uintptr)(unsafe.Pointer(mdst)) = uintptr(unsafe.Pointer(mval))
-}
+type muintptr uintptr
 
-// setPNoWriteBarriers does *pdst = pval without a write barrier.
-func setPNoWriteBarrier(pdst **p, pval *p) {
-	*(*uintptr)(unsafe.Pointer(pdst)) = uintptr(unsafe.Pointer(pval))
-}
-
-// setMcacheNoWriteBarriers does *mcachedst = mcacheval without a write barrier.
-func setMcacheNoWriteBarrier(mcachedst **mcache, mcacheval *mcache) {
-	*(*uintptr)(unsafe.Pointer(mcachedst)) = uintptr(unsafe.Pointer(mcacheval))
-}
+func (mp muintptr) ptr() *m   { return (*m)(unsafe.Pointer(mp)) }
+func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) }
 
 type gobuf struct {
 	// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
@@ -223,14 +217,14 @@
 	_panic       *_panic // innermost panic - offset known to liblink
 	_defer       *_defer // innermost defer
 	sched        gobuf
-	syscallsp    uintptr        // if status==gsyscall, syscallsp = sched.sp to use during gc
-	syscallpc    uintptr        // if status==gsyscall, syscallpc = sched.pc to use during gc
+	syscallsp    uintptr        // if status==Gsyscall, syscallsp = sched.sp to use during gc
+	syscallpc    uintptr        // if status==Gsyscall, syscallpc = sched.pc to use during gc
 	param        unsafe.Pointer // passed parameter on wakeup
 	atomicstatus uint32
 	goid         int64
 	waitsince    int64  // approx time when the g become blocked
-	waitreason   string // if status==gwaiting
-	schedlink    *g
+	waitreason   string // if status==Gwaiting
+	schedlink    guintptr
 	preempt      bool // preemption signal, duplicates stackguard0 = stackpreempt
 	paniconfault bool // panic (instead of crash) on unexpected fault address
 	preemptscan  bool // preempted g does scan for gc
@@ -249,6 +243,11 @@
 	startpc      uintptr // pc of goroutine function
 	racectx      uintptr
 	waiting      *sudog // sudog structures this g is waiting on (that have a valid elem ptr)
+	readyg       *g     // scratch for readyExecute
+
+	// Per-G gcController state
+	gcalloc    uintptr // bytes allocated during this GC cycle
+	gcscanwork int64   // scan work done (or stolen) this GC cycle
 }
 
 type mts struct {
@@ -268,11 +267,11 @@
 	procid        uint64     // for debuggers, but offset not hard-coded
 	gsignal       *g         // signal-handling g
 	tls           [4]uintptr // thread-local storage (for x86 extern register)
-	mstartfn      uintptr    // TODO: type as func(); note: this is a non-heap allocated func()
-	curg          *g         // current running goroutine
-	caughtsig     *g         // goroutine running during fatal signal
-	p             *p         // attached p for executing go code (nil if not executing go code)
-	nextp         *p
+	mstartfn      func()
+	curg          *g       // current running goroutine
+	caughtsig     guintptr // goroutine running during fatal signal
+	p             puintptr // attached p for executing go code (nil if not executing go code)
+	nextp         puintptr
 	id            int32
 	mallocing     int32
 	throwing      int32
@@ -289,10 +288,9 @@
 	fastrand      uint32
 	ncgocall      uint64 // number of cgo calls in total
 	ncgo          int32  // number of cgo calls currently in progress
-	cgomal        *cgomal
 	park          note
 	alllink       *m // on allm
-	schedlink     *m
+	schedlink     muintptr
 	machport      uint32 // return address for mach ipc (os x)
 	mcache        *mcache
 	lockedg       *g
@@ -306,7 +304,6 @@
 	waitsemacount uint32
 	waitsemalock  uint32
 	gcstats       gcstats
-	currentwbuf   uintptr // use locks or atomic operations such as xchguinptr to access.
 	needextram    bool
 	traceback     uint8
 	waitunlockf   unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
@@ -321,7 +318,7 @@
 	libcall   libcall
 	libcallpc uintptr // for cpu profiler
 	libcallsp uintptr
-	libcallg  *g
+	libcallg  guintptr
 	//#endif
 	//#ifdef GOOS_solaris
 	perrno *int32 // pointer to tls errno
@@ -342,10 +339,10 @@
 
 	id          int32
 	status      uint32 // one of pidle/prunning/...
-	link        *p
-	schedtick   uint32 // incremented on every scheduler call
-	syscalltick uint32 // incremented on every system call
-	m           *m     // back-link to associated m (nil if idle)
+	link        puintptr
+	schedtick   uint32   // incremented on every scheduler call
+	syscalltick uint32   // incremented on every system call
+	m           muintptr // back-link to associated m (nil if idle)
 	mcache      *mcache
 
 	deferpool    [5][]*_defer // pool of available defer structs of different sizes (see panic.go)
@@ -355,10 +352,20 @@
 	goidcache    uint64
 	goidcacheend uint64
 
-	// Queue of runnable goroutines.
+	// Queue of runnable goroutines. Accessed without lock.
 	runqhead uint32
 	runqtail uint32
 	runq     [256]*g
+	// runnext, if non-nil, is a runnable G that was ready'd by
+	// the current G and should be run next instead of what's in
+	// runq if there's time remaining in the running G's time
+	// slice. It will inherit the time left in the current time
+	// slice. If a set of goroutines is locked in a
+	// communicate-and-wait pattern, this schedules that set as a
+	// unit and eliminates the (potentially large) scheduling
+	// latency that otherwise arises from adding the ready'd
+	// goroutines to the end of the run queue.
+	runnext guintptr
 
 	// Available G's (status == Gdead)
 	gfree    *g
@@ -371,6 +378,18 @@
 
 	palloc persistentAlloc // per-P to avoid mutex
 
+	// Per-P GC state
+	gcAssistTime     int64 // Nanoseconds in assistAlloc
+	gcBgMarkWorker   *g
+	gcMarkWorkerMode gcMarkWorkerMode
+
+	// gcw is this P's GC work buffer cache. The work buffer is
+	// filled by write barriers, drained by mutator assists, and
+	// disposed on certain GC state transitions.
+	gcw gcWork
+
+	runSafePointFn uint32 // if 1, run sched.safePointFn at next safe point
+
 	pad [64]byte
 }
 
@@ -385,19 +404,19 @@
 
 	goidgen uint64
 
-	midle        *m    // idle m's waiting for work
-	nmidle       int32 // number of idle m's waiting for work
-	nmidlelocked int32 // number of locked m's waiting for work
-	mcount       int32 // number of m's that have been created
-	maxmcount    int32 // maximum number of m's allowed (or die)
+	midle        muintptr // idle m's waiting for work
+	nmidle       int32    // number of idle m's waiting for work
+	nmidlelocked int32    // number of locked m's waiting for work
+	mcount       int32    // number of m's that have been created
+	maxmcount    int32    // maximum number of m's allowed (or die)
 
-	pidle      *p // idle p's
+	pidle      puintptr // idle p's
 	npidle     uint32
 	nmspinning uint32
 
 	// Global runnable queue.
-	runqhead *g
-	runqtail *g
+	runqhead guintptr
+	runqtail guintptr
 	runqsize int32
 
 	// Global cache of dead G's.
@@ -420,7 +439,14 @@
 	sysmonnote note
 	lastpoll   uint64
 
+	// safepointFn should be called on each P at the next GC
+	// safepoint if p.runSafePointFn is set.
+	safePointFn func(*p)
+
 	profilehz int32 // cpu profiling rate
+
+	procresizetime int64 // nanotime() of last change to gomaxprocs
+	totaltime      int64 // ∫gomaxprocs dt up to procresizetime
 }
 
 // The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
@@ -488,32 +514,12 @@
 	pushcnt uintptr
 }
 
-// Track memory allocated by code not written in Go during a cgo call,
-// so that the garbage collector can see them.
-type cgomal struct {
-	next  *cgomal
-	alloc unsafe.Pointer
-}
-
-// Indicates to write barrier and sychronization task to preform.
-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
-	_GCmarktermination        // GC mark termination: allocate black, P's help GC, write barrier ENABLED
-	_GCsweep                  // GC mark completed; sweeping in background, write barrier disabled
-)
-
 type forcegcstate struct {
 	lock mutex
 	g    *g
 	idle uint32
 }
 
-var gcphase uint32
-
 /*
  * known to compiler
  */
@@ -620,6 +626,12 @@
 	lfenceBeforeRdtsc bool
 )
 
+// Set by the linker so the runtime can determine the buildmode.
+var (
+	islibrary bool // -buildmode=c-shared
+	isarchive bool // -buildmode=c-archive
+)
+
 /*
  * mutual exclusion locks.  in the uncontended case,
  * as fast as spin locks (just a few user-level instructions),
diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go
index 782b936..d4cccbf 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -99,8 +99,9 @@
 	case "android", "nacl":
 		t.Skipf("skipping on %s", GOOS)
 	case "darwin":
-		if GOARCH == "arm" {
-			t.Skipf("skipping on %s/%s", GOOS, GOARCH)
+		switch GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, no fork", GOOS, GOARCH)
 		}
 	}
 
diff --git a/src/runtime/runtime_unix_test.go b/src/runtime/runtime_unix_test.go
index 963de8c..cfec332 100644
--- a/src/runtime/runtime_unix_test.go
+++ b/src/runtime/runtime_unix_test.go
@@ -42,7 +42,7 @@
 	if testing.Short() {
 		max = 100
 	}
-	stk := make([]runtime.StackRecord, 100)
+	stk := make([]runtime.StackRecord, 128)
 	for n := 0; n < max; n++ {
 		_, ok := runtime.GoroutineProfile(stk)
 		if !ok {
diff --git a/src/runtime/select.go b/src/runtime/select.go
index 98ac5a3..29cc077 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -159,7 +159,7 @@
 }
 
 func sellock(sel *hselect) {
-	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	var c *hchan
 	for _, c0 := range lockorder {
@@ -181,7 +181,7 @@
 	// Now if the first M touches sel, it will access freed memory.
 	n := int(sel.ncase)
 	r := 0
-	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), n, n}
+	lockslice := slice{unsafe.Pointer(sel.lockorder), n, n}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	// skip the default case
 	if n > 0 && lockorder[0] == nil {
@@ -221,7 +221,7 @@
 		print("select: sel=", sel, "\n")
 	}
 
-	scaseslice := sliceStruct{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
+	scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
 	scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
 
 	var t0 int64
@@ -241,21 +241,17 @@
 	// optimizing (and needing to test).
 
 	// generate permuted order
-	pollslice := sliceStruct{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
+	pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
 	pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice))
-	for i := 0; i < int(sel.ncase); i++ {
-		pollorder[i] = uint16(i)
-	}
 	for i := 1; i < int(sel.ncase); i++ {
-		o := pollorder[i]
 		j := int(fastrand1()) % (i + 1)
 		pollorder[i] = pollorder[j]
-		pollorder[j] = o
+		pollorder[j] = uint16(i)
 	}
 
 	// sort the cases by Hchan address to get the locking order.
 	// simple heap sort, to guarantee n log n time and constant stack footprint.
-	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	for i := 0; i < int(sel.ncase); i++ {
 		j := i
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
index 184fd12..7577d43 100644
--- a/src/runtime/signal1_unix.go
+++ b/src/runtime/signal1_unix.go
@@ -11,6 +11,14 @@
 	_SIG_IGN uintptr = 1
 )
 
+// Stores the signal handlers registered before Go installed its own.
+// These signal handlers will be invoked in cases where Go doesn't want to
+// handle a particular signal (e.g., signal occurred on a non-Go thread).
+// See sigfwdgo() for more information on when the signals are forwarded.
+//
+// Signal forwarding is currently available only on Linux.
+var fwdSig [_NSIG]uintptr
+
 func initsig() {
 	// _NSIG is the number of signals on this operating system.
 	// sigtable should describe what to do for all the possible signals.
@@ -25,7 +33,7 @@
 		if t.flags == 0 || t.flags&_SigDefault != 0 {
 			continue
 		}
-
+		fwdSig[i] = getsig(i)
 		// For some signals, we respect an inherited SIG_IGN handler
 		// rather than insist on installing our own default handler.
 		// Even these signals can be fetched using the os/signal package.
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
index b632995..f3c36cb 100644
--- a/src/runtime/signal_386.go
+++ b/src/runtime/signal_386.go
@@ -100,7 +100,7 @@
 	}
 
 	_g_.m.throwing = 1
-	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	_g_.m.caughtsig.set(gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
index 5dc9d80..182b16e 100644
--- a/src/runtime/signal_amd64x.go
+++ b/src/runtime/signal_amd64x.go
@@ -136,7 +136,7 @@
 	}
 
 	_g_.m.throwing = 1
-	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	_g_.m.caughtsig.set(gp)
 
 	if crashing == 0 {
 		startpanic()
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
index 7d417fa..38d7181 100644
--- a/src/runtime/signal_arm.go
+++ b/src/runtime/signal_arm.go
@@ -95,7 +95,7 @@
 	}
 
 	_g_.m.throwing = 1
-	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	_g_.m.caughtsig.set(gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
index efb8402..dde3c7c 100644
--- a/src/runtime/signal_arm64.go
+++ b/src/runtime/signal_arm64.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.
 
-// +build linux
+// +build linux darwin
 
 package runtime
 
@@ -108,7 +108,7 @@
 	}
 
 	_g_.m.throwing = 1
-	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	_g_.m.caughtsig.set(gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
index 122648b..32ecce0 100644
--- a/src/runtime/signal_darwin.go
+++ b/src/runtime/signal_darwin.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 type sigTabT struct {
 	flags int32
 	name  string
@@ -43,3 +45,27 @@
 	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
 	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
 }
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
+func sigreturn(ctx unsafe.Pointer, infostyle uint32)
+
+//go:nosplit
+func sigtrampgo(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	if sigfwdgo(sig, info, ctx) {
+		sigreturn(ctx, infostyle)
+		return
+	}
+	g := getg()
+	if g == nil {
+		badsignal(uintptr(sig))
+		sigreturn(ctx, infostyle)
+		return
+	}
+	setg(g.m.gsignal)
+	sighandler(sig, info, ctx, g)
+	setg(g)
+	sigreturn(ctx, infostyle)
+}
diff --git a/src/runtime/signal_darwin_arm64.go b/src/runtime/signal_darwin_arm64.go
new file mode 100644
index 0000000..2df4229
--- /dev/null
+++ b/src/runtime/signal_darwin_arm64.go
@@ -0,0 +1,60 @@
+// 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 runtime
+
+import "unsafe"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *regs64 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) r0() uint64    { return c.regs().x[0] }
+func (c *sigctxt) r1() uint64    { return c.regs().x[1] }
+func (c *sigctxt) r2() uint64    { return c.regs().x[2] }
+func (c *sigctxt) r3() uint64    { return c.regs().x[3] }
+func (c *sigctxt) r4() uint64    { return c.regs().x[4] }
+func (c *sigctxt) r5() uint64    { return c.regs().x[5] }
+func (c *sigctxt) r6() uint64    { return c.regs().x[6] }
+func (c *sigctxt) r7() uint64    { return c.regs().x[7] }
+func (c *sigctxt) r8() uint64    { return c.regs().x[8] }
+func (c *sigctxt) r9() uint64    { return c.regs().x[9] }
+func (c *sigctxt) r10() uint64   { return c.regs().x[10] }
+func (c *sigctxt) r11() uint64   { return c.regs().x[11] }
+func (c *sigctxt) r12() uint64   { return c.regs().x[12] }
+func (c *sigctxt) r13() uint64   { return c.regs().x[13] }
+func (c *sigctxt) r14() uint64   { return c.regs().x[14] }
+func (c *sigctxt) r15() uint64   { return c.regs().x[15] }
+func (c *sigctxt) r16() uint64   { return c.regs().x[16] }
+func (c *sigctxt) r17() uint64   { return c.regs().x[17] }
+func (c *sigctxt) r18() uint64   { return c.regs().x[18] }
+func (c *sigctxt) r19() uint64   { return c.regs().x[19] }
+func (c *sigctxt) r20() uint64   { return c.regs().x[20] }
+func (c *sigctxt) r21() uint64   { return c.regs().x[21] }
+func (c *sigctxt) r22() uint64   { return c.regs().x[22] }
+func (c *sigctxt) r23() uint64   { return c.regs().x[23] }
+func (c *sigctxt) r24() uint64   { return c.regs().x[24] }
+func (c *sigctxt) r25() uint64   { return c.regs().x[25] }
+func (c *sigctxt) r26() uint64   { return c.regs().x[26] }
+func (c *sigctxt) r27() uint64   { return c.regs().x[27] }
+func (c *sigctxt) r28() uint64   { return c.regs().x[28] }
+func (c *sigctxt) r29() uint64   { return c.regs().fp }
+func (c *sigctxt) lr() uint64    { return c.regs().lr }
+func (c *sigctxt) sp() uint64    { return c.regs().sp }
+func (c *sigctxt) pc() uint64    { return c.regs().pc }
+func (c *sigctxt) fault() uint64 { return uint64(uintptr(unsafe.Pointer(c.info.si_addr))) }
+
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return uint64(uintptr(unsafe.Pointer(c.info.si_addr))) }
+
+func (c *sigctxt) set_pc(x uint64)  { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint64)  { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint64)  { c.regs().lr = x }
+func (c *sigctxt) set_r28(x uint64) { c.regs().x[28] = x }
+
+func (c *sigctxt) set_sigaddr(x uint64) {
+	c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x)))
+}
diff --git a/src/runtime/signal_linux.go b/src/runtime/signal_linux.go
index c71e619..f8250b9 100644
--- a/src/runtime/signal_linux.go
+++ b/src/runtime/signal_linux.go
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 type sigTabT struct {
 	flags int32
 	name  string
@@ -76,3 +78,19 @@
 	/* 63 */ {_SigNotify, "signal 63"},
 	/* 64 */ {_SigNotify, "signal 64"},
 }
+
+// Continuation of the (assembly) sigtramp() logic.
+//go:nosplit
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	if sigfwdgo(sig, info, ctx) {
+		return
+	}
+	g := getg()
+	if g == nil {
+		badsignal(uintptr(sig))
+		return
+	}
+	setg(g.m.gsignal)
+	sighandler(sig, info, ctx, g)
+	setg(g)
+}
diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go
index 018d7d6..04d8cfc 100644
--- a/src/runtime/signal_ppc64x.go
+++ b/src/runtime/signal_ppc64x.go
@@ -113,7 +113,7 @@
 	}
 
 	_g_.m.throwing = 1
-	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	_g_.m.caughtsig.set(gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 8834e51..ad3ab31 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -6,9 +6,43 @@
 
 package runtime
 
-import _ "unsafe" // for go:linkname
+import "unsafe"
 
 //go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
 	systemstack(sigpipe)
 }
+
+// Determines if the signal should be handled by Go and if not, forwards the
+// signal to the handler that was installed before Go's.  Returns whether the
+// signal was forwarded.
+//go:nosplit
+func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
+	g := getg()
+	c := &sigctxt{info, ctx}
+	if sig >= uint32(len(sigtable)) {
+		return false
+	}
+	fwdFn := fwdSig[sig]
+	flags := sigtable[sig].flags
+
+	// If there is no handler to forward to, no need to forward.
+	if fwdFn == _SIG_DFL {
+		return false
+	}
+	// Only forward synchronous signals.
+	if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
+		return false
+	}
+	// Determine if the signal occurred inside Go code.  We test that:
+	//   (1) we were in a goroutine (i.e., m.curg != nil), and
+	//   (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
+	if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+		return false
+	}
+	// Signal not handled by Go, forward it.
+	if fwdFn != _SIG_IGN {
+		sigfwd(fwdFn, sig, info, ctx)
+	}
+	return true
+}
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
new file mode 100644
index 0000000..da8a1c5
--- /dev/null
+++ b/src/runtime/signal_windows.go
@@ -0,0 +1,217 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+	"unsafe"
+)
+
+func disableWER() {
+	// do not display Windows Error Reporting dialogue
+	const (
+		SEM_FAILCRITICALERRORS     = 0x0001
+		SEM_NOGPFAULTERRORBOX      = 0x0002
+		SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
+		SEM_NOOPENFILEERRORBOX     = 0x8000
+	)
+	errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
+	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
+}
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func exceptiontramp()
+func firstcontinuetramp()
+func lastcontinuetramp()
+
+func initExceptionHandler() {
+	major, _ := getVersion()
+	stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
+	if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 || major < 6 {
+		// use SetUnhandledExceptionFilter for windows-386 or
+		// if VectoredContinueHandler is unavailable or
+		// if running windows-amd64 v5. V5 appears to fail to
+		// call the continue handlers if windows error reporting dialog
+		// is disabled.
+		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
+		stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
+	} else {
+		stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
+		stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
+	}
+}
+
+func isgoexception(info *exceptionrecord, r *context) bool {
+	// Only handle exception if executing instructions in Go binary
+	// (not Windows library code).
+	// TODO(mwhudson): needs to loop to support shared libs
+	if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
+		return false
+	}
+
+	// Go will only handle some exceptions.
+	switch info.exceptioncode {
+	default:
+		return false
+	case _EXCEPTION_ACCESS_VIOLATION:
+	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+	case _EXCEPTION_INT_OVERFLOW:
+	case _EXCEPTION_FLT_DENORMAL_OPERAND:
+	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
+	case _EXCEPTION_FLT_INEXACT_RESULT:
+	case _EXCEPTION_FLT_OVERFLOW:
+	case _EXCEPTION_FLT_UNDERFLOW:
+	case _EXCEPTION_BREAKPOINT:
+	}
+	return true
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
+	if !isgoexception(info, r) {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+
+	// Make it look like a call to the signal func.
+	// Have to pass arguments out of band since
+	// augmenting the stack frame would break
+	// the unwinding code.
+	gp.sig = info.exceptioncode
+	gp.sigcode0 = uintptr(info.exceptioninformation[0])
+	gp.sigcode1 = uintptr(info.exceptioninformation[1])
+	gp.sigpc = r.ip()
+
+	// Only push runtime·sigpanic if r.ip() != 0.
+	// If r.ip() == 0, probably panicked because of a
+	// call to a nil func.  Not pushing that onto sp will
+	// make the trace look like a call to runtime·sigpanic instead.
+	// (Otherwise the trace will end at runtime·sigpanic and we
+	// won't get to see who faulted.)
+	if r.ip() != 0 {
+		sp := unsafe.Pointer(r.sp())
+		sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
+		*((*uintptr)(sp)) = r.ip()
+		r.setsp(uintptr(sp))
+	}
+	r.setip(funcPC(sigpanic))
+	return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+// It seems Windows searches ContinueHandler's list even
+// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
+// firstcontinuehandler will stop that search,
+// if exceptionhandler did the same earlier.
+func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+	if !isgoexception(info, r) {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+	return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+var testingWER bool
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+	if testingWER {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+
+	_g_ := getg()
+
+	if panicking != 0 { // traceback already printed
+		exit(2)
+	}
+	panicking = 1
+
+	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
+
+	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")
+		gp = _g_.m.lockedg
+	}
+	print("\n")
+
+	var docrash bool
+	if gotraceback(&docrash) > 0 {
+		tracebacktrap(r.ip(), r.sp(), 0, gp)
+		tracebackothers(gp)
+		dumpregs(r)
+	}
+
+	if docrash {
+		crash()
+	}
+
+	exit(2)
+	return 0 // not reached
+}
+
+func sigpanic() {
+	g := getg()
+	if !canpanic(g) {
+		throw("unexpected signal during runtime execution")
+	}
+
+	switch uint32(g.sig) {
+	case _EXCEPTION_ACCESS_VIOLATION:
+		if g.sigcode1 < 0x1000 || g.paniconfault {
+			panicmem()
+		}
+		print("unexpected fault address ", hex(g.sigcode1), "\n")
+		throw("fault")
+	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+		panicdivide()
+	case _EXCEPTION_INT_OVERFLOW:
+		panicoverflow()
+	case _EXCEPTION_FLT_DENORMAL_OPERAND,
+		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
+		_EXCEPTION_FLT_INEXACT_RESULT,
+		_EXCEPTION_FLT_OVERFLOW,
+		_EXCEPTION_FLT_UNDERFLOW:
+		panicfloat()
+	}
+	throw("fault")
+}
+
+var (
+	badsignalmsg [100]byte
+	badsignallen int32
+)
+
+func setBadSignalMsg() {
+	const msg = "runtime: signal received on thread not created by Go.\n"
+	for i, c := range msg {
+		badsignalmsg[i] = byte(c)
+		badsignallen++
+	}
+}
+
+// Following are not implemented.
+
+func initsig() {
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func sigignore(sig uint32) {
+}
+
+func crash() {
+	// TODO: This routine should do whatever is needed
+	// to make the Windows program abort/crash as it
+	// would if Go was not intercepting signals.
+	// On Unix the routine would remove the custom signal
+	// handler and then raise a signal (like SIGABRT).
+	// Something like that should happen here.
+	// It's okay to leave this empty for now: if crash returns
+	// the ordinary exit-after-panic happens.
+}
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index ae46d9c..5ccc659 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -8,14 +8,14 @@
 	"unsafe"
 )
 
-type sliceStruct struct {
+type slice struct {
 	array unsafe.Pointer
 	len   int
 	cap   int
 }
 
 // TODO: take uintptrs instead of int64s?
-func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
+func makeslice(t *slicetype, len64, cap64 int64) slice {
 	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
 	// but it produces a 'len out of range' error instead of a 'cap out of range' error
 	// when someone does make([]T, bignumber). 'cap out of range' is true too,
@@ -30,10 +30,10 @@
 		panic(errorString("makeslice: cap out of range"))
 	}
 	p := newarray(t.elem, uintptr(cap))
-	return sliceStruct{p, len, cap}
+	return slice{p, len, cap}
 }
 
-func growslice(t *slicetype, old sliceStruct, n int) sliceStruct {
+func growslice(t *slicetype, old slice, n int) slice {
 	if n < 1 {
 		panic(errorString("growslice: invalid n"))
 	}
@@ -52,7 +52,7 @@
 	if et.size == 0 {
 		// append should not create a slice with nil pointer but non-zero len.
 		// We assume that append doesn't need to preserve old.array in this case.
-		return sliceStruct{unsafe.Pointer(&zerobase), old.len, cap}
+		return slice{unsafe.Pointer(&zerobase), old.len, cap}
 	}
 
 	newcap := old.cap
@@ -84,17 +84,17 @@
 		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 !needwb().
+		// 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))
 		}
 	}
 
-	return sliceStruct{p, old.len, newcap}
+	return slice{p, old.len, newcap}
 }
 
-func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int {
+func slicecopy(to, fm slice, width uintptr) int {
 	if fm.len == 0 || to.len == 0 {
 		return 0
 	}
diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go
index 8f184cc..4e97e13 100644
--- a/src/runtime/softfloat_arm.go
+++ b/src/runtime/softfloat_arm.go
@@ -437,8 +437,7 @@
 		break
 
 	case 0xeeb10bc0: // D[regd] = sqrt D[regm]
-		uval = float64bits(sqrt(float64frombits(fgetd(regm))))
-		fputd(regd, uval)
+		fputd(regd, sqrt(fgetd(regm)))
 
 		if fptrace > 0 {
 			print("*** D[", regd, "] = sqrt D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
diff --git a/src/runtime/sqrt.go b/src/runtime/sqrt.go
index d483f8a..7452a61 100644
--- a/src/runtime/sqrt.go
+++ b/src/runtime/sqrt.go
@@ -3,11 +3,12 @@
 // license that can be found in the LICENSE file.
 
 // Copy of math/sqrt.go, here for use by ARM softfloat.
+// Modified to not use any floating point arithmetic so
+// that we don't clobber any floating-point registers
+// while emulating the sqrt instruction.
 
 package runtime
 
-import "unsafe"
-
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
 // came with this notice.  The go code is a simplified
@@ -89,21 +90,30 @@
 	float64Mask  = 0x7FF
 	float64Shift = 64 - 11 - 1
 	float64Bias  = 1023
+	float64NaN   = 0x7FF8000000000001
+	float64Inf   = 0x7FF0000000000000
 	maxFloat64   = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
 )
 
-func float64bits(f float64) uint64     { return *(*uint64)(unsafe.Pointer(&f)) }
-func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
+// isnanu returns whether ix represents a NaN floating point number.
+func isnanu(ix uint64) bool {
+	exp := (ix >> float64Shift) & float64Mask
+	sig := ix << (64 - float64Shift) >> (64 - float64Shift)
+	return exp == float64Mask && sig != 0
+}
 
-func sqrt(x float64) float64 {
+func sqrt(ix uint64) uint64 {
 	// special cases
 	switch {
-	case x == 0 || x != x || x > maxFloat64:
-		return x
-	case x < 0:
-		return nan()
+	case ix == 0 || ix == 1<<63: // x == 0
+		return ix
+	case isnanu(ix): // x != x
+		return ix
+	case ix&(1<<63) != 0: // x < 0
+		return float64NaN
+	case ix == float64Inf: // x > MaxFloat
+		return ix
 	}
-	ix := float64bits(x)
 	// normalize x
 	exp := int((ix >> float64Shift) & float64Mask)
 	if exp == 0 { // subnormal x
@@ -139,5 +149,5 @@
 		q += q & 1 // round according to extra bit
 	}
 	ix = q>>1 + uint64(exp-1+float64Bias)<<float64Shift // significand + biased exponent
-	return float64frombits(ix)
+	return ix
 }
diff --git a/src/runtime/sqrt_test.go b/src/runtime/sqrt_test.go
new file mode 100644
index 0000000..f1a6e83
--- /dev/null
+++ b/src/runtime/sqrt_test.go
@@ -0,0 +1,85 @@
+// 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.
+
+// A copy of Sqrt tests from the math package to test the
+// purely integer arithmetic implementaiton in sqrt.go.
+
+package runtime_test
+
+import (
+	"math"
+	"runtime"
+	"testing"
+)
+
+func SqrtRT(x float64) float64 {
+	return math.Float64frombits(runtime.Sqrt(math.Float64bits(x)))
+}
+
+func TestSqrt(t *testing.T) {
+	for i := 0; i < len(vf); i++ {
+		a := math.Abs(vf[i])
+		if f := SqrtRT(a); sqrt[i] != f {
+			t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
+		}
+	}
+	for i := 0; i < len(vfsqrtSC); i++ {
+		if f := SqrtRT(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+			t.Errorf("Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+		}
+	}
+}
+
+func alike(a, b float64) bool {
+	switch {
+	case math.IsNaN(a) && math.IsNaN(b):
+		return true
+	case a == b:
+		return math.Signbit(a) == math.Signbit(b)
+	}
+	return false
+}
+
+var vf = []float64{
+	4.9790119248836735e+00,
+	7.7388724745781045e+00,
+	-2.7688005719200159e-01,
+	-5.0106036182710749e+00,
+	9.6362937071984173e+00,
+	2.9263772392439646e+00,
+	5.2290834314593066e+00,
+	2.7279399104360102e+00,
+	1.8253080916808550e+00,
+	-8.6859247685756013e+00,
+}
+
+var sqrt = []float64{
+	2.2313699659365484748756904e+00,
+	2.7818829009464263511285458e+00,
+	5.2619393496314796848143251e-01,
+	2.2384377628763938724244104e+00,
+	3.1042380236055381099288487e+00,
+	1.7106657298385224403917771e+00,
+	2.286718922705479046148059e+00,
+	1.6516476350711159636222979e+00,
+	1.3510396336454586262419247e+00,
+	2.9471892997524949215723329e+00,
+}
+
+var vfsqrtSC = []float64{
+	math.Inf(-1),
+	-math.Pi,
+	math.Copysign(0, -1),
+	0,
+	math.Inf(1),
+	math.NaN(),
+}
+var sqrtSC = []float64{
+	math.NaN(),
+	math.NaN(),
+	math.Copysign(0, -1),
+	0,
+	math.Inf(1),
+	math.NaN(),
+}
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index 5f28d28..f74694b 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -7,7 +7,7 @@
 import "unsafe"
 
 const (
-	// StackDebug == 0: no logging
+	// stackDebug == 0: no logging
 	//            == 1: logging of per-stack operations
 	//            == 2: logging of per-frame operations
 	//            == 3: logging of per-word updates
@@ -298,10 +298,9 @@
 
 var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real
 
-var mapnames = []string{
-	typeDead:    "---",
-	typeScalar:  "scalar",
-	typePointer: "ptr",
+var ptrnames = []string{
+	0: "scalar",
+	1: "ptr",
 }
 
 // Stack frame layout
@@ -365,8 +364,8 @@
 	}
 }
 
-func ptrbits(bv *gobitvector, i uintptr) uint8 {
-	return (bv.bytedata[i/4] >> ((i & 3) * 2)) & 3
+func ptrbit(bv *gobitvector, i uintptr) uint8 {
+	return (bv.bytedata[i/8] >> (i % 8)) & 1
 }
 
 // bv describes the memory starting at address scanp.
@@ -376,21 +375,12 @@
 	minp := adjinfo.old.lo
 	maxp := adjinfo.old.hi
 	delta := adjinfo.delta
-	num := uintptr(bv.n) / typeBitsWidth
+	num := uintptr(bv.n)
 	for i := uintptr(0); i < num; i++ {
 		if stackDebug >= 4 {
-			print("        ", add(scanp, i*ptrSize), ":", mapnames[ptrbits(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*ptrSize))), " # ", i, " ", bv.bytedata[i/4], "\n")
+			print("        ", add(scanp, i*ptrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*ptrSize))), " # ", i, " ", bv.bytedata[i/4], "\n")
 		}
-		switch ptrbits(&bv, i) {
-		default:
-			throw("unexpected pointer bits")
-		case typeDead:
-			if debug.gcdead != 0 {
-				*(*unsafe.Pointer)(add(scanp, i*ptrSize)) = unsafe.Pointer(uintptr(poisonStack))
-			}
-		case typeScalar:
-			// ok
-		case typePointer:
+		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 {
@@ -461,7 +451,7 @@
 			throw("bad symbol table")
 		}
 		bv = stackmapdata(stackmap, pcdata)
-		size = (uintptr(bv.n) / typeBitsWidth) * ptrSize
+		size = uintptr(bv.n) * ptrSize
 		if stackDebug >= 3 {
 			print("      locals ", pcdata, "/", stackmap.n, " ", size/ptrSize, " words ", bv.bytedata, "\n")
 		}
@@ -680,7 +670,7 @@
 	// it needs a lock held by the goroutine), that small preemption turns
 	// into a real deadlock.
 	if preempt {
-		if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.status != _Prunning {
+		if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.ptr().status != _Prunning {
 			// Let the goroutine keep running for now.
 			// gp->preempt is set, so it will be preempted next time.
 			gp.stackguard0 = gp.stack.lo + _StackGuard
@@ -724,7 +714,7 @@
 		if gp == thisg.m.g0 {
 			throw("runtime: preempt g0")
 		}
-		if thisg.m.p == nil && thisg.m.locks == 0 {
+		if thisg.m.p == 0 && thisg.m.locks == 0 {
 			throw("runtime: g is running but p is not")
 		}
 		if gp.preemptscan {
diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go
index 07a7d38..5ec8d8d 100644
--- a/src/runtime/stack2.go
+++ b/src/runtime/stack2.go
@@ -84,7 +84,7 @@
 
 	// The stack guard is a pointer this many bytes above the
 	// bottom of the stack.
-	_StackGuard = 640 + _StackSystem
+	_StackGuard = 640*stackGuardMultiplier + _StackSystem
 
 	// After a stack split check the SP is allowed to be this
 	// many bytes below the stack guard.  This saves an instruction
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 0ba309c..a5851b7 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -148,7 +148,7 @@
 	// for i, c := range []byte(str)
 
 	str := (*stringStruct)(unsafe.Pointer(&s))
-	ret := slice{array: (*byte)(str.str), len: uint(str.len), cap: uint(str.len)}
+	ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len}
 	return *(*[]byte)(unsafe.Pointer(&ret))
 }
 
@@ -266,9 +266,7 @@
 	(*stringStruct)(unsafe.Pointer(&s)).str = p
 	(*stringStruct)(unsafe.Pointer(&s)).len = size
 
-	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
-	(*slice)(unsafe.Pointer(&b)).len = uint(size)
-	(*slice)(unsafe.Pointer(&b)).cap = uint(size)
+	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
 
 	for {
 		ms := maxstring
@@ -286,9 +284,7 @@
 		memclr(add(p, uintptr(size)), cap-uintptr(size))
 	}
 
-	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
-	(*slice)(unsafe.Pointer(&b)).len = uint(size)
-	(*slice)(unsafe.Pointer(&b)).cap = uint(cap)
+	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
 	return
 }
 
@@ -303,9 +299,7 @@
 		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
 	}
 
-	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
-	(*slice)(unsafe.Pointer(&b)).len = uint(size)
-	(*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4)
+	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
 	return
 }
 
diff --git a/src/runtime/string1.go b/src/runtime/string1.go
index feeb341..4bfa3d9 100644
--- a/src/runtime/string1.go
+++ b/src/runtime/string1.go
@@ -35,10 +35,8 @@
 
 //go:nosplit
 func gostringnocopy(str *byte) string {
-	var s string
-	sp := (*stringStruct)(unsafe.Pointer(&s))
-	sp.str = unsafe.Pointer(str)
-	sp.len = findnull(str)
+	ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
+	s := *(*string)(unsafe.Pointer(&ss))
 	for {
 		ms := maxstring
 		if uintptr(len(s)) <= ms || casuintptr(&maxstring, ms, uintptr(len(s))) {
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 99d8dd4..6d5a98b 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -18,6 +18,9 @@
 	return unsafe.Pointer(uintptr(p) + x)
 }
 
+// getg returns the pointer to the current g.
+// The compiler rewrites calls to this function into instructions
+// that fetch the g directly (from TLS or from the dedicated register).
 func getg() *g
 
 // mcall switches from the g to the g0 stack and invokes fn(g),
@@ -30,7 +33,10 @@
 // run other goroutines.
 //
 // mcall can only be called from g stacks (not g0, not gsignal).
-//go:noescape
+//
+// This must NOT be go:noescape: if fn is a stack-allocated closure,
+// fn puts g on a run queue, and g executes before fn returns, the
+// closure will be invalidated while it is still executing.
 func mcall(fn func(*g))
 
 // systemstack runs fn on a system stack.
@@ -145,6 +151,22 @@
 //go:noescape
 func atomicloaduint(ptr *uint) uint
 
+// TODO: Write native implementations of int64 atomic ops (or improve
+// inliner). These portable ones can't be inlined right now, so we're
+// taking an extra function call hit.
+
+func atomicstoreint64(ptr *int64, new int64) {
+	atomicstore64((*uint64)(unsafe.Pointer(ptr)), uint64(new))
+}
+
+func atomicloadint64(ptr *int64) int64 {
+	return int64(atomicload64((*uint64)(unsafe.Pointer(ptr))))
+}
+
+func xaddint64(ptr *int64, delta int64) int64 {
+	return int64(xadd64((*uint64)(unsafe.Pointer(ptr)), delta))
+}
+
 //go:noescape
 func setcallerpc(argp unsafe.Pointer, pc uintptr)
 
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
index 60751dd..1cb6f91 100644
--- a/src/runtime/stubs2.go
+++ b/src/runtime/stubs2.go
@@ -12,7 +12,7 @@
 import "unsafe"
 
 func read(fd int32, p unsafe.Pointer, n int32) int32
-func close(fd int32) int32
+func closefd(fd int32) int32
 
 func exit(code int32)
 func nanotime() int64
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 689a336..25f5bf4 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -33,11 +33,11 @@
 // image. It is written by the linker. Any changes here must be
 // matched changes to the code in cmd/internal/ld/symtab.go:symtab.
 type moduledata struct {
-	pclntable                      []byte
-	ftab                           []functab
-	filetab                        []uint32
-	pclntab, epclntab, findfunctab uintptr
-	minpc, maxpc                   uintptr
+	pclntable    []byte
+	ftab         []functab
+	filetab      []uint32
+	findfunctab  uintptr
+	minpc, maxpc uintptr
 
 	text, etext           uintptr
 	noptrdata, enoptrdata uintptr
@@ -46,10 +46,22 @@
 	noptrbss, enoptrbss   uintptr
 	end, gcdata, gcbss    uintptr
 
-	typelink, etypelink uintptr
+	typelinks []*_type
+
+	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
 }
 
-var themoduledata moduledata // linker symbol
+var firstmoduledata moduledata  // linker symbol
+var lastmoduledatap *moduledata // linker symbol
 
 type functab struct {
 	entry   uintptr
@@ -72,63 +84,46 @@
 	subbuckets [16]byte
 }
 
-func symtabinit() {
+func moduledataverify() {
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		moduledataverify1(datap)
+	}
+}
+
+func moduledataverify1(datap *moduledata) {
 	// See golang.org/s/go12symtab for header: 0xfffffffb,
 	// two zero bytes, a byte giving the PC quantum,
 	// and a byte giving the pointer width in bytes.
-	pcln := (*[8]byte)(unsafe.Pointer(themoduledata.pclntab))
-	pcln32 := (*[2]uint32)(unsafe.Pointer(themoduledata.pclntab))
+	pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
+	pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
 	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
 		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
 		throw("invalid function symbol table\n")
 	}
 
-	// pclntable is all bytes of pclntab symbol.
-	sp := (*sliceStruct)(unsafe.Pointer(&themoduledata.pclntable))
-	sp.array = unsafe.Pointer(themoduledata.pclntab)
-	sp.len = int(uintptr(unsafe.Pointer(themoduledata.epclntab)) - uintptr(unsafe.Pointer(themoduledata.pclntab)))
-	sp.cap = sp.len
-
 	// ftab is lookup table for function by program counter.
-	nftab := int(*(*uintptr)(add(unsafe.Pointer(pcln), 8)))
-	p := add(unsafe.Pointer(pcln), 8+ptrSize)
-	sp = (*sliceStruct)(unsafe.Pointer(&themoduledata.ftab))
-	sp.array = p
-	sp.len = nftab + 1
-	sp.cap = sp.len
+	nftab := len(datap.ftab) - 1
 	for i := 0; i < nftab; i++ {
 		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
-		if themoduledata.ftab[i].entry > themoduledata.ftab[i+1].entry {
-			f1 := (*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[i].funcoff]))
-			f2 := (*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[i+1].funcoff]))
+		if datap.ftab[i].entry > datap.ftab[i+1].entry {
+			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
+			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
 			f2name := "end"
 			if i+1 < nftab {
 				f2name = funcname(f2)
 			}
-			println("function symbol table not sorted by program counter:", hex(themoduledata.ftab[i].entry), funcname(f1), ">", hex(themoduledata.ftab[i+1].entry), f2name)
+			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
 			for j := 0; j <= i; j++ {
-				print("\t", hex(themoduledata.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[j].funcoff]))), "\n")
+				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
 			}
 			throw("invalid runtime symbol table")
 		}
 	}
 
-	// The ftab ends with a half functab consisting only of
-	// 'entry', followed by a uint32 giving the pcln-relative
-	// offset of the file table.
-	sp = (*sliceStruct)(unsafe.Pointer(&themoduledata.filetab))
-	end := unsafe.Pointer(&themoduledata.ftab[nftab].funcoff) // just beyond ftab
-	fileoffset := *(*uint32)(end)
-	sp.array = unsafe.Pointer(&themoduledata.pclntable[fileoffset])
-	// length is in first element of array.
-	// set len to 1 so we can get first element.
-	sp.len = 1
-	sp.cap = 1
-	sp.len = int(themoduledata.filetab[0])
-	sp.cap = sp.len
-
-	themoduledata.minpc = themoduledata.ftab[0].entry
-	themoduledata.maxpc = themoduledata.ftab[nftab].entry
+	if datap.minpc != datap.ftab[0].entry ||
+		datap.maxpc != datap.ftab[nftab].entry {
+		throw("minpc or maxpc invalid")
+	}
 }
 
 // FuncForPC returns a *Func describing the function that contains the
@@ -158,34 +153,45 @@
 	return file, int(line32)
 }
 
+func findmoduledatap(pc uintptr) *moduledata {
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		if datap.minpc <= pc && pc <= datap.maxpc {
+			return datap
+		}
+	}
+	return nil
+}
+
 func findfunc(pc uintptr) *_func {
-	if pc < themoduledata.minpc || pc >= themoduledata.maxpc {
+	datap := findmoduledatap(pc)
+	if datap == nil {
 		return nil
 	}
 	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
 
-	x := pc - themoduledata.minpc
+	x := pc - datap.minpc
 	b := x / pcbucketsize
 	i := x % pcbucketsize / (pcbucketsize / nsub)
 
-	ffb := (*findfuncbucket)(add(unsafe.Pointer(themoduledata.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
+	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
 	idx := ffb.idx + uint32(ffb.subbuckets[i])
-	if pc < themoduledata.ftab[idx].entry {
+	if pc < datap.ftab[idx].entry {
 		throw("findfunc: bad findfunctab entry")
 	}
 
 	// linear search to find func with pc >= entry.
-	for themoduledata.ftab[idx+1].entry <= pc {
+	for datap.ftab[idx+1].entry <= pc {
 		idx++
 	}
-	return (*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[idx].funcoff]))
+	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
 }
 
 func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 	if off == 0 {
 		return -1
 	}
-	p := themoduledata.pclntable[off:]
+	datap := findmoduledatap(f.entry) // inefficient
+	p := datap.pclntable[off:]
 	pc := f.entry
 	val := int32(-1)
 	for {
@@ -207,7 +213,7 @@
 
 	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
 
-	p = themoduledata.pclntable[off:]
+	p = datap.pclntable[off:]
 	pc = f.entry
 	val = -1
 	for {
@@ -227,7 +233,8 @@
 	if f == nil || f.nameoff == 0 {
 		return nil
 	}
-	return (*byte)(unsafe.Pointer(&themoduledata.pclntable[f.nameoff]))
+	datap := findmoduledatap(f.entry) // inefficient
+	return (*byte)(unsafe.Pointer(&datap.pclntable[f.nameoff]))
 }
 
 func funcname(f *_func) string {
@@ -235,13 +242,14 @@
 }
 
 func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
+	datap := findmoduledatap(f.entry) // inefficient
 	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
 	line = pcvalue(f, f.pcln, targetpc, strict)
-	if fileno == -1 || line == -1 || fileno >= len(themoduledata.filetab) {
+	if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
 		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
 		return "?", 0
 	}
-	file = gostringnocopy(&themoduledata.pclntable[themoduledata.filetab[fileno]])
+	file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
 	return
 }
 
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index 20d6b72..abc5d32 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -34,7 +34,7 @@
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL	$6, AX
 	INT	$0x80
 	JAE	2(PC)
@@ -221,8 +221,7 @@
 	MOVL	DX, nsec+8(FP)
 	RET
 
-// int64 nanotime(void) so really
-// void nanotime(int64 *nsec)
+// func nanotime() int64
 TEXT runtime·nanotime(SB),NOSPLIT,$0
 	CALL	runtime·now(SB)
 	MOVL	AX, ret_lo+0(FP)
@@ -328,33 +327,32 @@
 	INT	$0x80
 	RET
 
-// void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void))
+// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 // System call args are: func arg stack pthread flags.
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
 	MOVL	$360, AX
 	// 0(SP) is where the caller PC would be; kernel skips it
-	MOVL	fn+12(FP), BX
+	MOVL	fn+8(FP), BX
 	MOVL	BX, 4(SP)	// func
-	MOVL	mm+4(FP), BX
+	MOVL	arg+4(FP), BX
 	MOVL	BX, 8(SP)	// arg
 	MOVL	stk+0(FP), BX
 	MOVL	BX, 12(SP)	// stack
-	MOVL	gg+8(FP), BX
-	MOVL	BX, 16(SP)	// pthread
+	MOVL    $0, 16(SP)      // pthread
 	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
 	INT	$0x80
 	JAE	4(PC)
 	NEGL	AX
-	MOVL	AX, ret+16(FP)
+	MOVL	AX, ret+12(FP)
 	RET
 	MOVL	$0, AX
-	MOVL	AX, ret+16(FP)
+	MOVL	AX, ret+12(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
 // because we registered this function using bsdthread_register
 // at startup.
-//	AX = "pthread" (= g)
+//	AX = "pthread" (= 0x0)
 //	BX = mach thread port
 //	CX = "func" (= fn)
 //	DX = "arg" (= m)
@@ -381,6 +379,7 @@
 
 	// Now segment is established.  Initialize m, g.
 	get_tls(BP)
+	MOVL    m_g0(DX), AX
 	MOVL	AX, g(BP)
 	MOVL	DX, g_m(AX)
 	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
@@ -389,7 +388,7 @@
 	CALL	runtime·exit1(SB)
 	RET
 
-// void bsdthread_register(void)
+// func bsdthread_register() int32
 // registers callbacks for threadstart (see bsdthread_create above
 // and wqthread and pthsize (not used).  returns 0 on success.
 TEXT runtime·bsdthread_register(SB),NOSPLIT,$40
@@ -448,35 +447,35 @@
 // Mach provides trap versions of the semaphore ops,
 // instead of requiring the use of RPC.
 
-// uint32 mach_semaphore_wait(uint32)
+// func mach_semaphore_wait(sema uint32) int32
 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	$-36, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	$-38, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+12(FP)
 	RET
 
-// uint32 mach_semaphore_signal(uint32)
+// func mach_semaphore_signal(sema uint32) int32
 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	$-33, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// uint32 mach_semaphore_signal_all(uint32)
+// func mach_semaphore_signal_all(sema uint32) int32
 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
 	MOVL	$-34, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// setldt(int entry, int address, int limit)
+// func setldt(entry int, address int, limit int)
 // entry and limit are ignored.
 TEXT runtime·setldt(SB),NOSPLIT,$32
 	MOVL	address+4(FP), BX	// aka base
@@ -523,7 +522,7 @@
 	MOVL	AX, ret+24(FP)
 	RET
 
-// int32 runtime·kqueue(void);
+// func kqueue() int32
 TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	$362, AX
 	INT	$0x80
@@ -532,7 +531,7 @@
 	MOVL	AX, ret+0(FP)
 	RET
 
-// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
 TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	$363, AX
 	INT	$0x80
@@ -541,7 +540,7 @@
 	MOVL	AX, ret+24(FP)
 	RET
 
-// int32 runtime·closeonexec(int32 fd);
+// func closeonexec(fd int32)
 TEXT runtime·closeonexec(SB),NOSPLIT,$32
 	MOVL	$92, AX  // fcntl
 	// 0(SP) is where the caller PC would be; kernel skips it
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index f856e95..692dbca 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -43,7 +43,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$(0x2000000+6), AX	// syscall entry
 	SYSCALL
@@ -200,7 +200,7 @@
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-TEXT runtime·sigaction(SB),NOSPLIT,$0
+TEXT runtime·sigaction(SB),NOSPLIT,$0-24
 	MOVL	mode+0(FP), DI		// arg 1 sig
 	MOVQ	new+8(FP), SI		// arg 2 act
 	MOVQ	old+16(FP), DX		// arg 3 oact
@@ -212,48 +212,29 @@
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
-	get_tls(BX)
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVQ fn+0(FP),    AX
+	MOVQ sig+8(FP),   DI
+	MOVQ info+16(FP), SI
+	MOVQ ctx+24(FP),  DX
+	CALL AX
+	RET
 
-	MOVQ	R8, 32(SP)	// save ucontext
-	MOVQ	SI, 40(SP)	// save infostyle
-
-	// check that g exists
-	MOVQ	g(BX), R10
-	CMPQ	R10, $0
-	JNE	5(PC)
-	MOVL	DX, 0(SP)
-	MOVQ	$runtime·badsignal(SB), AX
-	CALL	AX
-	JMP 	ret
-
-	// save g
-	MOVQ	R10, 48(SP)
-
-	// g = m->gsignal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
-
-	MOVL	DX, 0(SP)
-	MOVQ	CX, 8(SP)
-	MOVQ	R8, 16(SP)
-	MOVQ	R10, 24(SP)
-
-	CALL	DI
-
-	// restore g
-	get_tls(BX)
-	MOVQ	48(SP), R10
-	MOVQ	R10, g(BX)
-
-ret:
-	// call sigreturn
-	MOVL	$(0x2000000+184), AX	// sigreturn(ucontext, infostyle)
-	MOVQ	32(SP), DI	// saved ucontext
-	MOVQ	40(SP), SI	// saved infostyle
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-12
+	MOVQ ctx+0(FP),        DI
+	MOVL infostyle+8(FP),  SI
+	MOVL $(0x2000000+184), AX
 	SYSCALL
-	INT $3	// not reached
+	INT $3 // not reached
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$32
+	MOVQ DI,  0(SP) // fn
+	MOVL SI,  8(SP) // infostyle
+	MOVL DX, 12(SP) // sig
+	MOVQ CX, 16(SP) // info
+	MOVQ R8, 24(SP) // ctx
+	MOVQ $runtime·sigtrampgo(SB), AX
+	CALL AX
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
 	MOVQ	addr+0(FP), DI		// arg 1 addr
@@ -277,8 +258,8 @@
 	RET
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$0
-	MOVQ	new+8(SP), DI
-	MOVQ	old+16(SP), SI
+	MOVQ	new+0(FP), DI
+	MOVQ	old+8(FP), SI
 	MOVQ	$(0x2000000+53), AX
 	SYSCALL
 	JCC	2(PC)
@@ -303,25 +284,25 @@
 	SYSCALL
 	RET
 
-// void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void))
+// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
 	// Set up arguments to bsdthread_create system call.
 	// The ones in quotes pass through to the thread callback
 	// uninterpreted, so we can put whatever we want there.
-	MOVQ	fn+32(SP), DI	// "func"
-	MOVQ	mm+16(SP), SI	// "arg"
-	MOVQ	stk+8(SP), DX	// stack
-	MOVQ	gg+24(SP), R10	// "pthread"
-	MOVQ	$0x01000000, R8	// flags = PTHREAD_START_CUSTOM
-	MOVQ	$0, R9	// paranoia
+	MOVQ	fn+16(FP),   DI
+	MOVQ	arg+8(FP),  SI
+	MOVQ	stk+0(FP),   DX
+	MOVQ	$0x01000000, R8  // flags = PTHREAD_START_CUSTOM
+	MOVQ	$0,          R9  // paranoia
+	MOVQ	$0,          R10 // paranoia, "pthread"
 	MOVQ	$(0x2000000+360), AX	// bsdthread_create
 	SYSCALL
 	JCC 4(PC)
 	NEGQ	AX
-	MOVL	AX, ret+32(FP)
+	MOVL	AX, ret+24(FP)
 	RET
 	MOVL	$0, AX
-	MOVL	AX, ret+32(FP)
+	MOVL	AX, ret+24(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
@@ -359,7 +340,7 @@
 	CALL	runtime·exit1(SB)
 	RET
 
-// void bsdthread_register(void)
+// func bsdthread_register() int32
 // registers callbacks for threadstart (see bsdthread_create above
 // and wqthread and pthsize (not used).  returns 0 on success.
 TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
@@ -381,7 +362,7 @@
 
 // Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
 
-// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+// func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
 TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
 	MOVQ	h+0(FP), DI
 	MOVL	op+8(FP), SI
@@ -418,7 +399,7 @@
 // Mach provides trap versions of the semaphore ops,
 // instead of requiring the use of RPC.
 
-// uint32 mach_semaphore_wait(uint32)
+// func mach_semaphore_wait(sema uint32) int32
 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+36), AX	// semaphore_wait_trap
@@ -426,7 +407,7 @@
 	MOVL	AX, ret+8(FP)
 	RET
 
-// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	sec+4(FP), SI
@@ -436,7 +417,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-// uint32 mach_semaphore_signal(uint32)
+// func mach_semaphore_signal(sema uint32) int32
 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+33), AX	// semaphore_signal_trap
@@ -444,7 +425,7 @@
 	MOVL	AX, ret+8(FP)
 	RET
 
-// uint32 mach_semaphore_signal_all(uint32)
+// func mach_semaphore_signal_all(sema uint32) int32
 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+34), AX	// semaphore_signal_all_trap
@@ -482,7 +463,7 @@
 	MOVL	AX, ret+48(FP)
 	RET
 
-// int32 runtime·kqueue(void);
+// func kqueue() int32
 TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVQ    $0, DI
 	MOVQ    $0, SI
@@ -494,7 +475,7 @@
 	MOVL	AX, ret+0(FP)
 	RET
 
-// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
 TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL    kq+0(FP), DI
 	MOVQ    ch+8(FP), SI
@@ -509,7 +490,7 @@
 	MOVL	AX, ret+48(FP)
 	RET
 
-// void runtime·closeonexec(int32 fd);
+// func closeonexec(fd int32)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
 	MOVL    fd+0(FP), DI  // fd
 	MOVQ    $2, SI  // F_SETFD
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 5cb8601..b4c1b27 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -52,7 +52,7 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVW	fd+0(FP), R0
 	MOVW	$SYS_close, R12
 	SWI	$0x80
@@ -320,26 +320,25 @@
 	RET
 
 // Thread related functions
-// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
 	// Set up arguments to bsdthread_create system call.
 	// The ones in quotes pass through to the thread callback
 	// uninterpreted, so we can put whatever we want there.
-	MOVW    fn+12(FP), R0   // "func"
-	MOVW    mm+4(FP), R1 // "arg"
-	MOVW    stk+0(FP), R2 // stack
-	MOVW    gg+8(FP), R3 // "pthread"
+	MOVW    fn+8(FP),    R0 // "func"
+	MOVW    arg+4(FP),   R1 // "arg"
+	MOVW    stk+0(FP),   R2 // stack
 	MOVW	$0x01000000, R4	// flags = PTHREAD_START_CUSTOM
-	MOVW	$0, R5	// paranoia
+	MOVW	$0,          R5 // paranoia
 	MOVW	$SYS_bsdthread_create, R12
 	SWI	$0x80
 	BCC		create_ret
 	RSB 	$0, R0, R0
-	MOVW	R0, ret+16(FP)
+	MOVW	R0, ret+12(FP)
 	RET
 create_ret:
 	MOVW	$0, R0
-	MOVW	R0, ret+16(FP)
+	MOVW	R0, ret+12(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
new file mode 100644
index 0000000..7aaf6b6
--- /dev/null
+++ b/src/runtime/sys_darwin_arm64.s
@@ -0,0 +1,450 @@
+// 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.
+
+// System calls and other sys.stuff for ARM64, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+// Copied from /usr/include/sys/syscall.h
+#define	SYS_exit           1
+#define	SYS_read           3
+#define	SYS_write          4
+#define	SYS_open           5
+#define	SYS_close          6
+#define	SYS_mmap           197
+#define	SYS_munmap         73
+#define	SYS_madvise        75
+#define	SYS_mincore        78
+#define	SYS_gettimeofday   116
+#define	SYS_kill           37
+#define	SYS_getpid         20
+#define	SYS___pthread_kill 328
+#define	SYS_setitimer      83
+#define	SYS___sysctl       202
+#define	SYS_sigprocmask    48
+#define	SYS_sigaction      46
+#define	SYS_sigreturn      184
+#define	SYS_select         93
+#define	SYS_bsdthread_register 366
+#define	SYS_bsdthread_create 360
+#define	SYS_bsdthread_terminate 361
+#define	SYS_kqueue         362
+#define	SYS_kevent         363
+#define	SYS_fcntl          92
+
+TEXT notok<>(SB),NOSPLIT,$0
+	MOVD	$0, R8
+	MOVD	R8, (R8)
+	B	0(PC)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+	MOVD	name+0(FP), R0
+	MOVW	mode+8(FP), R1
+	MOVW	perm+12(FP), R2
+	MOVD	$SYS_open, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+16(FP)
+	RET
+
+TEXT runtime·closefd(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	$SYS_close, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+8(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVD	p+8(FP), R1
+	MOVW	n+16(FP), R2
+	MOVW	$SYS_write, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVD	p+8(FP), R1
+	MOVW	n+16(FP), R2
+	MOVW	$SYS_read, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·exit(SB),NOSPLIT,$-8
+	MOVW	code+0(FP), R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	MOVD	$1234, R0
+	MOVD	$1002, R1
+	MOVD	R0, (R1)	// fail hard
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT runtime·exit1(SB),NOSPLIT,$0
+	MOVW	$SYS_bsdthread_terminate, R16
+	SVC	$0x80
+	MOVD	$1234, R0
+	MOVD	$1003, R1
+	MOVD	R0, (R1)	// fail hard
+
+TEXT runtime·raise(SB),NOSPLIT,$0
+	MOVW	$SYS_getpid, R16
+	SVC	$0x80
+	// arg 1 pid already in R0 from getpid
+	MOVW	sig+0(FP), R1	// arg 2 - signal
+	MOVW	$1, R2	// arg 3 - posix
+	MOVW	$SYS_kill, R16
+	SVC	$0x80
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$0
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	prot+16(FP), R2
+	MOVW	flags+20(FP), R3
+	MOVW	fd+24(FP), R4
+	MOVW	off+28(FP), R5
+	MOVW	$SYS_mmap, R16
+	SVC	$0x80
+	MOVD	R0, ret+32(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	$SYS_munmap, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	flags+16(FP), R2
+	MOVW	$SYS_madvise, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0
+	MOVW	mode+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	$SYS_setitimer, R16
+	SVC	$0x80
+	RET
+
+TEXT time·now(SB),NOSPLIT,$32-12
+	MOVD	RSP, R0	// timeval
+	MOVD	R0, R9	// this is how dyld calls gettimeofday
+	MOVW	$0, R1	// zone
+	MOVW	$SYS_gettimeofday, R16
+	SVC	$0x80	// Note: x0 is tv_sec, w1 is tv_usec
+
+	MOVD	R0, sec+0(FP)
+	MOVW	$1000, R3
+	MUL	R3, R1
+	MOVW	R1, nsec+8(FP)
+	RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$32
+	MOVD	RSP, R0	// timeval
+	MOVD	R0, R9	// this is how dyld calls gettimeofday
+	MOVW	$0, R1	// zone
+	MOVW	$SYS_gettimeofday, R16
+	SVC	$0x80	// Note: x0 is tv_sec, w1 is tv_usec
+
+	MOVW	$1000000000, R3
+	MUL	R3, R0
+	MOVW	$1000, R3
+	MUL	R3, R1
+	ADD	R1, R0
+
+	MOVD	R0, ret+0(FP)
+	RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+//	LR	"return address" - ignored
+//	R0	actual handler
+//	R1	siginfo style - ignored
+//	R2	signal number
+//	R3	siginfo
+//	R4	context
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+	// this might be called in external code context,
+	// where g is not set.
+	// first save R0, because runtime·load_g will clobber it
+	MOVD.W	R0, -16(RSP)	// note: stack must be 16-byte aligned
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	2(PC)
+	BL	runtime·load_g(SB)
+
+	CMP	$0, g
+	BNE	cont
+	// fake function call stack frame for badsignal
+	// we only need to pass R2 (signal number), but
+	// badsignal will expect R2 at 8(RSP), so we also
+	// push R1 onto stack. turns out we do need R1
+	// to do sigreturn.
+	MOVD.W	R1, -16(RSP)
+	MOVD	R2, 8(RSP)
+	MOVD	R4, 24(RSP)	// save ucontext, badsignal might clobber R4
+	MOVD	$runtime·badsignal(SB), R26
+	BL	(R26)
+	MOVD	0(RSP), R1	// saved infostype
+	MOVD	24(RSP), R0	// the ucontext
+	ADD	$(16+16), RSP
+	B	ret
+
+cont:
+	// Restore R0
+	MOVD.P	16(RSP), R0
+
+	// NOTE: some Darwin/ARM kernels always use the main stack to run the
+	// signal handler. We need to switch to gsignal ourselves.
+	MOVD	g_m(g), R11
+	MOVD	m_gsignal(R11), R5
+	MOVD	(g_stack+stack_hi)(R5), R6
+	SUB	$64, R6
+
+	// copy arguments for call to sighandler
+	MOVD	R2, 8(R6)	// signal num
+	MOVD	R3, 16(R6)	// signal info
+	MOVD	R4, 24(R6)	// context
+	MOVD	g, 32(R6)	// old_g
+
+	// Backup ucontext and infostyle
+	MOVD	R4, 40(R6)
+	MOVD	R1, 48(R6)
+
+	// switch stack and g
+	MOVD	R6, RSP	// sigtramp can not re-entrant, so no need to back up RSP.
+	MOVD	R5, g
+
+	BL	(R0)
+
+	// call sigreturn
+	MOVD	40(RSP), R0	// saved ucontext
+	MOVD	48(RSP), R1	// saved infostyle
+ret:
+	MOVW	$SYS_sigreturn, R16 // sigreturn(ucontext, infostyle)
+	SVC	$0x80
+
+	// if sigreturn fails, we can do nothing but exit
+	B	runtime·exit(SB)
+
+TEXT runtime·sigprocmask(SB),NOSPLIT,$0
+	MOVW	sig+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	$SYS_sigprocmask, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·sigaction(SB),NOSPLIT,$0
+	MOVW	mode+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	$SYS_sigaction, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$12
+	MOVW	usec+0(FP), R0
+	MOVW	R0, R1
+	MOVW	$1000000, R2
+	UDIV	R2, R0
+	MUL	R0, R2
+	SUB	R2, R1
+	MOVD	R0, 0(RSP)
+	MOVW	R1, 8(RSP)
+
+	// select(0, 0, 0, 0, &tv)
+	MOVW	$0, R0
+	MOVW	$0, R1
+	MOVW	$0, R2
+	MOVW	$0, R3
+	MOVD	RSP, R4
+	MOVW	$SYS_select, R16
+	SVC	$0x80
+	RET
+
+TEXT runtime·sysctl(SB),NOSPLIT,$0
+	MOVD	mib+0(FP), R0
+	MOVW	miblen+8(FP), R1
+	MOVD	out+16(FP), R2
+	MOVD	size+24(FP), R3
+	MOVD	dst+32(FP), R4
+	MOVD	ndst+40(FP), R5
+	MOVW	$SYS___sysctl, R16
+	SVC	$0x80
+	BCC	ok
+	NEG	R0, R0
+	MOVW	R0, ret+48(FP)
+	RET
+ok:
+	MOVW	$0, R0
+	MOVW	R0, ret+48(FP)
+	RET
+
+// Thread related functions
+// Note: On darwin/arm64, it is no longer possible to use bsdthread_register
+// as the libc is always linked in. The runtime must use runtime/cgo to
+// create threads, so all thread related functions will just exit with a
+// unique status.
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
+	MOVD	$44, R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+//	R0 = "pthread"
+//	R1 = mach thread port
+//	R2 = "func" (= fn)
+//	R3 = "arg" (= m)
+//	R4 = stack
+//	R5 = flags (= 0)
+TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
+	MOVD	$45, R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	RET
+
+// int32 bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used).  returns 0 on success.
+TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
+	MOVD	$46, R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	RET
+
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
+	MOVD	h+0(FP), R0
+	MOVW	op+8(FP), R1
+	MOVW	send_size+12(FP), R2
+	MOVW	rcv_size+16(FP), R3
+	MOVW	rcv_name+20(FP), R4
+	MOVW	timeout+24(FP), R5
+	MOVW	notify+28(FP), R6
+	MOVN	$30, R16
+	SVC	$0x80
+	MOVW	R0, ret+32(FP)
+	RET
+
+TEXT runtime·mach_task_self(SB),NOSPLIT,$0
+	MOVN	$27, R16 // task_self_trap
+	SVC	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
+	MOVN	$26, R16 // thread_self_trap
+	SVC	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
+	MOVN	$25, R16	// mach_reply_port
+	SVC	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVN	$35, R16	// semaphore_wait_trap
+	SVC	$0x80
+	MOVW	R0, ret+8(FP)
+	RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVW	sec+4(FP), R1
+	MOVW	nsec+8(FP), R2
+	MOVN	$37, R16	// semaphore_timedwait_trap
+	SVC	$0x80
+	MOVW	R0, ret+16(FP)
+	RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVN	$32, R16	// semaphore_signal_trap
+	SVC	$0x80
+	MOVW	R0, ret+8(FP)
+	RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVN	$33, R16	// semaphore_signal_all_trap
+	SVC	$0x80
+	MOVW	R0, ret+8(FP)
+	RET
+
+// int32 runtime·kqueue(void)
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+	MOVW	$SYS_kqueue, R16
+	SVC	$0x80
+	BCC	2(PC)
+	NEG	R0, R0
+	MOVW	R0, ret+0(FP)
+	RET
+
+// int32 runtime·kevent(int kq, Kevent *ch, int nch, Kevent *ev, int nev, Timespec *ts)
+TEXT runtime·kevent(SB),NOSPLIT,$0
+	MOVW	kq+0(FP), R0
+	MOVD	ch+8(FP), R1
+	MOVW	nch+16(FP), R2
+	MOVD	ev+24(FP), R3
+	MOVW	nev+32(FP), R4
+	MOVD	ts+40(FP), R5
+	MOVW	$SYS_kevent, R16
+	SVC	$0x80
+	BCC	2(PC)
+	NEG	R0, R0
+	MOVW	R0, ret+48(FP)
+	RET
+
+// int32 runtime·closeonexec(int32 fd)
+TEXT runtime·closeonexec(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	$2, R1	// F_SETFD
+	MOVW	$1, R2	// FD_CLOEXEC
+	MOVW	$SYS_fcntl, R16
+	SVC	$0x80
+	RET
+
+// sigaltstack on some darwin/arm version is buggy and will always
+// run the signal handler on the main stack, so our sigtramp has
+// to do the stack switch ourselves.
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+	RET
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 1227196..efda432 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -82,7 +82,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index eed6b8d..94b8d95 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -67,7 +67,7 @@
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-4
+TEXT runtime·closefd(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
 	JAE	2(PC)
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index ecc40e3..a9a621b 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -72,7 +72,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index 613c1dc..2b5d754 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -117,7 +117,7 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-8
 	MOVW fd+0(FP), R0	// arg 1 fd
 	MOVW $SYS_close, R7
 	SWI $0
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index d4bd142..f5cfb64 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -36,7 +36,7 @@
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL	$6, AX		// syscall - close
 	MOVL	fd+0(FP), BX
 	CALL	*runtime·_vdso(SB)
@@ -191,43 +191,25 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$44
-	get_tls(CX)
-
-	// check that g exists
-	MOVL	g(CX), DI
-	CMPL	DI, $0
-	JNE	6(PC)
-	MOVL	sig+0(FP), BX
-	MOVL	BX, 0(SP)
-	MOVL	$runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+	MOVL	sig+4(FP), AX
+	MOVL	AX, 0(SP)
+	MOVL	info+8(FP), AX
+	MOVL	AX, 4(SP)
+	MOVL	ctx+12(FP), AX
+	MOVL	AX, 8(SP)
+	MOVL	fn+0(FP), AX
 	CALL	AX
 	RET
 
-	// save g
-	MOVL	DI, 20(SP)
-
-	// g = m->gsignal
-	MOVL	g_m(DI), BX
-	MOVL	m_gsignal(BX), BX
-	MOVL	BX, g(CX)
-
-	// copy arguments for call to sighandler
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	MOVL	sig+0(FP), BX
 	MOVL	BX, 0(SP)
 	MOVL	info+4(FP), BX
 	MOVL	BX, 4(SP)
 	MOVL	context+8(FP), BX
 	MOVL	BX, 8(SP)
-	MOVL	DI, 12(SP)
-
-	CALL	runtime·sighandler(SB)
-
-	// restore g
-	get_tls(CX)
-	MOVL	20(SP), BX
-	MOVL	BX, g(CX)
-
+	CALL	runtime·sigtrampgo(SB)
 	RET
 
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
@@ -291,18 +273,18 @@
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVL	$120, AX	// clone
-	MOVL	flags+4(SP), BX
-	MOVL	stack+8(SP), CX
+	MOVL	flags+0(FP), BX
+	MOVL	stack+4(FP), CX
 	MOVL	$0, DX	// parent tid ptr
 	MOVL	$0, DI	// child tid ptr
 
 	// Copy mp, gp, fn off parent stack for use by child.
 	SUBL	$16, CX
-	MOVL	mm+12(SP), SI
+	MOVL	mm+8(FP), SI
 	MOVL	SI, 0(CX)
-	MOVL	gg+16(SP), SI
+	MOVL	gg+12(FP), SI
 	MOVL	SI, 4(CX)
-	MOVL	fn+20(SP), SI
+	MOVL	fn+16(FP), SI
 	MOVL	SI, 8(CX)
 	MOVL	$1234, 12(CX)
 
@@ -319,7 +301,7 @@
 	RET
 
 	// Paranoia: check that SP is as we expect.
-	MOVL	mm+8(FP), BP
+	MOVL	12(SP), BP
 	CMPL	BP, $1234
 	JEQ	2(PC)
 	INT	$3
@@ -328,10 +310,14 @@
 	MOVL	$224, AX
 	CALL	*runtime·_vdso(SB)
 
-	// In child on new stack.  Reload registers (paranoia).
-	MOVL	0(SP), BX	// m
-	MOVL	flags+0(FP), DX	// g
-	MOVL	stk+4(FP), SI	// fn
+	MOVL	0(SP), BX	    // m
+	MOVL	4(SP), DX	    // g
+	MOVL	8(SP), SI	    // fn
+
+	CMPL	BX, $0
+	JEQ	nog
+	CMPL	DX, $0
+	JEQ	nog
 
 	MOVL	AX, m_procid(BX)	// save tid as m->procid
 
@@ -365,6 +351,7 @@
 	CALL	runtime·emptyfunc(SB)
 	POPAL
 
+nog:
 	CALL	SI	// fn()
 	CALL	runtime·exit1(SB)
 	MOVL	$0x1234, 0x1005
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 75e1c42..f36ac84 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -34,7 +34,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0-12
+TEXT runtime·closefd(SB),NOSPLIT,$0-12
 	MOVL	fd+0(FP), DI
 	MOVL	$3, AX			// syscall entry
 	SYSCALL
@@ -212,37 +212,20 @@
 	MOVL	AX, ret+32(FP)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
-	get_tls(BX)
-
-	// check that g exists
-	MOVQ	g(BX), R10
-	CMPQ	R10, $0
-	JNE	5(PC)
-	MOVQ	DI, 0(SP)
-	MOVQ	$runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVQ	sig+8(FP), DI
+	MOVQ	info+16(FP), SI
+	MOVQ	ctx+24(FP), DX
+	MOVQ	fn+0(FP), AX
 	CALL	AX
 	RET
 
-	// save g
-	MOVQ	R10, 40(SP)
-
-	// g = m->gsignal
-	MOVQ	g_m(R10), AX
-	MOVQ	m_gsignal(AX), AX
-	MOVQ	AX, g(BX)
-
-	MOVQ	DI, 0(SP)
-	MOVQ	SI, 8(SP)
-	MOVQ	DX, 16(SP)
-	MOVQ	R10, 24(SP)
-
-	CALL	runtime·sighandler(SB)
-
-	// restore g
-	get_tls(BX)
-	MOVQ	40(SP), R10
-	MOVQ	R10, g(BX)
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
+	MOVQ	DI, 0(SP)   // signum
+	MOVQ	SI, 8(SP)   // info
+	MOVQ	DX, 16(SP)  // ctx
+	MOVQ	$runtime·sigtrampgo(SB), AX
+	CALL AX
 	RET
 
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
@@ -302,14 +285,16 @@
 
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
-	MOVL	flags+8(SP), DI
-	MOVQ	stack+16(SP), SI
+	MOVL	flags+0(FP), DI
+	MOVQ	stack+8(FP), SI
+	MOVQ	$0, DX
+	MOVQ	$0, R10
 
 	// Copy mp, gp, fn off parent stack for use by child.
 	// Careful: Linux system call clobbers CX and R11.
-	MOVQ	mm+24(SP), R8
-	MOVQ	gg+32(SP), R9
-	MOVQ	fn+40(SP), R12
+	MOVQ	mp+16(FP), R8
+	MOVQ	gp+24(FP), R9
+	MOVQ	fn+32(FP), R12
 
 	MOVL	$56, AX
 	SYSCALL
@@ -323,6 +308,12 @@
 	// In child, on new stack.
 	MOVQ	SI, SP
 
+	// If g or m are nil, skip Go-related setup.
+	CMPQ	R8, $0    // m
+	JEQ	nog
+	CMPQ	R9, $0    // g
+	JEQ	nog
+
 	// Initialize m->procid to Linux tid
 	MOVL	$186, AX	// gettid
 	SYSCALL
@@ -338,10 +329,11 @@
 	MOVQ	R9, g(CX)
 	CALL	runtime·stackcheck(SB)
 
+nog:
 	// Call fn
 	CALL	R12
 
-	// It shouldn't return.  If it does, exit
+	// It shouldn't return.  If it does, exit that thread.
 	MOVL	$111, DI
 	MOVL	$60, AX
 	SYSCALL
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index fa07ef8..50f074a 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -63,7 +63,7 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVW	fd+0(FP), R0
 	MOVW	$SYS_close, R7
 	SWI	$0
@@ -241,7 +241,6 @@
 	MOVW	R0, ret+24(FP)
 	RET
 
-
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVW	flags+0(FP), R0
@@ -279,8 +278,15 @@
 	BEQ	2(PC)
 	BL	runtime·abort(SB)
 
-	MOVW	4(R13), g
-	MOVW	0(R13), R8
+	MOVW	0(R13), R8    // m
+	MOVW	4(R13), R0    // g
+
+	CMP	$0, R8
+	BEQ	nog
+	CMP	$0, R0
+	BEQ	nog
+
+	MOVW	R0, g
 	MOVW	R8, g_m(g)
 
 	// paranoia; check they are not nil
@@ -295,16 +301,18 @@
 	MOVW	g_m(g), R8
 	MOVW	R0, m_procid(R8)
 
+nog:
 	// Call fn
 	MOVW	8(R13), R0
 	MOVW	$16(R13), R13
 	BL	(R0)
 
+	// It shouldn't return.  If it does, exit that thread.
+	SUB	$16, R13 // restore the stack pointer to avoid memory corruption
 	MOVW	$0, R0
 	MOVW	R0, 4(R13)
 	BL	runtime·exit1(SB)
 
-	// It shouldn't return
 	MOVW	$1234, R0
 	MOVW	$1005, R1
 	MOVW	R0, (R1)
@@ -320,7 +328,15 @@
 	MOVW.HI	R8, (R8)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+	MOVW	sig+4(FP), R0
+	MOVW	info+8(FP), R1
+	MOVW	ctx+12(FP), R2
+	MOVW	fn+0(FP), R11
+	BL	(R11)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	// this might be called in external code context,
 	// where g is not set.
 	// first save R0, because runtime·load_g will clobber it
@@ -329,32 +345,10 @@
 	CMP 	$0, R0
 	BL.NE	runtime·load_g(SB)
 
-	CMP 	$0, g
-	BNE 	4(PC)
-	// signal number is already prepared in 4(R13)
-	MOVW  	$runtime·badsignal(SB), R11
-	BL	(R11)
-	RET
-
-	// save g
-	MOVW	g, R3
-	MOVW	g, 20(R13)
-
-	// g = m->gsignal
-	MOVW	g_m(g), R8
-	MOVW	m_gsignal(R8), g
-
-	// copy arguments for call to sighandler
-	// R0 is already saved above
 	MOVW	R1, 8(R13)
 	MOVW	R2, 12(R13)
-	MOVW	R3, 16(R13)
-
-	BL	runtime·sighandler(SB)
-
-	// restore g
-	MOVW	20(R13), g
-
+	MOVW  	$runtime·sigtrampgo(SB), R11
+	BL	(R11)
 	RET
 
 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 0d0131b8..0aca3a2 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -68,10 +68,11 @@
 	MOVW	R0, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8-12
+TEXT runtime·closefd(SB),NOSPLIT,$-8-12
 	MOVW	fd+0(FP), R0
 	MOVD	$SYS_close, R8
 	SVC
+	CMN	$4095, R0
 	BCC	done
 	MOVW	$-1, R0
 done:
@@ -84,6 +85,7 @@
 	MOVW	n+16(FP), R2
 	MOVD	$SYS_write, R8
 	SVC
+	CMN	$4095, R0
 	BCC	done
 	MOVW	$-1, R0
 done:
@@ -96,6 +98,7 @@
 	MOVW	n+16(FP), R2
 	MOVD	$SYS_read, R8
 	SVC
+	CMN	$4095, R0
 	BCC	done
 	MOVW	$-1, R0
 done:
@@ -212,38 +215,28 @@
 	MOVW	R0, ret+32(FP)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVW	sig+8(FP), R0
+	MOVD	info+16(FP), R1
+	MOVD	ctx+24(FP), R2
+	MOVD	fn+0(FP), R11
+	BL	(R11)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	// this might be called in external code context,
 	// where g is not set.
 	// first save R0, because runtime·load_g will clobber it
 	MOVW	R0, 8(RSP)
-	// TODO(minux): iscgo & load_g
+	MOVBU	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	2(PC)
+	BL	runtime·load_g(SB)
 
-	// check that g exists
-	CMP	g, ZR
-	BNE	ok
-	MOVD	$runtime·badsignal(SB), R0
-	BL	(R0)
-	RET
-
-ok:
-	// save g
-	MOVD	g, 40(RSP)
-	MOVD	g, R6
-
-	// g = m->gsignal
-	MOVD	g_m(g), R7
-	MOVD	m_gsignal(R7), g
-
-	// R0 is already saved above
 	MOVD	R1, 16(RSP)
 	MOVD	R2, 24(RSP)
-	MOVD	R6, 32(RSP)
-
-	BL	runtime·sighandler(SB)
-
-	// restore g
-	MOVD	40(RSP), g
+	MOVD	$runtime·sigtrampgo(SB), R0
+	BL	(R0)
 	RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$-8
@@ -327,14 +320,19 @@
 	MOVD	$0, R0
 	MOVD	R0, (R0)	// crash
 
-	// Initialize m->procid to Linux tid
 good:
+	// Initialize m->procid to Linux tid
 	MOVD	$SYS_gettid, R8
 	SVC
 
-	MOVD	-24(RSP), R12
-	MOVD	-16(RSP), R11
-	MOVD	-8(RSP), R10
+	MOVD	-24(RSP), R12     // fn
+	MOVD	-16(RSP), R11     // g
+	MOVD	-8(RSP), R10      // m
+
+	CMP	$0, R10
+	BEQ	nog
+	CMP	$0, R11
+	BEQ	nog
 
 	MOVD	R0, m_procid(R10)
 
@@ -345,14 +343,15 @@
 	MOVD	R11, g
 	//CALL	runtime·stackcheck(SB)
 
+nog:
 	// Call fn
 	MOVD	R12, R0
 	BL	(R0)
 
-	// It shouldn't return.	 If it does, exit
+	// It shouldn't return.	 If it does, exit that thread.
 	MOVW	$111, R0
 again:
-	MOVD	$SYS_exit_group, R8
+	MOVD	$SYS_exit, R8
 	SVC
 	B	again	// keep exiting
 
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 3070893..232f299 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -67,7 +67,7 @@
 	MOVW	R3, ret+16(FP)
 	RETURN
 
-TEXT runtime·close(SB),NOSPLIT,$-8-12
+TEXT runtime·closefd(SB),NOSPLIT,$-8-12
 	MOVW	fd+0(FP), R3
 	SYSCALL	$SYS_close
 	BVC	2(PC)
@@ -196,6 +196,15 @@
 	MOVW	R3, ret+32(FP)
 	RETURN
 
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVW	sig+8(FP), R3
+	MOVD	info+16(FP), R4
+	MOVD	ctx+24(FP), R5
+	MOVD	fn+0(FP), R31
+	MOVD	R31, CTR
+	BL	(CTR)
+	RETURN
+
 #ifdef GOARCH_ppc64le
 // ppc64le doesn't need function descriptors
 TEXT runtime·sigtramp(SB),NOSPLIT,$64
@@ -217,33 +226,12 @@
 	BEQ	2(PC)
 	BL	runtime·load_g(SB)
 
-	// check that g exists
-	CMP	g, $0
-	BNE	6(PC)
-	MOVD	R3, 8(R1)
-	MOVD	$runtime·badsignal(SB), R31
-	MOVD	R31, CTR
-	BL	(CTR)
-	RETURN
-
-	// save g
-	MOVD	g, 40(R1)
-	MOVD	g, R6
-
-	// g = m->gsignal
-	MOVD	g_m(g), R7
-	MOVD	m_gsignal(R7), g
-
 	MOVW	R3, 8(R1)
 	MOVD	R4, 16(R1)
 	MOVD	R5, 24(R1)
-	MOVD	R6, 32(R1)
-
-	BL	runtime·sighandler(SB)
-
-	// restore g
-	MOVD	40(R1), g
-
+	MOVD	$runtime·sigtrampgo(SB), R31
+	MOVD	R31, CTR
+	BL	(CTR)
 	RETURN
 
 TEXT runtime·mmap(SB),NOSPLIT,$-8
@@ -323,9 +311,14 @@
 	// Initialize m->procid to Linux tid
 	SYSCALL $SYS_gettid
 
-	MOVD	-24(R1), R12
-	MOVD	-16(R1), R8
-	MOVD	-8(R1), R7
+	MOVD	-24(R1), R12       // fn
+	MOVD	-16(R1), R8        // g
+	MOVD	-8(R1), R7         // m
+
+	CMP	R7, $0
+	BEQ	nog
+	CMP	R8, $0
+	BEQ	nog
 
 	MOVD	R3, m_procid(R7)
 
@@ -336,13 +329,14 @@
 	MOVD	R8, g
 	//CALL	runtime·stackcheck(SB)
 
+nog:
 	// Call fn
 	MOVD	R12, CTR
 	BL	(CTR)
 
-	// It shouldn't return.  If it does, exit
+	// It shouldn't return.	 If it does, exit that thread.
 	MOVW	$111, R3
-	SYSCALL $SYS_exit_group
+	SYSCALL	$SYS_exit
 	BR	-2(PC)	// keep exiting
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index 242040d..f8e7196 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -33,7 +33,7 @@
 	MOVL AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$4
+TEXT runtime·closefd(SB),NOSPLIT,$4
 	MOVL fd+0(FP), AX
 	MOVL AX, 0(SP)
 	NACL_SYSCALL(SYS_close)
diff --git a/src/runtime/sys_nacl_amd64p32.s b/src/runtime/sys_nacl_amd64p32.s
index 821610b..0b29c9f 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -32,7 +32,7 @@
 	MOVL AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL fd+0(FP), DI
 	NACL_SYSCALL(SYS_close)
 	MOVL AX, ret+8(FP)
diff --git a/src/runtime/sys_nacl_arm.s b/src/runtime/sys_nacl_arm.s
index 1bae0b3..39ef25a 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -28,7 +28,7 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVW	fd+0(FP), R0
 	NACL_SYSCALL(SYS_close)
 	MOVW	R0, ret+4(FP)
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index bfa7928..b43a72e 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -32,7 +32,7 @@
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-4
+TEXT runtime·closefd(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
 	JAE	2(PC)
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index a138286..5c1d957 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -96,7 +96,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index b421022..d275d6d 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -33,7 +33,7 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-8
 	MOVW fd+0(FP), R0
 	SWI $0xa00006
 	MOVW.CS	$-1, R0
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 1087709..fa3f0d9 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -36,7 +36,7 @@
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-4
+TEXT runtime·closefd(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
 	JAE	2(PC)
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index d05782c..185b82d 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -106,7 +106,7 @@
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
index f1be775..e28d43e 100644
--- a/src/runtime/sys_openbsd_arm.s
+++ b/src/runtime/sys_openbsd_arm.s
@@ -40,7 +40,7 @@
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-4
+TEXT runtime·closefd(SB),NOSPLIT,$-4
 	MOVW	path+0(FP), R0		// arg 1 - path
 	MOVW	$6, R12			// sys_close
 	SWI	$0
diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s
index b9db8cb..cae326a 100644
--- a/src/runtime/sys_plan9_386.s
+++ b/src/runtime/sys_plan9_386.s
@@ -52,7 +52,7 @@
 	MOVL	$-1, ret_hi+20(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL	$4, AX
 	INT	$64
 	MOVL	AX, ret+4(FP)
diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s
index 02c7c87..6aefe5f 100644
--- a/src/runtime/sys_plan9_amd64.s
+++ b/src/runtime/sys_plan9_amd64.s
@@ -51,7 +51,7 @@
 	MOVQ	$-1, ret+24(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVQ	$4, BP
 	SYSCALL
 	MOVL	AX, ret+8(FP)
diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s
index 54aeaea..e431564 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -41,7 +41,7 @@
 	SUBQ	$64, SP	// 16 bytes will do, but who knows in the future?
 	MOVQ	$3, DI	// CLOCK_REALTIME from <sys/time_impl.h>
 	MOVQ	SP, SI
-	MOVQ	libc_clock_gettime(SB), AX
+	LEAQ	libc_clock_gettime(SB), AX
 	CALL	AX
 	MOVQ	(SP), AX	// tv_sec from struct timespec
 	IMULQ	$1000000000, AX	// multiply into nanoseconds
@@ -54,7 +54,7 @@
 TEXT runtime·pipe1(SB),NOSPLIT,$0
 	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte alligned
 	MOVQ	SP, DI
-	MOVQ	libc_pipe(SB), AX
+	LEAQ	libc_pipe(SB), AX
 	CALL	AX
 	MOVL	0(SP), AX
 	MOVL	4(SP), DX
@@ -321,13 +321,13 @@
 
 // Runs on OS stack. duration (in µs units) is in DI.
 TEXT runtime·usleep2(SB),NOSPLIT,$0
-	MOVQ	libc_usleep(SB), AX
+	LEAQ	libc_usleep(SB), AX
 	CALL	AX
 	RET
 
 // Runs on OS stack, called from runtime·osyield.
 TEXT runtime·osyield1(SB),NOSPLIT,$0
-	MOVQ	libc_sched_yield(SB), AX
+	LEAQ	libc_sched_yield(SB), AX
 	CALL	AX
 	RET
 
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index 5f4a63b..e5fe88a 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -213,9 +213,11 @@
 	MOVL	CX, g_stackguard1(SP)
 	MOVL	DX, (g_stack+stack_hi)(SP)
 
+	PUSHL	AX			// room for return value
 	PUSHL	16(BP)			// arg for handler
 	CALL	8(BP)
 	POPL	CX
+	POPL	AX			// pass return value to Windows in AX
 
 	get_tls(CX)
 	MOVL	g(CX), CX
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index dd81ce0..ea4f3e0 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -250,9 +250,11 @@
 	MOVQ	CX, g_stackguard1(SP)
 	MOVQ	DX, (g_stack+stack_hi)(SP)
 
+	PUSHQ	AX			// room for return value
 	PUSHQ	32(BP)			// arg for handler
 	CALL	16(BP)
 	POPQ	CX
+	POPQ	AX			// pass return value to Windows in AX
 
 	get_tls(CX)
 	MOVQ	g(CX), CX
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index 440421d..ae1f334 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -9,9 +9,6 @@
 var (
 	libc_chdir,
 	libc_chroot,
-	libc_dlopen,
-	libc_dlclose,
-	libc_dlsym,
 	libc_execve,
 	libc_fcntl,
 	libc_forkx,
@@ -60,7 +57,7 @@
 //go:nosplit
 func syscall_chdir(path uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_chdir)),
+		fn:   uintptr(unsafe.Pointer(&libc_chdir)),
 		n:    1,
 		args: uintptr(unsafe.Pointer(&path)),
 	}
@@ -71,7 +68,7 @@
 //go:nosplit
 func syscall_chroot(path uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_chroot)),
+		fn:   uintptr(unsafe.Pointer(&libc_chroot)),
 		n:    1,
 		args: uintptr(unsafe.Pointer(&path)),
 	}
@@ -82,55 +79,13 @@
 // like close, but must not split stack, for forkx.
 //go:nosplit
 func syscall_close(fd int32) int32 {
-	return int32(sysvicall1(libc_close, uintptr(fd)))
-}
-
-func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_dlopen)),
-		n:    2,
-		args: uintptr(unsafe.Pointer(&name)),
-	}
-	entersyscallblock(0)
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
-	if call.r1 == 0 {
-		return call.r1, call.err
-	}
-	return call.r1, 0
-}
-
-func syscall_dlclose(handle uintptr) (err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_dlclose)),
-		n:    1,
-		args: uintptr(unsafe.Pointer(&handle)),
-	}
-	entersyscallblock(0)
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
-	return call.r1
-}
-
-func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_dlsym)),
-		n:    2,
-		args: uintptr(unsafe.Pointer(&handle)),
-	}
-	entersyscallblock(0)
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
-	if call.r1 == 0 {
-		return call.r1, call.err
-	}
-	return call.r1, 0
+	return int32(sysvicall1(&libc_close, uintptr(fd)))
 }
 
 //go:nosplit
 func syscall_execve(path, argv, envp uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_execve)),
+		fn:   uintptr(unsafe.Pointer(&libc_execve)),
 		n:    3,
 		args: uintptr(unsafe.Pointer(&path)),
 	}
@@ -141,13 +96,13 @@
 // like exit, but must not split stack, for forkx.
 //go:nosplit
 func syscall_exit(code uintptr) {
-	sysvicall1(libc_exit, code)
+	sysvicall1(&libc_exit, code)
 }
 
 //go:nosplit
 func syscall_fcntl(fd, cmd, arg uintptr) (val, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_fcntl)),
+		fn:   uintptr(unsafe.Pointer(&libc_fcntl)),
 		n:    3,
 		args: uintptr(unsafe.Pointer(&fd)),
 	}
@@ -158,7 +113,7 @@
 //go:nosplit
 func syscall_forkx(flags uintptr) (pid uintptr, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_forkx)),
+		fn:   uintptr(unsafe.Pointer(&libc_forkx)),
 		n:    1,
 		args: uintptr(unsafe.Pointer(&flags)),
 	}
@@ -170,7 +125,7 @@
 	cname := new([_MAXHOSTNAMELEN]byte)
 	var args = [2]uintptr{uintptr(unsafe.Pointer(&cname[0])), _MAXHOSTNAMELEN}
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_gethostname)),
+		fn:   uintptr(unsafe.Pointer(&libc_gethostname)),
 		n:    2,
 		args: uintptr(unsafe.Pointer(&args[0])),
 	}
@@ -187,9 +142,9 @@
 //go:nosplit
 func syscall_getpid() (pid, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_getpid)),
+		fn:   uintptr(unsafe.Pointer(&libc_getpid)),
 		n:    0,
-		args: uintptr(unsafe.Pointer(libc_getpid)), // it's unused but must be non-nil, otherwise crashes
+		args: uintptr(unsafe.Pointer(&libc_getpid)), // it's unused but must be non-nil, otherwise crashes
 	}
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
 	return call.r1, call.err
@@ -198,7 +153,7 @@
 //go:nosplit
 func syscall_ioctl(fd, req, arg uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_ioctl)),
+		fn:   uintptr(unsafe.Pointer(&libc_ioctl)),
 		n:    3,
 		args: uintptr(unsafe.Pointer(&fd)),
 	}
@@ -226,7 +181,7 @@
 // TODO(aram): make this panic once we stop calling fcntl(2) in net using it.
 func syscall_rawsyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_syscall)),
+		fn:   uintptr(unsafe.Pointer(&libc_syscall)),
 		n:    4,
 		args: uintptr(unsafe.Pointer(&trap)),
 	}
@@ -237,7 +192,7 @@
 //go:nosplit
 func syscall_setgid(gid uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_setgid)),
+		fn:   uintptr(unsafe.Pointer(&libc_setgid)),
 		n:    1,
 		args: uintptr(unsafe.Pointer(&gid)),
 	}
@@ -248,7 +203,7 @@
 //go:nosplit
 func syscall_setgroups(ngid, gid uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_setgroups)),
+		fn:   uintptr(unsafe.Pointer(&libc_setgroups)),
 		n:    2,
 		args: uintptr(unsafe.Pointer(&ngid)),
 	}
@@ -259,9 +214,9 @@
 //go:nosplit
 func syscall_setsid() (pid, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_setsid)),
+		fn:   uintptr(unsafe.Pointer(&libc_setsid)),
 		n:    0,
-		args: uintptr(unsafe.Pointer(libc_setsid)), // it's unused but must be non-nil, otherwise crashes
+		args: uintptr(unsafe.Pointer(&libc_setsid)), // it's unused but must be non-nil, otherwise crashes
 	}
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
 	return call.r1, call.err
@@ -270,7 +225,7 @@
 //go:nosplit
 func syscall_setuid(uid uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_setuid)),
+		fn:   uintptr(unsafe.Pointer(&libc_setuid)),
 		n:    1,
 		args: uintptr(unsafe.Pointer(&uid)),
 	}
@@ -281,7 +236,7 @@
 //go:nosplit
 func syscall_setpgid(pid, pgid uintptr) (err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_setpgid)),
+		fn:   uintptr(unsafe.Pointer(&libc_setpgid)),
 		n:    2,
 		args: uintptr(unsafe.Pointer(&pid)),
 	}
@@ -297,7 +252,7 @@
 // TODO(aram): make this panic once we stop calling fcntl(2) in net using it.
 func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_syscall)),
+		fn:   uintptr(unsafe.Pointer(&libc_syscall)),
 		n:    4,
 		args: uintptr(unsafe.Pointer(&trap)),
 	}
@@ -309,7 +264,7 @@
 
 func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.Pointer) (wpid int, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_wait4)),
+		fn:   uintptr(unsafe.Pointer(&libc_wait4)),
 		n:    4,
 		args: uintptr(unsafe.Pointer(&pid)),
 	}
@@ -322,7 +277,7 @@
 //go:nosplit
 func syscall_write(fd, buf, nbyte uintptr) (n, err uintptr) {
 	call := libcall{
-		fn:   uintptr(unsafe.Pointer(libc_write)),
+		fn:   uintptr(unsafe.Pointer(&libc_write)),
 		n:    3,
 		args: uintptr(unsafe.Pointer(&fd)),
 	}
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index cd8b884..370b172 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -95,7 +95,7 @@
 	c.fn = getLoadLibrary()
 	c.n = 1
 	c.args = uintptr(unsafe.Pointer(&filename))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	handle = c.r1
 	if handle == 0 {
 		err = c.err
@@ -110,7 +110,7 @@
 	c.fn = getGetProcAddress()
 	c.n = 2
 	c.args = uintptr(unsafe.Pointer(&handle))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	outhandle = c.r1
 	if outhandle == 0 {
 		err = c.err
@@ -125,7 +125,7 @@
 	c.fn = fn
 	c.n = nargs
 	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
@@ -136,7 +136,7 @@
 	c.fn = fn
 	c.n = nargs
 	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
@@ -147,7 +147,7 @@
 	c.fn = fn
 	c.n = nargs
 	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
@@ -158,7 +158,7 @@
 	c.fn = fn
 	c.n = nargs
 	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
@@ -169,6 +169,6 @@
 	c.fn = fn
 	c.n = nargs
 	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	cgocall_errno(asmstdcallAddr, unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
diff --git a/src/runtime/tls_arm64.h b/src/runtime/tls_arm64.h
new file mode 100644
index 0000000..d5676ab
--- /dev/null
+++ b/src/runtime/tls_arm64.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifdef GOOS_linux
+#define TPIDR TPIDR_EL0
+#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDR_EL0, R0
+#endif
+
+#ifdef GOOS_darwin
+#define TPIDR TPIDRRO_EL0
+#define TLSG_IS_VARIABLE
+#define MRS_TPIDR_R0 WORD $0xd53bd060 // MRS TPIDRRO_EL0, R0
+#endif
+
+// Define something that will break the build if
+// the GOOS is unknown.
+#ifndef TPIDR
+#define MRS_TPIDR_R0 TPIDR_UNKNOWN
+#endif
diff --git a/src/runtime/tls_arm64.s b/src/runtime/tls_arm64.s
new file mode 100644
index 0000000..a5f86c4
--- /dev/null
+++ b/src/runtime/tls_arm64.s
@@ -0,0 +1,60 @@
+// 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 "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+#include "tls_arm64.h"
+
+TEXT runtime·load_g(SB),NOSPLIT,$0
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	nocgo
+
+	MRS_TPIDR_R0
+#ifdef GOOS_darwin
+	// Darwin sometimes returns unaligned pointers
+	AND	$0xfffffffffffffff8, R0
+#endif
+#ifdef TLSG_IS_VARIABLE
+	MOVD	runtime·tls_g(SB), R27
+	ADD	R27, R0
+#else
+	// TODO(minux): use real TLS relocation, instead of hard-code for Linux
+	ADD	$0x10, R0
+#endif
+	MOVD	0(R0), g
+
+nocgo:
+	RET
+
+TEXT runtime·save_g(SB),NOSPLIT,$0
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	nocgo
+
+	MRS_TPIDR_R0
+#ifdef GOOS_darwin
+	// Darwin sometimes returns unaligned pointers
+	AND	$0xfffffffffffffff8, R0
+#endif
+#ifdef TLSG_IS_VARIABLE
+	MOVD	runtime·tls_g(SB), R27
+	ADD	R27, R0
+#else
+	// TODO(minux): use real TLS relocation, instead of hard-code for Linux
+	ADD	$0x10, R0
+#endif
+	MOVD	g, 0(R0)
+
+nocgo:
+	RET
+
+#ifdef TLSG_IS_VARIABLE
+// The runtime.tlsg name is being handled specially in the
+// linker. As we just need a regular variable here, don't
+// use that name.
+GLOBL runtime·tls_g+0(SB), NOPTR, $8
+#endif
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 7c4d8d3..3b7501b 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -45,11 +45,11 @@
 	traceEvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
 	traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
 	traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
-	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
+	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, real timestamp]
 	traceEvGoSysBlock     = 30 // syscall blocks [timestamp]
 	traceEvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
 	traceEvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
-	traceEvHeapAlloc      = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
+	traceEvHeapAlloc      = 33 // memstats.heap_live change [timestamp, heap_alloc]
 	traceEvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
 	traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
 	traceEvFutileWakeup   = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
@@ -60,8 +60,13 @@
 	// Timestamps in trace are cputicks/traceTickDiv.
 	// This makes absolute values of timestamp diffs smaller,
 	// and so they are encoded in less number of bytes.
-	// 64 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine).
-	traceTickDiv = 64
+	// 64 on x86 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine).
+	// The suggested increment frequency for PowerPC's time base register is
+	// 512 MHz according to Power ISA v2.07 section 6.2, so we use 16 on ppc64
+	// and ppc64le.
+	// Tracing won't work reliably for architectures where cputicks is emulated
+	// by nanotime, so the value doesn't matter for those architectures.
+	traceTickDiv = 16 + 48*(goarch_386|goarch_amd64|goarch_amd64p32)
 	// Maximum number of PCs in a single stack trace.
 	// Since events contain only stack id rather than whole stack trace,
 	// we can allow quite large values here.
@@ -506,7 +511,7 @@
 // traceAcquireBuffer returns trace buffer to use and, if necessary, locks it.
 func traceAcquireBuffer() (mp *m, pid int32, bufp **traceBuf) {
 	mp = acquirem()
-	if p := mp.p; p != nil {
+	if p := mp.p.ptr(); p != nil {
 		return mp, p.id, &p.tracebuf
 	}
 	lock(&trace.bufLock)
@@ -732,7 +737,7 @@
 	// to handle this we temporary employ the P.
 	mp := acquirem()
 	oldp := mp.p
-	mp.p = pp
+	mp.p.set(pp)
 	traceEvent(traceEvProcStop, -1)
 	mp.p = oldp
 	releasem(mp)
@@ -797,8 +802,8 @@
 	traceEvent(traceEvGoSysCall, 4)
 }
 
-func traceGoSysExit() {
-	traceEvent(traceEvGoSysExit, -1, uint64(getg().m.curg.goid))
+func traceGoSysExit(ts int64) {
+	traceEvent(traceEvGoSysExit, -1, uint64(getg().m.curg.goid), uint64(ts)/traceTickDiv)
 }
 
 func traceGoSysBlock(pp *p) {
@@ -806,14 +811,14 @@
 	// to handle this we temporary employ the P.
 	mp := acquirem()
 	oldp := mp.p
-	mp.p = pp
+	mp.p.set(pp)
 	traceEvent(traceEvGoSysBlock, -1)
 	mp.p = oldp
 	releasem(mp)
 }
 
 func traceHeapAlloc() {
-	traceEvent(traceEvHeapAlloc, -1, memstats.heap_alloc)
+	traceEvent(traceEvHeapAlloc, -1, memstats.heap_live)
 }
 
 func traceNextGC() {
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index b6f4374..9f34e37 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -44,6 +44,7 @@
 	bgsweepPC            uintptr
 	forcegchelperPC      uintptr
 	timerprocPC          uintptr
+	gcBgMarkWorkerPC     uintptr
 	systemstack_switchPC uintptr
 
 	externalthreadhandlerp uintptr // initialized elsewhere
@@ -66,6 +67,7 @@
 	bgsweepPC = funcPC(bgsweep)
 	forcegchelperPC = funcPC(forcegchelper)
 	timerprocPC = funcPC(timerproc)
+	gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
 	systemstack_switchPC = funcPC(systemstack_switch)
 }
 
@@ -528,7 +530,7 @@
 
 func showframe(f *_func, gp *g) bool {
 	g := getg()
-	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig) {
+	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
 		return true
 	}
 	traceback := gotraceback(nil)
@@ -625,7 +627,11 @@
 		}
 		print("\n")
 		goroutineheader(gp)
-		if readgstatus(gp)&^_Gscan == _Grunning {
+		// Note: gp.m == g.m occurs when tracebackothers is
+		// called from a signal handler initiated during a
+		// systemstack call.  The original G is still in the
+		// running state, and we want to print its stack.
+		if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
 			print("\tgoroutine running on other thread; stack unavailable\n")
 			printcreatedby(gp)
 		} else {
@@ -654,5 +660,6 @@
 		pc == backgroundgcPC ||
 		pc == bgsweepPC ||
 		pc == forcegchelperPC ||
-		pc == timerprocPC
+		pc == timerprocPC ||
+		pc == gcBgMarkWorkerPC
 }
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 70ed24c..48df2a4 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -8,9 +8,12 @@
 
 import "unsafe"
 
-// Needs to be in sync with ../../cmd/internal/ld/decodesym.go:/^commonsize and pkg/reflect/type.go:/type.
+// Needs to be in sync with ../cmd/internal/ld/decodesym.go:/^func.commonsize,
+// ../cmd/internal/gc/reflect.go:/^func.dcommontype and
+// ../reflect/type.go:/^type.rtype.
 type _type struct {
 	size       uintptr
+	ptrdata    uintptr // size of memory prefix holding all pointers
 	hash       uint32
 	_unused    uint8
 	align      uint8
diff --git a/src/runtime/wbfat.go b/src/runtime/wbfat.go
index 75c58b2..8fe2cef 100644
--- a/src/runtime/wbfat.go
+++ b/src/runtime/wbfat.go
@@ -3,74 +3,74 @@
 package runtime
 
 //go:nosplit
-func writebarrierfat01(dst *[2]uintptr, _ *byte, src [2]uintptr) {
+func writebarrierfat01(dst *[2]uintptr, _ uintptr, src [2]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 }
 
 //go:nosplit
-func writebarrierfat10(dst *[2]uintptr, _ *byte, src [2]uintptr) {
+func writebarrierfat10(dst *[2]uintptr, _ uintptr, src [2]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 }
 
 //go:nosplit
-func writebarrierfat11(dst *[2]uintptr, _ *byte, src [2]uintptr) {
+func writebarrierfat11(dst *[2]uintptr, _ uintptr, src [2]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 }
 
 //go:nosplit
-func writebarrierfat001(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat001(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	dst[0] = src[0]
 	dst[1] = src[1]
 	writebarrierptr(&dst[2], src[2])
 }
 
 //go:nosplit
-func writebarrierfat010(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat010(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 	dst[2] = src[2]
 }
 
 //go:nosplit
-func writebarrierfat011(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat011(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 	writebarrierptr(&dst[2], src[2])
 }
 
 //go:nosplit
-func writebarrierfat100(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat100(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 	dst[2] = src[2]
 }
 
 //go:nosplit
-func writebarrierfat101(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat101(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 	writebarrierptr(&dst[2], src[2])
 }
 
 //go:nosplit
-func writebarrierfat110(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat110(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 	dst[2] = src[2]
 }
 
 //go:nosplit
-func writebarrierfat111(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+func writebarrierfat111(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 	writebarrierptr(&dst[2], src[2])
 }
 
 //go:nosplit
-func writebarrierfat0001(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0001(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	dst[1] = src[1]
 	dst[2] = src[2]
@@ -78,7 +78,7 @@
 }
 
 //go:nosplit
-func writebarrierfat0010(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0010(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	dst[1] = src[1]
 	writebarrierptr(&dst[2], src[2])
@@ -86,7 +86,7 @@
 }
 
 //go:nosplit
-func writebarrierfat0011(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0011(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	dst[1] = src[1]
 	writebarrierptr(&dst[2], src[2])
@@ -94,7 +94,7 @@
 }
 
 //go:nosplit
-func writebarrierfat0100(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0100(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 	dst[2] = src[2]
@@ -102,7 +102,7 @@
 }
 
 //go:nosplit
-func writebarrierfat0101(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0101(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 	dst[2] = src[2]
@@ -110,7 +110,7 @@
 }
 
 //go:nosplit
-func writebarrierfat0110(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0110(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 	writebarrierptr(&dst[2], src[2])
@@ -118,7 +118,7 @@
 }
 
 //go:nosplit
-func writebarrierfat0111(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat0111(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	dst[0] = src[0]
 	writebarrierptr(&dst[1], src[1])
 	writebarrierptr(&dst[2], src[2])
@@ -126,7 +126,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1000(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1000(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 	dst[2] = src[2]
@@ -134,7 +134,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1001(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1001(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 	dst[2] = src[2]
@@ -142,7 +142,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1010(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1010(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 	writebarrierptr(&dst[2], src[2])
@@ -150,7 +150,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1011(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1011(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	dst[1] = src[1]
 	writebarrierptr(&dst[2], src[2])
@@ -158,7 +158,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1100(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1100(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 	dst[2] = src[2]
@@ -166,7 +166,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1101(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1101(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 	dst[2] = src[2]
@@ -174,7 +174,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1110(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1110(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 	writebarrierptr(&dst[2], src[2])
@@ -182,7 +182,7 @@
 }
 
 //go:nosplit
-func writebarrierfat1111(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+func writebarrierfat1111(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
 	writebarrierptr(&dst[0], src[0])
 	writebarrierptr(&dst[1], src[1])
 	writebarrierptr(&dst[2], src[2])
diff --git a/src/runtime/wbfat_gen.go b/src/runtime/wbfat_gen.go
index 78d5b62..9482cfe 100644
--- a/src/runtime/wbfat_gen.go
+++ b/src/runtime/wbfat_gen.go
@@ -27,7 +27,7 @@
 	for i := uint(2); i <= 4; i++ {
 		for j := 1; j < 1<<i; j++ {
 			fmt.Printf("\n//go:nosplit\n")
-			fmt.Printf("func writebarrierfat%0*b(dst *[%d]uintptr, _ *byte, src [%d]uintptr) {\n", int(i), j, i, i)
+			fmt.Printf("func writebarrierfat%0*b(dst *[%d]uintptr, _ uintptr, src [%d]uintptr) {\n", int(i), j, i, i)
 			for k := uint(0); k < i; k++ {
 				if j&(1<<(i-1-k)) != 0 {
 					fmt.Printf("\twritebarrierptr(&dst[%d], src[%d])\n", k, k)
diff --git a/src/strconv/decimal.go b/src/strconv/decimal.go
index 3d7c8d1..5252d6e 100644
--- a/src/strconv/decimal.go
+++ b/src/strconv/decimal.go
@@ -102,8 +102,9 @@
 }
 
 // Maximum shift that we can do in one pass without overflow.
-// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
-const maxShift = 27
+// A uint has 32 or 64 bits, and we have to be able to accommodate 9<<k.
+const uintSize = 32 << (^uint(0) >> 63)
+const maxShift = uintSize - 4
 
 // Binary shift right (/ 2) by k bits.  k <= maxShift to avoid overflow.
 func rightShift(a *decimal, k uint) {
@@ -111,7 +112,7 @@
 	w := 0 // write pointer
 
 	// Pick up enough leading digits to cover first shift.
-	n := 0
+	var n uint
 	for ; n>>k == 0; r++ {
 		if r >= a.nd {
 			if n == 0 {
@@ -125,14 +126,14 @@
 			}
 			break
 		}
-		c := int(a.d[r])
+		c := uint(a.d[r])
 		n = n*10 + c - '0'
 	}
 	a.dp -= r - 1
 
 	// Pick up a digit, put down a digit.
 	for ; r < a.nd; r++ {
-		c := int(a.d[r])
+		c := uint(a.d[r])
 		dig := n >> k
 		n -= dig << k
 		a.d[w] = byte(dig + '0')
@@ -169,50 +170,84 @@
 
 type leftCheat struct {
 	delta  int    // number of new digits
-	cutoff string //   minus one digit if original < a.
+	cutoff string // minus one digit if original < a.
 }
 
 var leftcheats = []leftCheat{
 	// Leading digits of 1/2^i = 5^i.
 	// 5^23 is not an exact 64-bit floating point number,
 	// so have to use bc for the math.
+	// Go up to 60 to be large enough for 32bit and 64bit platforms.
 	/*
-		seq 27 | sed 's/^/5^/' | bc |
-		awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
+		seq 60 | sed 's/^/5^/' | bc |
+		awk 'BEGIN{ print "\t{ 0, \"\" }," }
 		{
 			log2 = log(2)/log(10)
-			printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
+			printf("\t{ %d, \"%s\" },\t// * %d\n",
 				int(log2*NR+1), $0, 2**NR)
 		}'
 	*/
 	{0, ""},
-	{1, "5"},                   // * 2
-	{1, "25"},                  // * 4
-	{1, "125"},                 // * 8
-	{2, "625"},                 // * 16
-	{2, "3125"},                // * 32
-	{2, "15625"},               // * 64
-	{3, "78125"},               // * 128
-	{3, "390625"},              // * 256
-	{3, "1953125"},             // * 512
-	{4, "9765625"},             // * 1024
-	{4, "48828125"},            // * 2048
-	{4, "244140625"},           // * 4096
-	{4, "1220703125"},          // * 8192
-	{5, "6103515625"},          // * 16384
-	{5, "30517578125"},         // * 32768
-	{5, "152587890625"},        // * 65536
-	{6, "762939453125"},        // * 131072
-	{6, "3814697265625"},       // * 262144
-	{6, "19073486328125"},      // * 524288
-	{7, "95367431640625"},      // * 1048576
-	{7, "476837158203125"},     // * 2097152
-	{7, "2384185791015625"},    // * 4194304
-	{7, "11920928955078125"},   // * 8388608
-	{8, "59604644775390625"},   // * 16777216
-	{8, "298023223876953125"},  // * 33554432
-	{8, "1490116119384765625"}, // * 67108864
-	{9, "7450580596923828125"}, // * 134217728
+	{1, "5"},                                           // * 2
+	{1, "25"},                                          // * 4
+	{1, "125"},                                         // * 8
+	{2, "625"},                                         // * 16
+	{2, "3125"},                                        // * 32
+	{2, "15625"},                                       // * 64
+	{3, "78125"},                                       // * 128
+	{3, "390625"},                                      // * 256
+	{3, "1953125"},                                     // * 512
+	{4, "9765625"},                                     // * 1024
+	{4, "48828125"},                                    // * 2048
+	{4, "244140625"},                                   // * 4096
+	{4, "1220703125"},                                  // * 8192
+	{5, "6103515625"},                                  // * 16384
+	{5, "30517578125"},                                 // * 32768
+	{5, "152587890625"},                                // * 65536
+	{6, "762939453125"},                                // * 131072
+	{6, "3814697265625"},                               // * 262144
+	{6, "19073486328125"},                              // * 524288
+	{7, "95367431640625"},                              // * 1048576
+	{7, "476837158203125"},                             // * 2097152
+	{7, "2384185791015625"},                            // * 4194304
+	{7, "11920928955078125"},                           // * 8388608
+	{8, "59604644775390625"},                           // * 16777216
+	{8, "298023223876953125"},                          // * 33554432
+	{8, "1490116119384765625"},                         // * 67108864
+	{9, "7450580596923828125"},                         // * 134217728
+	{9, "37252902984619140625"},                        // * 268435456
+	{9, "186264514923095703125"},                       // * 536870912
+	{10, "931322574615478515625"},                      // * 1073741824
+	{10, "4656612873077392578125"},                     // * 2147483648
+	{10, "23283064365386962890625"},                    // * 4294967296
+	{10, "116415321826934814453125"},                   // * 8589934592
+	{11, "582076609134674072265625"},                   // * 17179869184
+	{11, "2910383045673370361328125"},                  // * 34359738368
+	{11, "14551915228366851806640625"},                 // * 68719476736
+	{12, "72759576141834259033203125"},                 // * 137438953472
+	{12, "363797880709171295166015625"},                // * 274877906944
+	{12, "1818989403545856475830078125"},               // * 549755813888
+	{13, "9094947017729282379150390625"},               // * 1099511627776
+	{13, "45474735088646411895751953125"},              // * 2199023255552
+	{13, "227373675443232059478759765625"},             // * 4398046511104
+	{13, "1136868377216160297393798828125"},            // * 8796093022208
+	{14, "5684341886080801486968994140625"},            // * 17592186044416
+	{14, "28421709430404007434844970703125"},           // * 35184372088832
+	{14, "142108547152020037174224853515625"},          // * 70368744177664
+	{15, "710542735760100185871124267578125"},          // * 140737488355328
+	{15, "3552713678800500929355621337890625"},         // * 281474976710656
+	{15, "17763568394002504646778106689453125"},        // * 562949953421312
+	{16, "88817841970012523233890533447265625"},        // * 1125899906842624
+	{16, "444089209850062616169452667236328125"},       // * 2251799813685248
+	{16, "2220446049250313080847263336181640625"},      // * 4503599627370496
+	{16, "11102230246251565404236316680908203125"},     // * 9007199254740992
+	{17, "55511151231257827021181583404541015625"},     // * 18014398509481984
+	{17, "277555756156289135105907917022705078125"},    // * 36028797018963968
+	{17, "1387778780781445675529539585113525390625"},   // * 72057594037927936
+	{18, "6938893903907228377647697925567626953125"},   // * 144115188075855872
+	{18, "34694469519536141888238489627838134765625"},  // * 288230376151711744
+	{18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
+	{19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
 }
 
 // Is the leading prefix of b lexicographically less than s?
@@ -237,11 +272,11 @@
 
 	r := a.nd         // read index
 	w := a.nd + delta // write index
-	n := 0
 
 	// Pick up a digit, put down a digit.
+	var n uint
 	for r--; r >= 0; r-- {
-		n += (int(a.d[r]) - '0') << k
+		n += (uint(a.d[r]) - '0') << k
 		quo := n / 10
 		rem := n - 10*quo
 		w--
diff --git a/src/strings/reader.go b/src/strings/reader.go
index 82df974..7a872fb 100644
--- a/src/strings/reader.go
+++ b/src/strings/reader.go
@@ -28,6 +28,12 @@
 	return int(int64(len(r.s)) - r.i)
 }
 
+// Size returns the original length of the underlying string.
+// Size is the number of bytes available for reading via ReadAt.
+// The returned value is always the same and is not affected by calls
+// to any other method.
+func (r *Reader) Size() int64 { return int64(len(r.s)) }
+
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
diff --git a/src/strings/reader_test.go b/src/strings/reader_test.go
index bee90eb..5003a37 100644
--- a/src/strings/reader_test.go
+++ b/src/strings/reader_test.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"os"
 	"strings"
 	"sync"
@@ -157,3 +158,15 @@
 		}
 	}
 }
+
+// tests that Len is affected by reads, but Size is not.
+func TestReaderLenSize(t *testing.T) {
+	r := strings.NewReader("abc")
+	io.CopyN(ioutil.Discard, r, 1)
+	if r.Len() != 2 {
+		t.Errorf("Len = %d; want 2", r.Len())
+	}
+	if r.Size() != 3 {
+		t.Errorf("Size = %d; want 3", r.Size())
+	}
+}
diff --git a/src/strings/strings.go b/src/strings/strings.go
index c6085f5..567a3c5b 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -185,14 +185,7 @@
 	case n == 0:
 		return len(s)
 	case n == 1:
-		// special case worth making fast
-		c := sep[0]
-		for i := len(s) - 1; i >= 0; i-- {
-			if s[i] == c {
-				return i
-			}
-		}
-		return -1
+		return LastIndexByte(s, sep[0])
 	case n == len(s):
 		if sep == s {
 			return 0
@@ -271,6 +264,16 @@
 	return -1
 }
 
+// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
+func LastIndexByte(s string, c byte) int {
+	for i := len(s) - 1; i >= 0; i-- {
+		if s[i] == c {
+			return i
+		}
+	}
+	return -1
+}
+
 // Generic split: splits after each instance of sep,
 // including sepSave bytes of sep in the subarrays.
 func genSplit(s, sep string, sepSave, n int) []string {
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index ee0c260..4e21dea 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -120,6 +120,23 @@
 func TestIndexAny(t *testing.T)     { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
 func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
 
+func TestLastIndexByte(t *testing.T) {
+	testCases := []IndexTest{
+		{"", "q", -1},
+		{"abcdef", "q", -1},
+		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle
+		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte
+		{"zabcdefabcdef", "z", 0},                 // first byte
+		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii
+	}
+	for _, test := range testCases {
+		actual := LastIndexByte(test.s, test.sep[0])
+		if actual != test.out {
+			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out)
+		}
+	}
+}
+
 var indexRuneTests = []struct {
 	s    string
 	rune rune
diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index ca9ebcf..d340ef5 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -1405,7 +1405,8 @@
 func TestNilDeref(t *testing.T) {
 	switch runtime.GOOS {
 	case "darwin", "freebsd", "netbsd":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			t.Skipf("issue 7338: skipping test on %s/%s", runtime.GOOS, runtime.GOARCH)
 		}
 	}
diff --git a/src/syscall/asm_darwin_arm64.s b/src/syscall/asm_darwin_arm64.s
new file mode 100644
index 0000000..e18ff6a
--- /dev/null
+++ b/src/syscall/asm_darwin_arm64.s
@@ -0,0 +1,127 @@
+// 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"
+
+//
+// System call support for ARM64, Darwin
+//
+
+// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT	·Syscall(SB),NOSPLIT,$0-56
+	BL	runtime·entersyscall(SB)
+	MOVD	syscall+0(FP), R16
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+32(FP)	// r1
+	MOVD	ZR, r2+40(FP)	// r2
+	MOVD	R0, errno+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+32(FP) // r1
+	MOVD	R1, r2+40(FP)	// r2
+	MOVD	ZR, errno+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+	MOVD	syscall+0(FP), R16	// syscall entry
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+32(FP)	// r1
+	MOVD	ZR, r2+40(FP)	// r2
+	MOVD	R0, errno+48(FP)	// errno
+	RET
+ok:
+	MOVD	R0, r1+32(FP) // r1
+	MOVD	R1, r2+40(FP)	// r2
+	MOVD	ZR, errno+48(FP)	// errno
+	RET
+
+// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT	·Syscall6(SB),NOSPLIT,$0-80
+	BL	runtime·entersyscall(SB)
+	MOVD	syscall+0(FP), R16	// syscall entry
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	a4+32(FP), R3
+	MOVD	a5+40(FP), R4
+	MOVD	a6+48(FP), R5
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+56(FP)	// r1
+	MOVD	ZR, r2+64(FP)	// r2
+	MOVD	R0, errno+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+56(FP) // r1
+	MOVD	R1, r2+64(FP)	// r2
+	MOVD	ZR, errno+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
+	MOVD	trap+0(FP), R16	// syscall entry
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	a4+32(FP), R3
+	MOVD	a5+40(FP), R4
+	MOVD	a6+48(FP), R5
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+56(FP)	// r1
+	MOVD	ZR, r2+64(FP)	// r2
+	MOVD	R0, errno+72(FP)	// errno
+	RET
+ok:
+	MOVD	R0, r1+56(FP) // r1
+	MOVD	R1, r2+64(FP)	// r2
+	MOVD	ZR, R0
+	MOVD	R0, errno+72(FP)	// errno
+	RET
+
+// Actually Syscall7
+TEXT	·Syscall9(SB),NOSPLIT,$0-104
+	BL	runtime·entersyscall(SB)
+	MOVD	syscall+0(FP), R16	// syscall entry
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	a4+32(FP), R3
+	MOVD	a5+40(FP), R4
+	MOVD	a6+48(FP), R5
+	MOVD	a7+56(FP), R6
+	//MOVD	a8+64(FP), R7
+	//MOVD	a9+72(FP), R8
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+80(FP)	// r1
+	MOVD	ZR, r2+88(FP)	// r2
+	MOVD	R0, errno+96(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+80(FP) // r1
+	MOVD	R1, r2+88(FP)	// r2
+	MOVD	ZR, errno+96(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
diff --git a/src/syscall/const_plan9.go b/src/syscall/const_plan9.go
new file mode 100644
index 0000000..ba26f12
--- /dev/null
+++ b/src/syscall/const_plan9.go
@@ -0,0 +1,59 @@
+package syscall
+
+// Plan 9 Constants
+
+// Open modes
+const (
+	O_RDONLY  = 0
+	O_WRONLY  = 1
+	O_RDWR    = 2
+	O_TRUNC   = 16
+	O_CLOEXEC = 32
+	O_EXCL    = 0x1000
+)
+
+// Rfork flags
+const (
+	RFNAMEG  = 1 << 0
+	RFENVG   = 1 << 1
+	RFFDG    = 1 << 2
+	RFNOTEG  = 1 << 3
+	RFPROC   = 1 << 4
+	RFMEM    = 1 << 5
+	RFNOWAIT = 1 << 6
+	RFCNAMEG = 1 << 10
+	RFCENVG  = 1 << 11
+	RFCFDG   = 1 << 12
+	RFREND   = 1 << 13
+	RFNOMNT  = 1 << 14
+)
+
+// Qid.Type bits
+const (
+	QTDIR    = 0x80
+	QTAPPEND = 0x40
+	QTEXCL   = 0x20
+	QTMOUNT  = 0x10
+	QTAUTH   = 0x08
+	QTTMP    = 0x04
+	QTFILE   = 0x00
+)
+
+// Dir.Mode bits
+const (
+	DMDIR    = 0x80000000
+	DMAPPEND = 0x40000000
+	DMEXCL   = 0x20000000
+	DMMOUNT  = 0x10000000
+	DMAUTH   = 0x08000000
+	DMTMP    = 0x04000000
+	DMREAD   = 0x4
+	DMWRITE  = 0x2
+	DMEXEC   = 0x1
+)
+
+const (
+	STATMAX    = 65535
+	ERRMAX     = 128
+	STATFIXLEN = 49
+)
diff --git a/src/syscall/creds_test.go b/src/syscall/creds_test.go
index b1894c6..b4a14ff 100644
--- a/src/syscall/creds_test.go
+++ b/src/syscall/creds_test.go
@@ -56,7 +56,13 @@
 		ucred.Gid = 0
 		oob := syscall.UnixCredentials(&ucred)
 		_, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
-		if err.(*net.OpError).Err != syscall.EPERM {
+		if op, ok := err.(*net.OpError); ok {
+			err = op.Err
+		}
+		if sys, ok := err.(*os.SyscallError); ok {
+			err = sys.Err
+		}
+		if err != syscall.EPERM {
 			t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
 		}
 	}
diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go
index bc21690..1cb4754 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -16,19 +16,17 @@
 	if err != nil {
 		return "", false
 	}
-	b := make([]uint16, 100)
-	n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-	if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
-		return "", false
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
-		n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-		if n > uint32(len(b)) {
-			n = 0
+	n := uint32(100)
+	for {
+		b := make([]uint16, n)
+		n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
+		if n == 0 && err == ERROR_ENVVAR_NOT_FOUND {
+			return "", false
+		}
+		if n <= uint32(len(b)) {
+			return string(utf16.Decode(b[:n])), true
 		}
 	}
-	return string(utf16.Decode(b[0:n])), true
 }
 
 func Setenv(key, value string) error {
diff --git a/src/syscall/zerrors_plan9_386.go b/src/syscall/errors_plan9.go
similarity index 100%
rename from src/syscall/zerrors_plan9_386.go
rename to src/syscall/errors_plan9.go
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 02474fc..ced2ca86 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -178,14 +178,14 @@
 	}
 
 	if sys.Foreground {
-		pgrp := sys.Pgid
+		pgrp := int32(sys.Pgid)
 		if pgrp == 0 {
 			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
 			if err1 != 0 {
 				goto childerror
 			}
 
-			pgrp = int(r1)
+			pgrp = int32(r1)
 		}
 
 		// Place process group in foreground.
diff --git a/src/syscall/exec_solaris_test.go b/src/syscall/exec_solaris_test.go
index 123d9f1..6b8f1ad 100644
--- a/src/syscall/exec_solaris_test.go
+++ b/src/syscall/exec_solaris_test.go
@@ -6,13 +6,21 @@
 
 package syscall
 
+import "unsafe"
+
+//go:cgo_import_dynamic libc_Getpgid getpgid "libc.so"
+//go:cgo_import_dynamic libc_Getpgrp getpgrp "libc.so"
+
+//go:linkname libc_Getpgid libc_Getpgid
+//go:linkname libc_Getpgrp libc_Getpgrp
+
 var (
-	procGetpgid = modlibc.NewProc("getpgid")
-	procGetpgrp = modlibc.NewProc("getpgrp")
+	libc_Getpgid,
+	libc_Getpgrp libcFunc
 )
 
 func Getpgid(pid int) (pgid int, err error) {
-	r0, _, e1 := sysvicall6(procGetpgid.Addr(), 1, uintptr(pid), 0, 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -21,7 +29,7 @@
 }
 
 func Getpgrp() (pgrp int) {
-	r0, _, _ := sysvicall6(procGetpgrp.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgrp)), 0, 0, 0, 0, 0, 0, 0)
 	pgrp = int(r0)
 	return
 }
diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
index 936aeb5..cc1abc4 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -135,23 +135,17 @@
 	if err != nil {
 		return "", err
 	}
-	buf := make([]uint16, 100)
-	n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
-	if err != nil {
-		return "", err
-	}
-	if n > uint32(len(buf)) {
-		// Windows is asking for bigger buffer.
-		buf = make([]uint16, n)
+	n := uint32(100)
+	for {
+		buf := make([]uint16, n)
 		n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
 		if err != nil {
 			return "", err
 		}
-		if n > uint32(len(buf)) {
-			return "", EINVAL
+		if n <= uint32(len(buf)) {
+			return UTF16ToString(buf[:n]), nil
 		}
 	}
-	return UTF16ToString(buf[:n]), nil
 }
 
 func isSlash(c uint8) bool {
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 7709ebf..1b7cd64 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -124,6 +124,11 @@
 	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+darwin_arm64)
+	mkerrors="$mkerrors -m64"
+	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+	;;
 dragonfly_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="./mksyscall.pl -l32 -dragonfly"
diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_solaris.pl
index 3f52aa4..f5eb4b3 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_solaris.pl
@@ -61,8 +61,8 @@
 my $package = "";
 my $text = "";
 my $vars = "";
-my $mods = "";
-my $modnames = "";
+my $dynimports = "";
+my $linknames = "";
 while(<>) {
 	chomp;
 	s/\s+/ /g;
@@ -93,11 +93,6 @@
 	if($modname eq "") {
 		$modname = "libc";
 	}
-	my $modvname = "mod$modname";
-	if($modnames !~ /$modname/) {
-		$modnames .= ".$modname";
-		$mods .= "\t$modvname = ${syscalldot}newLazySO(\"$modname.so\")\n";
-	}
 
 	# System call name.
 	if($sysname eq "") {
@@ -105,14 +100,20 @@
 	}
 
 	# System call pointer variable name.
-	my $sysvarname = "proc$sysname";
+	my $sysvarname = "libc_$sysname";
 
 	my $strconvfunc = "BytePtrFromString";
 	my $strconvtype = "*byte";
 
 	# Library proc address variable.
 	$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
-	$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
+	if($vars eq "") {
+		$vars .= "\t$sysvarname";
+	} else {
+		$vars .= ",\n\t$sysvarname";
+	}
+	$dynimports .= "//go:cgo_import_dynamic $sysvarname $sysname \"$modname.so\"\n";
+	$linknames .= "//go:linkname $sysvarname $sysvarname\n";
 
 	# Go function header.
 	$out = join(', ', @out);
@@ -196,7 +197,7 @@
 
 	# Actual call.
 	my $args = join(', ', @args);
-	my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
+	my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)";
 
 	# Assign return values.
 	my $body = "";
@@ -272,9 +273,12 @@
 
 print <<EOF;
 
+$dynimports
+$linknames
+type libcFunc uintptr
+
 var (
-$mods
-$vars
+$vars libcFunc
 )
 
 $text
diff --git a/src/syscall/pwd_plan9.go b/src/syscall/pwd_plan9.go
index f8cafad..1248613 100644
--- a/src/syscall/pwd_plan9.go
+++ b/src/syscall/pwd_plan9.go
@@ -29,10 +29,8 @@
 	if !wdSet {
 		return
 	}
-	wd, err := getwd()
-	if err != nil {
-		return
-	}
+	// always call chdir when getwd returns an error
+	wd, _ := getwd()
 	if wd == wdStr {
 		return
 	}
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
index b22ecf5..1625b07 100644
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -41,21 +41,20 @@
 	if e != nil {
 		return "", e
 	}
-	b := make([]uint16, 50)
-	n := uint32(len(b))
-	e = TranslateName(u, from, to, &b[0], &n)
-	if e != nil {
+	n := uint32(50)
+	for {
+		b := make([]uint16, n)
+		e = TranslateName(u, from, to, &b[0], &n)
+		if e == nil {
+			return UTF16ToString(b[:n]), nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]uint16, n)
-		e = TranslateName(u, from, to, &b[0], &n)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return "", e
 		}
 	}
-	return UTF16ToString(b), nil
 }
 
 const (
@@ -136,26 +135,23 @@
 			return nil, "", 0, e
 		}
 	}
-	db := make([]uint16, 50)
-	dn := uint32(len(db))
-	b := make([]byte, 50)
-	n := uint32(len(b))
-	sid = (*SID)(unsafe.Pointer(&b[0]))
-	e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-	if e != nil {
+	n := uint32(50)
+	dn := uint32(50)
+	for {
+		b := make([]byte, n)
+		db := make([]uint16, dn)
+		sid = (*SID)(unsafe.Pointer(&b[0]))
+		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+		if e == nil {
+			return sid, UTF16ToString(db), accType, nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return nil, "", 0, e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]byte, n)
-		sid = (*SID)(unsafe.Pointer(&b[0]))
-		db = make([]uint16, dn)
-		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return nil, "", 0, e
 		}
 	}
-	return sid, UTF16ToString(db), accType, nil
 }
 
 // String converts sid to a string format
@@ -197,24 +193,22 @@
 			return "", "", 0, err
 		}
 	}
-	b := make([]uint16, 50)
-	n := uint32(len(b))
-	db := make([]uint16, 50)
-	dn := uint32(len(db))
-	e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
-	if e != nil {
+	n := uint32(50)
+	dn := uint32(50)
+	for {
+		b := make([]uint16, n)
+		db := make([]uint16, dn)
+		e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+		if e == nil {
+			return UTF16ToString(b), UTF16ToString(db), accType, nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", "", 0, e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]uint16, n)
-		db = make([]uint16, dn)
-		e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return "", "", 0, e
 		}
 	}
-	return UTF16ToString(b), UTF16ToString(db), accType, nil
 }
 
 const (
@@ -326,21 +320,20 @@
 
 // getInfo retrieves a specified type of information about an access token.
 func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
-	b := make([]byte, initSize)
-	var n uint32
-	e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-	if e != nil {
+	n := uint32(initSize)
+	for {
+		b := make([]byte, n)
+		e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+		if e == nil {
+			return unsafe.Pointer(&b[0]), nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return nil, e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]byte, n)
-		e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return nil, e
 		}
 	}
-	return unsafe.Pointer(&b[0]), nil
 }
 
 // GetTokenUser retrieves access token t user account information.
@@ -366,19 +359,18 @@
 // GetUserProfileDirectory retrieves path to the
 // root directory of the access token t user's profile.
 func (t Token) GetUserProfileDirectory() (string, error) {
-	b := make([]uint16, 100)
-	n := uint32(len(b))
-	e := GetUserProfileDirectory(t, &b[0], &n)
-	if e != nil {
+	n := uint32(100)
+	for {
+		b := make([]uint16, n)
+		e := GetUserProfileDirectory(t, &b[0], &n)
+		if e == nil {
+			return UTF16ToString(b), nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]uint16, n)
-		e = GetUserProfileDirectory(t, &b[0], &n)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return "", e
 		}
 	}
-	return UTF16ToString(b), nil
 }
diff --git a/src/syscall/so_solaris.go b/src/syscall/so_solaris.go
deleted file mode 100644
index 8b1980f..0000000
--- a/src/syscall/so_solaris.go
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright 2011 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
-
-import (
-	"sync"
-	"sync/atomic"
-	"unsafe"
-)
-
-// soError describes reasons for shared library load failures.
-type soError struct {
-	Err     error
-	ObjName string
-	Msg     string
-}
-
-func (e *soError) Error() string { return e.Msg }
-
-// Implemented in asm_solaris_amd64.s.
-func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
-func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
-func dlclose(handle uintptr) (err Errno)
-func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno)
-func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno)
-
-// A so implements access to a single shared library object.
-type so struct {
-	Name   string
-	Handle uintptr
-}
-
-// loadSO loads shared library file into memory.
-func loadSO(name string) (*so, error) {
-	namep, err := BytePtrFromString(name)
-	if err != nil {
-		return nil, err
-	}
-	h, e := dlopen(namep, 1) // RTLD_LAZY
-	use(unsafe.Pointer(namep))
-	if e != 0 {
-		return nil, &soError{
-			Err:     e,
-			ObjName: name,
-			Msg:     "Failed to load " + name + ": " + e.Error(),
-		}
-	}
-	d := &so{
-		Name:   name,
-		Handle: uintptr(h),
-	}
-	return d, nil
-}
-
-// mustLoadSO is like loadSO but panics if load operation fails.
-func mustLoadSO(name string) *so {
-	d, e := loadSO(name)
-	if e != nil {
-		panic(e)
-	}
-	return d
-}
-
-// FindProc searches shared library d for procedure named name and returns
-// *proc if found. It returns an error if the search fails.
-func (d *so) FindProc(name string) (*proc, error) {
-	namep, err := BytePtrFromString(name)
-	if err != nil {
-		return nil, err
-	}
-	a, _ := dlsym(uintptr(d.Handle), namep)
-	use(unsafe.Pointer(namep))
-	if a == 0 {
-		return nil, &soError{
-			Err:     ENOSYS,
-			ObjName: name,
-			Msg:     "Failed to find " + name + " procedure in " + d.Name,
-		}
-	}
-	p := &proc{
-		SO:   d,
-		Name: name,
-		addr: a,
-	}
-	return p, nil
-}
-
-// MustFindProc is like FindProc but panics if search fails.
-func (d *so) MustFindProc(name string) *proc {
-	p, e := d.FindProc(name)
-	if e != nil {
-		panic(e)
-	}
-	return p
-}
-
-// Release unloads shared library d from memory.
-func (d *so) Release() (err error) {
-	return dlclose(d.Handle)
-}
-
-// A proc implements access to a procedure inside a shared library.
-type proc struct {
-	SO   *so
-	Name string
-	addr uintptr
-}
-
-// Addr returns the address of the procedure represented by p.
-// The return value can be passed to Syscall to run the procedure.
-func (p *proc) Addr() uintptr {
-	return p.addr
-}
-
-// Call executes procedure p with arguments a. It will panic, if more then
-// 6 arguments are supplied.
-//
-// The returned error is always non-nil, constructed from the result of
-// GetLastError.  Callers must inspect the primary return value to decide
-// whether an error occurred (according to the semantics of the specific
-// function being called) before consulting the error. The error will be
-// guaranteed to contain syscall.Errno.
-func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
-	switch len(a) {
-	case 0:
-		return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
-	case 1:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
-	case 2:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
-	case 3:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
-	case 4:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
-	case 5:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
-	case 6:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
-	default:
-		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
-	}
-	return
-}
-
-// A lazySO implements access to a single shared library.  It will delay
-// the load of the shared library until the first call to its Handle method
-// or to one of its lazyProc's Addr method.
-type lazySO struct {
-	mu   sync.Mutex
-	so   *so // non nil once SO is loaded
-	Name string
-}
-
-// Load loads single shared file d.Name into memory. It returns an error if
-// fails.  Load will not try to load SO, if it is already loaded into memory.
-func (d *lazySO) Load() error {
-	// Non-racy version of:
-	// if d.so == nil {
-	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
-		d.mu.Lock()
-		defer d.mu.Unlock()
-		if d.so == nil {
-			so, e := loadSO(d.Name)
-			if e != nil {
-				return e
-			}
-			// Non-racy version of:
-			// d.so = so
-			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
-		}
-	}
-	return nil
-}
-
-// mustLoad is like Load but panics if search fails.
-func (d *lazySO) mustLoad() {
-	e := d.Load()
-	if e != nil {
-		panic(e)
-	}
-}
-
-// Handle returns d's module handle.
-func (d *lazySO) Handle() uintptr {
-	d.mustLoad()
-	return uintptr(d.so.Handle)
-}
-
-// NewProc returns a lazyProc for accessing the named procedure in the SO d.
-func (d *lazySO) NewProc(name string) *lazyProc {
-	return &lazyProc{l: d, Name: name}
-}
-
-// newLazySO creates new lazySO associated with SO file.
-func newLazySO(name string) *lazySO {
-	return &lazySO{Name: name}
-}
-
-// A lazyProc implements access to a procedure inside a lazySO.
-// It delays the lookup until the Addr method is called.
-type lazyProc struct {
-	mu   sync.Mutex
-	Name string
-	l    *lazySO
-	proc *proc
-}
-
-// Find searches the shared library for procedure named p.Name. It returns an
-// error if search fails. Find will not search procedure, if it is already
-// found and loaded into memory.
-func (p *lazyProc) Find() error {
-	// Non-racy version of:
-	// if p.proc == nil {
-	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
-		p.mu.Lock()
-		defer p.mu.Unlock()
-		if p.proc == nil {
-			e := p.l.Load()
-			if e != nil {
-				return e
-			}
-			proc, e := p.l.so.FindProc(p.Name)
-			if e != nil {
-				return e
-			}
-			// Non-racy version of:
-			// p.proc = proc
-			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
-		}
-	}
-	return nil
-}
-
-// mustFind is like Find but panics if search fails.
-func (p *lazyProc) mustFind() {
-	e := p.Find()
-	if e != nil {
-		panic(e)
-	}
-}
-
-// Addr returns the address of the procedure represented by p.
-// The return value can be passed to Syscall to run the procedure.
-func (p *lazyProc) Addr() uintptr {
-	p.mustFind()
-	return p.proc.Addr()
-}
-
-// Call executes procedure p with arguments a. It will panic, if more then
-// 6 arguments are supplied.
-//
-// The returned error is always non-nil, constructed from the result of
-// GetLastError.  Callers must inspect the primary return value to decide
-// whether an error occurred (according to the semantics of the specific
-// function being called) before consulting the error. The error will be
-// guaranteed to contain syscall.Errno.
-func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
-	p.mustFind()
-	return p.proc.Call(a...)
-}
diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
new file mode 100644
index 0000000..de7a08b
--- /dev/null
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -0,0 +1,70 @@
+// 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
+
+import "unsafe"
+
+func Getpagesize() int { return 16384 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = nsec / 1e9
+	ts.Nsec = nsec % 1e9
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
+
+//sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
+func Gettimeofday(tv *Timeval) (err error) {
+	// The tv passed to gettimeofday must be non-nil
+	// but is otherwise unused.  The answers come back
+	// in the two registers.
+	sec, usec, err := gettimeofday(tv)
+	tv.Sec = sec
+	tv.Usec = usec
+	return err
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+	k.Ident = uint64(fd)
+	k.Filter = int16(mode)
+	k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+	msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+	cmsg.Len = uint32(length)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	var length = uint64(count)
+
+	_, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
+
+	written = int(length)
+
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index 4111c07..fad9c32 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -57,8 +57,6 @@
 //sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
 //sys	mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
 
-func Getpagesize() int { return 4096 }
-
 //go:noescape
 func gettimeofday(tv *Timeval) (err Errno)
 
@@ -70,6 +68,8 @@
 	return nil
 }
 
+func Getpagesize() int { return 4096 }
+
 func Time(t *Time_t) (tt Time_t, err error) {
 	var tv Timeval
 	errno := gettimeofday(&tv)
diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index f6a502b..7968708 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -140,12 +140,12 @@
 	return cstring(buf[:]), nil
 }
 
-//sys	pipe(p *[2]_C_int) (err error)
+//sys	pipe(p *[2]int32) (err error)
 func Pipe(p []int) (err error) {
 	if len(p) != 2 {
 		return NewError("bad arg in system call")
 	}
-	var pp [2]_C_int
+	var pp [2]int32
 	err = pipe(&pp)
 	p[0] = int(pp[0])
 	p[1] = int(pp[1])
diff --git a/src/syscall/syscall_solaris.go b/src/syscall/syscall_solaris.go
index adc52b1..0f60e21 100644
--- a/src/syscall/syscall_solaris.go
+++ b/src/syscall/syscall_solaris.go
@@ -14,6 +14,10 @@
 
 import "unsafe"
 
+// Implemented in asm_solaris_amd64.s.
+func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
 type SockaddrDatalink struct {
 	Family uint16
 	Index  uint16
@@ -283,7 +287,7 @@
 
 // FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
 func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
-	_, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
 	if e1 != 0 {
 		return e1
 	}
@@ -469,6 +473,7 @@
 //sys	Rename(from string, to string) (err error)
 //sys	Rmdir(path string) (err error)
 //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
 //sysnb	Setegid(egid int) (err error)
 //sysnb	Seteuid(euid int) (err error)
 //sysnb	Setgid(gid int) (err error)
@@ -505,7 +510,7 @@
 //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.recvmsg
 
 func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -514,7 +519,7 @@
 }
 
 func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
diff --git a/src/syscall/syscall_solaris_amd64.go b/src/syscall/syscall_solaris_amd64.go
index 37cf06d..67b8af1 100644
--- a/src/syscall/syscall_solaris_amd64.go
+++ b/src/syscall/syscall_solaris_amd64.go
@@ -30,8 +30,3 @@
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint32(length)
 }
-
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
-	// TODO(aram): implement this, see issue 5847.
-	panic("unimplemented")
-}
diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index ae8e8d9..01fc670 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -93,7 +93,8 @@
 		// TODO(aram): Figure out why ReadMsgUnix is returning empty message.
 		t.Skip("skipping test on solaris, see issue 7402")
 	case "darwin":
-		if runtime.GOARCH == "arm" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
 			t.Skipf("skipping test on %d/%s, no fork", runtime.GOOS, runtime.GOARCH)
 		}
 	}
diff --git a/src/syscall/types_plan9.c b/src/syscall/types_plan9.c
deleted file mode 100644
index cd9e15fa..0000000
--- a/src/syscall/types_plan9.c
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-Input to godefs.  See also mkerrors.sh and mkall.sh
-*/
-
-typedef unsigned short ushort;
-typedef unsigned char uchar;
-typedef unsigned long ulong;
-typedef unsigned int uint;
-typedef long long vlong;
-typedef unsigned long long uvlong;
-
-typedef int $_C_int;
-
-enum {
-	OREAD	= 0,	// open for read
-	OWRITE	= 1,	// write
-	ORDWR	= 2,	// read and write
-	OEXEC	= 3,	// execute, == read but check execute permission
-	OTRUNC	= 16,	// or'ed in (except for exec), truncate file first
-	OCEXEC	= 32,	// or'ed in, close on exec
-	ORCLOSE	= 64,		// or'ed in, remove on close
-	OEXCL	= 0x1000,	// or'ed in, exclusive use (create only)
-
-	$O_RDONLY	= OREAD,
-	$O_WRONLY	= OWRITE,
-	$O_RDWR		= ORDWR,
-	$O_TRUNC	= OTRUNC,
-	$O_CLOEXEC	= OCEXEC,
-	$O_EXCL		= OEXCL,
-
-	$STATMAX	= 65535U,
-	$ERRMAX		= 128,
-
-	$MORDER		= 0x0003,	// mask for bits defining order of mounting
-	$MREPL		= 0x0000,	// mount replaces object
-	$MBEFORE	= 0x0001,	// mount goes before others in union directory
-	$MAFTER		= 0x0002,	// mount goes after others in union directory
-	$MCREATE	= 0x0004,	// permit creation in mounted directory
-	$MCACHE		= 0x0010,	// cache some data
-	$MMASK		= 0x0017,	// all bits on
-
-	$RFNAMEG	= (1<<0),
-	$RFENVG		= (1<<1),
-	$RFFDG		= (1<<2),
-	$RFNOTEG	= (1<<3),
-	$RFPROC		= (1<<4),
-	$RFMEM		= (1<<5),
-	$RFNOWAIT	= (1<<6),
-	$RFCNAMEG	= (1<<10),
-	$RFCENVG	= (1<<11),
-	$RFCFDG		= (1<<12),
-	$RFREND		= (1<<13),
-	$RFNOMNT	= (1<<14),
-
-	// bits in Qid.type
-	$QTDIR		= 0x80,		// type bit for directories
-	$QTAPPEND	= 0x40,		// type bit for append only files
-	$QTEXCL		= 0x20,		// type bit for exclusive use files
-	$QTMOUNT	= 0x10,		// type bit for mounted channel
-	$QTAUTH		= 0x08,		// type bit for authentication file
-	$QTTMP		= 0x04,		// type bit for not-backed-up file
-	$QTFILE		= 0x00,		// plain file
-
-
-	// bits in Dir.mode
-	$DMDIR		= 0x80000000,	// mode bit for directories
-	$DMAPPEND	= 0x40000000,	// mode bit for append only files
-	$DMEXCL		= 0x20000000,	// mode bit for exclusive use files
-	$DMMOUNT	= 0x10000000,	// mode bit for mounted channel
-	$DMAUTH		= 0x08000000,	// mode bit for authentication file
-	$DMTMP		= 0x04000000,	// mode bit for non-backed-up files
-	$DMREAD		= 0x4,		// mode bit for read permission
-	$DMWRITE	= 0x2,		// mode bit for write permission
-	$DMEXEC		= 0x1,		// mode bit for execute permission
-
-	BIT8SZ	= 1,
-	BIT16SZ	= 2,
-	BIT32SZ	= 4,
-	BIT64SZ	= 8,
-	QIDSZ = BIT8SZ+BIT32SZ+BIT64SZ,
-
-	// STATFIXLEN includes leading 16-bit count
-	// The count, however, excludes itself; total size is BIT16SZ+count
-	$STATFIXLEN = BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ,	// amount of fixed length data in a stat buffer
-};
-
-
-struct Prof			// Per process profiling
-{
-	struct Plink	*pp;	// known to be 0(ptr)
-	struct Plink	*next;	// known to be 4(ptr)
-	struct Plink	*last;
-	struct Plink	*first;
-	ulong		pid;
-	ulong		what;
-};
-
-struct Tos {
-	struct Prof	prof;
-	uvlong		cyclefreq;	// cycle clock frequency if there is one, 0 otherwise
-	vlong		kcycles;	// cycles spent in kernel
-	vlong		pcycles;	// cycles spent in process (kernel + user)
-	ulong		pid;		// might as well put the pid here
-	ulong		clock;
-	// top of stack is here
-};
-
-typedef struct Prof $Prof;
-typedef struct Tos $Tos;
diff --git a/src/syscall/zerrors_darwin_arm64.go b/src/syscall/zerrors_darwin_arm64.go
new file mode 100644
index 0000000..a3841a2
--- /dev/null
+++ b/src/syscall/zerrors_darwin_arm64.go
@@ -0,0 +1,1434 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+	AF_APPLETALK                      = 0x10
+	AF_CCITT                          = 0xa
+	AF_CHAOS                          = 0x5
+	AF_CNT                            = 0x15
+	AF_COIP                           = 0x14
+	AF_DATAKIT                        = 0x9
+	AF_DECnet                         = 0xc
+	AF_DLI                            = 0xd
+	AF_E164                           = 0x1c
+	AF_ECMA                           = 0x8
+	AF_HYLINK                         = 0xf
+	AF_IEEE80211                      = 0x25
+	AF_IMPLINK                        = 0x3
+	AF_INET                           = 0x2
+	AF_INET6                          = 0x1e
+	AF_IPX                            = 0x17
+	AF_ISDN                           = 0x1c
+	AF_ISO                            = 0x7
+	AF_LAT                            = 0xe
+	AF_LINK                           = 0x12
+	AF_LOCAL                          = 0x1
+	AF_MAX                            = 0x28
+	AF_NATM                           = 0x1f
+	AF_NDRV                           = 0x1b
+	AF_NETBIOS                        = 0x21
+	AF_NS                             = 0x6
+	AF_OSI                            = 0x7
+	AF_PPP                            = 0x22
+	AF_PUP                            = 0x4
+	AF_RESERVED_36                    = 0x24
+	AF_ROUTE                          = 0x11
+	AF_SIP                            = 0x18
+	AF_SNA                            = 0xb
+	AF_SYSTEM                         = 0x20
+	AF_UNIX                           = 0x1
+	AF_UNSPEC                         = 0x0
+	AF_UTUN                           = 0x26
+	B0                                = 0x0
+	B110                              = 0x6e
+	B115200                           = 0x1c200
+	B1200                             = 0x4b0
+	B134                              = 0x86
+	B14400                            = 0x3840
+	B150                              = 0x96
+	B1800                             = 0x708
+	B19200                            = 0x4b00
+	B200                              = 0xc8
+	B230400                           = 0x38400
+	B2400                             = 0x960
+	B28800                            = 0x7080
+	B300                              = 0x12c
+	B38400                            = 0x9600
+	B4800                             = 0x12c0
+	B50                               = 0x32
+	B57600                            = 0xe100
+	B600                              = 0x258
+	B7200                             = 0x1c20
+	B75                               = 0x4b
+	B76800                            = 0x12c00
+	B9600                             = 0x2580
+	BIOCFLUSH                         = 0x20004268
+	BIOCGBLEN                         = 0x40044266
+	BIOCGDLT                          = 0x4004426a
+	BIOCGDLTLIST                      = 0xc00c4279
+	BIOCGETIF                         = 0x4020426b
+	BIOCGHDRCMPLT                     = 0x40044274
+	BIOCGRSIG                         = 0x40044272
+	BIOCGRTIMEOUT                     = 0x4010426e
+	BIOCGSEESENT                      = 0x40044276
+	BIOCGSTATS                        = 0x4008426f
+	BIOCIMMEDIATE                     = 0x80044270
+	BIOCPROMISC                       = 0x20004269
+	BIOCSBLEN                         = 0xc0044266
+	BIOCSDLT                          = 0x80044278
+	BIOCSETF                          = 0x80104267
+	BIOCSETIF                         = 0x8020426c
+	BIOCSHDRCMPLT                     = 0x80044275
+	BIOCSRSIG                         = 0x80044273
+	BIOCSRTIMEOUT                     = 0x8010426d
+	BIOCSSEESENT                      = 0x80044277
+	BIOCVERSION                       = 0x40044271
+	BPF_A                             = 0x10
+	BPF_ABS                           = 0x20
+	BPF_ADD                           = 0x0
+	BPF_ALIGNMENT                     = 0x4
+	BPF_ALU                           = 0x4
+	BPF_AND                           = 0x50
+	BPF_B                             = 0x10
+	BPF_DIV                           = 0x30
+	BPF_H                             = 0x8
+	BPF_IMM                           = 0x0
+	BPF_IND                           = 0x40
+	BPF_JA                            = 0x0
+	BPF_JEQ                           = 0x10
+	BPF_JGE                           = 0x30
+	BPF_JGT                           = 0x20
+	BPF_JMP                           = 0x5
+	BPF_JSET                          = 0x40
+	BPF_K                             = 0x0
+	BPF_LD                            = 0x0
+	BPF_LDX                           = 0x1
+	BPF_LEN                           = 0x80
+	BPF_LSH                           = 0x60
+	BPF_MAJOR_VERSION                 = 0x1
+	BPF_MAXBUFSIZE                    = 0x80000
+	BPF_MAXINSNS                      = 0x200
+	BPF_MEM                           = 0x60
+	BPF_MEMWORDS                      = 0x10
+	BPF_MINBUFSIZE                    = 0x20
+	BPF_MINOR_VERSION                 = 0x1
+	BPF_MISC                          = 0x7
+	BPF_MSH                           = 0xa0
+	BPF_MUL                           = 0x20
+	BPF_NEG                           = 0x80
+	BPF_OR                            = 0x40
+	BPF_RELEASE                       = 0x30bb6
+	BPF_RET                           = 0x6
+	BPF_RSH                           = 0x70
+	BPF_ST                            = 0x2
+	BPF_STX                           = 0x3
+	BPF_SUB                           = 0x10
+	BPF_TAX                           = 0x0
+	BPF_TXA                           = 0x80
+	BPF_W                             = 0x0
+	BPF_X                             = 0x8
+	BRKINT                            = 0x2
+	CFLUSH                            = 0xf
+	CLOCAL                            = 0x8000
+	CREAD                             = 0x800
+	CS5                               = 0x0
+	CS6                               = 0x100
+	CS7                               = 0x200
+	CS8                               = 0x300
+	CSIZE                             = 0x300
+	CSTART                            = 0x11
+	CSTATUS                           = 0x14
+	CSTOP                             = 0x13
+	CSTOPB                            = 0x400
+	CSUSP                             = 0x1a
+	CTL_MAXNAME                       = 0xc
+	CTL_NET                           = 0x4
+	DLT_APPLE_IP_OVER_IEEE1394        = 0x8a
+	DLT_ARCNET                        = 0x7
+	DLT_ATM_CLIP                      = 0x13
+	DLT_ATM_RFC1483                   = 0xb
+	DLT_AX25                          = 0x3
+	DLT_CHAOS                         = 0x5
+	DLT_CHDLC                         = 0x68
+	DLT_C_HDLC                        = 0x68
+	DLT_EN10MB                        = 0x1
+	DLT_EN3MB                         = 0x2
+	DLT_FDDI                          = 0xa
+	DLT_IEEE802                       = 0x6
+	DLT_IEEE802_11                    = 0x69
+	DLT_IEEE802_11_RADIO              = 0x7f
+	DLT_IEEE802_11_RADIO_AVS          = 0xa3
+	DLT_LINUX_SLL                     = 0x71
+	DLT_LOOP                          = 0x6c
+	DLT_NULL                          = 0x0
+	DLT_PFLOG                         = 0x75
+	DLT_PFSYNC                        = 0x12
+	DLT_PPP                           = 0x9
+	DLT_PPP_BSDOS                     = 0x10
+	DLT_PPP_SERIAL                    = 0x32
+	DLT_PRONET                        = 0x4
+	DLT_RAW                           = 0xc
+	DLT_SLIP                          = 0x8
+	DLT_SLIP_BSDOS                    = 0xf
+	DT_BLK                            = 0x6
+	DT_CHR                            = 0x2
+	DT_DIR                            = 0x4
+	DT_FIFO                           = 0x1
+	DT_LNK                            = 0xa
+	DT_REG                            = 0x8
+	DT_SOCK                           = 0xc
+	DT_UNKNOWN                        = 0x0
+	DT_WHT                            = 0xe
+	ECHO                              = 0x8
+	ECHOCTL                           = 0x40
+	ECHOE                             = 0x2
+	ECHOK                             = 0x4
+	ECHOKE                            = 0x1
+	ECHONL                            = 0x10
+	ECHOPRT                           = 0x20
+	EVFILT_AIO                        = -0x3
+	EVFILT_FS                         = -0x9
+	EVFILT_MACHPORT                   = -0x8
+	EVFILT_PROC                       = -0x5
+	EVFILT_READ                       = -0x1
+	EVFILT_SIGNAL                     = -0x6
+	EVFILT_SYSCOUNT                   = 0xe
+	EVFILT_THREADMARKER               = 0xe
+	EVFILT_TIMER                      = -0x7
+	EVFILT_USER                       = -0xa
+	EVFILT_VM                         = -0xc
+	EVFILT_VNODE                      = -0x4
+	EVFILT_WRITE                      = -0x2
+	EV_ADD                            = 0x1
+	EV_CLEAR                          = 0x20
+	EV_DELETE                         = 0x2
+	EV_DISABLE                        = 0x8
+	EV_DISPATCH                       = 0x80
+	EV_ENABLE                         = 0x4
+	EV_EOF                            = 0x8000
+	EV_ERROR                          = 0x4000
+	EV_FLAG0                          = 0x1000
+	EV_FLAG1                          = 0x2000
+	EV_ONESHOT                        = 0x10
+	EV_OOBAND                         = 0x2000
+	EV_POLL                           = 0x1000
+	EV_RECEIPT                        = 0x40
+	EV_SYSFLAGS                       = 0xf000
+	EXTA                              = 0x4b00
+	EXTB                              = 0x9600
+	EXTPROC                           = 0x800
+	FD_CLOEXEC                        = 0x1
+	FD_SETSIZE                        = 0x400
+	FLUSHO                            = 0x800000
+	F_ADDFILESIGS                     = 0x3d
+	F_ADDSIGS                         = 0x3b
+	F_ALLOCATEALL                     = 0x4
+	F_ALLOCATECONTIG                  = 0x2
+	F_CHKCLEAN                        = 0x29
+	F_DUPFD                           = 0x0
+	F_DUPFD_CLOEXEC                   = 0x43
+	F_FINDSIGS                        = 0x4e
+	F_FLUSH_DATA                      = 0x28
+	F_FREEZE_FS                       = 0x35
+	F_FULLFSYNC                       = 0x33
+	F_GETCODEDIR                      = 0x48
+	F_GETFD                           = 0x1
+	F_GETFL                           = 0x3
+	F_GETLK                           = 0x7
+	F_GETLKPID                        = 0x42
+	F_GETNOSIGPIPE                    = 0x4a
+	F_GETOWN                          = 0x5
+	F_GETPATH                         = 0x32
+	F_GETPATH_MTMINFO                 = 0x47
+	F_GETPROTECTIONCLASS              = 0x3f
+	F_GETPROTECTIONLEVEL              = 0x4d
+	F_GLOBAL_NOCACHE                  = 0x37
+	F_LOG2PHYS                        = 0x31
+	F_LOG2PHYS_EXT                    = 0x41
+	F_NOCACHE                         = 0x30
+	F_NODIRECT                        = 0x3e
+	F_OK                              = 0x0
+	F_PATHPKG_CHECK                   = 0x34
+	F_PEOFPOSMODE                     = 0x3
+	F_PREALLOCATE                     = 0x2a
+	F_RDADVISE                        = 0x2c
+	F_RDAHEAD                         = 0x2d
+	F_RDLCK                           = 0x1
+	F_SETBACKINGSTORE                 = 0x46
+	F_SETFD                           = 0x2
+	F_SETFL                           = 0x4
+	F_SETLK                           = 0x8
+	F_SETLKW                          = 0x9
+	F_SETLKWTIMEOUT                   = 0xa
+	F_SETNOSIGPIPE                    = 0x49
+	F_SETOWN                          = 0x6
+	F_SETPROTECTIONCLASS              = 0x40
+	F_SETSIZE                         = 0x2b
+	F_SINGLE_WRITER                   = 0x4c
+	F_THAW_FS                         = 0x36
+	F_TRANSCODEKEY                    = 0x4b
+	F_UNLCK                           = 0x2
+	F_VOLPOSMODE                      = 0x4
+	F_WRLCK                           = 0x3
+	HUPCL                             = 0x4000
+	ICANON                            = 0x100
+	ICMP6_FILTER                      = 0x12
+	ICRNL                             = 0x100
+	IEXTEN                            = 0x400
+	IFF_ALLMULTI                      = 0x200
+	IFF_ALTPHYS                       = 0x4000
+	IFF_BROADCAST                     = 0x2
+	IFF_DEBUG                         = 0x4
+	IFF_LINK0                         = 0x1000
+	IFF_LINK1                         = 0x2000
+	IFF_LINK2                         = 0x4000
+	IFF_LOOPBACK                      = 0x8
+	IFF_MULTICAST                     = 0x8000
+	IFF_NOARP                         = 0x80
+	IFF_NOTRAILERS                    = 0x20
+	IFF_OACTIVE                       = 0x400
+	IFF_POINTOPOINT                   = 0x10
+	IFF_PROMISC                       = 0x100
+	IFF_RUNNING                       = 0x40
+	IFF_SIMPLEX                       = 0x800
+	IFF_UP                            = 0x1
+	IFNAMSIZ                          = 0x10
+	IFT_1822                          = 0x2
+	IFT_AAL5                          = 0x31
+	IFT_ARCNET                        = 0x23
+	IFT_ARCNETPLUS                    = 0x24
+	IFT_ATM                           = 0x25
+	IFT_BRIDGE                        = 0xd1
+	IFT_CARP                          = 0xf8
+	IFT_CELLULAR                      = 0xff
+	IFT_CEPT                          = 0x13
+	IFT_DS3                           = 0x1e
+	IFT_ENC                           = 0xf4
+	IFT_EON                           = 0x19
+	IFT_ETHER                         = 0x6
+	IFT_FAITH                         = 0x38
+	IFT_FDDI                          = 0xf
+	IFT_FRELAY                        = 0x20
+	IFT_FRELAYDCE                     = 0x2c
+	IFT_GIF                           = 0x37
+	IFT_HDH1822                       = 0x3
+	IFT_HIPPI                         = 0x2f
+	IFT_HSSI                          = 0x2e
+	IFT_HY                            = 0xe
+	IFT_IEEE1394                      = 0x90
+	IFT_IEEE8023ADLAG                 = 0x88
+	IFT_ISDNBASIC                     = 0x14
+	IFT_ISDNPRIMARY                   = 0x15
+	IFT_ISO88022LLC                   = 0x29
+	IFT_ISO88023                      = 0x7
+	IFT_ISO88024                      = 0x8
+	IFT_ISO88025                      = 0x9
+	IFT_ISO88026                      = 0xa
+	IFT_L2VLAN                        = 0x87
+	IFT_LAPB                          = 0x10
+	IFT_LOCALTALK                     = 0x2a
+	IFT_LOOP                          = 0x18
+	IFT_MIOX25                        = 0x26
+	IFT_MODEM                         = 0x30
+	IFT_NSIP                          = 0x1b
+	IFT_OTHER                         = 0x1
+	IFT_P10                           = 0xc
+	IFT_P80                           = 0xd
+	IFT_PARA                          = 0x22
+	IFT_PDP                           = 0xff
+	IFT_PFLOG                         = 0xf5
+	IFT_PFSYNC                        = 0xf6
+	IFT_PPP                           = 0x17
+	IFT_PROPMUX                       = 0x36
+	IFT_PROPVIRTUAL                   = 0x35
+	IFT_PTPSERIAL                     = 0x16
+	IFT_RS232                         = 0x21
+	IFT_SDLC                          = 0x11
+	IFT_SIP                           = 0x1f
+	IFT_SLIP                          = 0x1c
+	IFT_SMDSDXI                       = 0x2b
+	IFT_SMDSICIP                      = 0x34
+	IFT_SONET                         = 0x27
+	IFT_SONETPATH                     = 0x32
+	IFT_SONETVT                       = 0x33
+	IFT_STARLAN                       = 0xb
+	IFT_STF                           = 0x39
+	IFT_T1                            = 0x12
+	IFT_ULTRA                         = 0x1d
+	IFT_V35                           = 0x2d
+	IFT_X25                           = 0x5
+	IFT_X25DDN                        = 0x4
+	IFT_X25PLE                        = 0x28
+	IFT_XETHER                        = 0x1a
+	IGNBRK                            = 0x1
+	IGNCR                             = 0x80
+	IGNPAR                            = 0x4
+	IMAXBEL                           = 0x2000
+	INLCR                             = 0x40
+	INPCK                             = 0x10
+	IN_CLASSA_HOST                    = 0xffffff
+	IN_CLASSA_MAX                     = 0x80
+	IN_CLASSA_NET                     = 0xff000000
+	IN_CLASSA_NSHIFT                  = 0x18
+	IN_CLASSB_HOST                    = 0xffff
+	IN_CLASSB_MAX                     = 0x10000
+	IN_CLASSB_NET                     = 0xffff0000
+	IN_CLASSB_NSHIFT                  = 0x10
+	IN_CLASSC_HOST                    = 0xff
+	IN_CLASSC_NET                     = 0xffffff00
+	IN_CLASSC_NSHIFT                  = 0x8
+	IN_CLASSD_HOST                    = 0xfffffff
+	IN_CLASSD_NET                     = 0xf0000000
+	IN_CLASSD_NSHIFT                  = 0x1c
+	IN_LINKLOCALNETNUM                = 0xa9fe0000
+	IN_LOOPBACKNET                    = 0x7f
+	IPPROTO_3PC                       = 0x22
+	IPPROTO_ADFS                      = 0x44
+	IPPROTO_AH                        = 0x33
+	IPPROTO_AHIP                      = 0x3d
+	IPPROTO_APES                      = 0x63
+	IPPROTO_ARGUS                     = 0xd
+	IPPROTO_AX25                      = 0x5d
+	IPPROTO_BHA                       = 0x31
+	IPPROTO_BLT                       = 0x1e
+	IPPROTO_BRSATMON                  = 0x4c
+	IPPROTO_CFTP                      = 0x3e
+	IPPROTO_CHAOS                     = 0x10
+	IPPROTO_CMTP                      = 0x26
+	IPPROTO_CPHB                      = 0x49
+	IPPROTO_CPNX                      = 0x48
+	IPPROTO_DDP                       = 0x25
+	IPPROTO_DGP                       = 0x56
+	IPPROTO_DIVERT                    = 0xfe
+	IPPROTO_DONE                      = 0x101
+	IPPROTO_DSTOPTS                   = 0x3c
+	IPPROTO_EGP                       = 0x8
+	IPPROTO_EMCON                     = 0xe
+	IPPROTO_ENCAP                     = 0x62
+	IPPROTO_EON                       = 0x50
+	IPPROTO_ESP                       = 0x32
+	IPPROTO_ETHERIP                   = 0x61
+	IPPROTO_FRAGMENT                  = 0x2c
+	IPPROTO_GGP                       = 0x3
+	IPPROTO_GMTP                      = 0x64
+	IPPROTO_GRE                       = 0x2f
+	IPPROTO_HELLO                     = 0x3f
+	IPPROTO_HMP                       = 0x14
+	IPPROTO_HOPOPTS                   = 0x0
+	IPPROTO_ICMP                      = 0x1
+	IPPROTO_ICMPV6                    = 0x3a
+	IPPROTO_IDP                       = 0x16
+	IPPROTO_IDPR                      = 0x23
+	IPPROTO_IDRP                      = 0x2d
+	IPPROTO_IGMP                      = 0x2
+	IPPROTO_IGP                       = 0x55
+	IPPROTO_IGRP                      = 0x58
+	IPPROTO_IL                        = 0x28
+	IPPROTO_INLSP                     = 0x34
+	IPPROTO_INP                       = 0x20
+	IPPROTO_IP                        = 0x0
+	IPPROTO_IPCOMP                    = 0x6c
+	IPPROTO_IPCV                      = 0x47
+	IPPROTO_IPEIP                     = 0x5e
+	IPPROTO_IPIP                      = 0x4
+	IPPROTO_IPPC                      = 0x43
+	IPPROTO_IPV4                      = 0x4
+	IPPROTO_IPV6                      = 0x29
+	IPPROTO_IRTP                      = 0x1c
+	IPPROTO_KRYPTOLAN                 = 0x41
+	IPPROTO_LARP                      = 0x5b
+	IPPROTO_LEAF1                     = 0x19
+	IPPROTO_LEAF2                     = 0x1a
+	IPPROTO_MAX                       = 0x100
+	IPPROTO_MAXID                     = 0x34
+	IPPROTO_MEAS                      = 0x13
+	IPPROTO_MHRP                      = 0x30
+	IPPROTO_MICP                      = 0x5f
+	IPPROTO_MTP                       = 0x5c
+	IPPROTO_MUX                       = 0x12
+	IPPROTO_ND                        = 0x4d
+	IPPROTO_NHRP                      = 0x36
+	IPPROTO_NONE                      = 0x3b
+	IPPROTO_NSP                       = 0x1f
+	IPPROTO_NVPII                     = 0xb
+	IPPROTO_OSPFIGP                   = 0x59
+	IPPROTO_PGM                       = 0x71
+	IPPROTO_PIGP                      = 0x9
+	IPPROTO_PIM                       = 0x67
+	IPPROTO_PRM                       = 0x15
+	IPPROTO_PUP                       = 0xc
+	IPPROTO_PVP                       = 0x4b
+	IPPROTO_RAW                       = 0xff
+	IPPROTO_RCCMON                    = 0xa
+	IPPROTO_RDP                       = 0x1b
+	IPPROTO_ROUTING                   = 0x2b
+	IPPROTO_RSVP                      = 0x2e
+	IPPROTO_RVD                       = 0x42
+	IPPROTO_SATEXPAK                  = 0x40
+	IPPROTO_SATMON                    = 0x45
+	IPPROTO_SCCSP                     = 0x60
+	IPPROTO_SCTP                      = 0x84
+	IPPROTO_SDRP                      = 0x2a
+	IPPROTO_SEP                       = 0x21
+	IPPROTO_SRPC                      = 0x5a
+	IPPROTO_ST                        = 0x7
+	IPPROTO_SVMTP                     = 0x52
+	IPPROTO_SWIPE                     = 0x35
+	IPPROTO_TCF                       = 0x57
+	IPPROTO_TCP                       = 0x6
+	IPPROTO_TP                        = 0x1d
+	IPPROTO_TPXX                      = 0x27
+	IPPROTO_TRUNK1                    = 0x17
+	IPPROTO_TRUNK2                    = 0x18
+	IPPROTO_TTP                       = 0x54
+	IPPROTO_UDP                       = 0x11
+	IPPROTO_VINES                     = 0x53
+	IPPROTO_VISA                      = 0x46
+	IPPROTO_VMTP                      = 0x51
+	IPPROTO_WBEXPAK                   = 0x4f
+	IPPROTO_WBMON                     = 0x4e
+	IPPROTO_WSN                       = 0x4a
+	IPPROTO_XNET                      = 0xf
+	IPPROTO_XTP                       = 0x24
+	IPV6_2292DSTOPTS                  = 0x17
+	IPV6_2292HOPLIMIT                 = 0x14
+	IPV6_2292HOPOPTS                  = 0x16
+	IPV6_2292NEXTHOP                  = 0x15
+	IPV6_2292PKTINFO                  = 0x13
+	IPV6_2292PKTOPTIONS               = 0x19
+	IPV6_2292RTHDR                    = 0x18
+	IPV6_BINDV6ONLY                   = 0x1b
+	IPV6_BOUND_IF                     = 0x7d
+	IPV6_CHECKSUM                     = 0x1a
+	IPV6_DEFAULT_MULTICAST_HOPS       = 0x1
+	IPV6_DEFAULT_MULTICAST_LOOP       = 0x1
+	IPV6_DEFHLIM                      = 0x40
+	IPV6_FAITH                        = 0x1d
+	IPV6_FLOWINFO_MASK                = 0xffffff0f
+	IPV6_FLOWLABEL_MASK               = 0xffff0f00
+	IPV6_FRAGTTL                      = 0x78
+	IPV6_FW_ADD                       = 0x1e
+	IPV6_FW_DEL                       = 0x1f
+	IPV6_FW_FLUSH                     = 0x20
+	IPV6_FW_GET                       = 0x22
+	IPV6_FW_ZERO                      = 0x21
+	IPV6_HLIMDEC                      = 0x1
+	IPV6_IPSEC_POLICY                 = 0x1c
+	IPV6_JOIN_GROUP                   = 0xc
+	IPV6_LEAVE_GROUP                  = 0xd
+	IPV6_MAXHLIM                      = 0xff
+	IPV6_MAXOPTHDR                    = 0x800
+	IPV6_MAXPACKET                    = 0xffff
+	IPV6_MAX_GROUP_SRC_FILTER         = 0x200
+	IPV6_MAX_MEMBERSHIPS              = 0xfff
+	IPV6_MAX_SOCK_SRC_FILTER          = 0x80
+	IPV6_MIN_MEMBERSHIPS              = 0x1f
+	IPV6_MMTU                         = 0x500
+	IPV6_MULTICAST_HOPS               = 0xa
+	IPV6_MULTICAST_IF                 = 0x9
+	IPV6_MULTICAST_LOOP               = 0xb
+	IPV6_PORTRANGE                    = 0xe
+	IPV6_PORTRANGE_DEFAULT            = 0x0
+	IPV6_PORTRANGE_HIGH               = 0x1
+	IPV6_PORTRANGE_LOW                = 0x2
+	IPV6_RECVTCLASS                   = 0x23
+	IPV6_RTHDR_LOOSE                  = 0x0
+	IPV6_RTHDR_STRICT                 = 0x1
+	IPV6_RTHDR_TYPE_0                 = 0x0
+	IPV6_SOCKOPT_RESERVED1            = 0x3
+	IPV6_TCLASS                       = 0x24
+	IPV6_UNICAST_HOPS                 = 0x4
+	IPV6_V6ONLY                       = 0x1b
+	IPV6_VERSION                      = 0x60
+	IPV6_VERSION_MASK                 = 0xf0
+	IP_ADD_MEMBERSHIP                 = 0xc
+	IP_ADD_SOURCE_MEMBERSHIP          = 0x46
+	IP_BLOCK_SOURCE                   = 0x48
+	IP_BOUND_IF                       = 0x19
+	IP_DEFAULT_MULTICAST_LOOP         = 0x1
+	IP_DEFAULT_MULTICAST_TTL          = 0x1
+	IP_DF                             = 0x4000
+	IP_DROP_MEMBERSHIP                = 0xd
+	IP_DROP_SOURCE_MEMBERSHIP         = 0x47
+	IP_DUMMYNET_CONFIGURE             = 0x3c
+	IP_DUMMYNET_DEL                   = 0x3d
+	IP_DUMMYNET_FLUSH                 = 0x3e
+	IP_DUMMYNET_GET                   = 0x40
+	IP_FAITH                          = 0x16
+	IP_FW_ADD                         = 0x28
+	IP_FW_DEL                         = 0x29
+	IP_FW_FLUSH                       = 0x2a
+	IP_FW_GET                         = 0x2c
+	IP_FW_RESETLOG                    = 0x2d
+	IP_FW_ZERO                        = 0x2b
+	IP_HDRINCL                        = 0x2
+	IP_IPSEC_POLICY                   = 0x15
+	IP_MAXPACKET                      = 0xffff
+	IP_MAX_GROUP_SRC_FILTER           = 0x200
+	IP_MAX_MEMBERSHIPS                = 0xfff
+	IP_MAX_SOCK_MUTE_FILTER           = 0x80
+	IP_MAX_SOCK_SRC_FILTER            = 0x80
+	IP_MF                             = 0x2000
+	IP_MIN_MEMBERSHIPS                = 0x1f
+	IP_MSFILTER                       = 0x4a
+	IP_MSS                            = 0x240
+	IP_MULTICAST_IF                   = 0x9
+	IP_MULTICAST_IFINDEX              = 0x42
+	IP_MULTICAST_LOOP                 = 0xb
+	IP_MULTICAST_TTL                  = 0xa
+	IP_MULTICAST_VIF                  = 0xe
+	IP_NAT__XXX                       = 0x37
+	IP_OFFMASK                        = 0x1fff
+	IP_OLD_FW_ADD                     = 0x32
+	IP_OLD_FW_DEL                     = 0x33
+	IP_OLD_FW_FLUSH                   = 0x34
+	IP_OLD_FW_GET                     = 0x36
+	IP_OLD_FW_RESETLOG                = 0x38
+	IP_OLD_FW_ZERO                    = 0x35
+	IP_OPTIONS                        = 0x1
+	IP_PKTINFO                        = 0x1a
+	IP_PORTRANGE                      = 0x13
+	IP_PORTRANGE_DEFAULT              = 0x0
+	IP_PORTRANGE_HIGH                 = 0x1
+	IP_PORTRANGE_LOW                  = 0x2
+	IP_RECVDSTADDR                    = 0x7
+	IP_RECVIF                         = 0x14
+	IP_RECVOPTS                       = 0x5
+	IP_RECVPKTINFO                    = 0x1a
+	IP_RECVRETOPTS                    = 0x6
+	IP_RECVTTL                        = 0x18
+	IP_RETOPTS                        = 0x8
+	IP_RF                             = 0x8000
+	IP_RSVP_OFF                       = 0x10
+	IP_RSVP_ON                        = 0xf
+	IP_RSVP_VIF_OFF                   = 0x12
+	IP_RSVP_VIF_ON                    = 0x11
+	IP_STRIPHDR                       = 0x17
+	IP_TOS                            = 0x3
+	IP_TRAFFIC_MGT_BACKGROUND         = 0x41
+	IP_TTL                            = 0x4
+	IP_UNBLOCK_SOURCE                 = 0x49
+	ISIG                              = 0x80
+	ISTRIP                            = 0x20
+	IUTF8                             = 0x4000
+	IXANY                             = 0x800
+	IXOFF                             = 0x400
+	IXON                              = 0x200
+	LOCK_EX                           = 0x2
+	LOCK_NB                           = 0x4
+	LOCK_SH                           = 0x1
+	LOCK_UN                           = 0x8
+	MADV_CAN_REUSE                    = 0x9
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x5
+	MADV_FREE_REUSABLE                = 0x7
+	MADV_FREE_REUSE                   = 0x8
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_WILLNEED                     = 0x3
+	MADV_ZERO_WIRED_PAGES             = 0x6
+	MAP_ANON                          = 0x1000
+	MAP_COPY                          = 0x2
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_JIT                           = 0x800
+	MAP_NOCACHE                       = 0x400
+	MAP_NOEXTEND                      = 0x100
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_RESERVED0080                  = 0x80
+	MAP_SHARED                        = 0x1
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
+	MSG_CTRUNC                        = 0x20
+	MSG_DONTROUTE                     = 0x4
+	MSG_DONTWAIT                      = 0x80
+	MSG_EOF                           = 0x100
+	MSG_EOR                           = 0x8
+	MSG_FLUSH                         = 0x400
+	MSG_HAVEMORE                      = 0x2000
+	MSG_HOLD                          = 0x800
+	MSG_NEEDSA                        = 0x10000
+	MSG_OOB                           = 0x1
+	MSG_PEEK                          = 0x2
+	MSG_RCVMORE                       = 0x4000
+	MSG_SEND                          = 0x1000
+	MSG_TRUNC                         = 0x10
+	MSG_WAITALL                       = 0x40
+	MSG_WAITSTREAM                    = 0x200
+	MS_ASYNC                          = 0x1
+	MS_DEACTIVATE                     = 0x8
+	MS_INVALIDATE                     = 0x2
+	MS_KILLPAGES                      = 0x4
+	MS_SYNC                           = 0x10
+	NAME_MAX                          = 0xff
+	NET_RT_DUMP                       = 0x1
+	NET_RT_DUMP2                      = 0x7
+	NET_RT_FLAGS                      = 0x2
+	NET_RT_IFLIST                     = 0x3
+	NET_RT_IFLIST2                    = 0x6
+	NET_RT_MAXID                      = 0xa
+	NET_RT_STAT                       = 0x4
+	NET_RT_TRASH                      = 0x5
+	NOFLSH                            = 0x80000000
+	NOTE_ABSOLUTE                     = 0x8
+	NOTE_ATTRIB                       = 0x8
+	NOTE_BACKGROUND                   = 0x40
+	NOTE_CHILD                        = 0x4
+	NOTE_CRITICAL                     = 0x20
+	NOTE_DELETE                       = 0x1
+	NOTE_EXEC                         = 0x20000000
+	NOTE_EXIT                         = 0x80000000
+	NOTE_EXITSTATUS                   = 0x4000000
+	NOTE_EXIT_CSERROR                 = 0x40000
+	NOTE_EXIT_DECRYPTFAIL             = 0x10000
+	NOTE_EXIT_DETAIL                  = 0x2000000
+	NOTE_EXIT_DETAIL_MASK             = 0x70000
+	NOTE_EXIT_MEMORY                  = 0x20000
+	NOTE_EXIT_REPARENTED              = 0x80000
+	NOTE_EXTEND                       = 0x4
+	NOTE_FFAND                        = 0x40000000
+	NOTE_FFCOPY                       = 0xc0000000
+	NOTE_FFCTRLMASK                   = 0xc0000000
+	NOTE_FFLAGSMASK                   = 0xffffff
+	NOTE_FFNOP                        = 0x0
+	NOTE_FFOR                         = 0x80000000
+	NOTE_FORK                         = 0x40000000
+	NOTE_LEEWAY                       = 0x10
+	NOTE_LINK                         = 0x10
+	NOTE_LOWAT                        = 0x1
+	NOTE_NONE                         = 0x80
+	NOTE_NSECONDS                     = 0x4
+	NOTE_PCTRLMASK                    = -0x100000
+	NOTE_PDATAMASK                    = 0xfffff
+	NOTE_REAP                         = 0x10000000
+	NOTE_RENAME                       = 0x20
+	NOTE_REVOKE                       = 0x40
+	NOTE_SECONDS                      = 0x1
+	NOTE_SIGNAL                       = 0x8000000
+	NOTE_TRACK                        = 0x1
+	NOTE_TRACKERR                     = 0x2
+	NOTE_TRIGGER                      = 0x1000000
+	NOTE_USECONDS                     = 0x2
+	NOTE_VM_ERROR                     = 0x10000000
+	NOTE_VM_PRESSURE                  = 0x80000000
+	NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000
+	NOTE_VM_PRESSURE_TERMINATE        = 0x40000000
+	NOTE_WRITE                        = 0x2
+	OCRNL                             = 0x10
+	OFDEL                             = 0x20000
+	OFILL                             = 0x80
+	ONLCR                             = 0x2
+	ONLRET                            = 0x40
+	ONOCR                             = 0x20
+	ONOEOT                            = 0x8
+	OPOST                             = 0x1
+	O_ACCMODE                         = 0x3
+	O_ALERT                           = 0x20000000
+	O_APPEND                          = 0x8
+	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x1000000
+	O_CREAT                           = 0x200
+	O_DIRECTORY                       = 0x100000
+	O_DP_GETRAWENCRYPTED              = 0x1
+	O_DSYNC                           = 0x400000
+	O_EVTONLY                         = 0x8000
+	O_EXCL                            = 0x800
+	O_EXLOCK                          = 0x20
+	O_FSYNC                           = 0x80
+	O_NDELAY                          = 0x4
+	O_NOCTTY                          = 0x20000
+	O_NOFOLLOW                        = 0x100
+	O_NONBLOCK                        = 0x4
+	O_POPUP                           = 0x80000000
+	O_RDONLY                          = 0x0
+	O_RDWR                            = 0x2
+	O_SHLOCK                          = 0x10
+	O_SYMLINK                         = 0x200000
+	O_SYNC                            = 0x80
+	O_TRUNC                           = 0x400
+	O_WRONLY                          = 0x1
+	PARENB                            = 0x1000
+	PARMRK                            = 0x8
+	PARODD                            = 0x2000
+	PENDIN                            = 0x20000000
+	PRIO_PGRP                         = 0x1
+	PRIO_PROCESS                      = 0x0
+	PRIO_USER                         = 0x2
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
+	PT_ATTACH                         = 0xa
+	PT_ATTACHEXC                      = 0xe
+	PT_CONTINUE                       = 0x7
+	PT_DENY_ATTACH                    = 0x1f
+	PT_DETACH                         = 0xb
+	PT_FIRSTMACH                      = 0x20
+	PT_FORCEQUOTA                     = 0x1e
+	PT_KILL                           = 0x8
+	PT_READ_D                         = 0x2
+	PT_READ_I                         = 0x1
+	PT_READ_U                         = 0x3
+	PT_SIGEXC                         = 0xc
+	PT_STEP                           = 0x9
+	PT_THUPDATE                       = 0xd
+	PT_TRACE_ME                       = 0x0
+	PT_WRITE_D                        = 0x5
+	PT_WRITE_I                        = 0x4
+	PT_WRITE_U                        = 0x6
+	RLIMIT_AS                         = 0x5
+	RLIMIT_CORE                       = 0x4
+	RLIMIT_CPU                        = 0x0
+	RLIMIT_CPU_USAGE_MONITOR          = 0x2
+	RLIMIT_DATA                       = 0x2
+	RLIMIT_FSIZE                      = 0x1
+	RLIMIT_NOFILE                     = 0x8
+	RLIMIT_STACK                      = 0x3
+	RLIM_INFINITY                     = 0x7fffffffffffffff
+	RTAX_AUTHOR                       = 0x6
+	RTAX_BRD                          = 0x7
+	RTAX_DST                          = 0x0
+	RTAX_GATEWAY                      = 0x1
+	RTAX_GENMASK                      = 0x3
+	RTAX_IFA                          = 0x5
+	RTAX_IFP                          = 0x4
+	RTAX_MAX                          = 0x8
+	RTAX_NETMASK                      = 0x2
+	RTA_AUTHOR                        = 0x40
+	RTA_BRD                           = 0x80
+	RTA_DST                           = 0x1
+	RTA_GATEWAY                       = 0x2
+	RTA_GENMASK                       = 0x8
+	RTA_IFA                           = 0x20
+	RTA_IFP                           = 0x10
+	RTA_NETMASK                       = 0x4
+	RTF_BLACKHOLE                     = 0x1000
+	RTF_BROADCAST                     = 0x400000
+	RTF_CLONING                       = 0x100
+	RTF_CONDEMNED                     = 0x2000000
+	RTF_DELCLONE                      = 0x80
+	RTF_DONE                          = 0x40
+	RTF_DYNAMIC                       = 0x10
+	RTF_GATEWAY                       = 0x2
+	RTF_HOST                          = 0x4
+	RTF_IFREF                         = 0x4000000
+	RTF_IFSCOPE                       = 0x1000000
+	RTF_LLINFO                        = 0x400
+	RTF_LOCAL                         = 0x200000
+	RTF_MODIFIED                      = 0x20
+	RTF_MULTICAST                     = 0x800000
+	RTF_PINNED                        = 0x100000
+	RTF_PRCLONING                     = 0x10000
+	RTF_PROTO1                        = 0x8000
+	RTF_PROTO2                        = 0x4000
+	RTF_PROTO3                        = 0x40000
+	RTF_PROXY                         = 0x8000000
+	RTF_REJECT                        = 0x8
+	RTF_ROUTER                        = 0x10000000
+	RTF_STATIC                        = 0x800
+	RTF_UP                            = 0x1
+	RTF_WASCLONED                     = 0x20000
+	RTF_XRESOLVE                      = 0x200
+	RTM_ADD                           = 0x1
+	RTM_CHANGE                        = 0x3
+	RTM_DELADDR                       = 0xd
+	RTM_DELETE                        = 0x2
+	RTM_DELMADDR                      = 0x10
+	RTM_GET                           = 0x4
+	RTM_GET2                          = 0x14
+	RTM_IFINFO                        = 0xe
+	RTM_IFINFO2                       = 0x12
+	RTM_LOCK                          = 0x8
+	RTM_LOSING                        = 0x5
+	RTM_MISS                          = 0x7
+	RTM_NEWADDR                       = 0xc
+	RTM_NEWMADDR                      = 0xf
+	RTM_NEWMADDR2                     = 0x13
+	RTM_OLDADD                        = 0x9
+	RTM_OLDDEL                        = 0xa
+	RTM_REDIRECT                      = 0x6
+	RTM_RESOLVE                       = 0xb
+	RTM_RTTUNIT                       = 0xf4240
+	RTM_VERSION                       = 0x5
+	RTV_EXPIRE                        = 0x4
+	RTV_HOPCOUNT                      = 0x2
+	RTV_MTU                           = 0x1
+	RTV_RPIPE                         = 0x8
+	RTV_RTT                           = 0x40
+	RTV_RTTVAR                        = 0x80
+	RTV_SPIPE                         = 0x10
+	RTV_SSTHRESH                      = 0x20
+	RUSAGE_CHILDREN                   = -0x1
+	RUSAGE_SELF                       = 0x0
+	SCM_CREDS                         = 0x3
+	SCM_RIGHTS                        = 0x1
+	SCM_TIMESTAMP                     = 0x2
+	SCM_TIMESTAMP_MONOTONIC           = 0x4
+	SHUT_RD                           = 0x0
+	SHUT_RDWR                         = 0x2
+	SHUT_WR                           = 0x1
+	SIOCADDMULTI                      = 0x80206931
+	SIOCAIFADDR                       = 0x8040691a
+	SIOCARPIPLL                       = 0xc0206928
+	SIOCATMARK                        = 0x40047307
+	SIOCAUTOADDR                      = 0xc0206926
+	SIOCAUTONETMASK                   = 0x80206927
+	SIOCDELMULTI                      = 0x80206932
+	SIOCDIFADDR                       = 0x80206919
+	SIOCDIFPHYADDR                    = 0x80206941
+	SIOCGDRVSPEC                      = 0xc028697b
+	SIOCGETVLAN                       = 0xc020697f
+	SIOCGHIWAT                        = 0x40047301
+	SIOCGIFADDR                       = 0xc0206921
+	SIOCGIFALTMTU                     = 0xc0206948
+	SIOCGIFASYNCMAP                   = 0xc020697c
+	SIOCGIFBOND                       = 0xc0206947
+	SIOCGIFBRDADDR                    = 0xc0206923
+	SIOCGIFCAP                        = 0xc020695b
+	SIOCGIFCONF                       = 0xc00c6924
+	SIOCGIFDEVMTU                     = 0xc0206944
+	SIOCGIFDSTADDR                    = 0xc0206922
+	SIOCGIFFLAGS                      = 0xc0206911
+	SIOCGIFGENERIC                    = 0xc020693a
+	SIOCGIFKPI                        = 0xc0206987
+	SIOCGIFMAC                        = 0xc0206982
+	SIOCGIFMEDIA                      = 0xc02c6938
+	SIOCGIFMETRIC                     = 0xc0206917
+	SIOCGIFMTU                        = 0xc0206933
+	SIOCGIFNETMASK                    = 0xc0206925
+	SIOCGIFPDSTADDR                   = 0xc0206940
+	SIOCGIFPHYS                       = 0xc0206935
+	SIOCGIFPSRCADDR                   = 0xc020693f
+	SIOCGIFSTATUS                     = 0xc331693d
+	SIOCGIFVLAN                       = 0xc020697f
+	SIOCGIFWAKEFLAGS                  = 0xc0206988
+	SIOCGLOWAT                        = 0x40047303
+	SIOCGPGRP                         = 0x40047309
+	SIOCIFCREATE                      = 0xc0206978
+	SIOCIFCREATE2                     = 0xc020697a
+	SIOCIFDESTROY                     = 0x80206979
+	SIOCIFGCLONERS                    = 0xc0106981
+	SIOCRSLVMULTI                     = 0xc010693b
+	SIOCSDRVSPEC                      = 0x8028697b
+	SIOCSETVLAN                       = 0x8020697e
+	SIOCSHIWAT                        = 0x80047300
+	SIOCSIFADDR                       = 0x8020690c
+	SIOCSIFALTMTU                     = 0x80206945
+	SIOCSIFASYNCMAP                   = 0x8020697d
+	SIOCSIFBOND                       = 0x80206946
+	SIOCSIFBRDADDR                    = 0x80206913
+	SIOCSIFCAP                        = 0x8020695a
+	SIOCSIFDSTADDR                    = 0x8020690e
+	SIOCSIFFLAGS                      = 0x80206910
+	SIOCSIFGENERIC                    = 0x80206939
+	SIOCSIFKPI                        = 0x80206986
+	SIOCSIFLLADDR                     = 0x8020693c
+	SIOCSIFMAC                        = 0x80206983
+	SIOCSIFMEDIA                      = 0xc0206937
+	SIOCSIFMETRIC                     = 0x80206918
+	SIOCSIFMTU                        = 0x80206934
+	SIOCSIFNETMASK                    = 0x80206916
+	SIOCSIFPHYADDR                    = 0x8040693e
+	SIOCSIFPHYS                       = 0x80206936
+	SIOCSIFVLAN                       = 0x8020697e
+	SIOCSLOWAT                        = 0x80047302
+	SIOCSPGRP                         = 0x80047308
+	SOCK_DGRAM                        = 0x2
+	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_RAW                          = 0x3
+	SOCK_RDM                          = 0x4
+	SOCK_SEQPACKET                    = 0x5
+	SOCK_STREAM                       = 0x1
+	SOL_SOCKET                        = 0xffff
+	SOMAXCONN                         = 0x80
+	SO_ACCEPTCONN                     = 0x2
+	SO_BROADCAST                      = 0x20
+	SO_DEBUG                          = 0x1
+	SO_DONTROUTE                      = 0x10
+	SO_DONTTRUNC                      = 0x2000
+	SO_ERROR                          = 0x1007
+	SO_KEEPALIVE                      = 0x8
+	SO_LABEL                          = 0x1010
+	SO_LINGER                         = 0x80
+	SO_LINGER_SEC                     = 0x1080
+	SO_NKE                            = 0x1021
+	SO_NOADDRERR                      = 0x1023
+	SO_NOSIGPIPE                      = 0x1022
+	SO_NOTIFYCONFLICT                 = 0x1026
+	SO_NP_EXTENSIONS                  = 0x1083
+	SO_NREAD                          = 0x1020
+	SO_NUMRCVPKT                      = 0x1112
+	SO_NWRITE                         = 0x1024
+	SO_OOBINLINE                      = 0x100
+	SO_PEERLABEL                      = 0x1011
+	SO_RANDOMPORT                     = 0x1082
+	SO_RCVBUF                         = 0x1002
+	SO_RCVLOWAT                       = 0x1004
+	SO_RCVTIMEO                       = 0x1006
+	SO_REUSEADDR                      = 0x4
+	SO_REUSEPORT                      = 0x200
+	SO_REUSESHAREUID                  = 0x1025
+	SO_SNDBUF                         = 0x1001
+	SO_SNDLOWAT                       = 0x1003
+	SO_SNDTIMEO                       = 0x1005
+	SO_TIMESTAMP                      = 0x400
+	SO_TIMESTAMP_MONOTONIC            = 0x800
+	SO_TYPE                           = 0x1008
+	SO_UPCALLCLOSEWAIT                = 0x1027
+	SO_USELOOPBACK                    = 0x40
+	SO_WANTMORE                       = 0x4000
+	SO_WANTOOBFLAG                    = 0x8000
+	S_IEXEC                           = 0x40
+	S_IFBLK                           = 0x6000
+	S_IFCHR                           = 0x2000
+	S_IFDIR                           = 0x4000
+	S_IFIFO                           = 0x1000
+	S_IFLNK                           = 0xa000
+	S_IFMT                            = 0xf000
+	S_IFREG                           = 0x8000
+	S_IFSOCK                          = 0xc000
+	S_IFWHT                           = 0xe000
+	S_IREAD                           = 0x100
+	S_IRGRP                           = 0x20
+	S_IROTH                           = 0x4
+	S_IRUSR                           = 0x100
+	S_IRWXG                           = 0x38
+	S_IRWXO                           = 0x7
+	S_IRWXU                           = 0x1c0
+	S_ISGID                           = 0x400
+	S_ISTXT                           = 0x200
+	S_ISUID                           = 0x800
+	S_ISVTX                           = 0x200
+	S_IWGRP                           = 0x10
+	S_IWOTH                           = 0x2
+	S_IWRITE                          = 0x80
+	S_IWUSR                           = 0x80
+	S_IXGRP                           = 0x8
+	S_IXOTH                           = 0x1
+	S_IXUSR                           = 0x40
+	TCIFLUSH                          = 0x1
+	TCIOFLUSH                         = 0x3
+	TCOFLUSH                          = 0x2
+	TCP_CONNECTIONTIMEOUT             = 0x20
+	TCP_ENABLE_ECN                    = 0x104
+	TCP_KEEPALIVE                     = 0x10
+	TCP_KEEPCNT                       = 0x102
+	TCP_KEEPINTVL                     = 0x101
+	TCP_MAXHLEN                       = 0x3c
+	TCP_MAXOLEN                       = 0x28
+	TCP_MAXSEG                        = 0x2
+	TCP_MAXWIN                        = 0xffff
+	TCP_MAX_SACK                      = 0x4
+	TCP_MAX_WINSHIFT                  = 0xe
+	TCP_MINMSS                        = 0xd8
+	TCP_MSS                           = 0x200
+	TCP_NODELAY                       = 0x1
+	TCP_NOOPT                         = 0x8
+	TCP_NOPUSH                        = 0x4
+	TCP_NOTSENT_LOWAT                 = 0x201
+	TCP_RXT_CONNDROPTIME              = 0x80
+	TCP_RXT_FINDROP                   = 0x100
+	TCP_SENDMOREACKS                  = 0x103
+	TCSAFLUSH                         = 0x2
+	TIOCCBRK                          = 0x2000747a
+	TIOCCDTR                          = 0x20007478
+	TIOCCONS                          = 0x80047462
+	TIOCDCDTIMESTAMP                  = 0x40107458
+	TIOCDRAIN                         = 0x2000745e
+	TIOCDSIMICROCODE                  = 0x20007455
+	TIOCEXCL                          = 0x2000740d
+	TIOCEXT                           = 0x80047460
+	TIOCFLUSH                         = 0x80047410
+	TIOCGDRAINWAIT                    = 0x40047456
+	TIOCGETA                          = 0x40487413
+	TIOCGETD                          = 0x4004741a
+	TIOCGPGRP                         = 0x40047477
+	TIOCGWINSZ                        = 0x40087468
+	TIOCIXOFF                         = 0x20007480
+	TIOCIXON                          = 0x20007481
+	TIOCMBIC                          = 0x8004746b
+	TIOCMBIS                          = 0x8004746c
+	TIOCMGDTRWAIT                     = 0x4004745a
+	TIOCMGET                          = 0x4004746a
+	TIOCMODG                          = 0x40047403
+	TIOCMODS                          = 0x80047404
+	TIOCMSDTRWAIT                     = 0x8004745b
+	TIOCMSET                          = 0x8004746d
+	TIOCM_CAR                         = 0x40
+	TIOCM_CD                          = 0x40
+	TIOCM_CTS                         = 0x20
+	TIOCM_DSR                         = 0x100
+	TIOCM_DTR                         = 0x2
+	TIOCM_LE                          = 0x1
+	TIOCM_RI                          = 0x80
+	TIOCM_RNG                         = 0x80
+	TIOCM_RTS                         = 0x4
+	TIOCM_SR                          = 0x10
+	TIOCM_ST                          = 0x8
+	TIOCNOTTY                         = 0x20007471
+	TIOCNXCL                          = 0x2000740e
+	TIOCOUTQ                          = 0x40047473
+	TIOCPKT                           = 0x80047470
+	TIOCPKT_DATA                      = 0x0
+	TIOCPKT_DOSTOP                    = 0x20
+	TIOCPKT_FLUSHREAD                 = 0x1
+	TIOCPKT_FLUSHWRITE                = 0x2
+	TIOCPKT_IOCTL                     = 0x40
+	TIOCPKT_NOSTOP                    = 0x10
+	TIOCPKT_START                     = 0x8
+	TIOCPKT_STOP                      = 0x4
+	TIOCPTYGNAME                      = 0x40807453
+	TIOCPTYGRANT                      = 0x20007454
+	TIOCPTYUNLK                       = 0x20007452
+	TIOCREMOTE                        = 0x80047469
+	TIOCSBRK                          = 0x2000747b
+	TIOCSCONS                         = 0x20007463
+	TIOCSCTTY                         = 0x20007461
+	TIOCSDRAINWAIT                    = 0x80047457
+	TIOCSDTR                          = 0x20007479
+	TIOCSETA                          = 0x80487414
+	TIOCSETAF                         = 0x80487416
+	TIOCSETAW                         = 0x80487415
+	TIOCSETD                          = 0x8004741b
+	TIOCSIG                           = 0x2000745f
+	TIOCSPGRP                         = 0x80047476
+	TIOCSTART                         = 0x2000746e
+	TIOCSTAT                          = 0x20007465
+	TIOCSTI                           = 0x80017472
+	TIOCSTOP                          = 0x2000746f
+	TIOCSWINSZ                        = 0x80087467
+	TIOCTIMESTAMP                     = 0x40107459
+	TIOCUCNTL                         = 0x80047466
+	TOSTOP                            = 0x400000
+	VDISCARD                          = 0xf
+	VDSUSP                            = 0xb
+	VEOF                              = 0x0
+	VEOL                              = 0x1
+	VEOL2                             = 0x2
+	VERASE                            = 0x3
+	VINTR                             = 0x8
+	VKILL                             = 0x5
+	VLNEXT                            = 0xe
+	VMIN                              = 0x10
+	VQUIT                             = 0x9
+	VREPRINT                          = 0x6
+	VSTART                            = 0xc
+	VSTATUS                           = 0x12
+	VSTOP                             = 0xd
+	VSUSP                             = 0xa
+	VT0                               = 0x0
+	VT1                               = 0x10000
+	VTDLY                             = 0x10000
+	VTIME                             = 0x11
+	VWERASE                           = 0x4
+	WCONTINUED                        = 0x10
+	WCOREFLAG                         = 0x80
+	WEXITED                           = 0x4
+	WNOHANG                           = 0x1
+	WNOWAIT                           = 0x20
+	WORDSIZE                          = 0x40
+	WSTOPPED                          = 0x8
+	WUNTRACED                         = 0x2
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x30)
+	EADDRNOTAVAIL   = Errno(0x31)
+	EAFNOSUPPORT    = Errno(0x2f)
+	EAGAIN          = Errno(0x23)
+	EALREADY        = Errno(0x25)
+	EAUTH           = Errno(0x50)
+	EBADARCH        = Errno(0x56)
+	EBADEXEC        = Errno(0x55)
+	EBADF           = Errno(0x9)
+	EBADMACHO       = Errno(0x58)
+	EBADMSG         = Errno(0x5e)
+	EBADRPC         = Errno(0x48)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x59)
+	ECHILD          = Errno(0xa)
+	ECONNABORTED    = Errno(0x35)
+	ECONNREFUSED    = Errno(0x3d)
+	ECONNRESET      = Errno(0x36)
+	EDEADLK         = Errno(0xb)
+	EDESTADDRREQ    = Errno(0x27)
+	EDEVERR         = Errno(0x53)
+	EDOM            = Errno(0x21)
+	EDQUOT          = Errno(0x45)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EFTYPE          = Errno(0x4f)
+	EHOSTDOWN       = Errno(0x40)
+	EHOSTUNREACH    = Errno(0x41)
+	EIDRM           = Errno(0x5a)
+	EILSEQ          = Errno(0x5c)
+	EINPROGRESS     = Errno(0x24)
+	EINTR           = Errno(0x4)
+	EINVAL          = Errno(0x16)
+	EIO             = Errno(0x5)
+	EISCONN         = Errno(0x38)
+	EISDIR          = Errno(0x15)
+	ELAST           = Errno(0x6a)
+	ELOOP           = Errno(0x3e)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x28)
+	EMULTIHOP       = Errno(0x5f)
+	ENAMETOOLONG    = Errno(0x3f)
+	ENEEDAUTH       = Errno(0x51)
+	ENETDOWN        = Errno(0x32)
+	ENETRESET       = Errno(0x34)
+	ENETUNREACH     = Errno(0x33)
+	ENFILE          = Errno(0x17)
+	ENOATTR         = Errno(0x5d)
+	ENOBUFS         = Errno(0x37)
+	ENODATA         = Errno(0x60)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOLCK          = Errno(0x4d)
+	ENOLINK         = Errno(0x61)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x5b)
+	ENOPOLICY       = Errno(0x67)
+	ENOPROTOOPT     = Errno(0x2a)
+	ENOSPC          = Errno(0x1c)
+	ENOSR           = Errno(0x62)
+	ENOSTR          = Errno(0x63)
+	ENOSYS          = Errno(0x4e)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x39)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x42)
+	ENOTRECOVERABLE = Errno(0x68)
+	ENOTSOCK        = Errno(0x26)
+	ENOTSUP         = Errno(0x2d)
+	ENOTTY          = Errno(0x19)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x66)
+	EOVERFLOW       = Errno(0x54)
+	EOWNERDEAD      = Errno(0x69)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x2e)
+	EPIPE           = Errno(0x20)
+	EPROCLIM        = Errno(0x43)
+	EPROCUNAVAIL    = Errno(0x4c)
+	EPROGMISMATCH   = Errno(0x4b)
+	EPROGUNAVAIL    = Errno(0x4a)
+	EPROTO          = Errno(0x64)
+	EPROTONOSUPPORT = Errno(0x2b)
+	EPROTOTYPE      = Errno(0x29)
+	EPWROFF         = Errno(0x52)
+	EQFULL          = Errno(0x6a)
+	ERANGE          = Errno(0x22)
+	EREMOTE         = Errno(0x47)
+	EROFS           = Errno(0x1e)
+	ERPCMISMATCH    = Errno(0x49)
+	ESHLIBVERS      = Errno(0x57)
+	ESHUTDOWN       = Errno(0x3a)
+	ESOCKTNOSUPPORT = Errno(0x2c)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESTALE          = Errno(0x46)
+	ETIME           = Errno(0x65)
+	ETIMEDOUT       = Errno(0x3c)
+	ETOOMANYREFS    = Errno(0x3b)
+	ETXTBSY         = Errno(0x1a)
+	EUSERS          = Errno(0x44)
+	EWOULDBLOCK     = Errno(0x23)
+	EXDEV           = Errno(0x12)
+)
+
+// Signals
+const (
+	SIGABRT   = Signal(0x6)
+	SIGALRM   = Signal(0xe)
+	SIGBUS    = Signal(0xa)
+	SIGCHLD   = Signal(0x14)
+	SIGCONT   = Signal(0x13)
+	SIGEMT    = Signal(0x7)
+	SIGFPE    = Signal(0x8)
+	SIGHUP    = Signal(0x1)
+	SIGILL    = Signal(0x4)
+	SIGINFO   = Signal(0x1d)
+	SIGINT    = Signal(0x2)
+	SIGIO     = Signal(0x17)
+	SIGIOT    = Signal(0x6)
+	SIGKILL   = Signal(0x9)
+	SIGPIPE   = Signal(0xd)
+	SIGPROF   = Signal(0x1b)
+	SIGQUIT   = Signal(0x3)
+	SIGSEGV   = Signal(0xb)
+	SIGSTOP   = Signal(0x11)
+	SIGSYS    = Signal(0xc)
+	SIGTERM   = Signal(0xf)
+	SIGTRAP   = Signal(0x5)
+	SIGTSTP   = Signal(0x12)
+	SIGTTIN   = Signal(0x15)
+	SIGTTOU   = Signal(0x16)
+	SIGURG    = Signal(0x10)
+	SIGUSR1   = Signal(0x1e)
+	SIGUSR2   = Signal(0x1f)
+	SIGVTALRM = Signal(0x1a)
+	SIGWINCH  = Signal(0x1c)
+	SIGXCPU   = Signal(0x18)
+	SIGXFSZ   = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+	1:   "operation not permitted",
+	2:   "no such file or directory",
+	3:   "no such process",
+	4:   "interrupted system call",
+	5:   "input/output error",
+	6:   "device not configured",
+	7:   "argument list too long",
+	8:   "exec format error",
+	9:   "bad file descriptor",
+	10:  "no child processes",
+	11:  "resource deadlock avoided",
+	12:  "cannot allocate memory",
+	13:  "permission denied",
+	14:  "bad address",
+	15:  "block device required",
+	16:  "resource busy",
+	17:  "file exists",
+	18:  "cross-device link",
+	19:  "operation not supported by device",
+	20:  "not a directory",
+	21:  "is a directory",
+	22:  "invalid argument",
+	23:  "too many open files in system",
+	24:  "too many open files",
+	25:  "inappropriate ioctl for device",
+	26:  "text file busy",
+	27:  "file too large",
+	28:  "no space left on device",
+	29:  "illegal seek",
+	30:  "read-only file system",
+	31:  "too many links",
+	32:  "broken pipe",
+	33:  "numerical argument out of domain",
+	34:  "result too large",
+	35:  "resource temporarily unavailable",
+	36:  "operation now in progress",
+	37:  "operation already in progress",
+	38:  "socket operation on non-socket",
+	39:  "destination address required",
+	40:  "message too long",
+	41:  "protocol wrong type for socket",
+	42:  "protocol not available",
+	43:  "protocol not supported",
+	44:  "socket type not supported",
+	45:  "operation not supported",
+	46:  "protocol family not supported",
+	47:  "address family not supported by protocol family",
+	48:  "address already in use",
+	49:  "can't assign requested address",
+	50:  "network is down",
+	51:  "network is unreachable",
+	52:  "network dropped connection on reset",
+	53:  "software caused connection abort",
+	54:  "connection reset by peer",
+	55:  "no buffer space available",
+	56:  "socket is already connected",
+	57:  "socket is not connected",
+	58:  "can't send after socket shutdown",
+	59:  "too many references: can't splice",
+	60:  "operation timed out",
+	61:  "connection refused",
+	62:  "too many levels of symbolic links",
+	63:  "file name too long",
+	64:  "host is down",
+	65:  "no route to host",
+	66:  "directory not empty",
+	67:  "too many processes",
+	68:  "too many users",
+	69:  "disc quota exceeded",
+	70:  "stale NFS file handle",
+	71:  "too many levels of remote in path",
+	72:  "RPC struct is bad",
+	73:  "RPC version wrong",
+	74:  "RPC prog. not avail",
+	75:  "program version wrong",
+	76:  "bad procedure for program",
+	77:  "no locks available",
+	78:  "function not implemented",
+	79:  "inappropriate file type or format",
+	80:  "authentication error",
+	81:  "need authenticator",
+	82:  "device power is off",
+	83:  "device error",
+	84:  "value too large to be stored in data type",
+	85:  "bad executable (or shared library)",
+	86:  "bad CPU type in executable",
+	87:  "shared library version mismatch",
+	88:  "malformed Mach-o file",
+	89:  "operation canceled",
+	90:  "identifier removed",
+	91:  "no message of desired type",
+	92:  "illegal byte sequence",
+	93:  "attribute not found",
+	94:  "bad message",
+	95:  "EMULTIHOP (Reserved)",
+	96:  "no message available on STREAM",
+	97:  "ENOLINK (Reserved)",
+	98:  "no STREAM resources",
+	99:  "not a STREAM",
+	100: "protocol error",
+	101: "STREAM ioctl timeout",
+	102: "operation not supported on socket",
+	103: "policy not found",
+	104: "state not recoverable",
+	105: "previous owner died",
+	106: "interface output queue is full",
+}
+
+// Signal table
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal instruction",
+	5:  "trace/BPT trap",
+	6:  "abort trap",
+	7:  "EMT trap",
+	8:  "floating point exception",
+	9:  "killed",
+	10: "bus error",
+	11: "segmentation fault",
+	12: "bad system call",
+	13: "broken pipe",
+	14: "alarm clock",
+	15: "terminated",
+	16: "urgent I/O condition",
+	17: "suspended (signal)",
+	18: "suspended",
+	19: "continued",
+	20: "child exited",
+	21: "stopped (tty input)",
+	22: "stopped (tty output)",
+	23: "I/O possible",
+	24: "cputime limit exceeded",
+	25: "filesize limit exceeded",
+	26: "virtual timer expired",
+	27: "profiling timer expired",
+	28: "window size changes",
+	29: "information request",
+	30: "user defined signal 1",
+	31: "user defined signal 2",
+}
diff --git a/src/syscall/zerrors_plan9_amd64.go b/src/syscall/zerrors_plan9_amd64.go
deleted file mode 100644
index ede3d6a..0000000
--- a/src/syscall/zerrors_plan9_amd64.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2011 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
-
-// Constants
-const (
-	// Invented values to support what package os expects.
-	O_CREAT    = 0x02000
-	O_APPEND   = 0x00400
-	O_NOCTTY   = 0x00000
-	O_NONBLOCK = 0x00000
-	O_SYNC     = 0x00000
-	O_ASYNC    = 0x00000
-
-	S_IFMT   = 0x1f000
-	S_IFIFO  = 0x1000
-	S_IFCHR  = 0x2000
-	S_IFDIR  = 0x4000
-	S_IFBLK  = 0x6000
-	S_IFREG  = 0x8000
-	S_IFLNK  = 0xa000
-	S_IFSOCK = 0xc000
-)
-
-// Errors
-var (
-	EINVAL       = NewError("bad arg in system call")
-	ENOTDIR      = NewError("not a directory")
-	EISDIR       = NewError("file is a directory")
-	ENOENT       = NewError("file does not exist")
-	EEXIST       = NewError("file already exists")
-	EMFILE       = NewError("no free file descriptors")
-	EIO          = NewError("i/o error")
-	ENAMETOOLONG = NewError("file name too long")
-	EINTR        = NewError("interrupted")
-	EPERM        = NewError("permission denied")
-	EBUSY        = NewError("no free devices")
-	ETIMEDOUT    = NewError("connection timed out")
-	EPLAN9       = NewError("not supported by plan 9")
-
-	// The following errors do not correspond to any
-	// Plan 9 system messages. Invented to support
-	// what package os and others expect.
-	EACCES       = NewError("access permission denied")
-	EAFNOSUPPORT = NewError("address family not supported by protocol")
-)
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
new file mode 100644
index 0000000..828b167
--- /dev/null
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -0,0 +1,1419 @@
+// mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+	wpid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
+	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+	var _p0 unsafe.Pointer
+	if len(mib) > 0 {
+		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe() (r int, w int, err error) {
+	r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+	r = int(r0)
+	w = int(r1)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kill(pid int, signum int, posix int) (err error) {
+	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(fd int) (nfd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exchangedata(path1 string, path2 string, options int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path1)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(path2)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+	Syscall(SYS_EXIT, uintptr(code), 0, 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdtablesize() (size int) {
+	r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
+	size = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+	r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+	egid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+	uid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+	gid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+	pgid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pgrp = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+	r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+	ppid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+	prio = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+	sid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+	uid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+	r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0)
+	tainted = bool(r0 != 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = 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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
+	use(unsafe.Pointer(_p0))
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(from)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(to)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
+	newoffset = int64(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setlogin(name string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(name)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setprivexec(flag int) (err error) {
+	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+	pid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, stat *Statfs_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+	r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+	oldmask = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Undelete(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+	ret = uintptr(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) {
+	r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	sec = int64(r0)
+	usec = int32(r1)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go
index ae0187f..06f1f04 100644
--- a/src/syscall/zsyscall_plan9_386.go
+++ b/src/syscall/zsyscall_plan9_386.go
@@ -23,7 +23,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
+func pipe(p *[2]int32) (err error) {
 	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if int32(r0) == -1 {
 		err = e1
diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go
index ae0187f..06f1f04 100644
--- a/src/syscall/zsyscall_plan9_amd64.go
+++ b/src/syscall/zsyscall_plan9_amd64.go
@@ -23,7 +23,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
+func pipe(p *[2]int32) (err error) {
 	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if int32(r0) == -1 {
 		err = e1
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index 886d2b0..be9bc28 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -5,94 +5,258 @@
 
 import "unsafe"
 
-var (
-	modlibc      = newLazySO("libc.so")
-	modlibsocket = newLazySO("libsocket.so")
+//go:cgo_import_dynamic libc_getgroups getgroups "libc.so"
+//go:cgo_import_dynamic libc_setgroups setgroups "libc.so"
+//go:cgo_import_dynamic libc_fcntl fcntl "libc.so"
+//go:cgo_import_dynamic libc_accept accept "libsocket.so"
+//go:cgo_import_dynamic libc_sendmsg sendmsg "libsocket.so"
+//go:cgo_import_dynamic libc_Access access "libc.so"
+//go:cgo_import_dynamic libc_Adjtime adjtime "libc.so"
+//go:cgo_import_dynamic libc_Chdir chdir "libc.so"
+//go:cgo_import_dynamic libc_Chmod chmod "libc.so"
+//go:cgo_import_dynamic libc_Chown chown "libc.so"
+//go:cgo_import_dynamic libc_Chroot chroot "libc.so"
+//go:cgo_import_dynamic libc_Close close "libc.so"
+//go:cgo_import_dynamic libc_Dup dup "libc.so"
+//go:cgo_import_dynamic libc_Exit exit "libc.so"
+//go:cgo_import_dynamic libc_Fchdir fchdir "libc.so"
+//go:cgo_import_dynamic libc_Fchmod fchmod "libc.so"
+//go:cgo_import_dynamic libc_Fchown fchown "libc.so"
+//go:cgo_import_dynamic libc_Fpathconf fpathconf "libc.so"
+//go:cgo_import_dynamic libc_Fstat fstat "libc.so"
+//go:cgo_import_dynamic libc_Getdents getdents "libc.so"
+//go:cgo_import_dynamic libc_Getgid getgid "libc.so"
+//go:cgo_import_dynamic libc_Getpid getpid "libc.so"
+//go:cgo_import_dynamic libc_Geteuid geteuid "libc.so"
+//go:cgo_import_dynamic libc_Getegid getegid "libc.so"
+//go:cgo_import_dynamic libc_Getppid getppid "libc.so"
+//go:cgo_import_dynamic libc_Getpriority getpriority "libc.so"
+//go:cgo_import_dynamic libc_Getrlimit getrlimit "libc.so"
+//go:cgo_import_dynamic libc_Gettimeofday gettimeofday "libc.so"
+//go:cgo_import_dynamic libc_Getuid getuid "libc.so"
+//go:cgo_import_dynamic libc_Kill kill "libc.so"
+//go:cgo_import_dynamic libc_Lchown lchown "libc.so"
+//go:cgo_import_dynamic libc_Link link "libc.so"
+//go:cgo_import_dynamic libc_listen listen "libsocket.so"
+//go:cgo_import_dynamic libc_Lstat lstat "libc.so"
+//go:cgo_import_dynamic libc_Mkdir mkdir "libc.so"
+//go:cgo_import_dynamic libc_Mknod mknod "libc.so"
+//go:cgo_import_dynamic libc_Nanosleep nanosleep "libc.so"
+//go:cgo_import_dynamic libc_Open open "libc.so"
+//go:cgo_import_dynamic libc_Pathconf pathconf "libc.so"
+//go:cgo_import_dynamic libc_Pread pread "libc.so"
+//go:cgo_import_dynamic libc_Pwrite pwrite "libc.so"
+//go:cgo_import_dynamic libc_read read "libc.so"
+//go:cgo_import_dynamic libc_Readlink readlink "libc.so"
+//go:cgo_import_dynamic libc_Rename rename "libc.so"
+//go:cgo_import_dynamic libc_Rmdir rmdir "libc.so"
+//go:cgo_import_dynamic libc_lseek lseek "libc.so"
+//go:cgo_import_dynamic libc_sendfile sendfile "libsendfile.so"
+//go:cgo_import_dynamic libc_Setegid setegid "libc.so"
+//go:cgo_import_dynamic libc_Seteuid seteuid "libc.so"
+//go:cgo_import_dynamic libc_Setgid setgid "libc.so"
+//go:cgo_import_dynamic libc_Setpgid setpgid "libc.so"
+//go:cgo_import_dynamic libc_Setpriority setpriority "libc.so"
+//go:cgo_import_dynamic libc_Setregid setregid "libc.so"
+//go:cgo_import_dynamic libc_Setreuid setreuid "libc.so"
+//go:cgo_import_dynamic libc_Setrlimit setrlimit "libc.so"
+//go:cgo_import_dynamic libc_Setsid setsid "libc.so"
+//go:cgo_import_dynamic libc_Setuid setuid "libc.so"
+//go:cgo_import_dynamic libc_shutdown shutdown "libsocket.so"
+//go:cgo_import_dynamic libc_Stat stat "libc.so"
+//go:cgo_import_dynamic libc_Symlink symlink "libc.so"
+//go:cgo_import_dynamic libc_Sync sync "libc.so"
+//go:cgo_import_dynamic libc_Truncate truncate "libc.so"
+//go:cgo_import_dynamic libc_Fsync fsync "libc.so"
+//go:cgo_import_dynamic libc_Ftruncate ftruncate "libc.so"
+//go:cgo_import_dynamic libc_Umask umask "libc.so"
+//go:cgo_import_dynamic libc_Unlink unlink "libc.so"
+//go:cgo_import_dynamic libc_Utimes utimes "libc.so"
+//go:cgo_import_dynamic libc_bind bind "libsocket.so"
+//go:cgo_import_dynamic libc_connect connect "libsocket.so"
+//go:cgo_import_dynamic libc_mmap mmap "libc.so"
+//go:cgo_import_dynamic libc_munmap munmap "libc.so"
+//go:cgo_import_dynamic libc_sendto sendto "libsocket.so"
+//go:cgo_import_dynamic libc_socket socket "libsocket.so"
+//go:cgo_import_dynamic libc_socketpair socketpair "libsocket.so"
+//go:cgo_import_dynamic libc_write write "libc.so"
+//go:cgo_import_dynamic libc_getsockopt getsockopt "libsocket.so"
+//go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so"
+//go:cgo_import_dynamic libc_getsockname getsockname "libsocket.so"
+//go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
+//go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so"
+//go:cgo_import_dynamic libc_recvmsg recvmsg "libsocket.so"
 
-	procgetgroups    = modlibc.NewProc("getgroups")
-	procsetgroups    = modlibc.NewProc("setgroups")
-	procfcntl        = modlibc.NewProc("fcntl")
-	procaccept       = modlibsocket.NewProc("accept")
-	procsendmsg      = modlibsocket.NewProc("sendmsg")
-	procAccess       = modlibc.NewProc("access")
-	procAdjtime      = modlibc.NewProc("adjtime")
-	procChdir        = modlibc.NewProc("chdir")
-	procChmod        = modlibc.NewProc("chmod")
-	procChown        = modlibc.NewProc("chown")
-	procChroot       = modlibc.NewProc("chroot")
-	procClose        = modlibc.NewProc("close")
-	procDup          = modlibc.NewProc("dup")
-	procExit         = modlibc.NewProc("exit")
-	procFchdir       = modlibc.NewProc("fchdir")
-	procFchmod       = modlibc.NewProc("fchmod")
-	procFchown       = modlibc.NewProc("fchown")
-	procFpathconf    = modlibc.NewProc("fpathconf")
-	procFstat        = modlibc.NewProc("fstat")
-	procGetdents     = modlibc.NewProc("getdents")
-	procGetgid       = modlibc.NewProc("getgid")
-	procGetpid       = modlibc.NewProc("getpid")
-	procGeteuid      = modlibc.NewProc("geteuid")
-	procGetegid      = modlibc.NewProc("getegid")
-	procGetppid      = modlibc.NewProc("getppid")
-	procGetpriority  = modlibc.NewProc("getpriority")
-	procGetrlimit    = modlibc.NewProc("getrlimit")
-	procGettimeofday = modlibc.NewProc("gettimeofday")
-	procGetuid       = modlibc.NewProc("getuid")
-	procKill         = modlibc.NewProc("kill")
-	procLchown       = modlibc.NewProc("lchown")
-	procLink         = modlibc.NewProc("link")
-	proclisten       = modlibsocket.NewProc("listen")
-	procLstat        = modlibc.NewProc("lstat")
-	procMkdir        = modlibc.NewProc("mkdir")
-	procMknod        = modlibc.NewProc("mknod")
-	procNanosleep    = modlibc.NewProc("nanosleep")
-	procOpen         = modlibc.NewProc("open")
-	procPathconf     = modlibc.NewProc("pathconf")
-	procPread        = modlibc.NewProc("pread")
-	procPwrite       = modlibc.NewProc("pwrite")
-	procread         = modlibc.NewProc("read")
-	procReadlink     = modlibc.NewProc("readlink")
-	procRename       = modlibc.NewProc("rename")
-	procRmdir        = modlibc.NewProc("rmdir")
-	proclseek        = modlibc.NewProc("lseek")
-	procSetegid      = modlibc.NewProc("setegid")
-	procSeteuid      = modlibc.NewProc("seteuid")
-	procSetgid       = modlibc.NewProc("setgid")
-	procSetpgid      = modlibc.NewProc("setpgid")
-	procSetpriority  = modlibc.NewProc("setpriority")
-	procSetregid     = modlibc.NewProc("setregid")
-	procSetreuid     = modlibc.NewProc("setreuid")
-	procSetrlimit    = modlibc.NewProc("setrlimit")
-	procSetsid       = modlibc.NewProc("setsid")
-	procSetuid       = modlibc.NewProc("setuid")
-	procshutdown     = modlibsocket.NewProc("shutdown")
-	procStat         = modlibc.NewProc("stat")
-	procSymlink      = modlibc.NewProc("symlink")
-	procSync         = modlibc.NewProc("sync")
-	procTruncate     = modlibc.NewProc("truncate")
-	procFsync        = modlibc.NewProc("fsync")
-	procFtruncate    = modlibc.NewProc("ftruncate")
-	procUmask        = modlibc.NewProc("umask")
-	procUnlink       = modlibc.NewProc("unlink")
-	procUtimes       = modlibc.NewProc("utimes")
-	procbind         = modlibsocket.NewProc("bind")
-	procconnect      = modlibsocket.NewProc("connect")
-	procmmap         = modlibc.NewProc("mmap")
-	procmunmap       = modlibc.NewProc("munmap")
-	procsendto       = modlibsocket.NewProc("sendto")
-	procsocket       = modlibsocket.NewProc("socket")
-	procsocketpair   = modlibsocket.NewProc("socketpair")
-	procwrite        = modlibc.NewProc("write")
-	procgetsockopt   = modlibsocket.NewProc("getsockopt")
-	procgetpeername  = modlibsocket.NewProc("getpeername")
-	procgetsockname  = modlibsocket.NewProc("getsockname")
-	procsetsockopt   = modlibsocket.NewProc("setsockopt")
-	procrecvfrom     = modlibsocket.NewProc("recvfrom")
-	procrecvmsg      = modlibsocket.NewProc("recvmsg")
+//go:linkname libc_getgroups libc_getgroups
+//go:linkname libc_setgroups libc_setgroups
+//go:linkname libc_fcntl libc_fcntl
+//go:linkname libc_accept libc_accept
+//go:linkname libc_sendmsg libc_sendmsg
+//go:linkname libc_Access libc_Access
+//go:linkname libc_Adjtime libc_Adjtime
+//go:linkname libc_Chdir libc_Chdir
+//go:linkname libc_Chmod libc_Chmod
+//go:linkname libc_Chown libc_Chown
+//go:linkname libc_Chroot libc_Chroot
+//go:linkname libc_Close libc_Close
+//go:linkname libc_Dup libc_Dup
+//go:linkname libc_Exit libc_Exit
+//go:linkname libc_Fchdir libc_Fchdir
+//go:linkname libc_Fchmod libc_Fchmod
+//go:linkname libc_Fchown libc_Fchown
+//go:linkname libc_Fpathconf libc_Fpathconf
+//go:linkname libc_Fstat libc_Fstat
+//go:linkname libc_Getdents libc_Getdents
+//go:linkname libc_Getgid libc_Getgid
+//go:linkname libc_Getpid libc_Getpid
+//go:linkname libc_Geteuid libc_Geteuid
+//go:linkname libc_Getegid libc_Getegid
+//go:linkname libc_Getppid libc_Getppid
+//go:linkname libc_Getpriority libc_Getpriority
+//go:linkname libc_Getrlimit libc_Getrlimit
+//go:linkname libc_Gettimeofday libc_Gettimeofday
+//go:linkname libc_Getuid libc_Getuid
+//go:linkname libc_Kill libc_Kill
+//go:linkname libc_Lchown libc_Lchown
+//go:linkname libc_Link libc_Link
+//go:linkname libc_listen libc_listen
+//go:linkname libc_Lstat libc_Lstat
+//go:linkname libc_Mkdir libc_Mkdir
+//go:linkname libc_Mknod libc_Mknod
+//go:linkname libc_Nanosleep libc_Nanosleep
+//go:linkname libc_Open libc_Open
+//go:linkname libc_Pathconf libc_Pathconf
+//go:linkname libc_Pread libc_Pread
+//go:linkname libc_Pwrite libc_Pwrite
+//go:linkname libc_read libc_read
+//go:linkname libc_Readlink libc_Readlink
+//go:linkname libc_Rename libc_Rename
+//go:linkname libc_Rmdir libc_Rmdir
+//go:linkname libc_lseek libc_lseek
+//go:linkname libc_sendfile libc_sendfile
+//go:linkname libc_Setegid libc_Setegid
+//go:linkname libc_Seteuid libc_Seteuid
+//go:linkname libc_Setgid libc_Setgid
+//go:linkname libc_Setpgid libc_Setpgid
+//go:linkname libc_Setpriority libc_Setpriority
+//go:linkname libc_Setregid libc_Setregid
+//go:linkname libc_Setreuid libc_Setreuid
+//go:linkname libc_Setrlimit libc_Setrlimit
+//go:linkname libc_Setsid libc_Setsid
+//go:linkname libc_Setuid libc_Setuid
+//go:linkname libc_shutdown libc_shutdown
+//go:linkname libc_Stat libc_Stat
+//go:linkname libc_Symlink libc_Symlink
+//go:linkname libc_Sync libc_Sync
+//go:linkname libc_Truncate libc_Truncate
+//go:linkname libc_Fsync libc_Fsync
+//go:linkname libc_Ftruncate libc_Ftruncate
+//go:linkname libc_Umask libc_Umask
+//go:linkname libc_Unlink libc_Unlink
+//go:linkname libc_Utimes libc_Utimes
+//go:linkname libc_bind libc_bind
+//go:linkname libc_connect libc_connect
+//go:linkname libc_mmap libc_mmap
+//go:linkname libc_munmap libc_munmap
+//go:linkname libc_sendto libc_sendto
+//go:linkname libc_socket libc_socket
+//go:linkname libc_socketpair libc_socketpair
+//go:linkname libc_write libc_write
+//go:linkname libc_getsockopt libc_getsockopt
+//go:linkname libc_getpeername libc_getpeername
+//go:linkname libc_getsockname libc_getsockname
+//go:linkname libc_setsockopt libc_setsockopt
+//go:linkname libc_recvfrom libc_recvfrom
+//go:linkname libc_recvmsg libc_recvmsg
+
+type libcFunc uintptr
+
+var (
+	libc_getgroups,
+	libc_setgroups,
+	libc_fcntl,
+	libc_accept,
+	libc_sendmsg,
+	libc_Access,
+	libc_Adjtime,
+	libc_Chdir,
+	libc_Chmod,
+	libc_Chown,
+	libc_Chroot,
+	libc_Close,
+	libc_Dup,
+	libc_Exit,
+	libc_Fchdir,
+	libc_Fchmod,
+	libc_Fchown,
+	libc_Fpathconf,
+	libc_Fstat,
+	libc_Getdents,
+	libc_Getgid,
+	libc_Getpid,
+	libc_Geteuid,
+	libc_Getegid,
+	libc_Getppid,
+	libc_Getpriority,
+	libc_Getrlimit,
+	libc_Gettimeofday,
+	libc_Getuid,
+	libc_Kill,
+	libc_Lchown,
+	libc_Link,
+	libc_listen,
+	libc_Lstat,
+	libc_Mkdir,
+	libc_Mknod,
+	libc_Nanosleep,
+	libc_Open,
+	libc_Pathconf,
+	libc_Pread,
+	libc_Pwrite,
+	libc_read,
+	libc_Readlink,
+	libc_Rename,
+	libc_Rmdir,
+	libc_lseek,
+	libc_sendfile,
+	libc_Setegid,
+	libc_Seteuid,
+	libc_Setgid,
+	libc_Setpgid,
+	libc_Setpriority,
+	libc_Setregid,
+	libc_Setreuid,
+	libc_Setrlimit,
+	libc_Setsid,
+	libc_Setuid,
+	libc_shutdown,
+	libc_Stat,
+	libc_Symlink,
+	libc_Sync,
+	libc_Truncate,
+	libc_Fsync,
+	libc_Ftruncate,
+	libc_Umask,
+	libc_Unlink,
+	libc_Utimes,
+	libc_bind,
+	libc_connect,
+	libc_mmap,
+	libc_munmap,
+	libc_sendto,
+	libc_socket,
+	libc_socketpair,
+	libc_write,
+	libc_getsockopt,
+	libc_getpeername,
+	libc_getsockname,
+	libc_setsockopt,
+	libc_recvfrom,
+	libc_recvmsg libcFunc
 )
 
 func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
-	r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -101,7 +265,7 @@
 }
 
 func setgroups(ngid int, gid *_Gid_t) (err error) {
-	_, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -109,7 +273,7 @@
 }
 
 func fcntl(fd int, cmd int, arg int) (val int, err error) {
-	r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -118,7 +282,7 @@
 }
 
 func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
-	r0, _, e1 := sysvicall6(procaccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_accept)), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -127,7 +291,7 @@
 }
 
 func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -141,7 +305,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Access)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -150,7 +314,7 @@
 }
 
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
-	_, _, e1 := sysvicall6(procAdjtime.Addr(), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Adjtime)), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -163,7 +327,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -177,7 +341,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chmod)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -191,7 +355,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -205,7 +369,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chroot)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -214,7 +378,7 @@
 }
 
 func Close(fd int) (err error) {
-	_, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Close)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -222,7 +386,7 @@
 }
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Dup)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -231,12 +395,12 @@
 }
 
 func Exit(code int) {
-	sysvicall6(procExit.Addr(), 1, uintptr(code), 0, 0, 0, 0, 0)
+	sysvicall6(uintptr(unsafe.Pointer(&libc_Exit)), 1, uintptr(code), 0, 0, 0, 0, 0)
 	return
 }
 
 func Fchdir(fd int) (err error) {
-	_, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -244,7 +408,7 @@
 }
 
 func Fchmod(fd int, mode uint32) (err error) {
-	_, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -252,7 +416,7 @@
 }
 
 func Fchown(fd int, uid int, gid int) (err error) {
-	_, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -260,7 +424,7 @@
 }
 
 func Fpathconf(fd int, name int) (val int, err error) {
-	r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -269,7 +433,7 @@
 }
 
 func Fstat(fd int, stat *Stat_t) (err error) {
-	_, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -281,7 +445,7 @@
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	r0, _, e1 := sysvicall6(procGetdents.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getdents)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -290,37 +454,37 @@
 }
 
 func Getgid() (gid int) {
-	r0, _, _ := rawSysvicall6(procGetgid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getgid)), 0, 0, 0, 0, 0, 0, 0)
 	gid = int(r0)
 	return
 }
 
 func Getpid() (pid int) {
-	r0, _, _ := rawSysvicall6(procGetpid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getpid)), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	return
 }
 
 func Geteuid() (euid int) {
-	r0, _, _ := sysvicall6(procGeteuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Geteuid)), 0, 0, 0, 0, 0, 0, 0)
 	euid = int(r0)
 	return
 }
 
 func Getegid() (egid int) {
-	r0, _, _ := sysvicall6(procGetegid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getegid)), 0, 0, 0, 0, 0, 0, 0)
 	egid = int(r0)
 	return
 }
 
 func Getppid() (ppid int) {
-	r0, _, _ := sysvicall6(procGetppid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getppid)), 0, 0, 0, 0, 0, 0, 0)
 	ppid = int(r0)
 	return
 }
 
 func Getpriority(which int, who int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpriority)), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -329,7 +493,7 @@
 }
 
 func Getrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -337,7 +501,7 @@
 }
 
 func Gettimeofday(tv *Timeval) (err error) {
-	_, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Gettimeofday)), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -345,13 +509,13 @@
 }
 
 func Getuid() (uid int) {
-	r0, _, _ := rawSysvicall6(procGetuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getuid)), 0, 0, 0, 0, 0, 0, 0)
 	uid = int(r0)
 	return
 }
 
 func Kill(pid int, signum Signal) (err error) {
-	_, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Kill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -364,7 +528,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lchown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -383,7 +547,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Link)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
@@ -393,7 +557,7 @@
 }
 
 func Listen(s int, backlog int) (err error) {
-	_, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -406,7 +570,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lstat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -420,7 +584,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mkdir)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -434,7 +598,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mknod)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -443,7 +607,7 @@
 }
 
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
-	_, _, e1 := sysvicall6(procNanosleep.Addr(), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Nanosleep)), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -456,7 +620,7 @@
 	if err != nil {
 		return
 	}
-	r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Open)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
@@ -471,7 +635,7 @@
 	if err != nil {
 		return
 	}
-	r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pathconf)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
@@ -485,7 +649,7 @@
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procPread.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pread)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -498,7 +662,7 @@
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procPwrite.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pwrite)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -511,7 +675,7 @@
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -529,7 +693,7 @@
 	if len(buf) > 0 {
 		_p1 = &buf[0]
 	}
-	r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Readlink)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
@@ -549,7 +713,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rename)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
@@ -564,7 +728,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rmdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -573,7 +737,7 @@
 }
 
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
-	r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -581,8 +745,17 @@
 	return
 }
 
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendfile)), 4, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+	written = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
 func Setegid(egid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setegid)), 1, uintptr(egid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -590,7 +763,7 @@
 }
 
 func Seteuid(euid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Seteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -598,7 +771,7 @@
 }
 
 func Setgid(gid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setgid)), 1, uintptr(gid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -606,7 +779,7 @@
 }
 
 func Setpgid(pid int, pgid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -614,7 +787,7 @@
 }
 
 func Setpriority(which int, who int, prio int) (err error) {
-	_, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Setpriority)), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -622,7 +795,7 @@
 }
 
 func Setregid(rgid int, egid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -630,7 +803,7 @@
 }
 
 func Setreuid(ruid int, euid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -638,7 +811,7 @@
 }
 
 func Setrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -646,7 +819,7 @@
 }
 
 func Setsid() (pid int, err error) {
-	r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setsid)), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -655,7 +828,7 @@
 }
 
 func Setuid(uid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -663,7 +836,7 @@
 }
 
 func Shutdown(s int, how int) (err error) {
-	_, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_shutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -676,7 +849,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Stat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -695,7 +868,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Symlink)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
@@ -705,7 +878,7 @@
 }
 
 func Sync() (err error) {
-	_, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Sync)), 0, 0, 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -718,7 +891,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Truncate)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -727,7 +900,7 @@
 }
 
 func Fsync(fd int) (err error) {
-	_, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -735,7 +908,7 @@
 }
 
 func Ftruncate(fd int, length int64) (err error) {
-	_, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -743,7 +916,7 @@
 }
 
 func Umask(newmask int) (oldmask int) {
-	r0, _, _ := sysvicall6(procUmask.Addr(), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Umask)), 1, uintptr(newmask), 0, 0, 0, 0, 0)
 	oldmask = int(r0)
 	return
 }
@@ -754,7 +927,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Unlink)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -768,7 +941,7 @@
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Utimes)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -777,7 +950,7 @@
 }
 
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
-	_, _, e1 := sysvicall6(procbind.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -785,7 +958,7 @@
 }
 
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
-	_, _, e1 := sysvicall6(procconnect.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -793,7 +966,7 @@
 }
 
 func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
-	r0, _, e1 := sysvicall6(procmmap.Addr(), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_mmap)), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -802,7 +975,7 @@
 }
 
 func munmap(addr uintptr, length uintptr) (err error) {
-	_, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -814,7 +987,7 @@
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	_, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendto)), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -822,7 +995,7 @@
 }
 
 func socket(domain int, typ int, proto int) (fd int, err error) {
-	r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -831,7 +1004,7 @@
 }
 
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
-	_, _, e1 := rawSysvicall6(procsocketpair.Addr(), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -843,7 +1016,7 @@
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -852,7 +1025,7 @@
 }
 
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
-	_, _, e1 := sysvicall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -860,7 +1033,7 @@
 }
 
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
-	_, _, e1 := rawSysvicall6(procgetpeername.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -868,7 +1041,7 @@
 }
 
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
-	_, _, e1 := sysvicall6(procgetsockname.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -876,7 +1049,7 @@
 }
 
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
-	_, _, e1 := sysvicall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -888,7 +1061,7 @@
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procrecvfrom.Addr(), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvfrom)), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -897,7 +1070,7 @@
 }
 
 func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = errnoErr(e1)
diff --git a/src/syscall/zsysnum_darwin_arm64.go b/src/syscall/zsysnum_darwin_arm64.go
new file mode 100644
index 0000000..723b1aa
--- /dev/null
+++ b/src/syscall/zsysnum_darwin_arm64.go
@@ -0,0 +1,356 @@
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	SYS_SYSCALL                        = 0
+	SYS_EXIT                           = 1
+	SYS_FORK                           = 2
+	SYS_READ                           = 3
+	SYS_WRITE                          = 4
+	SYS_OPEN                           = 5
+	SYS_CLOSE                          = 6
+	SYS_WAIT4                          = 7
+	SYS_LINK                           = 9
+	SYS_UNLINK                         = 10
+	SYS_CHDIR                          = 12
+	SYS_FCHDIR                         = 13
+	SYS_MKNOD                          = 14
+	SYS_CHMOD                          = 15
+	SYS_CHOWN                          = 16
+	SYS_GETFSSTAT                      = 18
+	SYS_GETPID                         = 20
+	SYS_SETUID                         = 23
+	SYS_GETUID                         = 24
+	SYS_GETEUID                        = 25
+	SYS_PTRACE                         = 26
+	SYS_RECVMSG                        = 27
+	SYS_SENDMSG                        = 28
+	SYS_RECVFROM                       = 29
+	SYS_ACCEPT                         = 30
+	SYS_GETPEERNAME                    = 31
+	SYS_GETSOCKNAME                    = 32
+	SYS_ACCESS                         = 33
+	SYS_CHFLAGS                        = 34
+	SYS_FCHFLAGS                       = 35
+	SYS_SYNC                           = 36
+	SYS_KILL                           = 37
+	SYS_GETPPID                        = 39
+	SYS_DUP                            = 41
+	SYS_PIPE                           = 42
+	SYS_GETEGID                        = 43
+	SYS_SIGACTION                      = 46
+	SYS_GETGID                         = 47
+	SYS_SIGPROCMASK                    = 48
+	SYS_GETLOGIN                       = 49
+	SYS_SETLOGIN                       = 50
+	SYS_ACCT                           = 51
+	SYS_SIGPENDING                     = 52
+	SYS_SIGALTSTACK                    = 53
+	SYS_IOCTL                          = 54
+	SYS_REBOOT                         = 55
+	SYS_REVOKE                         = 56
+	SYS_SYMLINK                        = 57
+	SYS_READLINK                       = 58
+	SYS_EXECVE                         = 59
+	SYS_UMASK                          = 60
+	SYS_CHROOT                         = 61
+	SYS_MSYNC                          = 65
+	SYS_VFORK                          = 66
+	SYS_MUNMAP                         = 73
+	SYS_MPROTECT                       = 74
+	SYS_MADVISE                        = 75
+	SYS_MINCORE                        = 78
+	SYS_GETGROUPS                      = 79
+	SYS_SETGROUPS                      = 80
+	SYS_GETPGRP                        = 81
+	SYS_SETPGID                        = 82
+	SYS_SETITIMER                      = 83
+	SYS_SWAPON                         = 85
+	SYS_GETITIMER                      = 86
+	SYS_GETDTABLESIZE                  = 89
+	SYS_DUP2                           = 90
+	SYS_FCNTL                          = 92
+	SYS_SELECT                         = 93
+	SYS_FSYNC                          = 95
+	SYS_SETPRIORITY                    = 96
+	SYS_SOCKET                         = 97
+	SYS_CONNECT                        = 98
+	SYS_GETPRIORITY                    = 100
+	SYS_BIND                           = 104
+	SYS_SETSOCKOPT                     = 105
+	SYS_LISTEN                         = 106
+	SYS_SIGSUSPEND                     = 111
+	SYS_GETTIMEOFDAY                   = 116
+	SYS_GETRUSAGE                      = 117
+	SYS_GETSOCKOPT                     = 118
+	SYS_READV                          = 120
+	SYS_WRITEV                         = 121
+	SYS_SETTIMEOFDAY                   = 122
+	SYS_FCHOWN                         = 123
+	SYS_FCHMOD                         = 124
+	SYS_SETREUID                       = 126
+	SYS_SETREGID                       = 127
+	SYS_RENAME                         = 128
+	SYS_FLOCK                          = 131
+	SYS_MKFIFO                         = 132
+	SYS_SENDTO                         = 133
+	SYS_SHUTDOWN                       = 134
+	SYS_SOCKETPAIR                     = 135
+	SYS_MKDIR                          = 136
+	SYS_RMDIR                          = 137
+	SYS_UTIMES                         = 138
+	SYS_FUTIMES                        = 139
+	SYS_ADJTIME                        = 140
+	SYS_GETHOSTUUID                    = 142
+	SYS_SETSID                         = 147
+	SYS_GETPGID                        = 151
+	SYS_SETPRIVEXEC                    = 152
+	SYS_PREAD                          = 153
+	SYS_PWRITE                         = 154
+	SYS_NFSSVC                         = 155
+	SYS_STATFS                         = 157
+	SYS_FSTATFS                        = 158
+	SYS_UNMOUNT                        = 159
+	SYS_GETFH                          = 161
+	SYS_QUOTACTL                       = 165
+	SYS_MOUNT                          = 167
+	SYS_CSOPS                          = 169
+	SYS_CSOPS_AUDITTOKEN               = 170
+	SYS_WAITID                         = 173
+	SYS_KDEBUG_TRACE                   = 180
+	SYS_SETGID                         = 181
+	SYS_SETEGID                        = 182
+	SYS_SETEUID                        = 183
+	SYS_SIGRETURN                      = 184
+	SYS_CHUD                           = 185
+	SYS_FDATASYNC                      = 187
+	SYS_STAT                           = 188
+	SYS_FSTAT                          = 189
+	SYS_LSTAT                          = 190
+	SYS_PATHCONF                       = 191
+	SYS_FPATHCONF                      = 192
+	SYS_GETRLIMIT                      = 194
+	SYS_SETRLIMIT                      = 195
+	SYS_GETDIRENTRIES                  = 196
+	SYS_MMAP                           = 197
+	SYS_LSEEK                          = 199
+	SYS_TRUNCATE                       = 200
+	SYS_FTRUNCATE                      = 201
+	SYS___SYSCTL                       = 202
+	SYS_MLOCK                          = 203
+	SYS_MUNLOCK                        = 204
+	SYS_UNDELETE                       = 205
+	SYS_ATSOCKET                       = 206
+	SYS_ATGETMSG                       = 207
+	SYS_ATPUTMSG                       = 208
+	SYS_ATPSNDREQ                      = 209
+	SYS_ATPSNDRSP                      = 210
+	SYS_ATPGETREQ                      = 211
+	SYS_ATPGETRSP                      = 212
+	SYS_OPEN_DPROTECTED_NP             = 216
+	SYS_GETATTRLIST                    = 220
+	SYS_SETATTRLIST                    = 221
+	SYS_GETDIRENTRIESATTR              = 222
+	SYS_EXCHANGEDATA                   = 223
+	SYS_SEARCHFS                       = 225
+	SYS_DELETE                         = 226
+	SYS_COPYFILE                       = 227
+	SYS_FGETATTRLIST                   = 228
+	SYS_FSETATTRLIST                   = 229
+	SYS_POLL                           = 230
+	SYS_WATCHEVENT                     = 231
+	SYS_WAITEVENT                      = 232
+	SYS_MODWATCH                       = 233
+	SYS_GETXATTR                       = 234
+	SYS_FGETXATTR                      = 235
+	SYS_SETXATTR                       = 236
+	SYS_FSETXATTR                      = 237
+	SYS_REMOVEXATTR                    = 238
+	SYS_FREMOVEXATTR                   = 239
+	SYS_LISTXATTR                      = 240
+	SYS_FLISTXATTR                     = 241
+	SYS_FSCTL                          = 242
+	SYS_INITGROUPS                     = 243
+	SYS_POSIX_SPAWN                    = 244
+	SYS_FFSCTL                         = 245
+	SYS_NFSCLNT                        = 247
+	SYS_FHOPEN                         = 248
+	SYS_MINHERIT                       = 250
+	SYS_SEMSYS                         = 251
+	SYS_MSGSYS                         = 252
+	SYS_SHMSYS                         = 253
+	SYS_SEMCTL                         = 254
+	SYS_SEMGET                         = 255
+	SYS_SEMOP                          = 256
+	SYS_MSGCTL                         = 258
+	SYS_MSGGET                         = 259
+	SYS_MSGSND                         = 260
+	SYS_MSGRCV                         = 261
+	SYS_SHMAT                          = 262
+	SYS_SHMCTL                         = 263
+	SYS_SHMDT                          = 264
+	SYS_SHMGET                         = 265
+	SYS_SHM_OPEN                       = 266
+	SYS_SHM_UNLINK                     = 267
+	SYS_SEM_OPEN                       = 268
+	SYS_SEM_CLOSE                      = 269
+	SYS_SEM_UNLINK                     = 270
+	SYS_SEM_WAIT                       = 271
+	SYS_SEM_TRYWAIT                    = 272
+	SYS_SEM_POST                       = 273
+	SYS_SEM_GETVALUE                   = 274
+	SYS_SEM_INIT                       = 275
+	SYS_SEM_DESTROY                    = 276
+	SYS_OPEN_EXTENDED                  = 277
+	SYS_UMASK_EXTENDED                 = 278
+	SYS_STAT_EXTENDED                  = 279
+	SYS_LSTAT_EXTENDED                 = 280
+	SYS_FSTAT_EXTENDED                 = 281
+	SYS_CHMOD_EXTENDED                 = 282
+	SYS_FCHMOD_EXTENDED                = 283
+	SYS_ACCESS_EXTENDED                = 284
+	SYS_SETTID                         = 285
+	SYS_GETTID                         = 286
+	SYS_SETSGROUPS                     = 287
+	SYS_GETSGROUPS                     = 288
+	SYS_SETWGROUPS                     = 289
+	SYS_GETWGROUPS                     = 290
+	SYS_MKFIFO_EXTENDED                = 291
+	SYS_MKDIR_EXTENDED                 = 292
+	SYS_IDENTITYSVC                    = 293
+	SYS_SHARED_REGION_CHECK_NP         = 294
+	SYS_VM_PRESSURE_MONITOR            = 296
+	SYS_PSYNCH_RW_LONGRDLOCK           = 297
+	SYS_PSYNCH_RW_YIELDWRLOCK          = 298
+	SYS_PSYNCH_RW_DOWNGRADE            = 299
+	SYS_PSYNCH_RW_UPGRADE              = 300
+	SYS_PSYNCH_MUTEXWAIT               = 301
+	SYS_PSYNCH_MUTEXDROP               = 302
+	SYS_PSYNCH_CVBROAD                 = 303
+	SYS_PSYNCH_CVSIGNAL                = 304
+	SYS_PSYNCH_CVWAIT                  = 305
+	SYS_PSYNCH_RW_RDLOCK               = 306
+	SYS_PSYNCH_RW_WRLOCK               = 307
+	SYS_PSYNCH_RW_UNLOCK               = 308
+	SYS_PSYNCH_RW_UNLOCK2              = 309
+	SYS_GETSID                         = 310
+	SYS_SETTID_WITH_PID                = 311
+	SYS_PSYNCH_CVCLRPREPOST            = 312
+	SYS_AIO_FSYNC                      = 313
+	SYS_AIO_RETURN                     = 314
+	SYS_AIO_SUSPEND                    = 315
+	SYS_AIO_CANCEL                     = 316
+	SYS_AIO_ERROR                      = 317
+	SYS_AIO_READ                       = 318
+	SYS_AIO_WRITE                      = 319
+	SYS_LIO_LISTIO                     = 320
+	SYS_IOPOLICYSYS                    = 322
+	SYS_PROCESS_POLICY                 = 323
+	SYS_MLOCKALL                       = 324
+	SYS_MUNLOCKALL                     = 325
+	SYS_ISSETUGID                      = 327
+	SYS___PTHREAD_KILL                 = 328
+	SYS___PTHREAD_SIGMASK              = 329
+	SYS___SIGWAIT                      = 330
+	SYS___DISABLE_THREADSIGNAL         = 331
+	SYS___PTHREAD_MARKCANCEL           = 332
+	SYS___PTHREAD_CANCELED             = 333
+	SYS___SEMWAIT_SIGNAL               = 334
+	SYS_PROC_INFO                      = 336
+	SYS_SENDFILE                       = 337
+	SYS_STAT64                         = 338
+	SYS_FSTAT64                        = 339
+	SYS_LSTAT64                        = 340
+	SYS_STAT64_EXTENDED                = 341
+	SYS_LSTAT64_EXTENDED               = 342
+	SYS_FSTAT64_EXTENDED               = 343
+	SYS_GETDIRENTRIES64                = 344
+	SYS_STATFS64                       = 345
+	SYS_FSTATFS64                      = 346
+	SYS_GETFSSTAT64                    = 347
+	SYS___PTHREAD_CHDIR                = 348
+	SYS___PTHREAD_FCHDIR               = 349
+	SYS_AUDIT                          = 350
+	SYS_AUDITON                        = 351
+	SYS_GETAUID                        = 353
+	SYS_SETAUID                        = 354
+	SYS_GETAUDIT_ADDR                  = 357
+	SYS_SETAUDIT_ADDR                  = 358
+	SYS_AUDITCTL                       = 359
+	SYS_BSDTHREAD_CREATE               = 360
+	SYS_BSDTHREAD_TERMINATE            = 361
+	SYS_KQUEUE                         = 362
+	SYS_KEVENT                         = 363
+	SYS_LCHOWN                         = 364
+	SYS_STACK_SNAPSHOT                 = 365
+	SYS_BSDTHREAD_REGISTER             = 366
+	SYS_WORKQ_OPEN                     = 367
+	SYS_WORKQ_KERNRETURN               = 368
+	SYS_KEVENT64                       = 369
+	SYS___OLD_SEMWAIT_SIGNAL           = 370
+	SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL  = 371
+	SYS_THREAD_SELFID                  = 372
+	SYS_LEDGER                         = 373
+	SYS___MAC_EXECVE                   = 380
+	SYS___MAC_SYSCALL                  = 381
+	SYS___MAC_GET_FILE                 = 382
+	SYS___MAC_SET_FILE                 = 383
+	SYS___MAC_GET_LINK                 = 384
+	SYS___MAC_SET_LINK                 = 385
+	SYS___MAC_GET_PROC                 = 386
+	SYS___MAC_SET_PROC                 = 387
+	SYS___MAC_GET_FD                   = 388
+	SYS___MAC_SET_FD                   = 389
+	SYS___MAC_GET_PID                  = 390
+	SYS___MAC_GET_LCID                 = 391
+	SYS___MAC_GET_LCTX                 = 392
+	SYS___MAC_SET_LCTX                 = 393
+	SYS_SETLCID                        = 394
+	SYS_GETLCID                        = 395
+	SYS_READ_NOCANCEL                  = 396
+	SYS_WRITE_NOCANCEL                 = 397
+	SYS_OPEN_NOCANCEL                  = 398
+	SYS_CLOSE_NOCANCEL                 = 399
+	SYS_WAIT4_NOCANCEL                 = 400
+	SYS_RECVMSG_NOCANCEL               = 401
+	SYS_SENDMSG_NOCANCEL               = 402
+	SYS_RECVFROM_NOCANCEL              = 403
+	SYS_ACCEPT_NOCANCEL                = 404
+	SYS_MSYNC_NOCANCEL                 = 405
+	SYS_FCNTL_NOCANCEL                 = 406
+	SYS_SELECT_NOCANCEL                = 407
+	SYS_FSYNC_NOCANCEL                 = 408
+	SYS_CONNECT_NOCANCEL               = 409
+	SYS_SIGSUSPEND_NOCANCEL            = 410
+	SYS_READV_NOCANCEL                 = 411
+	SYS_WRITEV_NOCANCEL                = 412
+	SYS_SENDTO_NOCANCEL                = 413
+	SYS_PREAD_NOCANCEL                 = 414
+	SYS_PWRITE_NOCANCEL                = 415
+	SYS_WAITID_NOCANCEL                = 416
+	SYS_POLL_NOCANCEL                  = 417
+	SYS_MSGSND_NOCANCEL                = 418
+	SYS_MSGRCV_NOCANCEL                = 419
+	SYS_SEM_WAIT_NOCANCEL              = 420
+	SYS_AIO_SUSPEND_NOCANCEL           = 421
+	SYS___SIGWAIT_NOCANCEL             = 422
+	SYS___SEMWAIT_SIGNAL_NOCANCEL      = 423
+	SYS___MAC_MOUNT                    = 424
+	SYS___MAC_GET_MOUNT                = 425
+	SYS___MAC_GETFSSTAT                = 426
+	SYS_FSGETPATH                      = 427
+	SYS_AUDIT_SESSION_SELF             = 428
+	SYS_AUDIT_SESSION_JOIN             = 429
+	SYS_FILEPORT_MAKEPORT              = 430
+	SYS_FILEPORT_MAKEFD                = 431
+	SYS_AUDIT_SESSION_PORT             = 432
+	SYS_PID_SUSPEND                    = 433
+	SYS_PID_RESUME                     = 434
+	SYS_PID_HIBERNATE                  = 435
+	SYS_PID_SHUTDOWN_SOCKETS           = 436
+	SYS_SHARED_REGION_MAP_AND_SLIDE_NP = 438
+	SYS_KAS_INFO                       = 439
+	SYS_MAXSYSCALL                     = 440
+)
diff --git a/src/syscall/zsysnum_plan9_386.go b/src/syscall/zsysnum_plan9.go
similarity index 100%
rename from src/syscall/zsysnum_plan9_386.go
rename to src/syscall/zsysnum_plan9.go
diff --git a/src/syscall/zsysnum_plan9_amd64.go b/src/syscall/zsysnum_plan9_amd64.go
deleted file mode 100644
index 07498c4..0000000
--- a/src/syscall/zsysnum_plan9_amd64.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
-
-package syscall
-
-const (
-	SYS_SYSR1       = 0
-	SYS_BIND        = 2
-	SYS_CHDIR       = 3
-	SYS_CLOSE       = 4
-	SYS_DUP         = 5
-	SYS_ALARM       = 6
-	SYS_EXEC        = 7
-	SYS_EXITS       = 8
-	SYS_FAUTH       = 10
-	SYS_SEGBRK      = 12
-	SYS_OPEN        = 14
-	SYS_OSEEK       = 16
-	SYS_SLEEP       = 17
-	SYS_RFORK       = 19
-	SYS_PIPE        = 21
-	SYS_CREATE      = 22
-	SYS_FD2PATH     = 23
-	SYS_BRK_        = 24
-	SYS_REMOVE      = 25
-	SYS_NOTIFY      = 28
-	SYS_NOTED       = 29
-	SYS_SEGATTACH   = 30
-	SYS_SEGDETACH   = 31
-	SYS_SEGFREE     = 32
-	SYS_SEGFLUSH    = 33
-	SYS_RENDEZVOUS  = 34
-	SYS_UNMOUNT     = 35
-	SYS_SEMACQUIRE  = 37
-	SYS_SEMRELEASE  = 38
-	SYS_SEEK        = 39
-	SYS_FVERSION    = 40
-	SYS_ERRSTR      = 41
-	SYS_STAT        = 42
-	SYS_FSTAT       = 43
-	SYS_WSTAT       = 44
-	SYS_FWSTAT      = 45
-	SYS_MOUNT       = 46
-	SYS_AWAIT       = 47
-	SYS_PREAD       = 50
-	SYS_PWRITE      = 51
-	SYS_TSEMACQUIRE = 52
-	SYS_NSEC        = 53
-)
diff --git a/src/syscall/ztypes_darwin_arm64.go b/src/syscall/ztypes_darwin_arm64.go
new file mode 100644
index 0000000..65b02ae
--- /dev/null
+++ b/src/syscall/ztypes_darwin_arm64.go
@@ -0,0 +1,456 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package syscall
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec       int64
+	Usec      int32
+	Pad_cgo_0 [4]byte
+}
+
+type Timeval32 struct {
+	Sec  int32
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+	Dev           int32
+	Mode          uint16
+	Nlink         uint16
+	Ino           uint64
+	Uid           uint32
+	Gid           uint32
+	Rdev          int32
+	Pad_cgo_0     [4]byte
+	Atimespec     Timespec
+	Mtimespec     Timespec
+	Ctimespec     Timespec
+	Birthtimespec Timespec
+	Size          int64
+	Blocks        int64
+	Blksize       int32
+	Flags         uint32
+	Gen           uint32
+	Lspare        int32
+	Qspare        [2]int64
+}
+
+type Statfs_t struct {
+	Bsize       uint32
+	Iosize      int32
+	Blocks      uint64
+	Bfree       uint64
+	Bavail      uint64
+	Files       uint64
+	Ffree       uint64
+	Fsid        Fsid
+	Owner       uint32
+	Type        uint32
+	Flags       uint32
+	Fssubtype   uint32
+	Fstypename  [16]int8
+	Mntonname   [1024]int8
+	Mntfromname [1024]int8
+	Reserved    [8]uint32
+}
+
+type Flock_t struct {
+	Start  int64
+	Len    int64
+	Pid    int32
+	Type   int16
+	Whence int16
+}
+
+type Fstore_t struct {
+	Flags      uint32
+	Posmode    int32
+	Offset     int64
+	Length     int64
+	Bytesalloc int64
+}
+
+type Radvisory_t struct {
+	Offset    int64
+	Count     int32
+	Pad_cgo_0 [4]byte
+}
+
+type Fbootstraptransfer_t struct {
+	Offset int64
+	Length uint64
+	Buffer *byte
+}
+
+type Log2phys_t struct {
+	Flags       uint32
+	Contigbytes int64
+	Devoffset   int64
+}
+
+type Fsid struct {
+	Val [2]int32
+}
+
+type Dirent struct {
+	Ino       uint64
+	Seekoff   uint64
+	Reclen    uint16
+	Namlen    uint16
+	Type      uint8
+	Name      [1024]int8
+	Pad_cgo_0 [3]byte
+}
+
+type RawSockaddrInet4 struct {
+	Len    uint8
+	Family uint8
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]int8
+}
+
+type RawSockaddrInet6 struct {
+	Len      uint8
+	Family   uint8
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+	Len    uint8
+	Family uint8
+	Path   [104]int8
+}
+
+type RawSockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [12]int8
+}
+
+type RawSockaddr struct {
+	Len    uint8
+	Family uint8
+	Data   [14]int8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+	Onoff  int32
+	Linger int32
+}
+
+type Iovec struct {
+	Base *byte
+	Len  uint64
+}
+
+type IPMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+	Multiaddr [16]byte /* in6_addr */
+	Interface uint32
+}
+
+type Msghdr struct {
+	Name       *byte
+	Namelen    uint32
+	Pad_cgo_0  [4]byte
+	Iov        *Iovec
+	Iovlen     int32
+	Pad_cgo_1  [4]byte
+	Control    *byte
+	Controllen uint32
+	Flags      int32
+}
+
+type Cmsghdr struct {
+	Len   uint32
+	Level int32
+	Type  int32
+}
+
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+	Addr    [16]byte /* in6_addr */
+	Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+	Addr RawSockaddrInet6
+	Mtu  uint32
+}
+
+type ICMPv6Filter struct {
+	Filt [8]uint32
+}
+
+const (
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x14
+	SizeofLinger           = 0x8
+	SizeofIPMreq           = 0x8
+	SizeofIPv6Mreq         = 0x14
+	SizeofMsghdr           = 0x30
+	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
+	SizeofInet6Pktinfo     = 0x14
+	SizeofIPv6MTUInfo      = 0x20
+	SizeofICMPv6Filter     = 0x20
+)
+
+const (
+	PTRACE_TRACEME = 0x0
+	PTRACE_CONT    = 0x7
+	PTRACE_KILL    = 0x8
+)
+
+type Kevent_t struct {
+	Ident  uint64
+	Filter int16
+	Flags  uint16
+	Fflags uint32
+	Data   int64
+	Udata  *byte
+}
+
+type FdSet struct {
+	Bits [32]int32
+}
+
+const (
+	SizeofIfMsghdr    = 0x70
+	SizeofIfData      = 0x60
+	SizeofIfaMsghdr   = 0x14
+	SizeofIfmaMsghdr  = 0x10
+	SizeofIfmaMsghdr2 = 0x14
+	SizeofRtMsghdr    = 0x5c
+	SizeofRtMetrics   = 0x38
+)
+
+type IfMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Data      IfData
+}
+
+type IfData struct {
+	Type       uint8
+	Typelen    uint8
+	Physical   uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Recvquota  uint8
+	Xmitquota  uint8
+	Unused1    uint8
+	Mtu        uint32
+	Metric     uint32
+	Baudrate   uint32
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Recvtiming uint32
+	Xmittiming uint32
+	Lastchange Timeval32
+	Unused2    uint32
+	Hwassist   uint32
+	Reserved1  uint32
+	Reserved2  uint32
+}
+
+type IfaMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Metric    int32
+}
+
+type IfmaMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+}
+
+type IfmaMsghdr2 struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Refcount  int32
+}
+
+type RtMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Flags     int32
+	Addrs     int32
+	Pid       int32
+	Seq       int32
+	Errno     int32
+	Use       int32
+	Inits     uint32
+	Rmx       RtMetrics
+}
+
+type RtMetrics struct {
+	Locks    uint32
+	Mtu      uint32
+	Hopcount uint32
+	Expire   int32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+	Filler   [4]uint32
+}
+
+const (
+	SizeofBpfVersion = 0x4
+	SizeofBpfStat    = 0x8
+	SizeofBpfProgram = 0x10
+	SizeofBpfInsn    = 0x8
+	SizeofBpfHdr     = 0x14
+)
+
+type BpfVersion struct {
+	Major uint16
+	Minor uint16
+}
+
+type BpfStat struct {
+	Recv uint32
+	Drop uint32
+}
+
+type BpfProgram struct {
+	Len       uint32
+	Pad_cgo_0 [4]byte
+	Insns     *BpfInsn
+}
+
+type BpfInsn struct {
+	Code uint16
+	Jt   uint8
+	Jf   uint8
+	K    uint32
+}
+
+type BpfHdr struct {
+	Tstamp    Timeval32
+	Caplen    uint32
+	Datalen   uint32
+	Hdrlen    uint16
+	Pad_cgo_0 [2]byte
+}
+
+type Termios struct {
+	Iflag     uint64
+	Oflag     uint64
+	Cflag     uint64
+	Lflag     uint64
+	Cc        [20]uint8
+	Pad_cgo_0 [4]byte
+	Ispeed    uint64
+	Ospeed    uint64
+}
diff --git a/src/syscall/ztypes_plan9_386.go b/src/syscall/ztypes_plan9_386.go
deleted file mode 100644
index 3e3a8d1..0000000
--- a/src/syscall/ztypes_plan9_386.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// godefs -gsyscall -f -m32 types_plan9.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package syscall
-
-// Constants
-const (
-	O_RDONLY   = 0
-	O_WRONLY   = 0x1
-	O_RDWR     = 0x2
-	O_TRUNC    = 0x10
-	O_CLOEXEC  = 0x20
-	O_EXCL     = 0x1000
-	STATMAX    = 0xffff
-	ERRMAX     = 0x80
-	MORDER     = 0x3
-	MREPL      = 0
-	MBEFORE    = 0x1
-	MAFTER     = 0x2
-	MCREATE    = 0x4
-	MCACHE     = 0x10
-	MMASK      = 0x17
-	RFNAMEG    = 0x1
-	RFENVG     = 0x2
-	RFFDG      = 0x4
-	RFNOTEG    = 0x8
-	RFPROC     = 0x10
-	RFMEM      = 0x20
-	RFNOWAIT   = 0x40
-	RFCNAMEG   = 0x400
-	RFCENVG    = 0x800
-	RFCFDG     = 0x1000
-	RFREND     = 0x2000
-	RFNOMNT    = 0x4000
-	QTDIR      = 0x80
-	QTAPPEND   = 0x40
-	QTEXCL     = 0x20
-	QTMOUNT    = 0x10
-	QTAUTH     = 0x8
-	QTTMP      = 0x4
-	QTFILE     = 0
-	DMDIR      = 0x80000000
-	DMAPPEND   = 0x40000000
-	DMEXCL     = 0x20000000
-	DMMOUNT    = 0x10000000
-	DMAUTH     = 0x8000000
-	DMTMP      = 0x4000000
-	DMREAD     = 0x4
-	DMWRITE    = 0x2
-	DMEXEC     = 0x1
-	STATFIXLEN = 0x31
-)
-
-// Types
-
-type _C_int int32
-
-type Prof struct {
-	Pp    *[0]byte /* sPlink */
-	Next  *[0]byte /* sPlink */
-	Last  *[0]byte /* sPlink */
-	First *[0]byte /* sPlink */
-	Pid   uint32
-	What  uint32
-}
-
-type Tos struct {
-	Prof      Prof
-	Cyclefreq uint64
-	Kcycles   int64
-	Pcycles   int64
-	Pid       uint32
-	Clock     uint32
-}
diff --git a/src/syscall/ztypes_plan9_amd64.go b/src/syscall/ztypes_plan9_amd64.go
deleted file mode 100644
index 3e3a8d1..0000000
--- a/src/syscall/ztypes_plan9_amd64.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// godefs -gsyscall -f -m32 types_plan9.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package syscall
-
-// Constants
-const (
-	O_RDONLY   = 0
-	O_WRONLY   = 0x1
-	O_RDWR     = 0x2
-	O_TRUNC    = 0x10
-	O_CLOEXEC  = 0x20
-	O_EXCL     = 0x1000
-	STATMAX    = 0xffff
-	ERRMAX     = 0x80
-	MORDER     = 0x3
-	MREPL      = 0
-	MBEFORE    = 0x1
-	MAFTER     = 0x2
-	MCREATE    = 0x4
-	MCACHE     = 0x10
-	MMASK      = 0x17
-	RFNAMEG    = 0x1
-	RFENVG     = 0x2
-	RFFDG      = 0x4
-	RFNOTEG    = 0x8
-	RFPROC     = 0x10
-	RFMEM      = 0x20
-	RFNOWAIT   = 0x40
-	RFCNAMEG   = 0x400
-	RFCENVG    = 0x800
-	RFCFDG     = 0x1000
-	RFREND     = 0x2000
-	RFNOMNT    = 0x4000
-	QTDIR      = 0x80
-	QTAPPEND   = 0x40
-	QTEXCL     = 0x20
-	QTMOUNT    = 0x10
-	QTAUTH     = 0x8
-	QTTMP      = 0x4
-	QTFILE     = 0
-	DMDIR      = 0x80000000
-	DMAPPEND   = 0x40000000
-	DMEXCL     = 0x20000000
-	DMMOUNT    = 0x10000000
-	DMAUTH     = 0x8000000
-	DMTMP      = 0x4000000
-	DMREAD     = 0x4
-	DMWRITE    = 0x2
-	DMEXEC     = 0x1
-	STATFIXLEN = 0x31
-)
-
-// Types
-
-type _C_int int32
-
-type Prof struct {
-	Pp    *[0]byte /* sPlink */
-	Next  *[0]byte /* sPlink */
-	Last  *[0]byte /* sPlink */
-	First *[0]byte /* sPlink */
-	Pid   uint32
-	What  uint32
-}
-
-type Tos struct {
-	Prof      Prof
-	Cyclefreq uint64
-	Kcycles   int64
-	Pcycles   int64
-	Pid       uint32
-	Clock     uint32
-}
diff --git a/src/testing/quick/quick_test.go b/src/testing/quick/quick_test.go
index ca340fe..1b97302 100644
--- a/src/testing/quick/quick_test.go
+++ b/src/testing/quick/quick_test.go
@@ -10,6 +10,12 @@
 	"testing"
 )
 
+func fArray(a [4]byte) [4]byte { return a }
+
+type TestArrayAlias [4]byte
+
+func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a }
+
 func fBool(a bool) bool { return a }
 
 type TestBoolAlias bool
@@ -76,6 +82,15 @@
 
 func fMapAlias(a TestMapAlias) TestMapAlias { return a }
 
+func fPtr(a *int) *int {
+	b := *a
+	return &b
+}
+
+type TestPtrAlias *int
+
+func fPtrAlias(a TestPtrAlias) TestPtrAlias { return a }
+
 func fSlice(a []byte) []byte { return a }
 
 type TestSliceAlias []byte
@@ -135,21 +150,6 @@
 
 func fUintptrAlias(a TestUintptrAlias) TestUintptrAlias { return a }
 
-func fIntptr(a *int) *int {
-	b := *a
-	return &b
-}
-
-type TestIntptrAlias *int
-
-func fIntptrAlias(a TestIntptrAlias) TestIntptrAlias { return a }
-
-func fArray(a [4]byte) [4]byte { return a }
-
-type TestArrayAlias [4]byte
-
-func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a }
-
 func reportError(property string, err error, t *testing.T) {
 	if err != nil {
 		t.Errorf("%s: %s", property, err)
@@ -157,6 +157,8 @@
 }
 
 func TestCheckEqual(t *testing.T) {
+	reportError("fArray", CheckEqual(fArray, fArray, nil), t)
+	reportError("fArrayAlias", CheckEqual(fArrayAlias, fArrayAlias, nil), t)
 	reportError("fBool", CheckEqual(fBool, fBool, nil), t)
 	reportError("fBoolAlias", CheckEqual(fBoolAlias, fBoolAlias, nil), t)
 	reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
@@ -181,6 +183,8 @@
 	reportError("fInt32Alias", CheckEqual(fInt32Alias, fInt32Alias, nil), t)
 	reportError("fMap", CheckEqual(fMap, fMap, nil), t)
 	reportError("fMapAlias", CheckEqual(fMapAlias, fMapAlias, nil), t)
+	reportError("fPtr", CheckEqual(fPtr, fPtr, nil), t)
+	reportError("fPtrAlias", CheckEqual(fPtrAlias, fPtrAlias, nil), t)
 	reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
 	reportError("fSliceAlias", CheckEqual(fSliceAlias, fSliceAlias, nil), t)
 	reportError("fString", CheckEqual(fString, fString, nil), t)
@@ -199,10 +203,6 @@
 	reportError("fUintAlias", CheckEqual(fUintAlias, fUintAlias, nil), t)
 	reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
 	reportError("fUintptrAlias", CheckEqual(fUintptrAlias, fUintptrAlias, nil), t)
-	reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
-	reportError("fIntptrAlias", CheckEqual(fIntptrAlias, fIntptrAlias, nil), t)
-	reportError("fArray", CheckEqual(fArray, fArray, nil), t)
-	reportError("fArrayAlais", CheckEqual(fArrayAlias, fArrayAlias, nil), t)
 }
 
 // This tests that ArbitraryValue is working by checking that all the arbitrary
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 5163123..280d76a 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -342,13 +342,15 @@
 }
 
 // Log formats its arguments using default formatting, analogous to Println,
-// and records the text in the error log. The text will be printed only if
-// the test fails or the -test.v flag is set.
+// and records the text in the error log. For tests, the text will be printed only if
+// the test fails or the -test.v flag is set. For benchmarks, the text is always
+// printed to avoid having performance depend on the value of the -test.v flag.
 func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
 
 // Logf formats its arguments according to the format, analogous to Printf,
-// and records the text in the error log. The text will be printed only if
-// the test fails or the -test.v flag is set.
+// and records the text in the error log. For tests, the text will be printed only if
+// the test fails or the -test.v flag is set. For benchmarks, the text is always
+// printed to avoid having performance depend on the value of the -test.v flag.
 func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
 
 // Error is equivalent to Log followed by Fail.
diff --git a/src/text/template/doc.go b/src/text/template/doc.go
index 223c595..0ce63f6 100644
--- a/src/text/template/doc.go
+++ b/src/text/template/doc.go
@@ -18,7 +18,7 @@
 The input text for a template is UTF-8-encoded text in any format.
 "Actions"--data evaluations or control structures--are delimited by
 "{{" and "}}"; all text outside actions is copied to the output unchanged.
-Actions may not span newlines, although comments can.
+Except for raw strings, actions may not span newlines, although comments can.
 
 Once parsed, a template may be executed safely in parallel.
 
@@ -106,7 +106,7 @@
 
 	- A boolean, string, character, integer, floating-point, imaginary
 	  or complex constant in Go syntax. These behave like Go's untyped
-	  constants, although raw strings may not span newlines.
+	  constants.
 	- The keyword nil, representing an untyped Go nil.
 	- The character '.' (period):
 		.
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index 613a778..e6e1287 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -519,7 +519,18 @@
 			if hasArgs {
 				s.errorf("%s is not a method but has arguments", fieldName)
 			}
-			return receiver.MapIndex(nameVal)
+			result := receiver.MapIndex(nameVal)
+			if !result.IsValid() {
+				switch s.tmpl.option.missingKey {
+				case mapInvalid:
+					// Just use the invalid value.
+				case mapZeroValue:
+					result = reflect.Zero(receiver.Type().Elem())
+				case mapError:
+					s.errorf("map has no entry for key %q", fieldName)
+				}
+			}
+			return result
 		}
 	}
 	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index b1f7787..abce27f 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -527,8 +527,10 @@
 	{"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
 	// Chained nodes did not work as arguments. Issue 8473.
 	{"bug13", "{{print (.Copy).I}}", "17", tVal, true},
-	// Didn't protect against explicit nil in field chains.
-	{"bug14", "{{nil.True}}", "", tVal, false},
+	// Didn't protect against nil or literal values in field chains.
+	{"bug14a", "{{(nil).True}}", "", tVal, false},
+	{"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
+	{"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
 }
 
 func zeroArgs() string {
@@ -1044,3 +1046,67 @@
 		}
 	}
 }
+
+func TestMissingMapKey(t *testing.T) {
+	data := map[string]int{
+		"x": 99,
+	}
+	tmpl, err := New("t1").Parse("{{.x}} {{.y}}")
+	if err != nil {
+		t.Fatal(err)
+	}
+	var b bytes.Buffer
+	// By default, just get "<no value>"
+	err = tmpl.Execute(&b, data)
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := "99 <no value>"
+	got := b.String()
+	if got != want {
+		t.Errorf("got %q; expected %q", got, want)
+	}
+	// Same if we set the option explicitly to the default.
+	tmpl.Option("missingkey=default")
+	b.Reset()
+	err = tmpl.Execute(&b, data)
+	if err != nil {
+		t.Fatal("default:", err)
+	}
+	want = "99 <no value>"
+	got = b.String()
+	if got != want {
+		t.Errorf("got %q; expected %q", got, want)
+	}
+	// Next we ask for a zero value
+	tmpl.Option("missingkey=zero")
+	b.Reset()
+	err = tmpl.Execute(&b, data)
+	if err != nil {
+		t.Fatal("zero:", err)
+	}
+	want = "99 0"
+	got = b.String()
+	if got != want {
+		t.Errorf("got %q; expected %q", got, want)
+	}
+	// Now we ask for an error.
+	tmpl.Option("missingkey=error")
+	err = tmpl.Execute(&b, data)
+	if err == nil {
+		t.Errorf("expected error; got none")
+	}
+}
+
+// Test that the error message for multiline unterminated string
+// refers to the line number of the opening quote.
+func TestUnterminatedStringError(t *testing.T) {
+	_, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n")
+	if err == nil {
+		t.Fatal("expected error")
+	}
+	str := err.Error()
+	if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") {
+		t.Fatalf("unexpected error: %s", str)
+	}
+}
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index 39ee5ed..cdd187b 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -590,7 +590,7 @@
 			a, ok := printableValue(reflect.ValueOf(arg))
 			if ok {
 				args[i] = a
-			} // else left fmt do its thing
+			} // else let fmt do its thing
 		}
 		s = fmt.Sprint(args...)
 	}
diff --git a/src/text/template/option.go b/src/text/template/option.go
new file mode 100644
index 0000000..fcdd871
--- /dev/null
+++ b/src/text/template/option.go
@@ -0,0 +1,73 @@
+// 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.
+
+// This file contains the code to handle template options.
+
+package template
+
+import "strings"
+
+// missingKeyAction defines how to respond to indexing a map with a key that is not present.
+type missingKeyAction int
+
+const (
+	mapInvalid   missingKeyAction = iota // Return an invalid reflect.Value.
+	mapZeroValue                         // Return the zero value for the map element.
+	mapError                             // Error out
+)
+
+type option struct {
+	missingKey missingKeyAction
+}
+
+// Option sets options for the template. Options are described by
+// strings, either a simple string or "key=value". There can be at
+// most one equals sign in an option string. If the option string
+// is unrecognized or otherwise invalid, Option panics.
+//
+// Known options:
+//
+// missingkey: Control the behavior during execution if a map is
+// indexed with a key that is not present in the map.
+//	"missingkey=default" or "missingkey=invalid"
+//		The default behavior: Do nothing and continue execution.
+//		If printed, the result of the index operation is the string
+//		"<no value>".
+//	"missingkey=zero"
+//		The operation returns the zero value for the map type's element.
+//	"missingkey=error"
+//		Execution stops immediately with an error.
+//
+func (t *Template) Option(opt ...string) *Template {
+	for _, s := range opt {
+		t.setOption(s)
+	}
+	return t
+}
+
+func (t *Template) setOption(opt string) {
+	if opt == "" {
+		panic("empty option string")
+	}
+	elems := strings.Split(opt, "=")
+	switch len(elems) {
+	case 2:
+		// key=value
+		switch elems[0] {
+		case "missingkey":
+			switch elems[1] {
+			case "invalid", "default":
+				t.option.missingKey = mapInvalid
+				return
+			case "zero":
+				t.option.missingKey = mapZeroValue
+				return
+			case "error":
+				t.option.missingKey = mapError
+				return
+			}
+		}
+	}
+	panic("unrecognized option: " + opt)
+}
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index 1674aaf..8f9fe1d 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -167,12 +167,20 @@
 }
 
 // nextItem returns the next item from the input.
+// Called by the parser, not in the lexing goroutine.
 func (l *lexer) nextItem() item {
 	item := <-l.items
 	l.lastPos = item.pos
 	return item
 }
 
+// drain drains the output so the lexing goroutine will exit.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) drain() {
+	for range l.items {
+	}
+}
+
 // lex creates a new scanner for the input string.
 func lex(name, input, left, right string) *lexer {
 	if left == "" {
@@ -197,6 +205,7 @@
 	for l.state = lexText; l.state != nil; {
 		l.state = l.state(l)
 	}
+	close(l.items)
 }
 
 // state functions
@@ -313,14 +322,12 @@
 	case r == '(':
 		l.emit(itemLeftParen)
 		l.parenDepth++
-		return lexInsideAction
 	case r == ')':
 		l.emit(itemRightParen)
 		l.parenDepth--
 		if l.parenDepth < 0 {
 			return l.errorf("unexpected right paren %#U", r)
 		}
-		return lexInsideAction
 	case r <= unicode.MaxASCII && unicode.IsPrint(r):
 		l.emit(itemChar)
 		return lexInsideAction
@@ -525,7 +532,7 @@
 Loop:
 	for {
 		switch l.next() {
-		case eof, '\n':
+		case eof:
 			return l.errorf("unterminated raw quoted string")
 		case '`':
 			break Loop
diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go
index d251ccf..be551d8 100644
--- a/src/text/template/parse/lex_test.go
+++ b/src/text/template/parse/lex_test.go
@@ -58,18 +58,20 @@
 }
 
 var (
-	tEOF      = item{itemEOF, 0, ""}
-	tFor      = item{itemIdentifier, 0, "for"}
-	tLeft     = item{itemLeftDelim, 0, "{{"}
-	tLpar     = item{itemLeftParen, 0, "("}
-	tPipe     = item{itemPipe, 0, "|"}
-	tQuote    = item{itemString, 0, `"abc \n\t\" "`}
-	tRange    = item{itemRange, 0, "range"}
-	tRight    = item{itemRightDelim, 0, "}}"}
-	tRpar     = item{itemRightParen, 0, ")"}
-	tSpace    = item{itemSpace, 0, " "}
-	raw       = "`" + `abc\n\t\" ` + "`"
-	tRawQuote = item{itemRawString, 0, raw}
+	tEOF        = item{itemEOF, 0, ""}
+	tFor        = item{itemIdentifier, 0, "for"}
+	tLeft       = item{itemLeftDelim, 0, "{{"}
+	tLpar       = item{itemLeftParen, 0, "("}
+	tPipe       = item{itemPipe, 0, "|"}
+	tQuote      = item{itemString, 0, `"abc \n\t\" "`}
+	tRange      = item{itemRange, 0, "range"}
+	tRight      = item{itemRightDelim, 0, "}}"}
+	tRpar       = item{itemRightParen, 0, ")"}
+	tSpace      = item{itemSpace, 0, " "}
+	raw         = "`" + `abc\n\t\" ` + "`"
+	rawNL       = "`now is{{\n}}the time`" // Contains newline inside raw quote.
+	tRawQuote   = item{itemRawString, 0, raw}
+	tRawQuoteNL = item{itemRawString, 0, rawNL}
 )
 
 var lexTests = []lexTest{
@@ -104,6 +106,7 @@
 	{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
 	{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
 	{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
+	{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
 	{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
 		tLeft,
 		{itemNumber, 0, "1"},
@@ -294,7 +297,7 @@
 		tLeft,
 		{itemError, 0, "unterminated quoted string"},
 	}},
-	{"unclosed raw quote", "{{`xx\n`}}", []item{
+	{"unclosed raw quote", "{{`xx}}", []item{
 		tLeft,
 		{itemError, 0, "unterminated raw quoted string"},
 	}},
@@ -463,3 +466,31 @@
 		}
 	}
 }
+
+// Test that an error shuts down the lexing goroutine.
+func TestShutdown(t *testing.T) {
+	// We need to duplicate template.Parse here to hold on to the lexer.
+	const text = "erroneous{{define}}{{else}}1234"
+	lexer := lex("foo", text, "{{", "}}")
+	_, err := New("root").parseLexer(lexer, text)
+	if err == nil {
+		t.Fatalf("expected error")
+	}
+	// The error should have drained the input. Therefore, the lexer should be shut down.
+	token, ok := <-lexer.items
+	if ok {
+		t.Fatalf("input was not drained; got %v", token)
+	}
+}
+
+// parseLexer is a local version of parse that lets us pass in the lexer instead of building it.
+// We expect an error, so the tree set and funcs list are explicitly nil.
+func (t *Tree) parseLexer(lex *lexer, text string) (tree *Tree, err error) {
+	defer t.recover(&err)
+	t.ParseName = t.Name
+	t.startParse(nil, lex)
+	t.parse(nil)
+	t.add(nil)
+	t.stopParse()
+	return t, nil
+}
diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go
index 55c37f6..728181b 100644
--- a/src/text/template/parse/node.go
+++ b/src/text/template/parse/node.go
@@ -592,6 +592,11 @@
 	} else {
 		f, err := strconv.ParseFloat(text, 64)
 		if err == nil {
+			// If we parsed it as a float but it looks like an integer,
+			// it's a huge number too large to fit in an int. Reject it.
+			if !strings.ContainsAny(text, ".eE") {
+				return nil, fmt.Errorf("integer overflow: %q", text)
+			}
 			n.IsFloat = true
 			n.Float64 = f
 			// If a floating-point extraction succeeded, extract the int if needed.
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index af33880..88aacd1 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -196,6 +196,7 @@
 			panic(e)
 		}
 		if t != nil {
+			t.lex.drain()
 			t.stopParse()
 		}
 		*errp = e.(error)
@@ -288,11 +289,12 @@
 			}
 			t.backup2(delim)
 		}
-		n := t.textOrAction()
-		if n.Type() == nodeEnd {
+		switch n := t.textOrAction(); n.Type() {
+		case nodeEnd, nodeElse:
 			t.errorf("unexpected %s", n)
+		default:
+			t.Root.append(n)
 		}
-		t.Root.append(n)
 	}
 	return nil
 }
@@ -411,9 +413,8 @@
 	for {
 		switch token := t.nextNonSpace(); token.typ {
 		case itemRightDelim, itemRightParen:
-			if len(pipe.Cmds) == 0 {
-				t.errorf("missing value for %s", context)
-			}
+			// At this point, the pipeline is complete
+			t.checkPipeline(pipe, context)
 			if token.typ == itemRightParen {
 				t.backup()
 			}
@@ -428,6 +429,21 @@
 	}
 }
 
+func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
+	// Reject empty pipelines
+	if len(pipe.Cmds) == 0 {
+		t.errorf("missing value for %s", context)
+	}
+	// Only the first command of a pipeline can start with a non executable operand
+	for i, c := range pipe.Cmds[1:] {
+		switch c.Args[0].Type() {
+		case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
+			// With A|B|C, pipeline stage 2 is B
+			t.errorf("non executable command in pipeline stage %d", i+2)
+		}
+	}
+}
+
 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
 	defer t.popVars(len(t.vars))
 	line = t.lex.lineNumber()
@@ -553,7 +569,7 @@
 			t.backup()
 		case itemPipe:
 		default:
-			t.errorf("unexpected %s in operand; missing space?", token)
+			t.errorf("unexpected %s in operand", token)
 		}
 		break
 	}
@@ -581,12 +597,15 @@
 		// Compatibility with original API: If the term is of type NodeField
 		// or NodeVariable, just put more fields on the original.
 		// Otherwise, keep the Chain node.
-		// TODO: Switch to Chains always when we can.
+		// Obvious parsing errors involving literal values are detected here.
+		// More complex error cases will have to be handled at execution time.
 		switch node.Type() {
 		case NodeField:
 			node = t.newField(chain.Position(), chain.String())
 		case NodeVariable:
 			node = t.newVariable(chain.Position(), chain.String())
+		case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
+			t.errorf("unexpected . after term %q", node.String())
 		default:
 			node = chain
 		}
diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go
index 4a504fa..9e62bd2 100644
--- a/src/text/template/parse/parse_test.go
+++ b/src/text/template/parse/parse_test.go
@@ -69,6 +69,7 @@
 	{text: "1+2."},
 	{text: "'x"},
 	{text: "'xx'"},
+	{text: "'433937734937734969526500969526500'"}, // Integer too large - issue 10634.
 	// Issue 8622 - 0xe parsed as floating point. Very embarrassing.
 	{"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0},
 }
@@ -230,6 +231,9 @@
 	// Errors.
 	{"unclosed action", "hello{{range", hasError, ""},
 	{"unmatched end", "{{end}}", hasError, ""},
+	{"unmatched else", "{{else}}", hasError, ""},
+	{"unmatched else after if", "{{if .X}}hello{{end}}{{else}}", hasError, ""},
+	{"multiple else", "{{if .X}}1{{else}}2{{else}}3{{end}}", hasError, ""},
 	{"missing end", "hello{{range .x}}", hasError, ""},
 	{"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
 	{"undefined function", "hello{{undefined}}", hasError, ""},
@@ -257,6 +261,22 @@
 	{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""},                     // ! is just illegal here.
 	{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""},                     // $x+2 should not parse as ($x) (+2).
 	{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
+	// dot following a literal value
+	{"dot after integer", "{{1.E}}", hasError, ""},
+	{"dot after float", "{{0.1.E}}", hasError, ""},
+	{"dot after boolean", "{{true.E}}", hasError, ""},
+	{"dot after char", "{{'a'.any}}", hasError, ""},
+	{"dot after string", `{{"hello".guys}}`, hasError, ""},
+	{"dot after dot", "{{..E}}", hasError, ""},
+	{"dot after nil", "{{nil.E}}", hasError, ""},
+	// Wrong pipeline
+	{"wrong pipeline dot", "{{12|.}}", hasError, ""},
+	{"wrong pipeline number", "{{.|12|printf}}", hasError, ""},
+	{"wrong pipeline string", "{{.|print|\"error\"}}", hasError, ""},
+	{"wrong pipeline char", "{{12|print|html|'e'}}", hasError, ""},
+	{"wrong pipeline boolean", "{{.|true}}", hasError, ""},
+	{"wrong pipeline nil", "{{'c'|nil}}", hasError, ""},
+	{"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
 }
 
 var builtins = map[string]interface{}{
@@ -375,7 +395,7 @@
 		hasError, `unexpected ")"`},
 	{"space",
 		"{{`x`3}}",
-		hasError, `missing space?`},
+		hasError, `in operand`},
 	{"idchar",
 		"{{a#}}",
 		hasError, `'#'`},
@@ -407,6 +427,15 @@
 	{"undefvar",
 		"{{$a}}",
 		hasError, `undefined variable`},
+	{"wrongdot",
+		"{{true.any}}",
+		hasError, `unexpected . after term`},
+	{"wrongpipeline",
+		"{{12|false}}",
+		hasError, `non executable command in pipeline`},
+	{"emptypipeline",
+		`{{ ( ) }}`,
+		hasError, `missing value for parenthesized pipeline`},
 }
 
 func TestErrors(t *testing.T) {
diff --git a/src/text/template/template.go b/src/text/template/template.go
index 249d0cb..8611faa 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -18,6 +18,7 @@
 	// expose reflection to the client.
 	parseFuncs FuncMap
 	execFuncs  map[string]reflect.Value
+	option     option
 }
 
 // Template is the representation of a parsed template. The *parse.Tree
diff --git a/src/time/format.go b/src/time/format.go
index 5716108..b15101e 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -315,36 +315,34 @@
 	return -1, val, errBad
 }
 
-// appendUint appends the decimal form of x to b and returns the result.
-// If x is a single-digit number and pad != 0, appendUint inserts the pad byte
-// before the digit.
+// appendInt appends the decimal form of x to b and returns the result.
+// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's.
 // Duplicates functionality in strconv, but avoids dependency.
-func appendUint(b []byte, x uint, pad byte) []byte {
-	if x < 10 {
-		if pad != 0 {
-			b = append(b, pad)
-		}
-		return append(b, byte('0'+x))
-	}
-	if x < 100 {
-		b = append(b, byte('0'+x/10))
-		b = append(b, byte('0'+x%10))
-		return b
+func appendInt(b []byte, x int, width int) []byte {
+	u := uint(x)
+	if x < 0 {
+		b = append(b, '-')
+		u = uint(-x)
 	}
 
-	var buf [32]byte
-	n := len(buf)
-	if x == 0 {
-		return append(b, '0')
+	// Assemble decimal in reverse order.
+	var buf [20]byte
+	i := len(buf)
+	for u >= 10 {
+		i--
+		q := u / 10
+		buf[i] = byte('0' + u - q*10)
+		u = q
 	}
-	for x >= 10 {
-		n--
-		buf[n] = byte(x%10 + '0')
-		x /= 10
+	i--
+	buf[i] = byte('0' + u)
+
+	// Add 0-padding.
+	for w := len(buf) - i; w < width; w++ {
+		b = append(b, '0')
 	}
-	n--
-	buf[n] = byte(x + '0')
-	return append(b, buf[n:]...)
+
+	return append(b, buf[i:]...)
 }
 
 // Never printed, just needs to be non-nil for return by atoi.
@@ -412,6 +410,22 @@
 // about the formats and the definition of the reference time, see the
 // documentation for ANSIC and the other constants defined by this package.
 func (t Time) Format(layout string) string {
+	const bufSize = 64
+	var b []byte
+	max := len(layout) + 10
+	if max < bufSize {
+		var buf [bufSize]byte
+		b = buf[:0]
+	} else {
+		b = make([]byte, 0, max)
+	}
+	b = t.AppendFormat(b, layout)
+	return string(b)
+}
+
+// AppendFormat is like Format but appends the textual
+// representation to b and returns the extended buffer.
+func (t Time) AppendFormat(b []byte, layout string) []byte {
 	var (
 		name, offset, abs = t.locabs()
 
@@ -421,16 +435,7 @@
 		hour  int = -1
 		min   int
 		sec   int
-
-		b   []byte
-		buf [64]byte
 	)
-	max := len(layout) + 10
-	if max <= len(buf) {
-		b = buf[:0]
-	} else {
-		b = make([]byte, 0, max)
-	}
 	// Each iteration generates one std value.
 	for layout != "" {
 		prefix, std, suffix := nextStdChunk(layout)
@@ -458,75 +463,56 @@
 			if y < 0 {
 				y = -y
 			}
-			b = appendUint(b, uint(y%100), '0')
+			b = appendInt(b, y%100, 2)
 		case stdLongYear:
-			// Pad year to at least 4 digits.
-			y := year
-			switch {
-			case year <= -1000:
-				b = append(b, '-')
-				y = -y
-			case year <= -100:
-				b = append(b, "-0"...)
-				y = -y
-			case year <= -10:
-				b = append(b, "-00"...)
-				y = -y
-			case year < 0:
-				b = append(b, "-000"...)
-				y = -y
-			case year < 10:
-				b = append(b, "000"...)
-			case year < 100:
-				b = append(b, "00"...)
-			case year < 1000:
-				b = append(b, '0')
-			}
-			b = appendUint(b, uint(y), 0)
+			b = appendInt(b, year, 4)
 		case stdMonth:
 			b = append(b, month.String()[:3]...)
 		case stdLongMonth:
 			m := month.String()
 			b = append(b, m...)
 		case stdNumMonth:
-			b = appendUint(b, uint(month), 0)
+			b = appendInt(b, int(month), 0)
 		case stdZeroMonth:
-			b = appendUint(b, uint(month), '0')
+			b = appendInt(b, int(month), 2)
 		case stdWeekDay:
 			b = append(b, absWeekday(abs).String()[:3]...)
 		case stdLongWeekDay:
 			s := absWeekday(abs).String()
 			b = append(b, s...)
 		case stdDay:
-			b = appendUint(b, uint(day), 0)
+			b = appendInt(b, day, 0)
 		case stdUnderDay:
-			b = appendUint(b, uint(day), ' ')
+			if day < 10 {
+				b = append(b, ' ')
+			}
+			b = appendInt(b, day, 0)
 		case stdZeroDay:
-			b = appendUint(b, uint(day), '0')
+			b = appendInt(b, day, 2)
 		case stdHour:
-			b = appendUint(b, uint(hour), '0')
+			b = appendInt(b, hour, 2)
 		case stdHour12:
 			// Noon is 12PM, midnight is 12AM.
 			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			b = appendUint(b, uint(hr), 0)
+			b = appendInt(b, hr, 0)
 		case stdZeroHour12:
 			// Noon is 12PM, midnight is 12AM.
 			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			b = appendUint(b, uint(hr), '0')
+			b = appendInt(b, hr, 2)
 		case stdMinute:
-			b = appendUint(b, uint(min), 0)
+			b = appendInt(b, min, 0)
 		case stdZeroMinute:
-			b = appendUint(b, uint(min), '0')
+			b = appendInt(b, min, 2)
 		case stdSecond:
-			b = appendUint(b, uint(sec), 0)
+			b = appendInt(b, sec, 2)
 		case stdZeroSecond:
-			b = appendUint(b, uint(sec), '0')
+			b = appendInt(b, sec, 2)
 		case stdPM:
 			if hour >= 12 {
 				b = append(b, "PM"...)
@@ -555,18 +541,18 @@
 			} else {
 				b = append(b, '+')
 			}
-			b = appendUint(b, uint(zone/60), '0')
+			b = appendInt(b, zone/60, 2)
 			if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
 				b = append(b, ':')
 			}
-			b = appendUint(b, uint(zone%60), '0')
+			b = appendInt(b, zone%60, 2)
 
 			// append seconds if appropriate
 			if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
 				if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
 					b = append(b, ':')
 				}
-				b = appendUint(b, uint(absoffset%60), '0')
+				b = appendInt(b, absoffset%60, 2)
 			}
 
 		case stdTZ:
@@ -583,13 +569,13 @@
 			} else {
 				b = append(b, '+')
 			}
-			b = appendUint(b, uint(zone/60), '0')
-			b = appendUint(b, uint(zone%60), '0')
+			b = appendInt(b, zone/60, 2)
+			b = appendInt(b, zone%60, 2)
 		case stdFracSecond0, stdFracSecond9:
 			b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9)
 		}
 	}
-	return string(b)
+	return b
 }
 
 var errBad = errors.New("bad value for field") // placeholder not passed to user
diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go
index 6452a9e..dd0a820 100644
--- a/src/time/sleep_test.go
+++ b/src/time/sleep_test.go
@@ -8,7 +8,6 @@
 	"errors"
 	"fmt"
 	"runtime"
-	"sort"
 	"strings"
 	"sync"
 	"sync/atomic"
@@ -224,10 +223,11 @@
 func TestAfterQueuing(t *testing.T) {
 	// This test flakes out on some systems,
 	// so we'll try it a few times before declaring it a failure.
-	const attempts = 3
+	const attempts = 5
 	err := errors.New("!=nil")
 	for i := 0; i < attempts && err != nil; i++ {
-		if err = testAfterQueuing(t); err != nil {
+		delta := Duration(20+i*50) * Millisecond
+		if err = testAfterQueuing(t, delta); err != nil {
 			t.Logf("attempt %v failed: %v", i, err)
 		}
 	}
@@ -247,11 +247,7 @@
 	result <- afterResult{slot, <-ac}
 }
 
-func testAfterQueuing(t *testing.T) error {
-	Delta := 100 * Millisecond
-	if testing.Short() {
-		Delta = 20 * Millisecond
-	}
+func testAfterQueuing(t *testing.T, delta Duration) error {
 	// make the result channel buffered because we don't want
 	// to depend on channel queueing semantics that might
 	// possibly change in the future.
@@ -259,18 +255,25 @@
 
 	t0 := Now()
 	for _, slot := range slots {
-		go await(slot, result, After(Duration(slot)*Delta))
+		go await(slot, result, After(Duration(slot)*delta))
 	}
-	sort.Ints(slots)
-	for _, slot := range slots {
+	var order []int
+	var times []Time
+	for range slots {
 		r := <-result
-		if r.slot != slot {
-			return fmt.Errorf("after slot %d, expected %d", r.slot, slot)
+		order = append(order, r.slot)
+		times = append(times, r.t)
+	}
+	for i := range order {
+		if i > 0 && order[i] < order[i-1] {
+			return fmt.Errorf("After calls returned out of order: %v", order)
 		}
-		dt := r.t.Sub(t0)
-		target := Duration(slot) * Delta
-		if dt < target-Delta/2 || dt > target+Delta*10 {
-			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10)
+	}
+	for i, t := range times {
+		dt := t.Sub(t0)
+		target := Duration(order[i]) * delta
+		if dt < target-delta/2 || dt > target+delta*10 {
+			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10)
 		}
 	}
 	return nil
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index 5077f4b..9f987ab 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -6,9 +6,9 @@
 
 import (
 	"errors"
+	"internal/syscall/windows/registry"
 	"runtime"
 	"syscall"
-	"unsafe"
 )
 
 //go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
@@ -20,39 +20,23 @@
 // The implementation assumes that this year's rules for daylight savings
 // time apply to all previous and future years as well.
 
-// getKeyValue retrieves the string value kname associated with the open registry key kh.
-func getKeyValue(kh syscall.Handle, kname string) (string, error) {
-	var buf [50]uint16 // buf needs to be large enough to fit zone descriptions
-	var typ uint32
-	n := uint32(len(buf) * 2) // RegQueryValueEx's signature expects array of bytes, not uint16
-	p, _ := syscall.UTF16PtrFromString(kname)
-	if err := syscall.RegQueryValueEx(kh, p, nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n); err != nil {
-		return "", err
-	}
-	if typ != syscall.REG_SZ { // null terminated strings only
-		return "", errors.New("Key is not string")
-	}
-	return syscall.UTF16ToString(buf[:]), nil
-}
-
 // matchZoneKey checks if stdname and dstname match the corresponding "Std"
 // and "Dlt" key values in the kname key stored under the open registry key zones.
-func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (matched bool, err2 error) {
-	var h syscall.Handle
-	p, _ := syscall.UTF16PtrFromString(kname)
-	if err := syscall.RegOpenKeyEx(zones, p, 0, syscall.KEY_READ, &h); err != nil {
+func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) {
+	k, err := registry.OpenKey(zones, kname, registry.READ)
+	if err != nil {
 		return false, err
 	}
-	defer syscall.RegCloseKey(h)
+	defer k.Close()
 
-	s, err := getKeyValue(h, "Std")
+	s, _, err := k.GetStringValue("Std")
 	if err != nil {
 		return false, err
 	}
 	if s != stdname {
 		return false, nil
 	}
-	s, err = getKeyValue(h, "Dlt")
+	s, _, err = k.GetStringValue("Dlt")
 	if err != nil {
 		return false, err
 	}
@@ -65,28 +49,20 @@
 // 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) {
-	var zones syscall.Handle
-	p, _ := syscall.UTF16PtrFromString(`SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`)
-	if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, p, 0, syscall.KEY_READ, &zones); err != nil {
+	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS)
+	if err != nil {
 		return "", err
 	}
-	defer syscall.RegCloseKey(zones)
+	defer k.Close()
 
-	var count uint32
-	if err := syscall.RegQueryInfoKey(zones, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil); err != nil {
+	names, err := k.ReadSubKeyNames(-1)
+	if err != nil {
 		return "", err
 	}
-
-	var buf [50]uint16 // buf needs to be large enough to fit zone descriptions
-	for i := uint32(0); i < count; i++ {
-		n := uint32(len(buf))
-		if syscall.RegEnumKeyEx(zones, i, &buf[0], &n, nil, nil, nil, nil) != nil {
-			continue
-		}
-		kname := syscall.UTF16ToString(buf[:])
-		matched, err := matchZoneKey(zones, kname, stdname, dstname)
+	for _, name := range names {
+		matched, err := matchZoneKey(k, name, stdname, dstname)
 		if err == nil && matched {
-			return kname, nil
+			return name, nil
 		}
 	}
 	return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
diff --git a/test/escape2.go b/test/escape2.go
index 65dbd7a..cc71471 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -18,94 +18,94 @@
 
 var gxx *int
 
-func foo1(x int) { // ERROR "moved to heap: x"
-	gxx = &x // ERROR "&x escapes to heap"
+func foo1(x int) { // ERROR "moved to heap: x$"
+	gxx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo2(yy *int) { // ERROR "leaking param: yy"
+func foo2(yy *int) { // ERROR "leaking param: yy$"
 	gxx = yy
 }
 
-func foo3(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func foo3(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
 type T *T
 
-func foo3b(t T) { // ERROR "leaking param: t"
+func foo3b(t T) { // ERROR "leaking param: t$"
 	*t = t
 }
 
 // xx isn't going anywhere, so use of yy is ok
-func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$"
 	xx = yy
 }
 
 // xx isn't going anywhere, so taking address of yy is ok
-func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
-	xx = &yy // ERROR "&yy does not escape"
+func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$"
+	xx = &yy // ERROR "foo5 &yy does not escape$"
 }
 
-func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy"
+func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$"
 	*xx = yy
 }
 
-func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$"
 	**xx = *yy
 }
 
-func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape"
+func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$"
 	xx = yy
 	return *xx
 }
 
-func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy"
+func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$"
 	xx = yy
 	return xx
 }
 
-func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$"
 	*xx = *yy
 }
 
 func foo11() int {
 	x, y := 0, 42
-	xx := &x // ERROR "&x does not escape"
-	yy := &y // ERROR "&y does not escape"
+	xx := &x // ERROR "foo11 &x does not escape$"
+	yy := &y // ERROR "foo11 &y does not escape$"
 	*xx = *yy
 	return x
 }
 
 var xxx **int
 
-func foo12(yyy **int) { // ERROR "leaking param: yyy"
+func foo12(yyy **int) { // ERROR "leaking param: yyy$"
 	xxx = yyy
 }
 
 // Must treat yyy as leaking because *yyy leaks, and the escape analysis
 // summaries in exported metadata do not distinguish these two cases.
-func foo13(yyy **int) { // ERROR "leaking param: yyy"
+func foo13(yyy **int) { // ERROR "leaking param content: yyy$"
 	*xxx = *yyy
 }
 
-func foo14(yyy **int) { // ERROR "yyy does not escape"
+func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$"
 	**xxx = **yyy
 }
 
-func foo15(yy *int) { // ERROR "moved to heap: yy"
-	xxx = &yy // ERROR "&yy escapes to heap"
+func foo15(yy *int) { // ERROR "moved to heap: yy$"
+	xxx = &yy // ERROR "&yy escapes to heap$"
 }
 
-func foo16(yy *int) { // ERROR "leaking param: yy"
+func foo16(yy *int) { // ERROR "leaking param: yy$"
 	*xxx = yy
 }
 
-func foo17(yy *int) { // ERROR "yy does not escape"
+func foo17(yy *int) { // ERROR "foo17 yy does not escape$"
 	**xxx = *yy
 }
 
-func foo18(y int) { // ERROR "moved to heap: "y"
-	*xxx = &y // ERROR "&y escapes to heap"
+func foo18(y int) { // ERROR "moved to heap: y$"
+	*xxx = &y // ERROR "&y escapes to heap$"
 }
 
 func foo19(y int) {
@@ -118,52 +118,52 @@
 }
 
 func NewBar() *Bar {
-	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap"
+	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp(x *int) *Bar { // ERROR "leaking param: x"
-	return &Bar{42, x} // ERROR "&Bar literal escapes to heap"
+func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return &Bar{42, x} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp2(x *int) *Bar { // ERROR "x does not escape"
-	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap"
+func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$"
+	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func (b *Bar) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$"
 	return *(b.ii)
 }
 
-func (b *Bar) Leak() *int { // ERROR "leaking param: b"
-	return &b.i // ERROR "&b.i escapes to heap"
+func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return &b.i // ERROR "&b.i escapes to heap$"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii
 }
 
-func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
+func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
 	return b.ii
 }
 
-func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b Bar) StillNoLeak() int { // ERROR "b does not escape"
+func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$"
 	v := 0
-	b.ii = &v // ERROR "&v does not escape"
+	b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$"
 	return b.i
 }
 
-func goLeak(b *Bar) { // ERROR "leaking param: b"
+func goLeak(b *Bar) { // ERROR "leaking param: b$"
 	go b.NoLeak()
 }
 
@@ -173,105 +173,105 @@
 }
 
 func NewBar2() *Bar2 {
-	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap"
+	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$"
 }
 
-func (b *Bar2) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$"
 	return b.i[0]
 }
 
-func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
-	return b.i[:] // ERROR "b.i escapes to heap"
+func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return b.i[:] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii[0:1]
 }
 
-func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape"
+func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$"
 	return b.i
 }
 
-func (b *Bar2) LeakSelf() { // ERROR "leaking param: b"
-	b.ii = b.i[0:4] // ERROR "b.i escapes to heap"
+func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$"
+	b.ii = b.i[0:4] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
+func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$"
 	var buf []int
-	buf = b.i[0:] // ERROR "b.i escapes to heap"
+	buf = b.i[0:] // ERROR "b.i escapes to heap$"
 	b.ii = buf
 }
 
 func foo21() func() int {
 	x := 42
-	return func() int { // ERROR "func literal escapes to heap"
+	return func() int { // ERROR "func literal escapes to heap$"
 		return x
 	}
 }
 
 func foo21a() func() int {
-	x := 42             // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		x++ // ERROR "&x escapes to heap"
+	x := 42             // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
 		return x
 	}
 }
 
 func foo22() int {
 	x := 42
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo22 func literal does not escape$"
 		return x
 	}()
 }
 
 func foo23(x int) func() int {
-	return func() int { // ERROR "func literal escapes to heap"
+	return func() int { // ERROR "func literal escapes to heap$"
 		return x
 	}
 }
 
 func foo23a(x int) func() int {
-	f := func() int { // ERROR "func literal escapes to heap"
+	f := func() int { // ERROR "func literal escapes to heap$"
 		return x
 	}
 	return f
 }
 
 func foo23b(x int) *(func() int) {
-	f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap"
-	return &f                    // ERROR "&f escapes to heap"
+	f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$"
+	return &f                    // ERROR "&f escapes to heap$"
 }
 
-func foo23c(x int) func() int { // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		x++ // ERROR "&x escapes to heap"
+func foo23c(x int) func() int { // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
 		return x
 	}
 }
 
 func foo24(x int) int {
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo24 func literal does not escape$"
 		return x
 	}()
 }
 
 var x *int
 
-func fooleak(xx *int) int { // ERROR "leaking param: xx"
+func fooleak(xx *int) int { // ERROR "leaking param: xx$"
 	x = xx
 	return *x
 }
 
-func foonoleak(xx *int) int { // ERROR "xx does not escape"
+func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$"
 	return *x + *xx
 }
 
-func foo31(x int) int { // ERROR "moved to heap: x"
-	return fooleak(&x) // ERROR "&x escapes to heap"
+func foo31(x int) int { // ERROR "moved to heap: x$"
+	return fooleak(&x) // ERROR "&x escapes to heap$"
 }
 
 func foo32(x int) int {
-	return foonoleak(&x) // ERROR "&x does not escape"
+	return foonoleak(&x) // ERROR "foo32 &x does not escape$"
 }
 
 type Foo struct {
@@ -282,114 +282,114 @@
 var F Foo
 var pf *Foo
 
-func (f *Foo) fooleak() { // ERROR "leaking param: f"
+func (f *Foo) fooleak() { // ERROR "leaking param: f$"
 	pf = f
 }
 
-func (f *Foo) foonoleak() { // ERROR "f does not escape"
+func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$"
 	F.x = f.x
 }
 
-func (f *Foo) Leak() { // ERROR "leaking param: f"
+func (f *Foo) Leak() { // ERROR "leaking param: f$"
 	f.fooleak()
 }
 
-func (f *Foo) NoLeak() { // ERROR "f does not escape"
+func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$"
 	f.foonoleak()
 }
 
-func foo41(x int) { // ERROR "moved to heap: x"
-	F.xx = &x // ERROR "&x escapes to heap"
+func foo41(x int) { // ERROR "moved to heap: x$"
+	F.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo44(yy *int) { // ERROR "leaking param: yy"
+func foo44(yy *int) { // ERROR "leaking param: yy$"
 	F.xx = yy
 }
 
-func (f *Foo) foo45() { // ERROR "f does not escape"
+func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$"
 	F.x = f.x
 }
 
 // See foo13 above for explanation of why f leaks.
-func (f *Foo) foo46() { // ERROR "leaking param: f"
+func (f *Foo) foo46() { // ERROR "leaking param content: f$"
 	F.xx = f.xx
 }
 
-func (f *Foo) foo47() { // ERROR "leaking param: f"
-	f.xx = &f.x // ERROR "&f.x escapes to heap"
+func (f *Foo) foo47() { // ERROR "leaking param: f$"
+	f.xx = &f.x // ERROR "&f.x escapes to heap$"
 }
 
 var ptrSlice []*int
 
-func foo50(i *int) { // ERROR "leaking param: i"
+func foo50(i *int) { // ERROR "leaking param: i$"
 	ptrSlice[0] = i
 }
 
 var ptrMap map[*int]*int
 
-func foo51(i *int) { // ERROR "leaking param: i"
+func foo51(i *int) { // ERROR "leaking param: i$"
 	ptrMap[i] = i
 }
 
-func indaddr1(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func indaddr1(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
-func indaddr2(x *int) *int { // ERROR "leaking param: x"
-	return *&x // ERROR "&x does not escape"
+func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *&x // ERROR "indaddr2 &x does not escape$"
 }
 
-func indaddr3(x *int32) *int { // ERROR "leaking param: x"
-	return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape"
+func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$"
 }
 
 // From package math:
 
 func Float32bits(f float32) uint32 {
-	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$"
 }
 
 func Float32frombits(b uint32) float32 {
-	return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$"
 }
 
 func Float64bits(f float64) uint64 {
-	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$"
 }
 
 func Float64frombits(b uint64) float64 {
-	return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$"
 }
 
 // contrast with
-func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f"
-	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap"
+func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$"
+	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$"
 }
 
-func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f"
+func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$"
 	return (*uint64)(unsafe.Pointer(f))
 }
 
-func typesw(i interface{}) *int { // ERROR "leaking param: i"
+func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch val := i.(type) {
 	case *int:
 		return val
 	case *int8:
-		v := int(*val) // ERROR "moved to heap: v"
-		return &v      // ERROR "&v escapes to heap"
+		v := int(*val) // ERROR "moved to heap: v$"
+		return &v      // ERROR "&v escapes to heap$"
 	}
 	return nil
 }
 
-func exprsw(i *int) *int { // ERROR "leaking param: i"
+func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch j := i; *j + 110 {
 	case 12:
 		return j
@@ -401,20 +401,20 @@
 }
 
 // assigning to an array element is like assigning to the array
-func foo60(i *int) *int { // ERROR "leaking param: i"
+func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	var a [12]*int
 	a[0] = i
 	return a[1]
 }
 
-func foo60a(i *int) *int { // ERROR "i does not escape"
+func foo60a(i *int) *int { // ERROR "foo60a i does not escape$"
 	var a [12]*int
 	a[0] = i
 	return nil
 }
 
 // assigning to a struct field  is like assigning to the struct
-func foo61(i *int) *int { // ERROR "leaking param: i"
+func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	type S struct {
 		a, b *int
 	}
@@ -423,7 +423,7 @@
 	return s.b
 }
 
-func foo61a(i *int) *int { // ERROR "i does not escape"
+func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
 	type S struct {
 		a, b *int
 	}
@@ -435,11 +435,11 @@
 // assigning to a struct field is like assigning to the struct but
 // here this subtlety is lost, since s.a counts as an assignment to a
 // track-losing dereference.
-func foo62(i *int) *int { // ERROR "leaking param: i"
+func foo62(i *int) *int { // ERROR "leaking param: i$"
 	type S struct {
 		a, b *int
 	}
-	s := new(S) // ERROR "new[(]S[)] does not escape"
+	s := new(S) // ERROR "foo62 new\(S\) does not escape$"
 	s.a = i
 	return nil // s.b
 }
@@ -448,14 +448,14 @@
 	M()
 }
 
-func foo63(m M) { // ERROR "m does not escape"
+func foo63(m M) { // ERROR "foo63 m does not escape$"
 }
 
-func foo64(m M) { // ERROR "leaking param: m"
+func foo64(m M) { // ERROR "leaking param: m$"
 	m.M()
 }
 
-func foo64b(m M) { // ERROR "leaking param: m"
+func foo64b(m M) { // ERROR "leaking param: m$"
 	defer m.M()
 }
 
@@ -465,56 +465,56 @@
 
 func foo65() {
 	var mv MV
-	foo63(&mv) // ERROR "&mv does not escape"
+	foo63(&mv) // ERROR "foo65 &mv does not escape$"
 }
 
 func foo66() {
-	var mv MV  // ERROR "moved to heap: mv"
-	foo64(&mv) // ERROR "&mv escapes to heap"
+	var mv MV  // ERROR "moved to heap: mv$"
+	foo64(&mv) // ERROR "&mv escapes to heap$"
 }
 
 func foo67() {
 	var mv MV
-	foo63(mv) // ERROR "mv does not escape"
+	foo63(mv) // ERROR "foo67 mv does not escape$"
 }
 
 func foo68() {
 	var mv MV
 	// escapes but it's an int so irrelevant
-	foo64(mv) // ERROR "mv escapes to heap"
+	foo64(mv) // ERROR "mv escapes to heap$"
 }
 
-func foo69(m M) { // ERROR "leaking param: m"
+func foo69(m M) { // ERROR "leaking param: m$"
 	foo64(m)
 }
 
-func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
-	m = mv1 // ERROR "mv1 escapes to heap"
+func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
+	m = mv1 // ERROR "mv1 escapes to heap$"
 	foo64(m)
 }
 
-func foo71(x *int) []*int { // ERROR "leaking param: x"
+func foo71(x *int) []*int { // ERROR "leaking param: x$"
 	var y []*int
 	y = append(y, x)
 	return y
 }
 
-func foo71a(x int) []*int { // ERROR "moved to heap: x"
+func foo71a(x int) []*int { // ERROR "moved to heap: x$"
 	var y []*int
-	y = append(y, &x) // ERROR "&x escapes to heap"
+	y = append(y, &x) // ERROR "&x escapes to heap$"
 	return y
 }
 
 func foo72() {
 	var x int
 	var y [1]*int
-	y[0] = &x // ERROR "&x does not escape"
+	y[0] = &x // ERROR "foo72 &x does not escape$"
 }
 
 func foo72aa() [10]*int {
-	var x int // ERROR "moved to heap: x"
+	var x int // ERROR "moved to heap: x$"
 	var y [10]*int
-	y[0] = &x // ERROR "&x escapes to heap"
+	y[0] = &x // ERROR "&x escapes to heap$"
 	return y
 }
 
@@ -522,8 +522,8 @@
 	var y [10]*int
 	for i := 0; i < 10; i++ {
 		// escapes its scope
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return
 }
@@ -531,42 +531,42 @@
 func foo72b() [10]*int {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return y
 }
 
 // issue 2145
 func foo73() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$"
 	for _, v := range s {
 		vv := v
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap"
+		defer func() { // ERROR "func literal escapes to heap$"
 			println(vv)
 		}()
 	}
 }
 
 func foo731() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap"
-			vv = 42 // ERROR "&vv escapes to heap"
+		defer func() { // ERROR "func literal escapes to heap$"
+			vv = 42 // ERROR "&vv escapes to heap$"
 			println(vv)
 		}()
 	}
 }
 
 func foo74() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$"
 	for _, v := range s {
 		vv := v
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap"
+		fn := func() { // ERROR "func literal escapes to heap$"
 			println(vv)
 		}
 		defer fn()
@@ -574,12 +574,12 @@
 }
 
 func foo74a() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap"
-			vv += 1 // ERROR "&vv escapes to heap"
+		fn := func() { // ERROR "func literal escapes to heap$"
+			vv += 1 // ERROR "&vv escapes to heap$"
 			println(vv)
 		}
 		defer fn()
@@ -589,11 +589,11 @@
 // issue 3975
 func foo74b() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$"
 	for i, v := range s {
 		vv := v
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap"
+		array[i] = func() { // ERROR "func literal escapes to heap$"
 			println(vv)
 		}
 	}
@@ -601,130 +601,130 @@
 
 func foo74c() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$"
 	for i, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap"
-			println(&vv) // ERROR "&vv escapes to heap" "&vv does not escape"
+		array[i] = func() { // ERROR "func literal escapes to heap$"
+			println(&vv) // ERROR "&vv escapes to heap$" "<S> &vv does not escape$"
 		}
 	}
 }
 
-func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y to result ~r2"
+func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x to result ~r2"
-	return &x[0] // ERROR "&x.0. escapes to heap"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$"
+	return &x[0] // ERROR "&x\[0\] escapes to heap$"
 }
 
-func foo75(z *int) { // ERROR "z does not escape"
-	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75(z *int) { // ERROR "foo75 z does not escape$"
+	myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75 ... argument does not escape$"
 }
 
-func foo75a(z *int) { // ERROR "z does not escape"
-	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75a(z *int) { // ERROR "foo75a z does not escape$"
+	myprint1(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75a ... argument does not escape$"
 }
 
-func foo75esc(z *int) { // ERROR "leaking param: z"
-	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75esc(z *int) { // ERROR "leaking param: z$"
+	gxx = myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75esc ... argument does not escape$"
 }
 
-func foo75aesc(z *int) { // ERROR "z does not escape"
+func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$"
 	var ppi **interface{}       // assignments to pointer dereferences lose track
-	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	*ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 }
 
-func foo75aesc1(z *int) { // ERROR "z does not escape"
-	sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "myprint1\(z, 1, 2, 3\) escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$"
+	sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$"
 }
 
 // BAD: z does not escape here
-func foo76(z *int) { // ERROR "leaking param: z"
-	myprint(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
+func foo76(z *int) { // ERROR "leaking param: z$"
+	myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z escapes to heap$"
 }
 
 // BAD: z does not escape here
-func foo76a(z *int) { // ERROR "leaking param: z"
-	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
+func foo76a(z *int) { // ERROR "leaking param: z$"
+	myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z escapes to heap$"
 }
 
 func foo76b() {
-	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76b ... argument does not escape$"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76c ... argument does not escape$"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	defer myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76d ... argument does not escape$"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	defer myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76e ... argument does not escape$"
 }
 
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+		defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+		defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
-func foo77(z []interface{}) { // ERROR "z does not escape"
+func foo77(z []interface{}) { // ERROR "foo77 z does not escape$"
 	myprint(nil, z...) // z does not escape
 }
 
-func foo77a(z []interface{}) { // ERROR "z does not escape"
+func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$"
 	myprint1(nil, z...)
 }
 
-func foo77b(z []interface{}) { // ERROR "leaking param: z"
+func foo77b(z []interface{}) { // ERROR "leaking param: z$"
 	var ppi **interface{}
 	*ppi = myprint1(nil, z...)
 }
 
-func foo77c(z []interface{}) { // ERROR "leaking param: z"
-	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z\.\.\.\) escapes to heap"
+func foo77c(z []interface{}) { // ERROR "leaking param: z$"
+	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$"
 }
 
 func dotdotdot() {
 	// BAD: i should not escape here
-	i := 0           // ERROR "moved to heap: i"
-	myprint(nil, &i) // ERROR "&i escapes to heap" "\.\.\. argument does not escape"
+	i := 0           // ERROR "moved to heap: i$"
+	myprint(nil, &i) // ERROR "&i escapes to heap$" "dotdotdot ... argument does not escape$"
 
 	// BAD: j should not escape here
-	j := 0            // ERROR "moved to heap: j"
-	myprint1(nil, &j) // ERROR "&j escapes to heap" "\.\.\. argument does not escape"
+	j := 0            // ERROR "moved to heap: j$"
+	myprint1(nil, &j) // ERROR "&j escapes to heap$" "dotdotdot ... argument does not escape$"
 }
 
-func foo78(z int) *int { // ERROR "moved to heap: z"
-	return &z // ERROR "&z escapes to heap"
+func foo78(z int) *int { // ERROR "moved to heap: z$"
+	return &z // ERROR "&z escapes to heap$"
 }
 
-func foo78a(z int) *int { // ERROR "moved to heap: z"
-	y := &z   // ERROR "&z escapes to heap"
-	x := &y   // ERROR "&y does not escape"
+func foo78a(z int) *int { // ERROR "moved to heap: z$"
+	y := &z   // ERROR "&z escapes to heap$"
+	x := &y   // ERROR "foo78a &y does not escape$"
 	return *x // really return y
 }
 
 func foo79() *int {
-	return new(int) // ERROR "new[(]int[)] escapes to heap"
+	return new(int) // ERROR "new\(int\) escapes to heap$"
 }
 
 func foo80() *int {
 	var z *int
 	for {
 		// Really just escapes its scope but we don't distinguish
-		z = new(int) // ERROR "new[(]int[)] escapes to heap"
+		z = new(int) // ERROR "new\(int\) escapes to heap$"
 	}
 	_ = z
 	return nil
@@ -732,24 +732,24 @@
 
 func foo81() *int {
 	for {
-		z := new(int) // ERROR "new[(]int[)] does not escape"
+		z := new(int) // ERROR "foo81 new\(int\) does not escape$"
 		_ = z
 	}
 	return nil
 }
 
-func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$"
 
-func noop(x, y *int) {} // ERROR "does not escape"
+func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$"
 
 func foo82() {
-	var x, y, z int  // ERROR "moved to heap"
-	go noop(tee(&z)) // ERROR "&z escapes to heap"
-	go noop(&x, &y)  // ERROR "escapes to heap"
+	var x, y, z int  // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$"
+	go noop(tee(&z)) // ERROR "&z escapes to heap$"
+	go noop(&x, &y)  // ERROR "&x escapes to heap$" "&y escapes to heap$"
 	for {
-		var u, v, w int     // ERROR "moved to heap"
-		defer noop(tee(&u)) // ERROR "&u escapes to heap"
-		defer noop(&v, &w)  // ERROR "escapes to heap"
+		var u, v, w int     // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$"
+		defer noop(tee(&u)) // ERROR "&u escapes to heap$"
+		defer noop(&v, &w)  // ERROR "&v escapes to heap$" "&w escapes to heap$"
 	}
 }
 
@@ -762,24 +762,24 @@
 	N int64
 }
 
-func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r"
-	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap"
+func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$"
+	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$"
 }
 
-func foo90(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo91(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo92(x *int) [2]*int { // ERROR "leaking param: x"
+func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return [2]*int{x, nil}
 }
 
 // does not leak c
-func foo93(c chan *int) *int { // ERROR "c does not escape"
+func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
 	for v := range c {
 		return v
 	}
@@ -787,7 +787,7 @@
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$"
 	for k, v := range m {
 		if b {
 			return k
@@ -798,32 +798,32 @@
 }
 
 // does leak x
-func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$"
 	m[x] = x
 }
 
 // does not leak m
-func foo96(m []*int) *int { // ERROR "m does not escape"
+func foo96(m []*int) *int { // ERROR "foo96 m does not escape$"
 	return m[0]
 }
 
 // does leak m
-func foo97(m [1]*int) *int { // ERROR "leaking param: m"
+func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[0]
 }
 
 // does not leak m
-func foo98(m map[int]*int) *int { // ERROR "m does not escape"
+func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$"
 	return m[0]
 }
 
 // does leak m
-func foo99(m *[1]*int) []*int { // ERROR "leaking param: m"
+func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[:]
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "m does not escape"
+func foo100(m []*int) *int { // ERROR "foo100 m does not escape$"
 	for _, v := range m {
 		return v
 	}
@@ -831,7 +831,7 @@
 }
 
 // does leak m
-func foo101(m [1]*int) *int { // ERROR "leaking param: m"
+func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	for _, v := range m {
 		return v
 	}
@@ -839,109 +839,109 @@
 }
 
 // does not leak m
-func foo101a(m [1]*int) *int { // ERROR "m does not escape"
-	for i := range m { // ERROR "moved to heap: i"
-		return &i // ERROR "&i escapes to heap"
+func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$"
+	for i := range m { // ERROR "moved to heap: i$"
+		return &i // ERROR "&i escapes to heap$"
 	}
 	return nil
 }
 
 // does leak x
-func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$"
 	m[0] = x
 }
 
 // does not leak x
-func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape"
+func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$"
 	m[0] = x
 }
 
 var y []*int
 
 // does not leak x
-func foo104(x []*int) { // ERROR "x does not escape"
+func foo104(x []*int) { // ERROR "foo104 x does not escape$"
 	copy(y, x)
 }
 
 // does not leak x
-func foo105(x []*int) { // ERROR "x does not escape"
+func foo105(x []*int) { // ERROR "foo105 x does not escape$"
 	_ = append(y, x...)
 }
 
 // does leak x
-func foo106(x *int) { // ERROR "leaking param: x"
+func foo106(x *int) { // ERROR "leaking param: x$"
 	_ = append(y, x)
 }
 
-func foo107(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap"
+func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo108(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap"
+func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo109(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape"
+func foo109(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$"
 	for k, _ := range m {
 		return k
 	}
 	return nil
 }
 
-func foo110(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape"
+func foo110(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$"
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x"
-	m := []*int{x} // ERROR "\[\]\*int literal does not escape"
+func foo111(x *int) *int { // ERROR "leaking param: x$"
+	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
 
-func foo112(x *int) *int { // ERROR "leaking param: x"
+func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := [1]*int{x}
 	return m[0]
 }
 
-func foo113(x *int) *int { // ERROR "leaking param: x"
+func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := Bar{ii: x}
 	return m.ii
 }
 
-func foo114(x *int) *int { // ERROR "leaking param: x"
-	m := &Bar{ii: x} // ERROR "&Bar literal does not escape"
+func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$"
 	return m.ii
 }
 
-func foo115(x *int) *int { // ERROR "leaking param: x"
+func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1))
 }
 
 func foo116(b bool) *int {
 	if b {
-		x := 1    // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+		x := 1    // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	} else {
-		y := 1    // ERROR "moved to heap: y"
-		return &y // ERROR "&y escapes to heap"
+		y := 1    // ERROR "moved to heap: y$"
+		return &y // ERROR "&y escapes to heap$"
 	}
 	return nil
 }
 
-func foo117(unknown func(interface{})) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
-func foo118(unknown func(*int)) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
 func external(*int)
 
-func foo119(x *int) { // ERROR "leaking param: x"
+func foo119(x *int) { // ERROR "leaking param: x$"
 	external(x)
 }
 
@@ -1152,16 +1152,16 @@
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
-		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		go myprint(nil, i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
-		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		go fmt.Printf("%d", i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
 	}
 }
 
@@ -1171,7 +1171,7 @@
 
 	goto L1
 L1:
-	i = new(int) // ERROR "new.int. does not escape"
+	i = new(int) // ERROR "foo122 new\(int\) does not escape$"
 	_ = i
 }
 
@@ -1180,25 +1180,25 @@
 	var i *int
 
 L1:
-	i = new(int) // ERROR "new.int. escapes to heap"
+	i = new(int) // ERROR "new\(int\) escapes to heap$"
 
 	goto L1
 	_ = i
 }
 
-func foo124(x **int) { // ERROR "x does not escape"
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes"
-	func() {  // ERROR "func literal does not escape"
-		*x = p // ERROR "leaking closure reference p"
+func foo124(x **int) { // ERROR "foo124 x does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo124 func literal does not escape$"
+		*x = p // ERROR "leaking closure reference p$"
 	}()
 }
 
-func foo125(ch chan *int) { // ERROR "does not escape"
-	var i int // ERROR "moved to heap"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		ch <- p // ERROR "leaking closure reference p"
+func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo125 func literal does not escape$"
+		ch <- p // ERROR "leaking closure reference p$"
 	}()
 }
 
@@ -1206,9 +1206,9 @@
 	var px *int // loopdepth 0
 	for {
 		// loopdepth 1
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo126 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$"
 		}()
 	}
 	_ = px
@@ -1217,26 +1217,26 @@
 var px *int
 
 func foo127() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
 	q := p
 	px = q
 }
 
 func foo128() {
 	var i int
-	p := &i // ERROR "&i does not escape"
+	p := &i // ERROR "foo128 &i does not escape$"
 	q := p
 	_ = q
 }
 
 func foo129() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p   // ERROR "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo129 func literal does not escape$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "<S> func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
@@ -1244,40 +1244,40 @@
 
 func foo130() {
 	for {
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes" "leaking closure reference i"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo130 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 		}()
 	}
 }
 
 func foo131() {
-	var i int // ERROR "moved to heap"
-	func() {  // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int // ERROR "moved to heap: i$"
+	func() {  // ERROR "foo131 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo132() {
-	var i int   // ERROR "moved to heap"
-	go func() { // ERROR "func literal escapes to heap"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int   // ERROR "moved to heap: i$"
+	go func() { // ERROR "func literal escapes to heap$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo133() {
-	var i int      // ERROR "moved to heap"
-	defer func() { // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int      // ERROR "moved to heap: i$"
+	defer func() { // ERROR "foo133 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo134() {
 	var i int
-	p := &i  // ERROR "&i does not escape"
-	func() { // ERROR "func literal does not escape"
+	p := &i  // ERROR "foo134 &i does not escape$"
+	func() { // ERROR "foo134 func literal does not escape$"
 		q := p
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "<S> func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1285,11 +1285,11 @@
 }
 
 func foo135() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap"
-	go func() { // ERROR "func literal escapes to heap"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
 		q := p
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "<S> func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1297,23 +1297,23 @@
 }
 
 func foo136() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap"
-	go func() { // ERROR "func literal escapes to heap"
-		q := p   // ERROR "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "<S> func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
 }
 
 func foo137() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p      // ERROR "leaking closure reference p"
-		go func() { // ERROR "func literal escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo137 func literal does not escape$"
+		q := p      // ERROR "leaking closure reference p$"
+		go func() { // ERROR "func literal escapes to heap$"
 			r := q
 			_ = r
 		}()
@@ -1324,8 +1324,8 @@
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new.T. escapes to heap"
-	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
+	t := new(T)    // ERROR "new\(T\) escapes to heap$"
+	return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$"
 }
 
 func foo139() *byte {
@@ -1334,8 +1334,8 @@
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new.T. escapes to heap"
-	return &t.x.y // ERROR "&t.x.y escapes to heap"
+	t := new(T)   // ERROR "new\(T\) escapes to heap$"
+	return &t.x.y // ERROR "&t.x.y escapes to heap$"
 }
 
 // issue 4751
@@ -1347,8 +1347,8 @@
 		X string
 		T *T
 	}
-	t := &T{} // ERROR "&T literal escapes to heap"
-	return U{ // ERROR "U literal escapes to heap"
+	t := &T{} // ERROR "&T literal escapes to heap$"
+	return U{ // ERROR "U literal escapes to heap$"
 		X: t.X,
 		T: t,
 	}
@@ -1362,53 +1362,53 @@
 
 //go:noescape
 
-func F3(x []byte) // ERROR "F3 x does not escape"
+func F3(x []byte) // ERROR "F3 x does not escape$"
 
 func F4(x []byte)
 
 func G() {
 	var buf1 [10]byte
-	F1(buf1[:]) // ERROR "buf1 does not escape"
+	F1(buf1[:]) // ERROR "G buf1 does not escape$"
 
-	var buf2 [10]byte // ERROR "moved to heap: buf2"
-	F2(buf2[:])       // ERROR "buf2 escapes to heap"
+	var buf2 [10]byte // ERROR "moved to heap: buf2$"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap$"
 
 	var buf3 [10]byte
-	F3(buf3[:]) // ERROR "buf3 does not escape"
+	F3(buf3[:]) // ERROR "G buf3 does not escape$"
 
-	var buf4 [10]byte // ERROR "moved to heap: buf4"
-	F4(buf4[:])       // ERROR "buf4 escapes to heap"
+	var buf4 [10]byte // ERROR "moved to heap: buf4$"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap$"
 }
 
 type Tm struct {
 	x int
 }
 
-func (t *Tm) M() { // ERROR "t does not escape"
+func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$"
 }
 
 func foo141() {
 	var f func()
 
-	t := new(Tm) // ERROR "escapes to heap"
-	f = t.M      // ERROR "t.M does not escape"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	f = t.M      // ERROR "foo141 t.M does not escape$"
 	_ = f
 }
 
 var gf func()
 
 func foo142() {
-	t := new(Tm) // ERROR "escapes to heap"
-	gf = t.M     // ERROR "t.M escapes to heap"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	gf = t.M     // ERROR "t.M escapes to heap$"
 }
 
 // issue 3888.
 func foo143() {
 	for i := 0; i < 1000; i++ {
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "foo143 func literal does not escape$"
 			for i := 0; i < 1; i++ {
 				var t Tm
-				t.M() // ERROR "t does not escape"
+				t.M() // ERROR "<S> t does not escape$"
 			}
 		}()
 	}
@@ -1424,9 +1424,9 @@
 
 func foo144() {
 	var x int
-	foo144a(&x) // ERROR "&x does not escape"
+	foo144a(&x) // ERROR "foo144 &x does not escape$"
 	var y int
-	foo144b(&y) // ERROR "&y does not escape"
+	foo144b(&y) // ERROR "foo144 &y does not escape$"
 }
 
 //go:noescape
@@ -1439,38 +1439,38 @@
 	Next *List
 }
 
-func foo145(l List) { // ERROR "l does not escape"
+func foo145(l List) { // ERROR "foo145 l does not escape$"
 	var p *List
-	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$"
 	}
 }
 
-func foo146(l List) { // ERROR "l does not escape"
+func foo146(l List) { // ERROR "foo146 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo146 &l does not escape$"
 	for ; p.Next != nil; p = p.Next {
 	}
 }
 
-func foo147(l List) { // ERROR "l does not escape"
+func foo147(l List) { // ERROR "foo147 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo147 &l does not escape$"
 	for p.Next != nil {
 		p = p.Next
 	}
 }
 
-func foo148(l List) { // ERROR " l does not escape"
-	for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+func foo148(l List) { // ERROR "foo148 l does not escape$"
+	for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$"
 	}
 }
 
 // related: address of variable should have depth of variable, not of loop
 
-func foo149(l List) { // ERROR " l does not escape"
+func foo149(l List) { // ERROR "foo149 l does not escape$"
 	var p *List
 	for {
-		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$"
 		}
 	}
 }
@@ -1479,44 +1479,44 @@
 
 var save150 []byte
 
-func foo150(x ...byte) { // ERROR "leaking param: x"
+func foo150(x ...byte) { // ERROR "leaking param: x$"
 	save150 = x
 }
 
 func bar150() {
-	foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+	foo150(1, 2, 3) // ERROR "... argument escapes to heap$"
 }
 
 // issue 7931: bad handling of slice of array
 
 var save151 *int
 
-func foo151(x *int) { // ERROR "leaking param: x"
+func foo151(x *int) { // ERROR "leaking param: x$"
 	save151 = x
 }
 
 func bar151() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151b() {
-	var a [10]int      // ERROR "moved to heap: a"
-	b := a[:]          // ERROR "a escapes to heap"
-	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap"
+	var a [10]int      // ERROR "moved to heap: a$"
+	b := a[:]          // ERROR "a escapes to heap$"
+	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap$"
 }
 
 func bar151c() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151d() {
-	var a [10]int        // ERROR "moved to heap: a"
-	b := a[:]            // ERROR "a escapes to heap"
-	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap"
+	var a [10]int        // ERROR "moved to heap: a$"
+	b := a[:]            // ERROR "a escapes to heap$"
+	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap$"
 }
 
 // issue 8120
@@ -1525,7 +1525,7 @@
 	s *string
 }
 
-func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
+func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$"
 	return u.s
 }
 
@@ -1533,36 +1533,37 @@
 	s *string
 }
 
-func NewV(u U) *V { // ERROR "leaking param: u"
-	return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape"
+// BAD -- level of leak ought to be 0
+func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1"
+	return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape"
 }
 
 func foo152() {
-	a := "a"   // ERROR "moved to heap: a"
-	u := U{&a} // ERROR "&a escapes to heap"
+	a := "a"   // ERROR "moved to heap: a$"
+	u := U{&a} // ERROR "&a escapes to heap$"
 	v := NewV(u)
 	println(v)
 }
 
 // issue 8176 - &x in type switch body not marked as escaping
 
-func foo153(v interface{}) *int { // ERROR "leaking param: v"
+func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$"
 	switch x := v.(type) {
-	case int: // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+	case int: // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	}
 	panic(0)
 }
 
 // issue 8185 - &result escaping into result
 
-func f() (x int, y *int) { // ERROR "moved to heap: x"
-	y = &x // ERROR "&x escapes to heap"
+func f() (x int, y *int) { // ERROR "moved to heap: x$"
+	y = &x // ERROR "&x escapes to heap$"
 	return
 }
 
-func g() (x interface{}) { // ERROR "moved to heap: x"
-	x = &x // ERROR "&x escapes to heap"
+func g() (x interface{}) { // ERROR "moved to heap: x$"
+	x = &x // ERROR "&x escapes to heap$"
 	return
 }
 
@@ -1575,22 +1576,22 @@
 func ptrlitNoescape() {
 	// Both literal and element do not escape.
 	i := 0
-	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape"
+	x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$"
 	_ = x
 }
 
 func ptrlitNoEscape2() {
 	// Literal does not escape, but element does.
-	i := 0        // ERROR "moved to heap: i"
-	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
-	sink = *x     // ERROR "\*x escapes to heap"
+	i := 0        // ERROR "moved to heap: i$"
+	x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$"
+	sink = *x     // ERROR "\*x escapes to heap$"
 }
 
 func ptrlitEscape() {
 	// Both literal and element escape.
-	i := 0        // ERROR "moved to heap: i"
-	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
-	sink = x      // ERROR "x escapes to heap"
+	i := 0        // ERROR "moved to heap: i$"
+	x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" "&i escapes to heap$"
+	sink = x      // ERROR "x escapes to heap$"
 }
 
 // self-assignments
@@ -1603,31 +1604,31 @@
 	str2 string
 }
 
-func (b *Buffer) foo() { // ERROR "b does not escape"
-	b.buf1 = b.buf1[1:2]   // ERROR "ignoring self-assignment to b.buf1"
-	b.buf1 = b.buf1[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
-	b.buf1 = b.buf2[1:2]   // ERROR "ignoring self-assignment to b.buf1"
-	b.buf1 = b.buf2[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
+func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$"
+	b.buf1 = b.buf1[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
 }
 
-func (b *Buffer) bar() { // ERROR "leaking param: b"
-	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap"
+func (b *Buffer) bar() { // ERROR "leaking param: b$"
+	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$"
 }
 
-func (b *Buffer) baz() { // ERROR "b does not escape"
-	b.str1 = b.str1[1:2] // ERROR "ignoring self-assignment to b.str1"
-	b.str1 = b.str2[1:2] // ERROR "ignoring self-assignment to b.str1"
+func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$"
+	b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
+	b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
 }
 
-func (b *Buffer) bat() { // ERROR "leaking param: b"
-	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
+func (b *Buffer) bat() { // ERROR "leaking param content: b$"
+	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$"
 	o.buf1 = b.buf1[1:2]
-	sink = o // ERROR "o escapes to heap"
+	sink = o // ERROR "o escapes to heap$"
 }
 
-func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
-	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp"
-	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp"
+func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$"
+	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp$"
+	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp$"
 }
 
 type StructWithString struct {
@@ -1640,44 +1641,44 @@
 // to just x, and thus &i looks escaping.
 func fieldFlowTracking() {
 	var x StructWithString
-	i := 0     // ERROR "moved to heap: i"
-	x.p = &i   // ERROR "&i escapes to heap"
-	sink = x.s // ERROR "x.s escapes to heap"
+	i := 0     // ERROR "moved to heap: i$"
+	x.p = &i   // ERROR "&i escapes to heap$"
+	sink = x.s // ERROR "x.s escapes to heap$"
 }
 
 // String operations.
 
 func slicebytetostring0() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) does not escape"
+	b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring0 string\(b\) does not escape$"
 	_ = s
 }
 
 func slicebytetostring1() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) does not escape"
+	b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring1 string\(b\) does not escape$"
 	s1 := s[0:1]
 	_ = s1
 }
 
 func slicebytetostring2() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) escapes to heap"
-	s1 := s[0:1]          // ERROR "moved to heap: s1"
-	sink = &s1            // ERROR "&s1 escapes to heap"
+	b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
+	s1 := s[0:1]          // ERROR "moved to heap: s1$"
+	sink = &s1            // ERROR "&s1 escapes to heap$"
 }
 
 func slicebytetostring3() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) escapes to heap"
+	b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
 	s1 := s[0:1]
-	sink = s1 // ERROR "s1 escapes to heap"
+	sink = s1 // ERROR "s1 escapes to heap$"
 }
 
 func addstr0() {
 	s0 := "a"
 	s1 := "b"
-	s := s0 + s1 // ERROR "s0 \+ s1 does not escape"
+	s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$"
 	_ = s
 }
 
@@ -1685,115 +1686,137 @@
 	s0 := "a"
 	s1 := "b"
 	s := "c"
-	s += s0 + s1 // ERROR "s0 \+ s1 does not escape"
+	s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$"
 	_ = s
 }
 
 func addstr2() {
-	b := make([]byte, 20) // ERROR "does not escape"
+	b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$"
 	s0 := "a"
-	s := string(b) + s0 // ERROR "string\(b\) does not escape" "string\(b\) \+ s0 does not escape"
+	s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$"
 	_ = s
 }
 
 func addstr3() {
 	s0 := "a"
 	s1 := "b"
-	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
+	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$"
 	s2 := s[0:1]
-	sink = s2 // ERROR "s2 escapes to heap"
+	sink = s2 // ERROR "s2 escapes to heap$"
 }
 
 func intstring0() bool {
 	// string does not escape
 	x := '0'
-	s := string(x) // ERROR "string\(x\) does not escape"
+	s := string(x) // ERROR "intstring0 string\(x\) does not escape$"
 	return s == "0"
 }
 
 func intstring1() string {
 	// string does not escape, but the buffer does
 	x := '0'
-	s := string(x) // ERROR "string\(x\) escapes to heap"
+	s := string(x) // ERROR "string\(x\) escapes to heap$"
 	return s
 }
 
 func intstring2() {
 	// string escapes to heap
 	x := '0'
-	s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
-	sink = &s      // ERROR "&s escapes to heap"
+	s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$"
+	sink = &s      // ERROR "&s escapes to heap$"
 }
 
 func stringtoslicebyte0() {
 	s := "foo"
-	x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape"
+	x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$"
 	_ = x
 }
 
 func stringtoslicebyte1() []byte {
 	s := "foo"
-	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
 }
 
 func stringtoslicebyte2() {
 	s := "foo"
-	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
 }
 
 func stringtoslicerune0() {
 	s := "foo"
-	x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape"
+	x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$"
 	_ = x
 }
 
 func stringtoslicerune1() []rune {
 	s := "foo"
-	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
 }
 
 func stringtoslicerune2() {
 	s := "foo"
-	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
 }
 
 func slicerunetostring0() {
-	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
-	s := string(r)       // ERROR "string\(r\) does not escape"
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$"
+	s := string(r)       // ERROR "slicerunetostring0 string\(r\) does not escape$"
 	_ = s
 }
 
 func slicerunetostring1() string {
-	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
-	return string(r)     // ERROR "string\(r\) escapes to heap"
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$"
+	return string(r)     // ERROR "string\(r\) escapes to heap$"
 }
 
 func slicerunetostring2() {
-	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
-	sink = string(r)     // ERROR "string\(r\) escapes to heap"
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$"
+	sink = string(r)     // ERROR "string\(r\) escapes to heap$"
 }
 
 func makemap0() {
-	m := make(map[int]int) // ERROR "make\(map\[int\]int\) does not escape"
+	m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$"
 	m[0] = 0
 	m[1]++
 	delete(m, 1)
-	sink = m[0] // ERROR "m\[0\] escapes to heap"
+	sink = m[0] // ERROR "m\[0\] escapes to heap$"
 }
 
 func makemap1() map[int]int {
-	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
+	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
 }
 
 func makemap2() {
-	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
-	sink = m               // ERROR "m escapes to heap"
+	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
+	sink = m               // ERROR "m escapes to heap$"
 }
 
-func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"
-	return m["foo"] // ERROR `"foo" does not escape`
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$"
+	return m["foo"] // ERROR "nonescapingEface .foo. does not escape$"
 }
 
-func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape"
-	return m[MV(0)] // ERROR "MV\(0\) does not escape"
+func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$"
+	return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$"
+}
+
+func issue10353() {
+	x := new(int) // ERROR "new\(int\) escapes to heap$"
+	issue10353a(x)()
+}
+
+func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return func() { // ERROR "func literal escapes to heap$"
+		println(*x)
+	}
+}
+
+func issue10353b() {
+	var f func()
+	for {
+		x := new(int) // ERROR "new\(int\) escapes to heap$"
+		f = func() {  // ERROR "func literal escapes to heap$"
+			println(*x)
+		}
+	}
+	_ = f
 }
diff --git a/test/escape2n.go b/test/escape2n.go
index 59f64c0..bf8c534 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -18,94 +18,94 @@
 
 var gxx *int
 
-func foo1(x int) { // ERROR "moved to heap: x"
-	gxx = &x // ERROR "&x escapes to heap"
+func foo1(x int) { // ERROR "moved to heap: x$"
+	gxx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo2(yy *int) { // ERROR "leaking param: yy"
+func foo2(yy *int) { // ERROR "leaking param: yy$"
 	gxx = yy
 }
 
-func foo3(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func foo3(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
 type T *T
 
-func foo3b(t T) { // ERROR "leaking param: t"
+func foo3b(t T) { // ERROR "leaking param: t$"
 	*t = t
 }
 
 // xx isn't going anywhere, so use of yy is ok
-func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$"
 	xx = yy
 }
 
 // xx isn't going anywhere, so taking address of yy is ok
-func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
-	xx = &yy // ERROR "&yy does not escape"
+func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$"
+	xx = &yy // ERROR "foo5 &yy does not escape$"
 }
 
-func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy"
+func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$"
 	*xx = yy
 }
 
-func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$"
 	**xx = *yy
 }
 
-func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape"
+func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$"
 	xx = yy
 	return *xx
 }
 
-func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy"
+func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$"
 	xx = yy
 	return xx
 }
 
-func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$"
 	*xx = *yy
 }
 
 func foo11() int {
 	x, y := 0, 42
-	xx := &x // ERROR "&x does not escape"
-	yy := &y // ERROR "&y does not escape"
+	xx := &x // ERROR "foo11 &x does not escape$"
+	yy := &y // ERROR "foo11 &y does not escape$"
 	*xx = *yy
 	return x
 }
 
 var xxx **int
 
-func foo12(yyy **int) { // ERROR "leaking param: yyy"
+func foo12(yyy **int) { // ERROR "leaking param: yyy$"
 	xxx = yyy
 }
 
 // Must treat yyy as leaking because *yyy leaks, and the escape analysis
 // summaries in exported metadata do not distinguish these two cases.
-func foo13(yyy **int) { // ERROR "leaking param: yyy"
+func foo13(yyy **int) { // ERROR "leaking param content: yyy$"
 	*xxx = *yyy
 }
 
-func foo14(yyy **int) { // ERROR "yyy does not escape"
+func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$"
 	**xxx = **yyy
 }
 
-func foo15(yy *int) { // ERROR "moved to heap: yy"
-	xxx = &yy // ERROR "&yy escapes to heap"
+func foo15(yy *int) { // ERROR "moved to heap: yy$"
+	xxx = &yy // ERROR "&yy escapes to heap$"
 }
 
-func foo16(yy *int) { // ERROR "leaking param: yy"
+func foo16(yy *int) { // ERROR "leaking param: yy$"
 	*xxx = yy
 }
 
-func foo17(yy *int) { // ERROR "yy does not escape"
+func foo17(yy *int) { // ERROR "foo17 yy does not escape$"
 	**xxx = *yy
 }
 
-func foo18(y int) { // ERROR "moved to heap: "y"
-	*xxx = &y // ERROR "&y escapes to heap"
+func foo18(y int) { // ERROR "moved to heap: y$"
+	*xxx = &y // ERROR "&y escapes to heap$"
 }
 
 func foo19(y int) {
@@ -118,52 +118,52 @@
 }
 
 func NewBar() *Bar {
-	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap"
+	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp(x *int) *Bar { // ERROR "leaking param: x"
-	return &Bar{42, x} // ERROR "&Bar literal escapes to heap"
+func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return &Bar{42, x} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp2(x *int) *Bar { // ERROR "x does not escape"
-	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap"
+func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$"
+	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func (b *Bar) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$"
 	return *(b.ii)
 }
 
-func (b *Bar) Leak() *int { // ERROR "leaking param: b"
-	return &b.i // ERROR "&b.i escapes to heap"
+func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return &b.i // ERROR "&b.i escapes to heap$"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii
 }
 
-func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
+func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
 	return b.ii
 }
 
-func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b Bar) StillNoLeak() int { // ERROR "b does not escape"
+func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$"
 	v := 0
-	b.ii = &v // ERROR "&v does not escape"
+	b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$"
 	return b.i
 }
 
-func goLeak(b *Bar) { // ERROR "leaking param: b"
+func goLeak(b *Bar) { // ERROR "leaking param: b$"
 	go b.NoLeak()
 }
 
@@ -173,105 +173,105 @@
 }
 
 func NewBar2() *Bar2 {
-	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap"
+	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$"
 }
 
-func (b *Bar2) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$"
 	return b.i[0]
 }
 
-func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
-	return b.i[:] // ERROR "b.i escapes to heap"
+func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return b.i[:] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii[0:1]
 }
 
-func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape"
+func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$"
 	return b.i
 }
 
-func (b *Bar2) LeakSelf() { // ERROR "leaking param: b"
-	b.ii = b.i[0:4] // ERROR "b.i escapes to heap"
+func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$"
+	b.ii = b.i[0:4] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
+func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$"
 	var buf []int
-	buf = b.i[0:] // ERROR "b.i escapes to heap"
+	buf = b.i[0:] // ERROR "b.i escapes to heap$"
 	b.ii = buf
 }
 
 func foo21() func() int {
 	x := 42
-	return func() int { // ERROR "func literal escapes to heap"
+	return func() int { // ERROR "func literal escapes to heap$"
 		return x
 	}
 }
 
 func foo21a() func() int {
-	x := 42             // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		x++ // ERROR "&x escapes to heap"
+	x := 42             // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
 		return x
 	}
 }
 
 func foo22() int {
 	x := 42
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo22 func literal does not escape$"
 		return x
 	}()
 }
 
 func foo23(x int) func() int {
-	return func() int { // ERROR "func literal escapes to heap"
+	return func() int { // ERROR "func literal escapes to heap$"
 		return x
 	}
 }
 
 func foo23a(x int) func() int {
-	f := func() int { // ERROR "func literal escapes to heap"
+	f := func() int { // ERROR "func literal escapes to heap$"
 		return x
 	}
 	return f
 }
 
 func foo23b(x int) *(func() int) {
-	f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap"
-	return &f                    // ERROR "&f escapes to heap"
+	f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$"
+	return &f                    // ERROR "&f escapes to heap$"
 }
 
-func foo23c(x int) func() int { // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		x++ // ERROR "&x escapes to heap"
+func foo23c(x int) func() int { // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
 		return x
 	}
 }
 
 func foo24(x int) int {
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo24 func literal does not escape$"
 		return x
 	}()
 }
 
 var x *int
 
-func fooleak(xx *int) int { // ERROR "leaking param: xx"
+func fooleak(xx *int) int { // ERROR "leaking param: xx$"
 	x = xx
 	return *x
 }
 
-func foonoleak(xx *int) int { // ERROR "xx does not escape"
+func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$"
 	return *x + *xx
 }
 
-func foo31(x int) int { // ERROR "moved to heap: x"
-	return fooleak(&x) // ERROR "&x escapes to heap"
+func foo31(x int) int { // ERROR "moved to heap: x$"
+	return fooleak(&x) // ERROR "&x escapes to heap$"
 }
 
 func foo32(x int) int {
-	return foonoleak(&x) // ERROR "&x does not escape"
+	return foonoleak(&x) // ERROR "foo32 &x does not escape$"
 }
 
 type Foo struct {
@@ -282,114 +282,114 @@
 var F Foo
 var pf *Foo
 
-func (f *Foo) fooleak() { // ERROR "leaking param: f"
+func (f *Foo) fooleak() { // ERROR "leaking param: f$"
 	pf = f
 }
 
-func (f *Foo) foonoleak() { // ERROR "f does not escape"
+func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$"
 	F.x = f.x
 }
 
-func (f *Foo) Leak() { // ERROR "leaking param: f"
+func (f *Foo) Leak() { // ERROR "leaking param: f$"
 	f.fooleak()
 }
 
-func (f *Foo) NoLeak() { // ERROR "f does not escape"
+func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$"
 	f.foonoleak()
 }
 
-func foo41(x int) { // ERROR "moved to heap: x"
-	F.xx = &x // ERROR "&x escapes to heap"
+func foo41(x int) { // ERROR "moved to heap: x$"
+	F.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo44(yy *int) { // ERROR "leaking param: yy"
+func foo44(yy *int) { // ERROR "leaking param: yy$"
 	F.xx = yy
 }
 
-func (f *Foo) foo45() { // ERROR "f does not escape"
+func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$"
 	F.x = f.x
 }
 
 // See foo13 above for explanation of why f leaks.
-func (f *Foo) foo46() { // ERROR "leaking param: f"
+func (f *Foo) foo46() { // ERROR "leaking param content: f$"
 	F.xx = f.xx
 }
 
-func (f *Foo) foo47() { // ERROR "leaking param: f"
-	f.xx = &f.x // ERROR "&f.x escapes to heap"
+func (f *Foo) foo47() { // ERROR "leaking param: f$"
+	f.xx = &f.x // ERROR "&f.x escapes to heap$"
 }
 
 var ptrSlice []*int
 
-func foo50(i *int) { // ERROR "leaking param: i"
+func foo50(i *int) { // ERROR "leaking param: i$"
 	ptrSlice[0] = i
 }
 
 var ptrMap map[*int]*int
 
-func foo51(i *int) { // ERROR "leaking param: i"
+func foo51(i *int) { // ERROR "leaking param: i$"
 	ptrMap[i] = i
 }
 
-func indaddr1(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func indaddr1(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
-func indaddr2(x *int) *int { // ERROR "leaking param: x"
-	return *&x // ERROR "&x does not escape"
+func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *&x // ERROR "indaddr2 &x does not escape$"
 }
 
-func indaddr3(x *int32) *int { // ERROR "leaking param: x"
-	return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape"
+func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$"
 }
 
 // From package math:
 
 func Float32bits(f float32) uint32 {
-	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$"
 }
 
 func Float32frombits(b uint32) float32 {
-	return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$"
 }
 
 func Float64bits(f float64) uint64 {
-	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$"
 }
 
 func Float64frombits(b uint64) float64 {
-	return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$"
 }
 
 // contrast with
-func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f"
-	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap"
+func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$"
+	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$"
 }
 
-func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f"
+func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$"
 	return (*uint64)(unsafe.Pointer(f))
 }
 
-func typesw(i interface{}) *int { // ERROR "leaking param: i"
+func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch val := i.(type) {
 	case *int:
 		return val
 	case *int8:
-		v := int(*val) // ERROR "moved to heap: v"
-		return &v      // ERROR "&v escapes to heap"
+		v := int(*val) // ERROR "moved to heap: v$"
+		return &v      // ERROR "&v escapes to heap$"
 	}
 	return nil
 }
 
-func exprsw(i *int) *int { // ERROR "leaking param: i"
+func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch j := i; *j + 110 {
 	case 12:
 		return j
@@ -401,20 +401,20 @@
 }
 
 // assigning to an array element is like assigning to the array
-func foo60(i *int) *int { // ERROR "leaking param: i"
+func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	var a [12]*int
 	a[0] = i
 	return a[1]
 }
 
-func foo60a(i *int) *int { // ERROR "i does not escape"
+func foo60a(i *int) *int { // ERROR "foo60a i does not escape$"
 	var a [12]*int
 	a[0] = i
 	return nil
 }
 
 // assigning to a struct field  is like assigning to the struct
-func foo61(i *int) *int { // ERROR "leaking param: i"
+func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	type S struct {
 		a, b *int
 	}
@@ -423,7 +423,7 @@
 	return s.b
 }
 
-func foo61a(i *int) *int { // ERROR "i does not escape"
+func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
 	type S struct {
 		a, b *int
 	}
@@ -435,11 +435,11 @@
 // assigning to a struct field is like assigning to the struct but
 // here this subtlety is lost, since s.a counts as an assignment to a
 // track-losing dereference.
-func foo62(i *int) *int { // ERROR "leaking param: i"
+func foo62(i *int) *int { // ERROR "leaking param: i$"
 	type S struct {
 		a, b *int
 	}
-	s := new(S) // ERROR "new[(]S[)] does not escape"
+	s := new(S) // ERROR "foo62 new\(S\) does not escape$"
 	s.a = i
 	return nil // s.b
 }
@@ -448,14 +448,14 @@
 	M()
 }
 
-func foo63(m M) { // ERROR "m does not escape"
+func foo63(m M) { // ERROR "foo63 m does not escape$"
 }
 
-func foo64(m M) { // ERROR "leaking param: m"
+func foo64(m M) { // ERROR "leaking param: m$"
 	m.M()
 }
 
-func foo64b(m M) { // ERROR "leaking param: m"
+func foo64b(m M) { // ERROR "leaking param: m$"
 	defer m.M()
 }
 
@@ -465,56 +465,56 @@
 
 func foo65() {
 	var mv MV
-	foo63(&mv) // ERROR "&mv does not escape"
+	foo63(&mv) // ERROR "foo65 &mv does not escape$"
 }
 
 func foo66() {
-	var mv MV  // ERROR "moved to heap: mv"
-	foo64(&mv) // ERROR "&mv escapes to heap"
+	var mv MV  // ERROR "moved to heap: mv$"
+	foo64(&mv) // ERROR "&mv escapes to heap$"
 }
 
 func foo67() {
 	var mv MV
-	foo63(mv) // ERROR "mv does not escape"
+	foo63(mv) // ERROR "foo67 mv does not escape$"
 }
 
 func foo68() {
 	var mv MV
 	// escapes but it's an int so irrelevant
-	foo64(mv) // ERROR "mv escapes to heap"
+	foo64(mv) // ERROR "mv escapes to heap$"
 }
 
-func foo69(m M) { // ERROR "leaking param: m"
+func foo69(m M) { // ERROR "leaking param: m$"
 	foo64(m)
 }
 
-func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
-	m = mv1 // ERROR "mv1 escapes to heap"
+func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
+	m = mv1 // ERROR "mv1 escapes to heap$"
 	foo64(m)
 }
 
-func foo71(x *int) []*int { // ERROR "leaking param: x"
+func foo71(x *int) []*int { // ERROR "leaking param: x$"
 	var y []*int
 	y = append(y, x)
 	return y
 }
 
-func foo71a(x int) []*int { // ERROR "moved to heap: x"
+func foo71a(x int) []*int { // ERROR "moved to heap: x$"
 	var y []*int
-	y = append(y, &x) // ERROR "&x escapes to heap"
+	y = append(y, &x) // ERROR "&x escapes to heap$"
 	return y
 }
 
 func foo72() {
 	var x int
 	var y [1]*int
-	y[0] = &x // ERROR "&x does not escape"
+	y[0] = &x // ERROR "foo72 &x does not escape$"
 }
 
 func foo72aa() [10]*int {
-	var x int // ERROR "moved to heap: x"
+	var x int // ERROR "moved to heap: x$"
 	var y [10]*int
-	y[0] = &x // ERROR "&x escapes to heap"
+	y[0] = &x // ERROR "&x escapes to heap$"
 	return y
 }
 
@@ -522,8 +522,8 @@
 	var y [10]*int
 	for i := 0; i < 10; i++ {
 		// escapes its scope
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return
 }
@@ -531,42 +531,42 @@
 func foo72b() [10]*int {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return y
 }
 
 // issue 2145
 func foo73() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$"
 	for _, v := range s {
 		vv := v
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap"
+		defer func() { // ERROR "func literal escapes to heap$"
 			println(vv)
 		}()
 	}
 }
 
 func foo731() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap"
-			vv = 42 // ERROR "&vv escapes to heap"
+		defer func() { // ERROR "func literal escapes to heap$"
+			vv = 42 // ERROR "&vv escapes to heap$"
 			println(vv)
 		}()
 	}
 }
 
 func foo74() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$"
 	for _, v := range s {
 		vv := v
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap"
+		fn := func() { // ERROR "func literal escapes to heap$"
 			println(vv)
 		}
 		defer fn()
@@ -574,12 +574,12 @@
 }
 
 func foo74a() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap"
-			vv += 1 // ERROR "&vv escapes to heap"
+		fn := func() { // ERROR "func literal escapes to heap$"
+			vv += 1 // ERROR "&vv escapes to heap$"
 			println(vv)
 		}
 		defer fn()
@@ -589,11 +589,11 @@
 // issue 3975
 func foo74b() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$"
 	for i, v := range s {
 		vv := v
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap"
+		array[i] = func() { // ERROR "func literal escapes to heap$"
 			println(vv)
 		}
 	}
@@ -601,130 +601,130 @@
 
 func foo74c() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$"
 	for i, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap"
-			println(&vv) // ERROR "&vv escapes to heap" "&vv does not escape"
+		array[i] = func() { // ERROR "func literal escapes to heap$"
+			println(&vv) // ERROR "&vv escapes to heap$" "<S> &vv does not escape$"
 		}
 	}
 }
 
-func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y to result ~r2"
+func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x to result ~r2"
-	return &x[0] // ERROR "&x.0. escapes to heap"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$"
+	return &x[0] // ERROR "&x\[0\] escapes to heap$"
 }
 
-func foo75(z *int) { // ERROR "z does not escape"
-	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75(z *int) { // ERROR "foo75 z does not escape$"
+	myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75 ... argument does not escape$"
 }
 
-func foo75a(z *int) { // ERROR "z does not escape"
-	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75a(z *int) { // ERROR "foo75a z does not escape$"
+	myprint1(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75a ... argument does not escape$"
 }
 
-func foo75esc(z *int) { // ERROR "leaking param: z"
-	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75esc(z *int) { // ERROR "leaking param: z$"
+	gxx = myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75esc ... argument does not escape$"
 }
 
-func foo75aesc(z *int) { // ERROR "z does not escape"
+func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$"
 	var ppi **interface{}       // assignments to pointer dereferences lose track
-	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	*ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 }
 
-func foo75aesc1(z *int) { // ERROR "z does not escape"
-	sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "myprint1\(z, 1, 2, 3\) escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$"
+	sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$"
 }
 
 // BAD: z does not escape here
-func foo76(z *int) { // ERROR "leaking param: z"
-	myprint(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
+func foo76(z *int) { // ERROR "leaking param: z$"
+	myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z escapes to heap$"
 }
 
 // BAD: z does not escape here
-func foo76a(z *int) { // ERROR "leaking param: z"
-	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
+func foo76a(z *int) { // ERROR "leaking param: z$"
+	myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z escapes to heap$"
 }
 
 func foo76b() {
-	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76b ... argument does not escape$"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76c ... argument does not escape$"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	defer myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76d ... argument does not escape$"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+	defer myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76e ... argument does not escape$"
 }
 
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+		defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+		defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
 	}
 }
 
-func foo77(z []interface{}) { // ERROR "z does not escape"
+func foo77(z []interface{}) { // ERROR "foo77 z does not escape$"
 	myprint(nil, z...) // z does not escape
 }
 
-func foo77a(z []interface{}) { // ERROR "z does not escape"
+func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$"
 	myprint1(nil, z...)
 }
 
-func foo77b(z []interface{}) { // ERROR "leaking param: z"
+func foo77b(z []interface{}) { // ERROR "leaking param: z$"
 	var ppi **interface{}
 	*ppi = myprint1(nil, z...)
 }
 
-func foo77c(z []interface{}) { // ERROR "leaking param: z"
-	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z\.\.\.\) escapes to heap"
+func foo77c(z []interface{}) { // ERROR "leaking param: z$"
+	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$"
 }
 
 func dotdotdot() {
 	// BAD: i should not escape here
-	i := 0           // ERROR "moved to heap: i"
-	myprint(nil, &i) // ERROR "&i escapes to heap" "\.\.\. argument does not escape"
+	i := 0           // ERROR "moved to heap: i$"
+	myprint(nil, &i) // ERROR "&i escapes to heap$" "dotdotdot ... argument does not escape$"
 
 	// BAD: j should not escape here
-	j := 0            // ERROR "moved to heap: j"
-	myprint1(nil, &j) // ERROR "&j escapes to heap" "\.\.\. argument does not escape"
+	j := 0            // ERROR "moved to heap: j$"
+	myprint1(nil, &j) // ERROR "&j escapes to heap$" "dotdotdot ... argument does not escape$"
 }
 
-func foo78(z int) *int { // ERROR "moved to heap: z"
-	return &z // ERROR "&z escapes to heap"
+func foo78(z int) *int { // ERROR "moved to heap: z$"
+	return &z // ERROR "&z escapes to heap$"
 }
 
-func foo78a(z int) *int { // ERROR "moved to heap: z"
-	y := &z   // ERROR "&z escapes to heap"
-	x := &y   // ERROR "&y does not escape"
+func foo78a(z int) *int { // ERROR "moved to heap: z$"
+	y := &z   // ERROR "&z escapes to heap$"
+	x := &y   // ERROR "foo78a &y does not escape$"
 	return *x // really return y
 }
 
 func foo79() *int {
-	return new(int) // ERROR "new[(]int[)] escapes to heap"
+	return new(int) // ERROR "new\(int\) escapes to heap$"
 }
 
 func foo80() *int {
 	var z *int
 	for {
 		// Really just escapes its scope but we don't distinguish
-		z = new(int) // ERROR "new[(]int[)] escapes to heap"
+		z = new(int) // ERROR "new\(int\) escapes to heap$"
 	}
 	_ = z
 	return nil
@@ -732,24 +732,24 @@
 
 func foo81() *int {
 	for {
-		z := new(int) // ERROR "new[(]int[)] does not escape"
+		z := new(int) // ERROR "foo81 new\(int\) does not escape$"
 		_ = z
 	}
 	return nil
 }
 
-func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$"
 
-func noop(x, y *int) {} // ERROR "does not escape"
+func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$"
 
 func foo82() {
-	var x, y, z int  // ERROR "moved to heap"
-	go noop(tee(&z)) // ERROR "&z escapes to heap"
-	go noop(&x, &y)  // ERROR "escapes to heap"
+	var x, y, z int  // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$"
+	go noop(tee(&z)) // ERROR "&z escapes to heap$"
+	go noop(&x, &y)  // ERROR "&x escapes to heap$" "&y escapes to heap$"
 	for {
-		var u, v, w int     // ERROR "moved to heap"
-		defer noop(tee(&u)) // ERROR "&u escapes to heap"
-		defer noop(&v, &w)  // ERROR "escapes to heap"
+		var u, v, w int     // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$"
+		defer noop(tee(&u)) // ERROR "&u escapes to heap$"
+		defer noop(&v, &w)  // ERROR "&v escapes to heap$" "&w escapes to heap$"
 	}
 }
 
@@ -762,24 +762,24 @@
 	N int64
 }
 
-func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r"
-	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap"
+func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$"
+	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$"
 }
 
-func foo90(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo91(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo92(x *int) [2]*int { // ERROR "leaking param: x"
+func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return [2]*int{x, nil}
 }
 
 // does not leak c
-func foo93(c chan *int) *int { // ERROR "c does not escape"
+func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
 	for v := range c {
 		return v
 	}
@@ -787,7 +787,7 @@
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$"
 	for k, v := range m {
 		if b {
 			return k
@@ -798,32 +798,32 @@
 }
 
 // does leak x
-func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$"
 	m[x] = x
 }
 
 // does not leak m
-func foo96(m []*int) *int { // ERROR "m does not escape"
+func foo96(m []*int) *int { // ERROR "foo96 m does not escape$"
 	return m[0]
 }
 
 // does leak m
-func foo97(m [1]*int) *int { // ERROR "leaking param: m"
+func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[0]
 }
 
 // does not leak m
-func foo98(m map[int]*int) *int { // ERROR "m does not escape"
+func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$"
 	return m[0]
 }
 
 // does leak m
-func foo99(m *[1]*int) []*int { // ERROR "leaking param: m"
+func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[:]
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "m does not escape"
+func foo100(m []*int) *int { // ERROR "foo100 m does not escape$"
 	for _, v := range m {
 		return v
 	}
@@ -831,7 +831,7 @@
 }
 
 // does leak m
-func foo101(m [1]*int) *int { // ERROR "leaking param: m"
+func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	for _, v := range m {
 		return v
 	}
@@ -839,109 +839,109 @@
 }
 
 // does not leak m
-func foo101a(m [1]*int) *int { // ERROR "m does not escape"
-	for i := range m { // ERROR "moved to heap: i"
-		return &i // ERROR "&i escapes to heap"
+func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$"
+	for i := range m { // ERROR "moved to heap: i$"
+		return &i // ERROR "&i escapes to heap$"
 	}
 	return nil
 }
 
 // does leak x
-func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$"
 	m[0] = x
 }
 
 // does not leak x
-func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape"
+func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$"
 	m[0] = x
 }
 
 var y []*int
 
 // does not leak x
-func foo104(x []*int) { // ERROR "x does not escape"
+func foo104(x []*int) { // ERROR "foo104 x does not escape$"
 	copy(y, x)
 }
 
 // does not leak x
-func foo105(x []*int) { // ERROR "x does not escape"
+func foo105(x []*int) { // ERROR "foo105 x does not escape$"
 	_ = append(y, x...)
 }
 
 // does leak x
-func foo106(x *int) { // ERROR "leaking param: x"
+func foo106(x *int) { // ERROR "leaking param: x$"
 	_ = append(y, x)
 }
 
-func foo107(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap"
+func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo108(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap"
+func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo109(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape"
+func foo109(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$"
 	for k, _ := range m {
 		return k
 	}
 	return nil
 }
 
-func foo110(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape"
+func foo110(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$"
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x"
-	m := []*int{x} // ERROR "\[\]\*int literal does not escape"
+func foo111(x *int) *int { // ERROR "leaking param: x$"
+	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
 
-func foo112(x *int) *int { // ERROR "leaking param: x"
+func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := [1]*int{x}
 	return m[0]
 }
 
-func foo113(x *int) *int { // ERROR "leaking param: x"
+func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := Bar{ii: x}
 	return m.ii
 }
 
-func foo114(x *int) *int { // ERROR "leaking param: x"
-	m := &Bar{ii: x} // ERROR "&Bar literal does not escape"
+func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$"
 	return m.ii
 }
 
-func foo115(x *int) *int { // ERROR "leaking param: x"
+func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1))
 }
 
 func foo116(b bool) *int {
 	if b {
-		x := 1    // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+		x := 1    // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	} else {
-		y := 1    // ERROR "moved to heap: y"
-		return &y // ERROR "&y escapes to heap"
+		y := 1    // ERROR "moved to heap: y$"
+		return &y // ERROR "&y escapes to heap$"
 	}
 	return nil
 }
 
-func foo117(unknown func(interface{})) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
-func foo118(unknown func(*int)) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
 func external(*int)
 
-func foo119(x *int) { // ERROR "leaking param: x"
+func foo119(x *int) { // ERROR "leaking param: x$"
 	external(x)
 }
 
@@ -1152,16 +1152,16 @@
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
-		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		go myprint(nil, i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
-		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		go fmt.Printf("%d", i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
 	}
 }
 
@@ -1171,7 +1171,7 @@
 
 	goto L1
 L1:
-	i = new(int) // ERROR "new.int. does not escape"
+	i = new(int) // ERROR "foo122 new\(int\) does not escape$"
 	_ = i
 }
 
@@ -1180,25 +1180,25 @@
 	var i *int
 
 L1:
-	i = new(int) // ERROR "new.int. escapes to heap"
+	i = new(int) // ERROR "new\(int\) escapes to heap$"
 
 	goto L1
 	_ = i
 }
 
-func foo124(x **int) { // ERROR "x does not escape"
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes"
-	func() {  // ERROR "func literal does not escape"
-		*x = p // ERROR "leaking closure reference p"
+func foo124(x **int) { // ERROR "foo124 x does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo124 func literal does not escape$"
+		*x = p // ERROR "leaking closure reference p$"
 	}()
 }
 
-func foo125(ch chan *int) { // ERROR "does not escape"
-	var i int // ERROR "moved to heap"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		ch <- p // ERROR "leaking closure reference p"
+func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo125 func literal does not escape$"
+		ch <- p // ERROR "leaking closure reference p$"
 	}()
 }
 
@@ -1206,9 +1206,9 @@
 	var px *int // loopdepth 0
 	for {
 		// loopdepth 1
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo126 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$"
 		}()
 	}
 	_ = px
@@ -1217,26 +1217,26 @@
 var px *int
 
 func foo127() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
 	q := p
 	px = q
 }
 
 func foo128() {
 	var i int
-	p := &i // ERROR "&i does not escape"
+	p := &i // ERROR "foo128 &i does not escape$"
 	q := p
 	_ = q
 }
 
 func foo129() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p   // ERROR "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo129 func literal does not escape$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "<S> func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
@@ -1244,40 +1244,40 @@
 
 func foo130() {
 	for {
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes" "leaking closure reference i"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo130 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 		}()
 	}
 }
 
 func foo131() {
-	var i int // ERROR "moved to heap"
-	func() {  // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int // ERROR "moved to heap: i$"
+	func() {  // ERROR "foo131 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo132() {
-	var i int   // ERROR "moved to heap"
-	go func() { // ERROR "func literal escapes to heap"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int   // ERROR "moved to heap: i$"
+	go func() { // ERROR "func literal escapes to heap$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo133() {
-	var i int      // ERROR "moved to heap"
-	defer func() { // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int      // ERROR "moved to heap: i$"
+	defer func() { // ERROR "foo133 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo134() {
 	var i int
-	p := &i  // ERROR "&i does not escape"
-	func() { // ERROR "func literal does not escape"
+	p := &i  // ERROR "foo134 &i does not escape$"
+	func() { // ERROR "foo134 func literal does not escape$"
 		q := p
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "<S> func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1285,11 +1285,11 @@
 }
 
 func foo135() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap"
-	go func() { // ERROR "func literal escapes to heap"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
 		q := p
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "<S> func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1297,23 +1297,23 @@
 }
 
 func foo136() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap"
-	go func() { // ERROR "func literal escapes to heap"
-		q := p   // ERROR "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "<S> func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
 }
 
 func foo137() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p      // ERROR "leaking closure reference p"
-		go func() { // ERROR "func literal escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo137 func literal does not escape$"
+		q := p      // ERROR "leaking closure reference p$"
+		go func() { // ERROR "func literal escapes to heap$"
 			r := q
 			_ = r
 		}()
@@ -1324,8 +1324,8 @@
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new.T. escapes to heap"
-	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
+	t := new(T)    // ERROR "new\(T\) escapes to heap$"
+	return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$"
 }
 
 func foo139() *byte {
@@ -1334,8 +1334,8 @@
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new.T. escapes to heap"
-	return &t.x.y // ERROR "&t.x.y escapes to heap"
+	t := new(T)   // ERROR "new\(T\) escapes to heap$"
+	return &t.x.y // ERROR "&t.x.y escapes to heap$"
 }
 
 // issue 4751
@@ -1347,8 +1347,8 @@
 		X string
 		T *T
 	}
-	t := &T{} // ERROR "&T literal escapes to heap"
-	return U{ // ERROR "U literal escapes to heap"
+	t := &T{} // ERROR "&T literal escapes to heap$"
+	return U{ // ERROR "U literal escapes to heap$"
 		X: t.X,
 		T: t,
 	}
@@ -1362,53 +1362,53 @@
 
 //go:noescape
 
-func F3(x []byte) // ERROR "F3 x does not escape"
+func F3(x []byte) // ERROR "F3 x does not escape$"
 
 func F4(x []byte)
 
 func G() {
 	var buf1 [10]byte
-	F1(buf1[:]) // ERROR "buf1 does not escape"
+	F1(buf1[:]) // ERROR "G buf1 does not escape$"
 
-	var buf2 [10]byte // ERROR "moved to heap: buf2"
-	F2(buf2[:])       // ERROR "buf2 escapes to heap"
+	var buf2 [10]byte // ERROR "moved to heap: buf2$"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap$"
 
 	var buf3 [10]byte
-	F3(buf3[:]) // ERROR "buf3 does not escape"
+	F3(buf3[:]) // ERROR "G buf3 does not escape$"
 
-	var buf4 [10]byte // ERROR "moved to heap: buf4"
-	F4(buf4[:])       // ERROR "buf4 escapes to heap"
+	var buf4 [10]byte // ERROR "moved to heap: buf4$"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap$"
 }
 
 type Tm struct {
 	x int
 }
 
-func (t *Tm) M() { // ERROR "t does not escape"
+func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$"
 }
 
 func foo141() {
 	var f func()
 
-	t := new(Tm) // ERROR "escapes to heap"
-	f = t.M      // ERROR "t.M does not escape"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	f = t.M      // ERROR "foo141 t.M does not escape$"
 	_ = f
 }
 
 var gf func()
 
 func foo142() {
-	t := new(Tm) // ERROR "escapes to heap"
-	gf = t.M     // ERROR "t.M escapes to heap"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	gf = t.M     // ERROR "t.M escapes to heap$"
 }
 
 // issue 3888.
 func foo143() {
 	for i := 0; i < 1000; i++ {
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "foo143 func literal does not escape$"
 			for i := 0; i < 1; i++ {
 				var t Tm
-				t.M() // ERROR "t does not escape"
+				t.M() // ERROR "<S> t does not escape$"
 			}
 		}()
 	}
@@ -1424,9 +1424,9 @@
 
 func foo144() {
 	var x int
-	foo144a(&x) // ERROR "&x does not escape"
+	foo144a(&x) // ERROR "foo144 &x does not escape$"
 	var y int
-	foo144b(&y) // ERROR "&y does not escape"
+	foo144b(&y) // ERROR "foo144 &y does not escape$"
 }
 
 //go:noescape
@@ -1439,38 +1439,38 @@
 	Next *List
 }
 
-func foo145(l List) { // ERROR "l does not escape"
+func foo145(l List) { // ERROR "foo145 l does not escape$"
 	var p *List
-	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$"
 	}
 }
 
-func foo146(l List) { // ERROR "l does not escape"
+func foo146(l List) { // ERROR "foo146 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo146 &l does not escape$"
 	for ; p.Next != nil; p = p.Next {
 	}
 }
 
-func foo147(l List) { // ERROR "l does not escape"
+func foo147(l List) { // ERROR "foo147 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo147 &l does not escape$"
 	for p.Next != nil {
 		p = p.Next
 	}
 }
 
-func foo148(l List) { // ERROR " l does not escape"
-	for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+func foo148(l List) { // ERROR "foo148 l does not escape$"
+	for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$"
 	}
 }
 
 // related: address of variable should have depth of variable, not of loop
 
-func foo149(l List) { // ERROR " l does not escape"
+func foo149(l List) { // ERROR "foo149 l does not escape$"
 	var p *List
 	for {
-		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$"
 		}
 	}
 }
@@ -1479,44 +1479,44 @@
 
 var save150 []byte
 
-func foo150(x ...byte) { // ERROR "leaking param: x"
+func foo150(x ...byte) { // ERROR "leaking param: x$"
 	save150 = x
 }
 
 func bar150() {
-	foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+	foo150(1, 2, 3) // ERROR "... argument escapes to heap$"
 }
 
 // issue 7931: bad handling of slice of array
 
 var save151 *int
 
-func foo151(x *int) { // ERROR "leaking param: x"
+func foo151(x *int) { // ERROR "leaking param: x$"
 	save151 = x
 }
 
 func bar151() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151b() {
-	var a [10]int      // ERROR "moved to heap: a"
-	b := a[:]          // ERROR "a escapes to heap"
-	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap"
+	var a [10]int      // ERROR "moved to heap: a$"
+	b := a[:]          // ERROR "a escapes to heap$"
+	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap$"
 }
 
 func bar151c() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151d() {
-	var a [10]int        // ERROR "moved to heap: a"
-	b := a[:]            // ERROR "a escapes to heap"
-	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap"
+	var a [10]int        // ERROR "moved to heap: a$"
+	b := a[:]            // ERROR "a escapes to heap$"
+	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap$"
 }
 
 // issue 8120
@@ -1525,7 +1525,7 @@
 	s *string
 }
 
-func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
+func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$"
 	return u.s
 }
 
@@ -1533,36 +1533,37 @@
 	s *string
 }
 
-func NewV(u U) *V { // ERROR "leaking param: u"
-	return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape"
+// BAD -- level of leak ought to be 0
+func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1"
+	return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape"
 }
 
 func foo152() {
-	a := "a"   // ERROR "moved to heap: a"
-	u := U{&a} // ERROR "&a escapes to heap"
+	a := "a"   // ERROR "moved to heap: a$"
+	u := U{&a} // ERROR "&a escapes to heap$"
 	v := NewV(u)
 	println(v)
 }
 
 // issue 8176 - &x in type switch body not marked as escaping
 
-func foo153(v interface{}) *int { // ERROR "leaking param: v"
+func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$"
 	switch x := v.(type) {
-	case int: // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+	case int: // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	}
 	panic(0)
 }
 
 // issue 8185 - &result escaping into result
 
-func f() (x int, y *int) { // ERROR "moved to heap: x"
-	y = &x // ERROR "&x escapes to heap"
+func f() (x int, y *int) { // ERROR "moved to heap: x$"
+	y = &x // ERROR "&x escapes to heap$"
 	return
 }
 
-func g() (x interface{}) { // ERROR "moved to heap: x"
-	x = &x // ERROR "&x escapes to heap"
+func g() (x interface{}) { // ERROR "moved to heap: x$"
+	x = &x // ERROR "&x escapes to heap$"
 	return
 }
 
@@ -1575,22 +1576,22 @@
 func ptrlitNoescape() {
 	// Both literal and element do not escape.
 	i := 0
-	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape"
+	x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$"
 	_ = x
 }
 
 func ptrlitNoEscape2() {
 	// Literal does not escape, but element does.
-	i := 0        // ERROR "moved to heap: i"
-	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
-	sink = *x     // ERROR "\*x escapes to heap"
+	i := 0        // ERROR "moved to heap: i$"
+	x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$"
+	sink = *x     // ERROR "\*x escapes to heap$"
 }
 
 func ptrlitEscape() {
 	// Both literal and element escape.
-	i := 0        // ERROR "moved to heap: i"
-	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
-	sink = x      // ERROR "x escapes to heap"
+	i := 0        // ERROR "moved to heap: i$"
+	x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" "&i escapes to heap$"
+	sink = x      // ERROR "x escapes to heap$"
 }
 
 // self-assignments
@@ -1603,31 +1604,31 @@
 	str2 string
 }
 
-func (b *Buffer) foo() { // ERROR "b does not escape"
-	b.buf1 = b.buf1[1:2]   // ERROR "ignoring self-assignment to b.buf1"
-	b.buf1 = b.buf1[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
-	b.buf1 = b.buf2[1:2]   // ERROR "ignoring self-assignment to b.buf1"
-	b.buf1 = b.buf2[1:2:3] // ERROR "ignoring self-assignment to b.buf1"
+func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$"
+	b.buf1 = b.buf1[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
 }
 
-func (b *Buffer) bar() { // ERROR "leaking param: b"
-	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap"
+func (b *Buffer) bar() { // ERROR "leaking param: b$"
+	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$"
 }
 
-func (b *Buffer) baz() { // ERROR "b does not escape"
-	b.str1 = b.str1[1:2] // ERROR "ignoring self-assignment to b.str1"
-	b.str1 = b.str2[1:2] // ERROR "ignoring self-assignment to b.str1"
+func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$"
+	b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
+	b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
 }
 
-func (b *Buffer) bat() { // ERROR "leaking param: b"
-	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
+func (b *Buffer) bat() { // ERROR "leaking param content: b$"
+	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$"
 	o.buf1 = b.buf1[1:2]
-	sink = o // ERROR "o escapes to heap"
+	sink = o // ERROR "o escapes to heap$"
 }
 
-func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
-	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp"
-	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp"
+func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$"
+	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp$"
+	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp$"
 }
 
 type StructWithString struct {
@@ -1640,44 +1641,44 @@
 // to just x, and thus &i looks escaping.
 func fieldFlowTracking() {
 	var x StructWithString
-	i := 0     // ERROR "moved to heap: i"
-	x.p = &i   // ERROR "&i escapes to heap"
-	sink = x.s // ERROR "x.s escapes to heap"
+	i := 0     // ERROR "moved to heap: i$"
+	x.p = &i   // ERROR "&i escapes to heap$"
+	sink = x.s // ERROR "x.s escapes to heap$"
 }
 
 // String operations.
 
 func slicebytetostring0() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) does not escape"
+	b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring0 string\(b\) does not escape$"
 	_ = s
 }
 
 func slicebytetostring1() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) does not escape"
+	b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring1 string\(b\) does not escape$"
 	s1 := s[0:1]
 	_ = s1
 }
 
 func slicebytetostring2() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) escapes to heap"
-	s1 := s[0:1]          // ERROR "moved to heap: s1"
-	sink = &s1            // ERROR "&s1 escapes to heap"
+	b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
+	s1 := s[0:1]          // ERROR "moved to heap: s1$"
+	sink = &s1            // ERROR "&s1 escapes to heap$"
 }
 
 func slicebytetostring3() {
-	b := make([]byte, 20) // ERROR "does not escape"
-	s := string(b)        // ERROR "string\(b\) escapes to heap"
+	b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
 	s1 := s[0:1]
-	sink = s1 // ERROR "s1 escapes to heap"
+	sink = s1 // ERROR "s1 escapes to heap$"
 }
 
 func addstr0() {
 	s0 := "a"
 	s1 := "b"
-	s := s0 + s1 // ERROR "s0 \+ s1 does not escape"
+	s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$"
 	_ = s
 }
 
@@ -1685,115 +1686,137 @@
 	s0 := "a"
 	s1 := "b"
 	s := "c"
-	s += s0 + s1 // ERROR "s0 \+ s1 does not escape"
+	s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$"
 	_ = s
 }
 
 func addstr2() {
-	b := make([]byte, 20) // ERROR "does not escape"
+	b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$"
 	s0 := "a"
-	s := string(b) + s0 // ERROR "string\(b\) does not escape" "string\(b\) \+ s0 does not escape"
+	s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$"
 	_ = s
 }
 
 func addstr3() {
 	s0 := "a"
 	s1 := "b"
-	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
+	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$"
 	s2 := s[0:1]
-	sink = s2 // ERROR "s2 escapes to heap"
+	sink = s2 // ERROR "s2 escapes to heap$"
 }
 
 func intstring0() bool {
 	// string does not escape
 	x := '0'
-	s := string(x) // ERROR "string\(x\) does not escape"
+	s := string(x) // ERROR "intstring0 string\(x\) does not escape$"
 	return s == "0"
 }
 
 func intstring1() string {
 	// string does not escape, but the buffer does
 	x := '0'
-	s := string(x) // ERROR "string\(x\) escapes to heap"
+	s := string(x) // ERROR "string\(x\) escapes to heap$"
 	return s
 }
 
 func intstring2() {
 	// string escapes to heap
 	x := '0'
-	s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
-	sink = &s      // ERROR "&s escapes to heap"
+	s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$"
+	sink = &s      // ERROR "&s escapes to heap$"
 }
 
 func stringtoslicebyte0() {
 	s := "foo"
-	x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape"
+	x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$"
 	_ = x
 }
 
 func stringtoslicebyte1() []byte {
 	s := "foo"
-	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
 }
 
 func stringtoslicebyte2() {
 	s := "foo"
-	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
 }
 
 func stringtoslicerune0() {
 	s := "foo"
-	x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape"
+	x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$"
 	_ = x
 }
 
 func stringtoslicerune1() []rune {
 	s := "foo"
-	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
 }
 
 func stringtoslicerune2() {
 	s := "foo"
-	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
 }
 
 func slicerunetostring0() {
-	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
-	s := string(r)       // ERROR "string\(r\) does not escape"
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$"
+	s := string(r)       // ERROR "slicerunetostring0 string\(r\) does not escape$"
 	_ = s
 }
 
 func slicerunetostring1() string {
-	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
-	return string(r)     // ERROR "string\(r\) escapes to heap"
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$"
+	return string(r)     // ERROR "string\(r\) escapes to heap$"
 }
 
 func slicerunetostring2() {
-	r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
-	sink = string(r)     // ERROR "string\(r\) escapes to heap"
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$"
+	sink = string(r)     // ERROR "string\(r\) escapes to heap$"
 }
 
 func makemap0() {
-	m := make(map[int]int) // ERROR "make\(map\[int\]int\) does not escape"
+	m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$"
 	m[0] = 0
 	m[1]++
 	delete(m, 1)
-	sink = m[0] // ERROR "m\[0\] escapes to heap"
+	sink = m[0] // ERROR "m\[0\] escapes to heap$"
 }
 
 func makemap1() map[int]int {
-	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
+	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
 }
 
 func makemap2() {
-	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
-	sink = m               // ERROR "m escapes to heap"
+	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
+	sink = m               // ERROR "m escapes to heap$"
 }
 
-func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"
-	return m["foo"] // ERROR `"foo" does not escape`
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$"
+	return m["foo"] // ERROR "nonescapingEface .foo. does not escape$"
 }
 
-func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape"
-	return m[MV(0)] // ERROR "MV\(0\) does not escape"
+func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$"
+	return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$"
+}
+
+func issue10353() {
+	x := new(int) // ERROR "new\(int\) escapes to heap$"
+	issue10353a(x)()
+}
+
+func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return func() { // ERROR "func literal escapes to heap$"
+		println(*x)
+	}
+}
+
+func issue10353b() {
+	var f func()
+	for {
+		x := new(int) // ERROR "new\(int\) escapes to heap$"
+		f = func() {  // ERROR "func literal escapes to heap$"
+			println(*x)
+		}
+	}
+	_ = f
 }
diff --git a/test/escape_array.go b/test/escape_array.go
new file mode 100644
index 0000000..ac51fe7
--- /dev/null
+++ b/test/escape_array.go
@@ -0,0 +1,72 @@
+// errorcheck -0 -m -l
+
+// 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 escape analysis for function parameters.
+
+// In this test almost everything is BAD except the simplest cases
+// where input directly flows to output.
+
+package foo
+
+var Ssink *string
+
+type U [2]*string
+
+func bar(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "leaking param: b to result ~r2 level=0$"
+	return U{a, b}
+}
+
+func foo(x U) U { // ERROR "leaking param: x to result ~r1 level=0$"
+	return U{x[1], x[0]}
+}
+
+func bff(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "leaking param: b to result ~r2 level=0$"
+	return foo(foo(bar(a, b)))
+}
+
+func tbff1() *string {
+	a := "cat"
+	b := "dog"       // ERROR "moved to heap: b$"
+	u := bff(&a, &b) // ERROR "tbff1 &a does not escape$" "tbff1 &b does not escape$"
+	_ = u[0]
+	return &b // ERROR "&b escapes to heap$"
+}
+
+// BAD: need fine-grained analysis to track u[0] and u[1] differently.
+func tbff2() *string {
+	a := "cat"       // ERROR "moved to heap: a$"
+	b := "dog"       // ERROR "moved to heap: b$"
+	u := bff(&a, &b) // ERROR "&a escapes to heap$" "&b escapes to heap$"
+	_ = u[0]
+	return u[1]
+}
+
+func car(x U) *string { // ERROR "leaking param: x to result ~r1 level=0$"
+	return x[0]
+}
+
+// BAD: need fine-grained analysis to track x[0] and x[1] differently.
+func fun(x U, y *string) *string { // ERROR "leaking param: x to result ~r2 level=0$" "leaking param: y to result ~r2 level=0$"
+	x[0] = y
+	return x[1]
+}
+
+func fup(x *U, y *string) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param: y$"
+	x[0] = y // leaking y to heap is intended
+	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]
+}
diff --git a/test/escape_calls.go b/test/escape_calls.go
new file mode 100644
index 0000000..f289670
--- /dev/null
+++ b/test/escape_calls.go
@@ -0,0 +1,44 @@
+// errorcheck -0 -m -l
+
+// 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 escape analysis for function parameters.
+
+// In this test almost everything is BAD except the simplest cases
+// where input directly flows to output.
+
+package foo
+
+func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r1 level=0$"
+	return buf
+}
+
+func g(*byte) string
+
+func h(e int) {
+	var x [32]byte // ERROR "moved to heap: x$"
+	g(&f(x[:])[0]) // ERROR "&f\(x\[:\]\)\[0\] escapes to heap$" "x escapes to heap$"
+}
+
+type Node struct {
+	s           string
+	left, right *Node
+}
+
+func walk(np **Node) int { // ERROR "leaking param content: np"
+	n := *np
+	w := len(n.s)
+	if n == nil {
+		return 0
+	}
+	wl := walk(&n.left)  // ERROR "walk &n.left does not escape"
+	wr := walk(&n.right) // ERROR "walk &n.right does not escape"
+	if wl < wr {
+		n.left, n.right = n.right, n.left
+		wl, wr = wr, wl
+	}
+	*np = n
+	return w + wl + wr
+}
diff --git a/test/escape_closure.go b/test/escape_closure.go
index 0a5f326..4cdb06e 100644
--- a/test/escape_closure.go
+++ b/test/escape_closure.go
@@ -131,7 +131,7 @@
 	x := 0 // ERROR "moved to heap: x"
 	// BAD: &x should not escape here
 	p := &x                  // ERROR "moved to heap: p" "&x escapes to heap"
-	_ = func(p **int) *int { // ERROR "leaking param p content to result ~r1" "func literal does not escape"
+	_ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape"
 		return *p
 		// BAD: p should not escape here
 	}(&p) // ERROR "&p escapes to heap"
@@ -140,7 +140,7 @@
 func ClosureCallArgs15() {
 	x := 0                      // ERROR "moved to heap: x"
 	p := &x                     // ERROR "moved to heap: p" "&x escapes to heap"
-	sink = func(p **int) *int { // ERROR "leaking param p content to result ~r1" "func literal does not escape"
+	sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape"
 		return *p
 		// BAD: p should not escape here
 	}(&p) // ERROR "&p escapes to heap" "\(func literal\)\(&p\) escapes to heap"
diff --git a/test/escape_field.go b/test/escape_field.go
index dcf8a31..16d1e74 100644
--- a/test/escape_field.go
+++ b/test/escape_field.go
@@ -23,7 +23,7 @@
 func field0() {
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
-	x.p1 = &i // ERROR "&i escapes to heap$"
+	x.p1 = &i   // ERROR "&i escapes to heap$"
 	sink = x.p1 // ERROR "x\.p1 escapes to heap"
 }
 
@@ -31,7 +31,7 @@
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
 	// BAD: &i should not escape
-	x.p1 = &i // ERROR "&i escapes to heap$"
+	x.p1 = &i   // ERROR "&i escapes to heap$"
 	sink = x.p2 // ERROR "x\.p2 escapes to heap"
 }
 
@@ -39,7 +39,7 @@
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
 	x.p1 = &i // ERROR "&i escapes to heap$"
-	sink = x // ERROR "x escapes to heap"
+	sink = x  // ERROR "x escapes to heap"
 }
 
 func field4() {
@@ -54,22 +54,21 @@
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
 	// BAD: &i should not escape here
-	x.a[0] = &i // ERROR "&i escapes to heap$"
+	x.a[0] = &i   // ERROR "&i escapes to heap$"
 	sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap"
 }
 
 // BAD: we are not leaking param x, only x.p2
-func field6(x *X) { // ERROR "leaking param: x$"
+func field6(x *X) { // ERROR "leaking param content: x$"
 	sink = x.p2 // ERROR "x\.p2 escapes to heap"
 }
 
 func field6a() {
-	i := 0  // ERROR "moved to heap: i$"
-	var x X // ERROR "moved to heap: x$"
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
 	// BAD: &i should not escape
-	x.p1 = &i // ERROR "&i escapes to heap$"
-	// BAD: &x should not escape
-	field6(&x) // ERROR "&x escapes to heap$"
+	x.p1 = &i  // ERROR "&i escapes to heap$"
+	field6(&x) // ERROR "field6a &x does not escape"
 }
 
 func field7() {
@@ -116,40 +115,40 @@
 func field11() {
 	i := 0         // ERROR "moved to heap: i$"
 	x := X{p1: &i} // ERROR "&i escapes to heap$"
-	sink = x.p1 // ERROR "x\.p1 escapes to heap"
+	sink = x.p1    // ERROR "x\.p1 escapes to heap"
 }
 
 func field12() {
 	i := 0 // ERROR "moved to heap: i$"
 	// BAD: &i should not escape
 	x := X{p1: &i} // ERROR "&i escapes to heap$"
-	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+	sink = x.p2    // ERROR "x\.p2 escapes to heap"
 }
 
 func field13() {
 	i := 0          // ERROR "moved to heap: i$"
 	x := &X{p1: &i} // ERROR "&i escapes to heap$" "field13 &X literal does not escape$"
-	sink = x.p1 // ERROR "x\.p1 escapes to heap"
+	sink = x.p1     // ERROR "x\.p1 escapes to heap"
 }
 
 func field14() {
 	i := 0 // ERROR "moved to heap: i$"
 	// BAD: &i should not escape
 	x := &X{p1: &i} // ERROR "&i escapes to heap$" "field14 &X literal does not escape$"
-	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+	sink = x.p2     // ERROR "x\.p2 escapes to heap"
 }
 
 func field15() {
 	i := 0          // ERROR "moved to heap: i$"
 	x := &X{p1: &i} // ERROR "&X literal escapes to heap$" "&i escapes to heap$"
-	sink = x // ERROR "x escapes to heap"
+	sink = x        // ERROR "x escapes to heap"
 }
 
 func field16() {
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
 	// BAD: &i should not escape
-	x.p1 = &i // ERROR "&i escapes to heap$"
+	x.p1 = &i                 // ERROR "&i escapes to heap$"
 	var iface interface{} = x // ERROR "x escapes to heap"
 	x1 := iface.(X)
 	sink = x1.p2 // ERROR "x1\.p2 escapes to heap"
@@ -158,7 +157,7 @@
 func field17() {
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
-	x.p1 = &i // ERROR "&i escapes to heap$"
+	x.p1 = &i                 // ERROR "&i escapes to heap$"
 	var iface interface{} = x // ERROR "x escapes to heap"
 	x1 := iface.(X)
 	sink = x1.p1 // ERROR "x1\.p1 escapes to heap"
@@ -168,8 +167,8 @@
 	i := 0 // ERROR "moved to heap: i$"
 	var x X
 	// BAD: &i should not escape
-	x.p1 = &i // ERROR "&i escapes to heap$"
+	x.p1 = &i                 // ERROR "&i escapes to heap$"
 	var iface interface{} = x // ERROR "x escapes to heap"
-	y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized.
-	sink = y // ERROR "y escapes to heap"
+	y, _ := iface.(Y)         // Put X, but extracted Y. The cast will fail, so y is zero initialized.
+	sink = y                  // ERROR "y escapes to heap"
 }
diff --git a/test/escape_indir.go b/test/escape_indir.go
index 7c06ceb..fe03c3f 100644
--- a/test/escape_indir.go
+++ b/test/escape_indir.go
@@ -54,14 +54,14 @@
 	i := 0           // ERROR "moved to heap: i"
 	x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap"
 	x.p = &i         // ERROR "&i escapes to heap"
-	sink = x // ERROR "x escapes to heap"
+	sink = x         // ERROR "x escapes to heap"
 }
 
 func constptr2() {
 	i := 0           // ERROR "moved to heap: i"
 	x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
 	x.p = &i         // ERROR "&i escapes to heap"
-	sink = *x// ERROR "\*x escapes to heap"
+	sink = *x        // ERROR "\*x escapes to heap"
 }
 
 func constptr4() *ConstPtr {
@@ -78,7 +78,7 @@
 }
 
 // BAD: p should not escape here
-func constptr6(p *ConstPtr) { // ERROR "leaking param: p"
+func constptr6(p *ConstPtr) { // ERROR "leaking param content: p"
 	p1 := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
 	*p1 = *p
 	_ = p1
@@ -151,3 +151,10 @@
 	i := 0  // ERROR "moved to heap: i"
 	*p = &i // ERROR "&i escapes to heap"
 }
+
+var global *byte
+
+func f() {
+	var x byte    // ERROR "moved to heap: x"
+	global = &*&x // ERROR "&\(\*\(&x\)\) escapes to heap" "&x escapes to heap"
+}
diff --git a/test/escape_level.go b/test/escape_level.go
index 581e4a9..867c81a 100644
--- a/test/escape_level.go
+++ b/test/escape_level.go
@@ -27,18 +27,18 @@
 }
 
 func level2() {
-	i := 0    // ERROR "moved to heap: i"
-	p0 := &i  // ERROR "moved to heap: p0" "&i escapes to heap"
-	p1 := &p0 // ERROR "&p0 escapes to heap"
-	p2 := &p1 // ERROR "&p1 does not escape"
+	i := 0     // ERROR "moved to heap: i"
+	p0 := &i   // ERROR "moved to heap: p0" "&i escapes to heap"
+	p1 := &p0  // ERROR "&p0 escapes to heap"
+	p2 := &p1  // ERROR "&p1 does not escape"
 	sink = *p2 // ERROR "\*p2 escapes to heap"
 }
 
 func level3() {
-	i := 0    // ERROR "moved to heap: i"
-	p0 := &i  // ERROR "&i escapes to heap"
-	p1 := &p0 // ERROR "&p0 does not escape"
-	p2 := &p1 // ERROR "&p1 does not escape"
+	i := 0      // ERROR "moved to heap: i"
+	p0 := &i    // ERROR "&i escapes to heap"
+	p1 := &p0   // ERROR "&p0 does not escape"
+	p2 := &p1   // ERROR "&p1 does not escape"
 	sink = **p2 // ERROR "\* \(\*p2\) escapes to heap"
 }
 
@@ -67,10 +67,10 @@
 }
 
 func level7() {
-	i := 0     // ERROR "moved to heap: i"
-	p0 := &i   // ERROR "moved to heap: p0" "&i escapes to heap"
-	// BAD: p0 should not escape here
-	p1 := &p0  // ERROR "&p0 escapes to heap"
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 does not escape"
+	// note *p1 == &i
 	p2 := *p1  // ERROR "moved to heap: p2"
 	sink = &p2 // ERROR "&p2 escapes to heap"
 }
@@ -95,7 +95,7 @@
 	i := 0
 	p0 := &i // ERROR "&i does not escape"
 	p1 := *p0
-	p2 := &p1 // ERROR "&p1 does not escape"
+	p2 := &p1  // ERROR "&p1 does not escape"
 	sink = *p2 // ERROR "\*p2 escapes to heap"
 }
 
diff --git a/test/escape_param.go b/test/escape_param.go
index 91ad437..cfbcd51 100644
--- a/test/escape_param.go
+++ b/test/escape_param.go
@@ -14,7 +14,7 @@
 var sink interface{}
 
 // in -> out
-func param0(p *int) *int { // ERROR "leaking param: p to result ~r1$"
+func param0(p *int) *int { // ERROR "leaking param: p to result ~r1"
 	return p
 }
 
@@ -29,7 +29,7 @@
 }
 
 // in, in -> out, out
-func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2$" "leaking param: p2 to result ~r3$"
+func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2" "leaking param: p2 to result ~r3"
 	return p1, p2
 }
 
@@ -64,23 +64,23 @@
 	p2 *int
 }
 
-func param3(p *Pair) { // ERROR "leaking param: p$"
+func param3(p *Pair) { // ERROR "leaking param content: p$"
 	p.p1 = p.p2
 }
 
 func caller3a() {
 	i := 0            // ERROR "moved to heap: i$"
 	j := 0            // ERROR "moved to heap: j$"
-	p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$" "moved to heap: p$"
-	param3(&p)        // ERROR "&p escapes to heap$"
+	p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$"
+	param3(&p)        // ERROR "caller3a &p does not escape"
 	_ = p
 }
 
 func caller3b() {
 	i := 0            // ERROR "moved to heap: i$"
 	j := 0            // ERROR "moved to heap: j$"
-	p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$" "moved to heap: p$"
-	param3(&p)        // ERROR "&p escapes to heap$"
+	p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$"
+	param3(&p)        // ERROR "caller3b &p does not escape"
 	sink = p          // ERROR "p escapes to heap$"
 }
 
@@ -114,27 +114,27 @@
 }
 
 // *in -> heap
-func param6(i ***int) { // ERROR "leaking param: i$"
+func param6(i ***int) { // ERROR "leaking param content: i$"
 	sink = *i // ERROR "\*i escapes to heap$"
 }
 
 func caller6a() {
 	i := 0      // ERROR "moved to heap: i$"
 	p := &i     // ERROR "&i escapes to heap$" "moved to heap: p$"
-	p2 := &p    // ERROR "&p escapes to heap$" "moved to heap: p2$"
-	param6(&p2) // ERROR "&p2 escapes to heap$"
+	p2 := &p    // ERROR "&p escapes to heap$"
+	param6(&p2) // ERROR "caller6a &p2 does not escape"
 }
 
 // **in -> heap
-func param7(i ***int) { // ERROR "leaking param: i$"
+func param7(i ***int) { // ERROR "leaking param content: i$"
 	sink = **i // ERROR "\* \(\*i\) escapes to heap"
 }
 
 func caller7() {
 	i := 0      // ERROR "moved to heap: i$"
 	p := &i     // ERROR "&i escapes to heap$" "moved to heap: p$"
-	p2 := &p    // ERROR "&p escapes to heap$" "moved to heap: p2$"
-	param7(&p2) // ERROR "&p2 escapes to heap$"
+	p2 := &p    // ERROR "&p escapes to heap$"
+	param7(&p2) // ERROR "caller7 &p2 does not escape"
 }
 
 // **in -> heap
@@ -149,14 +149,14 @@
 }
 
 // *in -> out
-func param9(p ***int) **int { // ERROR "param9 leaking param p content to result ~r1$"
+func param9(p ***int) **int { // ERROR "leaking param: p to result ~r1 level=1"
 	return *p
 }
 
 func caller9a() {
-	i := 0          // ERROR "moved to heap: i$"
-	p := &i         // ERROR "&i escapes to heap$" "moved to heap: p$"
-	p2 := &p        // ERROR "&p escapes to heap$"
+	i := 0
+	p := &i         // ERROR "caller9a &i does not escape"
+	p2 := &p        // ERROR "caller9a &p does not escape"
 	_ = param9(&p2) // ERROR "caller9a &p2 does not escape$"
 }
 
@@ -168,33 +168,33 @@
 }
 
 // **in -> out
-func param10(p ***int) *int { // ERROR "param10 leaking param p content to result ~r1$"
+func param10(p ***int) *int { // ERROR "leaking param: p to result ~r1 level=2"
 	return **p
 }
 
 func caller10a() {
-	i := 0           // ERROR "moved to heap: i$"
-	p := &i          // ERROR "&i escapes to heap$" "moved to heap: p$"
-	p2 := &p         // ERROR "&p escapes to heap$"
+	i := 0
+	p := &i          // ERROR "caller10a &i does not escape"
+	p2 := &p         // ERROR "caller10a &p does not escape"
 	_ = param10(&p2) // ERROR "caller10a &p2 does not escape$"
 }
 
 func caller10b() {
 	i := 0              // ERROR "moved to heap: i$"
-	p := &i             // ERROR "&i escapes to heap$" "moved to heap: p$"
-	p2 := &p            // ERROR "&p escapes to heap$"
+	p := &i             // ERROR "&i escapes to heap$"
+	p2 := &p            // ERROR "caller10b &p does not escape$"
 	sink = param10(&p2) // ERROR "caller10b &p2 does not escape$" "param10\(&p2\) escapes to heap"
 }
 
-// &in -> out
+// in escapes to heap (address of param taken and returned)
 func param11(i **int) ***int { // ERROR "moved to heap: i$"
 	return &i // ERROR "&i escapes to heap$"
 }
 
 func caller11a() {
-	i := 0          // ERROR "moved to heap: i$"
-	p := &i         // ERROR "&i escapes to heap$" "moved to heap: p$"
-	_ = param11(&p) // ERROR "&p escapes to heap$"
+	i := 0          // ERROR "moved to heap: i"
+	p := &i         // ERROR "moved to heap: p" "&i escapes to heap"
+	_ = param11(&p) // ERROR "&p escapes to heap"
 }
 
 func caller11b() {
@@ -203,10 +203,17 @@
 	sink = param11(&p) // ERROR "&p escapes to heap$" "param11\(&p\) escapes to heap"
 }
 
-func caller11c() {
+func caller11c() { // GOOD
 	i := 0              // ERROR "moved to heap: i$"
-	p := &i             // ERROR "&i escapes to heap$" "moved to heap: p$"
-	sink = *param11(&p) // ERROR "&p escapes to heap$" "\*param11\(&p\) escapes to heap"
+	p := &i             // ERROR "moved to heap: p" "&i escapes to heap"
+	sink = *param11(&p) // ERROR "&p escapes to heap" "\*param11\(&p\) escapes to heap"
+}
+
+func caller11d() {
+	i := 0             // ERROR "moved to heap: i$"
+	p := &i            // ERROR "&i escapes to heap" "moved to heap: p"
+	p2 := &p           // ERROR "&p escapes to heap"
+	sink = param11(p2) // ERROR "param11\(p2\) escapes to heap"
 }
 
 // &in -> rcvr
@@ -324,3 +331,23 @@
 	v.param13(&i) // ERROR "&i escapes to heap$"
 	sink = **v.p  // ERROR "\* \(\*v\.p\) escapes to heap"
 }
+
+type Node struct {
+	p *Node
+}
+
+var Sink *Node
+
+func f(x *Node) { // ERROR "leaking param content: x"
+	Sink = &Node{x.p} // ERROR "&Node literal escapes to heap"
+}
+
+func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0"
+	return &Node{x.p} // ERROR "&Node literal escapes to heap"
+}
+
+func h(x *Node) { // ERROR "leaking param: x"
+	y := &Node{x} // ERROR "h &Node literal does not escape"
+	Sink = g(y)
+	f(y)
+}
diff --git a/test/escape_struct_param1.go b/test/escape_struct_param1.go
new file mode 100644
index 0000000..e30e327
--- /dev/null
+++ b/test/escape_struct_param1.go
@@ -0,0 +1,298 @@
+// errorcheck -0 -m -l
+
+// 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 escape analysis for *struct function parameters.
+// Note companion strict_param2 checks struct function parameters with similar tests.
+
+package notmain
+
+var Ssink *string
+
+type U struct {
+	_sp  *string
+	_spp **string
+}
+
+type V struct {
+	_u   U
+	_up  *U
+	_upp **U
+}
+
+func (u *U) SP() *string { // ERROR "leaking param: u to result ~r0 level=1$"
+	return u._sp
+}
+
+func (u *U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=1$"
+	return u._spp
+}
+
+func (u *U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=2$"
+	return *u._spp
+}
+
+func tSPPi() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tSPPi &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$"
+	Ssink = pu.SPPi()
+}
+
+func tiSPP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tiSPP &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$"
+	Ssink = *pu.SPP()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of ps
+func tSP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$" "moved to heap: ps$"
+	pps := &ps        // ERROR "&ps escapes to heap$"
+	pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$"
+	Ssink = pu.SP()
+}
+
+func (v *V) u() U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._u
+}
+
+func (v *V) UP() *U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._up
+}
+
+func (v *V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._upp
+}
+
+func (v *V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._upp
+}
+
+func (v *V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v.UPP()
+}
+
+func (v *V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._u._sp
+}
+
+func (v *V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v.u()._sp
+}
+
+func (v *V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._u._spp
+}
+
+func (v *V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._u.SPPi() // ERROR "\(\*V\).USPPib v._u does not escape$"
+}
+
+func (v *V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up._sp
+}
+
+func (v *V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up.SP()
+}
+
+func (v *V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP()._sp
+}
+
+func (v *V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP().SP()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPa() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$"
+	Ssink = v.UPiSPa()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPb() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$"
+	Ssink = v.UPiSPb()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPc() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$"
+	Ssink = v.UPiSPc()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPd() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$"
+	Ssink = v.UPiSPd()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+func (v V) UPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._up._spp
+}
+
+func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up.SPPi()
+}
+
+func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v.UP()._spp // ERROR "V.UPiSPPic v does not escape$"
+}
+
+func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP().SPPi() // ERROR "V.UPiSPPid v does not escape$"
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPia() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPia &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$"
+	Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPib() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPib &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$"
+	Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPic() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPic &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$"
+	Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPid() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPid &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$"
+	Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+func (v *V) UPPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=4$"
+	return *(*v._upp)._spp
+}
+
+// This test isolates the one value that needs to escape, not because
+// it distinguishes fields but because it knows that &s6 is the only
+// value reachable by two indirects from v.
+// The test depends on the level cap in the escape analysis tags
+// being able to encode that fact.
+func tUPPiSPPia() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"
+	s5 := "emu"
+	s6 := "fox"           // ERROR "moved to heap: s6$"
+	ps2 := &s2            // ERROR "tUPPiSPPia &s2 does not escape$"
+	ps4 := &s4            // ERROR "tUPPiSPPia &s4 does not escape$"
+	ps6 := &s6            // ERROR "&s6 escapes to heap$"
+	u1 := U{&s1, &ps2}    // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$"
+	v := &V{u1, u2, &u3}  // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$"
+	Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes)
+}
diff --git a/test/escape_struct_param2.go b/test/escape_struct_param2.go
new file mode 100644
index 0000000..c10c336
--- /dev/null
+++ b/test/escape_struct_param2.go
@@ -0,0 +1,298 @@
+// errorcheck -0 -m -l
+
+// 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 escape analysis for struct function parameters.
+// Note companion strict_param1 checks *struct function parameters with similar tests.
+
+package notmain
+
+var Ssink *string
+
+type U struct {
+	_sp  *string
+	_spp **string
+}
+
+type V struct {
+	_u   U
+	_up  *U
+	_upp **U
+}
+
+func (u U) SP() *string { // ERROR "leaking param: u to result ~r0 level=0$"
+	return u._sp
+}
+
+func (u U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=0$"
+	return u._spp
+}
+
+func (u U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=1$"
+	return *u._spp
+}
+
+func tSPPi() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tSPPi &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$"
+	Ssink = pu.SPPi()
+}
+
+func tiSPP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tiSPP &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$"
+	Ssink = *pu.SPP()
+}
+
+// BAD: need fine-grained analysis to avoid spurious escape of ps
+func tSP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$" "moved to heap: ps$"
+	pps := &ps        // ERROR "&ps escapes to heap$"
+	pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$"
+	Ssink = pu.SP()
+}
+
+func (v V) u() U { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._u
+}
+
+func (v V) UP() *U { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._up
+}
+
+func (v V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._upp
+}
+
+func (v V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return *v._upp
+}
+
+func (v V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return *v.UPP()
+}
+
+func (v V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._u._sp
+}
+
+func (v V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v.u()._sp
+}
+
+func (v V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return *v._u._spp
+}
+
+func (v V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._u.SPPi()
+}
+
+func (v V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._up._sp
+}
+
+func (v V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._up.SP()
+}
+
+func (v V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v.UP()._sp
+}
+
+func (v V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v.UP().SP()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPa() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$"
+	Ssink = v.UPiSPa()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPb() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$"
+	Ssink = v.UPiSPb()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPc() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$"
+	Ssink = v.UPiSPc()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPd() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$"
+	Ssink = v.UPiSPd()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+func (v V) UPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._up._spp
+}
+
+func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up.SPPi()
+}
+
+func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v.UP()._spp
+}
+
+func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP().SPPi()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPia() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPia &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$"
+	Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPib() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPib &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$"
+	Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPic() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPic &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$"
+	Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPid() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPid &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$"
+	Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+func (v V) UPPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=3$"
+	return *(*v._upp)._spp
+}
+
+// This test isolates the one value that needs to escape, not because
+// it distinguishes fields but because it knows that &s6 is the only
+// value reachable by two indirects from v.
+// The test depends on the level cap in the escape analysis tags
+// being able to encode that fact.
+func tUPPiSPPia() { // This test is sensitive to the level cap in function summary results.
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"
+	s5 := "emu"
+	s6 := "fox"           // ERROR "moved to heap: s6$"
+	ps2 := &s2            // ERROR "tUPPiSPPia &s2 does not escape$"
+	ps4 := &s4            // ERROR "tUPPiSPPia &s4 does not escape$"
+	ps6 := &s6            // ERROR "&s6 escapes to heap$"
+	u1 := U{&s1, &ps2}    // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$"
+	v := &V{u1, u2, &u3}  // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$"
+	Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes)
+}
diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go
new file mode 100644
index 0000000..b423ebd
--- /dev/null
+++ b/test/escape_struct_return.go
@@ -0,0 +1,74 @@
+// errorcheck -0 -m -l
+
+// 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 escape analysis for function parameters.
+
+package foo
+
+var Ssink *string
+
+type U struct {
+	_sp  *string
+	_spp **string
+}
+
+func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 level=0$" "leaking param: spp to result ~r2 level=0$"
+	return U{sp, spp}
+}
+
+func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$"
+	return U{*spp, spp}
+}
+
+func tA1() {
+	s := "cat"
+	sp := &s   // ERROR "tA1 &s does not escape$"
+	spp := &sp // ERROR "tA1 &sp does not escape$"
+	u := A(sp, spp)
+	_ = u
+	println(s)
+}
+
+func tA2() {
+	s := "cat"
+	sp := &s   // ERROR "tA2 &s does not escape$"
+	spp := &sp // ERROR "tA2 &sp does not escape$"
+	u := A(sp, spp)
+	println(*u._sp)
+}
+
+func tA3() {
+	s := "cat"
+	sp := &s   // ERROR "tA3 &s does not escape$"
+	spp := &sp // ERROR "tA3 &sp does not escape$"
+	u := A(sp, spp)
+	println(**u._spp)
+}
+
+func tB1() {
+	s := "cat"
+	sp := &s   // ERROR "tB1 &s does not escape$"
+	spp := &sp // ERROR "tB1 &sp does not escape$"
+	u := B(spp)
+	_ = u
+	println(s)
+}
+
+func tB2() {
+	s := "cat"
+	sp := &s   // ERROR "tB2 &s does not escape$"
+	spp := &sp // ERROR "tB2 &sp does not escape$"
+	u := B(spp)
+	println(*u._sp)
+}
+
+func tB3() {
+	s := "cat"
+	sp := &s   // ERROR "tB3 &s does not escape$"
+	spp := &sp // ERROR "tB3 &sp does not escape$"
+	u := B(spp)
+	println(**u._spp)
+}
diff --git a/test/fixedbugs/bug121.go b/test/fixedbugs/bug121.go
index 3492401..22c7181 100644
--- a/test/fixedbugs/bug121.go
+++ b/test/fixedbugs/bug121.go
@@ -1,6 +1,3 @@
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
 // errorcheck
 
 // Copyright 2009 The Go Authors. All rights reserved.
@@ -18,4 +15,3 @@
 type J interface {
 	h T;  // ERROR "syntax|signature"
 }
-
diff --git a/test/fixedbugs/bug349.go b/test/fixedbugs/bug349.go
index 2157d07..a3e6bd1 100644
--- a/test/fixedbugs/bug349.go
+++ b/test/fixedbugs/bug349.go
@@ -1,6 +1,3 @@
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
 // errorcheck
 
 // Copyright 2011 The Go Authors.  All rights reserved.
diff --git a/test/fixedbugs/bug388.go b/test/fixedbugs/bug388.go
index 4431f0c..d41f9ea 100644
--- a/test/fixedbugs/bug388.go
+++ b/test/fixedbugs/bug388.go
@@ -1,6 +1,3 @@
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
 // errorcheck
 
 // Copyright 2011 The Go Authors.  All rights reserved.
diff --git a/test/fixedbugs/bug435.go b/test/fixedbugs/bug435.go
index fc5bf8a..0c2ac7b 100644
--- a/test/fixedbugs/bug435.go
+++ b/test/fixedbugs/bug435.go
@@ -1,6 +1,3 @@
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
 // errorcheck
 
 // Copyright 2012 The Go Authors.  All rights reserved.
diff --git a/test/fixedbugs/gcc65755.go b/test/fixedbugs/gcc65755.go
new file mode 100644
index 0000000..e76f4d1
--- /dev/null
+++ b/test/fixedbugs/gcc65755.go
@@ -0,0 +1,37 @@
+// 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.
+
+// PR65755: Incorrect type descriptor for type defined within method.
+
+package main
+
+import "reflect"
+
+type S1 struct{}
+
+func (S1) Fix() string {
+	type s struct {
+		f int
+	}
+	return reflect.TypeOf(s{}).Field(0).Name
+}
+
+type S2 struct{}
+
+func (S2) Fix() string {
+	type s struct {
+		g bool
+	}
+	return reflect.TypeOf(s{}).Field(0).Name
+}
+
+func main() {
+	f1 := S1{}.Fix()
+	f2 := S2{}.Fix()
+	if f1 != "f" || f2 != "g" {
+		panic(f1 + f2)
+	}
+}
diff --git a/test/fixedbugs/issue10253.go b/test/fixedbugs/issue10253.go
new file mode 100644
index 0000000..fafca6c
--- /dev/null
+++ b/test/fixedbugs/issue10253.go
@@ -0,0 +1,26 @@
+// 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.
+
+// issue 10253: cmd/7g: bad codegen, probably regopt related
+
+package main
+
+func main() {
+	if !eq() {
+		panic("wrong value")
+	}
+}
+
+var text = "abc"
+var s = &str{text}
+
+func eq() bool {
+	return text[0] == s.text[0]
+}
+
+type str struct {
+	text string
+}
diff --git a/test/fixedbugs/issue10320.go b/test/fixedbugs/issue10320.go
new file mode 100644
index 0000000..697aad1
--- /dev/null
+++ b/test/fixedbugs/issue10320.go
@@ -0,0 +1,55 @@
+// 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.
+
+// Issue 10320: 7g failed to compile a program because it attempted
+// to use ZR as register. Other programs compiled but failed to
+// execute correctly because they clobbered the g register.
+
+package main
+
+func main() {
+	var x00, x01, x02, x03, x04, x05, x06, x07, x08, x09 int
+	var x10, x11, x12, x13, x14, x15, x16, x17, x18, x19 int
+	var x20, x21, x22, x23, x24, x25, x26, x27, x28, x29 int
+	var x30, x31, x32 int
+
+	_ = x00
+	_ = x01
+	_ = x02
+	_ = x03
+	_ = x04
+	_ = x05
+	_ = x06
+	_ = x07
+	_ = x08
+	_ = x09
+
+	_ = x10
+	_ = x11
+	_ = x12
+	_ = x13
+	_ = x14
+	_ = x15
+	_ = x16
+	_ = x17
+	_ = x18
+	_ = x19
+
+	_ = x20
+	_ = x21
+	_ = x22
+	_ = x23
+	_ = x24
+	_ = x25
+	_ = x26
+	_ = x27
+	_ = x28
+	_ = x29
+
+	_ = x30
+	_ = x31
+	_ = x32
+}
diff --git a/test/fixedbugs/issue10332.go b/test/fixedbugs/issue10332.go
new file mode 100644
index 0000000..e00a8b4
--- /dev/null
+++ b/test/fixedbugs/issue10332.go
@@ -0,0 +1,25 @@
+// 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.
+
+// The PkgPath of unexported fields of types defined in package main was incorrectly ""
+
+package main
+
+import (
+	"fmt"
+	"reflect"
+)
+
+type foo struct {
+	bar int
+}
+
+func main() {
+	pkgpath := reflect.ValueOf(foo{}).Type().Field(0).PkgPath
+	if pkgpath != "main" {
+		fmt.Printf("BUG: incorrect PkgPath: %v", pkgpath)
+	}
+}
diff --git a/test/fixedbugs/issue10353.go b/test/fixedbugs/issue10353.go
new file mode 100644
index 0000000..87771d4
--- /dev/null
+++ b/test/fixedbugs/issue10353.go
@@ -0,0 +1,49 @@
+// 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.
+
+// issue 10253: cmd/gc: incorrect escape analysis of closures
+// Partial call x.foo was not promoted to heap.
+
+package main
+
+func main() {
+	c := make(chan bool)
+	// Create a new goroutine to get a default-size stack segment.
+	go func() {
+		x := new(X)
+		clos(x.foo)()
+		c <- true
+	}()
+	<-c
+}
+
+type X int
+
+func (x *X) foo() {
+}
+
+func clos(x func()) func() {
+	f := func() {
+		print("")
+		x() // This statement crashed, because the partial call was allocated on the old stack.
+	}
+	// Grow stack so that partial call x becomes invalid if allocated on stack.
+	growstack(10000)
+	c := make(chan bool)
+	// Spoil the previous stack segment.
+	go func() {
+		c <- true
+	}()
+	<-c
+	return f
+}
+
+func growstack(x int) {
+	if x == 0 {
+		return
+	}
+	growstack(x - 1)
+}
diff --git a/test/fixedbugs/issue10407.go b/test/fixedbugs/issue10407.go
new file mode 100644
index 0000000..fe033ef
--- /dev/null
+++ b/test/fixedbugs/issue10407.go
@@ -0,0 +1,16 @@
+// runoutput
+
+// 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.
+
+// Issue 10407: gccgo failed to remove carriage returns
+// from raw string literals.
+
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("package main\nfunc main() { if `a\rb\r\nc` != \"ab\\nc\" { panic(42) }}")
+}
diff --git a/test/fixedbugs/issue10441.go b/test/fixedbugs/issue10441.go
new file mode 100644
index 0000000..25832fa
--- /dev/null
+++ b/test/fixedbugs/issue10441.go
@@ -0,0 +1,17 @@
+// build
+
+// 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 p
+
+func bar() {
+	f := func() {}
+	foo(&f)
+}
+
+func foo(f *func()) func() {
+	defer func() {}() // prevent inlining of foo
+	return *f
+}
diff --git a/test/fixedbugs/issue10700.dir/other.go b/test/fixedbugs/issue10700.dir/other.go
new file mode 100644
index 0000000..12908b9
--- /dev/null
+++ b/test/fixedbugs/issue10700.dir/other.go
@@ -0,0 +1,10 @@
+// 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 other
+
+type Exported interface {
+	Do()
+	secret()
+}
diff --git a/test/fixedbugs/issue10700.dir/test.go b/test/fixedbugs/issue10700.dir/test.go
new file mode 100644
index 0000000..2033efc
--- /dev/null
+++ b/test/fixedbugs/issue10700.dir/test.go
@@ -0,0 +1,49 @@
+// errorcheck -0 -m -l
+
+// 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 "./other"
+
+type Imported interface {
+	Do()
+}
+
+type HasAMethod struct {
+	x int
+}
+
+func (me *HasAMethod) Do() {
+	println(me.x)
+}
+
+func InMyCode(x *Imported, y *HasAMethod, z *other.Exported) {
+	x.Do() // ERROR "x\.Do undefined \(type \*Imported is pointer to interface, not interface\)"
+	x.do() // ERROR "x\.do undefined \(type \*Imported is pointer to interface, not interface\)"
+	(*x).Do()
+	x.Dont()    // ERROR "x\.Dont undefined \(type \*Imported is pointer to interface, not interface\)"
+	(*x).Dont() // ERROR "\(\*x\)\.Dont undefined \(type Imported has no field or method Dont\)"
+
+	y.Do()
+	y.do() // ERROR "y\.do undefined \(type \*HasAMethod has no field or method do, but does have Do\)"
+	(*y).Do()
+	(*y).do()   // ERROR "\(\*y\)\.do undefined \(type HasAMethod has no field or method do, but does have Do\)"
+	y.Dont()    // ERROR "y\.Dont undefined \(type \*HasAMethod has no field or method Dont\)"
+	(*y).Dont() // ERROR "\(\*y\)\.Dont undefined \(type HasAMethod has no field or method Dont\)"
+
+	z.Do() // ERROR "z\.Do undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	z.do() // ERROR "z\.do undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	(*z).Do()
+	(*z).do()     // ERROR "\(\*z\)\.do undefined \(type other.Exported has no field or method do, but does have Do\)"
+	z.Dont()      // ERROR "z\.Dont undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	(*z).Dont()   // ERROR "\(\*z\)\.Dont undefined \(type other\.Exported has no field or method Dont\)"
+	z.secret()    // ERROR "z\.secret undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	(*z).secret() // ERROR "\(\*z\)\.secret undefined \(cannot refer to unexported field or method secret\)"
+
+}
+
+func main() {
+}
diff --git a/test/fixedbugs/issue10700.go b/test/fixedbugs/issue10700.go
new file mode 100644
index 0000000..25544ef
--- /dev/null
+++ b/test/fixedbugs/issue10700.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// 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 ignored
diff --git a/test/fixedbugs/issue4468.go b/test/fixedbugs/issue4468.go
index 67b0a5d..ef0b46b 100644
--- a/test/fixedbugs/issue4468.go
+++ b/test/fixedbugs/issue4468.go
@@ -1,6 +1,3 @@
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
 // errorcheck
 
 // Copyright 2012 The Go Authors.  All rights reserved.
diff --git a/test/fixedbugs/issue6866.go b/test/fixedbugs/issue6866.go
new file mode 100644
index 0000000..1080b27
--- /dev/null
+++ b/test/fixedbugs/issue6866.go
@@ -0,0 +1,80 @@
+// 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.
+
+// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
+// (To generate, in go/types directory: go test -run=Hilbert -H=2 -out="h2.src")
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+	if !ok {
+		print()
+		return
+	}
+}
+
+// Hilbert matrix, n = 2
+const (
+	h0_0, h0_1 = 1.0 / (iota + 1), 1.0 / (iota + 2)
+	h1_0, h1_1
+)
+
+// Inverse Hilbert matrix
+const (
+	i0_0 = +1 * b2_1 * b2_1 * b0_0 * b0_0
+	i0_1 = -2 * b2_0 * b3_1 * b1_0 * b1_0
+
+	i1_0 = -2 * b3_1 * b2_0 * b1_1 * b1_1
+	i1_1 = +3 * b3_0 * b3_0 * b2_1 * b2_1
+)
+
+// Product matrix
+const (
+	p0_0 = h0_0*i0_0 + h0_1*i1_0
+	p0_1 = h0_0*i0_1 + h0_1*i1_1
+
+	p1_0 = h1_0*i0_0 + h1_1*i1_0
+	p1_1 = h1_0*i0_1 + h1_1*i1_1
+)
+
+// Verify that product is identity matrix
+const ok = p0_0 == 1 && p0_1 == 0 &&
+	p1_0 == 0 && p1_1 == 1 &&
+	true
+
+func print() {
+	println(p0_0, p0_1)
+	println(p1_0, p1_1)
+}
+
+// Binomials
+const (
+	b0_0 = f0 / (f0 * f0)
+
+	b1_0 = f1 / (f0 * f1)
+	b1_1 = f1 / (f1 * f0)
+
+	b2_0 = f2 / (f0 * f2)
+	b2_1 = f2 / (f1 * f1)
+	b2_2 = f2 / (f2 * f0)
+
+	b3_0 = f3 / (f0 * f3)
+	b3_1 = f3 / (f1 * f2)
+	b3_2 = f3 / (f2 * f1)
+	b3_3 = f3 / (f3 * f0)
+)
+
+// Factorials
+const (
+	f0 = 1
+	f1 = 1
+	f2 = f1 * 2
+	f3 = f2 * 3
+)
diff --git a/test/fixedbugs/issue6889.go b/test/fixedbugs/issue6889.go
index 46bb5da..805a877 100644
--- a/test/fixedbugs/issue6889.go
+++ b/test/fixedbugs/issue6889.go
@@ -99,5 +99,13 @@
 	f88 = f87 * 88
 	f89 = f88 * 89
 	f90 = f89 * 90
-	f91 = f90 * 91 // ERROR "overflow"
+	f91 = f90 * 91
+	f92 = f91 * 92
+	f93 = f92 * 93
+	f94 = f93 * 94
+	f95 = f94 * 95
+	f96 = f95 * 96
+	f97 = f96 * 97
+	f98 = f97 * 98
+	f99 = f98 * 99 // ERROR "overflow"
 )
diff --git a/test/fixedbugs/issue7740.go b/test/fixedbugs/issue7740.go
new file mode 100644
index 0000000..8f1afe8
--- /dev/null
+++ b/test/fixedbugs/issue7740.go
@@ -0,0 +1,35 @@
+// 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.
+
+// This test computes the precision of the compiler's internal multiprecision floats.
+
+package main
+
+import (
+	"fmt"
+	"math"
+	"runtime"
+)
+
+const ulp = (1.0 + (2.0 / 3.0)) - (5.0 / 3.0)
+
+func main() {
+	// adjust precision depending on compiler
+	var prec float64
+	switch runtime.Compiler {
+	case "gc":
+		prec = 512
+	case "gccgo":
+		prec = 256
+	default:
+		// unknown compiler
+		return
+	}
+	p := 1 - math.Log(math.Abs(ulp))/math.Log(2)
+	if math.Abs(p-prec) > 1e-10 {
+		fmt.Printf("BUG: got %g; want %g\n", p, prec)
+	}
+}
diff --git a/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go
index 7294633..b9e861f 100644
--- a/test/fixedbugs/issue9110.go
+++ b/test/fixedbugs/issue9110.go
@@ -17,6 +17,7 @@
 )
 
 func main() {
+	runtime.GOMAXPROCS(1)
 	debug.SetGCPercent(1000000) // only GC when we ask for GC
 
 	var stats, stats1, stats2 runtime.MemStats
diff --git a/test/interface/embed2.go b/test/interface/embed2.go
index 1636db78..df3e2e4 100644
--- a/test/interface/embed2.go
+++ b/test/interface/embed2.go
@@ -12,20 +12,25 @@
 
 const Value = 1e12
 
-type Inter interface { M() int64 }
+type Inter interface {
+	M() int64
+}
 
 type T int64
+
 func (t T) M() int64 { return int64(t) }
+
 var t = T(Value)
 var pt = &t
 var ti Inter = t
 var pti = &ti
 
-type S struct { Inter }
-var s = S{ ti }
+type S struct{ Inter }
+
+var s = S{ti}
 var ps = &s
 
-type SP struct { *Inter }	// ERROR "interface"
+type SP struct{ *Inter } // ERROR "interface"
 
 var i Inter
 var pi = &i
@@ -43,25 +48,25 @@
 	check("t.M()", t.M())
 	check("pt.M()", pt.M())
 	check("ti.M()", ti.M())
-	check("pti.M()", pti.M())	// ERROR "method"
+	check("pti.M()", pti.M()) // ERROR "pointer to interface, not interface"
 	check("s.M()", s.M())
 	check("ps.M()", ps.M())
 
 	i = t
 	check("i = t; i.M()", i.M())
-	check("i = t; pi.M()", pi.M())	// ERROR "method"
+	check("i = t; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	i = pt
 	check("i = pt; i.M()", i.M())
-	check("i = pt; pi.M()", pi.M())	// ERROR "method"
+	check("i = pt; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	i = s
 	check("i = s; i.M()", i.M())
-	check("i = s; pi.M()", pi.M())	// ERROR "method"
+	check("i = s; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	i = ps
 	check("i = ps; i.M()", i.M())
-	check("i = ps; pi.M()", pi.M())	// ERROR "method"
+	check("i = ps; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	if !ok {
 		println("BUG: interface10")
diff --git a/test/live.go b/test/live.go
index 2f42106..ae982f4 100644
--- a/test/live.go
+++ b/test/live.go
@@ -64,7 +64,7 @@
 		printpointer(&y) // ERROR "live at call to printpointer: x y$"
 		printpointer(&y) // ERROR "live at call to printpointer: x y$"
 	}
-	printint(0) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+	printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
 }
 
 // The old algorithm treated x as live on all code that
@@ -103,7 +103,7 @@
 		*y = 54
 		z = &y
 	}
-	printint(**z) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+	printint(**z) // ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
 }
 
 // confusion about the _ result used to cause spurious "live at entry to f6: _".
@@ -137,7 +137,7 @@
 func f9() bool {
 	g8()
 	x := i9
-	return x != interface{}(99.0i) // ERROR "live at call to convT2E: x"
+	return x != interface{}(99.0i) // ERROR "live at call to convT2E: x$"
 }
 
 // liveness formerly confused by UNDEF followed by RET,
@@ -157,10 +157,10 @@
 
 // this used to have a spurious "live at entry to f11a: ~r0"
 func f11a() *int {
-	select { // ERROR "live at call to newselect: autotmp" "live at call to selectgo: autotmp"
-	case <-c: // ERROR "live at call to selectrecv: autotmp"
+	select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
+	case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 		return nil
-	case <-c: // ERROR "live at call to selectrecv: autotmp"
+	case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 		return nil
 	}
 }
@@ -172,10 +172,10 @@
 		// get to the bottom of the function.
 		// This used to have a spurious "live at call to printint: p".
 		printint(1) // nothing live here!
-		select {    // ERROR "live at call to newselect: autotmp" "live at call to selectgo: autotmp"
-		case <-c: // ERROR "live at call to selectrecv: autotmp"
+		select {    // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 			return nil
-		case <-c: // ERROR "live at call to selectrecv: autotmp"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 			return nil
 		}
 	}
@@ -188,10 +188,10 @@
 	if b {
 		// Unlike previous, the cases in this select fall through,
 		// so we can get to the println, so p is not dead.
-		printint(1) // ERROR "live at call to printint: p"
-		select {    // ERROR "live at call to newselect: autotmp.* p" "live at call to selectgo: autotmp.* p"
-		case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
-		case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
+		printint(1) // ERROR "live at call to printint: p$"
+		select {    // ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
 		}
 	}
 	println(*p)
@@ -215,7 +215,7 @@
 
 func f13() {
 	s := "hello"
-	s = h13(s, g13(s)) // ERROR "live at call to g13: s"
+	s = h13(s, g13(s)) // ERROR "live at call to g13: s$"
 }
 
 func g13(string) string
@@ -225,7 +225,7 @@
 
 func f14() {
 	x := g14()
-	printstringpointer(&x) // ERROR "live at call to printstringpointer: x"
+	printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
 }
 
 func g14() string
@@ -233,8 +233,8 @@
 func f15() {
 	var x string
 	_ = &x
-	x = g15()      // ERROR "live at call to g15: x"
-	printstring(x) // ERROR "live at call to printstring: x"
+	x = g15()      // ERROR "live at call to g15: x$"
+	printstring(x) // ERROR "live at call to printstring: x$"
 }
 
 func g15() string
@@ -367,9 +367,9 @@
 	}
 	var x string
 	_ = &x
-	x = g15()      // ERROR "live at call to g15: x"
-	printstring(x) // ERROR "live at call to printstring: x"
-} // ERROR "live at call to deferreturn: x"
+	x = g15()      // ERROR "live at call to g15: x$"
+	printstring(x) // ERROR "live at call to printstring: x$"
+} // ERROR "live at call to deferreturn: x$"
 
 func g25()
 
@@ -408,7 +408,7 @@
 	if b {
 		defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
 	}
-	defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$" "ambiguously live"
+	defer call27(func() { x++ }) // ERROR "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
 	printnl()                    // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
 } // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
 
@@ -417,9 +417,9 @@
 func f27go(b bool) {
 	x := 0
 	if b {
-		go call27(func() { x++ }) // ERROR "live at call to newobject: &x" "live at call to newproc: &x$"
+		go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newproc: &x$"
 	}
-	go call27(func() { x++ }) // ERROR "live at call to newobject: &x"
+	go call27(func() { x++ }) // ERROR "live at call to newobject: &x$"
 	printnl()
 }
 
@@ -481,7 +481,7 @@
 		g31("a") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
 	}
 	if b2 {
-		h31("b") // ERROR "live at call to newobject: autotmp_[0-9]+$" "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$"
+		h31("b") // ERROR "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
 	}
 	if b3 {
 		panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to gopanic: autotmp_[0-9]+$"
@@ -496,7 +496,7 @@
 
 type T32 int
 
-func (t *T32) Inc() { // ERROR "live at entry"
+func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
 	*t++
 }
 
@@ -573,14 +573,14 @@
 	// we care that the println lines have no live variables
 	// and therefore no output.
 	if b {
-		select { // ERROR "live at call"
-		case <-fc38(): // ERROR "live at call"
+		select { // ERROR "live at call to newselect: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+		case <-fc38(): // ERROR "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
 			printnl()
-		case fc38() <- *fi38(1): // ERROR "live at call"
+		case fc38() <- *fi38(1): // ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
 			printnl()
-		case *fi38(2) = <-fc38(): // ERROR "live at call"
+		case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
 			printnl()
-		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call"
+		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
 			printnl()
 		}
 		printnl()
@@ -592,27 +592,27 @@
 
 func f39() (x []int) {
 	x = []int{1}
-	printnl() // ERROR "live at call to printnl: x"
+	printnl() // ERROR "live at call to printnl: x$"
 	return x
 }
 
 func f39a() (x []int) {
 	x = []int{1}
-	printnl() // ERROR "live at call to printnl: x"
+	printnl() // ERROR "live at call to printnl: x$"
 	return
 }
 
 func f39b() (x [10]*int) {
 	x = [10]*int{}
-	x[0] = new(int) // ERROR "live at call to newobject: x"
-	printnl()       // ERROR "live at call to printnl: x"
+	x[0] = new(int) // ERROR "live at call to newobject: x$"
+	printnl()       // ERROR "live at call to printnl: x$"
 	return x
 }
 
 func f39c() (x [10]*int) {
 	x = [10]*int{}
-	x[0] = new(int) // ERROR "live at call to newobject: x"
-	printnl()       // ERROR "live at call to printnl: x"
+	x[0] = new(int) // ERROR "live at call to newobject: x$"
+	printnl()       // ERROR "live at call to printnl: x$"
 	return
 }
 
@@ -625,7 +625,7 @@
 
 func newT40() *T40 {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
 	return &ret
 }
 
@@ -637,8 +637,8 @@
 
 func good40() {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_.* ret"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
 	t := &ret
-	printnl() // ERROR "live at call to printnl: autotmp_.* ret"
+	printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
 	_ = t
 }
diff --git a/test/nilptr3.go b/test/nilptr3.go
index a62b262..607c6fb 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,7 +1,7 @@
 // errorcheck -0 -d=nil
-// Fails on ppc64x and arm64 because of incomplete optimization.
-// See issues 9058 and 10105.
-// +build !ppc64,!ppc64le,!arm64
+// Fails on ppc64x because of incomplete optimization.
+// See issues 9058.
+// +build !ppc64,!ppc64le
 
 // Copyright 2013 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/test/nosplit.go b/test/nosplit.go
index bd4e60b..bd7a8dd 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -292,9 +292,16 @@
 
 				// The limit was originally 128 but is now 512.
 				// Instead of rewriting the test cases above, adjust
-				// the first stack frame to use up the extra 32 bytes.
+				// the first stack frame to use up the extra bytes.
 				if i == 0 {
 					size += 512 - 128
+					// Noopt builds have a larger stackguard.
+					// See ../cmd/dist/buildruntime.go:stackGuardMultiplier
+					for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
+						if s == "-N" {
+							size += 640
+						}
+					}
 				}
 
 				if size%ptrSize == 4 {
diff --git a/test/run.go b/test/run.go
index bcd89a0..10ba7a8 100644
--- a/test/run.go
+++ b/test/run.go
@@ -36,6 +36,7 @@
 	numParallel    = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
 	summary        = flag.Bool("summary", false, "show summary of results")
 	showSkips      = flag.Bool("show_skips", false, "show skipped tests")
+	updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
 	runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
 )
 
@@ -50,8 +51,7 @@
 
 	// dirs are the directories to look for *.go files in.
 	// TODO(bradfitz): just use all directories?
-	// TODO(rsc): Put syntax back. See issue 9968.
-	dirs = []string{".", "ken", "chan", "interface", "dwarf", "fixedbugs", "bugs"}
+	dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "bugs"}
 
 	// ratec controls the max number of tests running at a time.
 	ratec chan bool
@@ -521,6 +521,9 @@
 				return
 			}
 		}
+		if *updateErrors {
+			t.updateErrors(string(out), long)
+		}
 		t.err = t.errorCheck(string(out), long, t.gofile)
 		return
 
@@ -721,6 +724,25 @@
 	return string(b)
 }
 
+func splitOutput(out string) []string {
+	// 6g error messages continue onto additional lines with leading tabs.
+	// Split the output at the beginning of each line that doesn't begin with a tab.
+	var res []string
+	for _, line := range strings.Split(out, "\n") {
+		if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
+			line = line[:len(line)-1]
+		}
+		if strings.HasPrefix(line, "\t") {
+			res[len(res)-1] += "\n" + line
+		} else if strings.HasPrefix(line, "go tool") {
+			continue
+		} else if strings.TrimSpace(line) != "" {
+			res = append(res, line)
+		}
+	}
+	return res
+}
+
 func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
 	defer func() {
 		if *verbose && err != nil {
@@ -728,22 +750,7 @@
 		}
 	}()
 	var errs []error
-
-	var out []string
-	// 6g error messages continue onto additional lines with leading tabs.
-	// Split the output at the beginning of each line that doesn't begin with a tab.
-	for _, line := range strings.Split(outStr, "\n") {
-		if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
-			line = line[:len(line)-1]
-		}
-		if strings.HasPrefix(line, "\t") {
-			out[len(out)-1] += "\n" + line
-		} else if strings.HasPrefix(line, "go tool") {
-			continue
-		} else if strings.TrimSpace(line) != "" {
-			out = append(out, line)
-		}
-	}
+	out := splitOutput(outStr)
 
 	// Cut directory name.
 	for i := range out {
@@ -800,7 +807,72 @@
 		fmt.Fprintf(&buf, "%s\n", err.Error())
 	}
 	return errors.New(buf.String())
+}
 
+func (t *test) updateErrors(out string, file string) {
+	// Read in source file.
+	src, err := ioutil.ReadFile(file)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		return
+	}
+	lines := strings.Split(string(src), "\n")
+	// Remove old errors.
+	for i, ln := range lines {
+		pos := strings.Index(ln, " // ERROR ")
+		if pos >= 0 {
+			lines[i] = ln[:pos]
+		}
+	}
+	// Parse new errors.
+	errors := make(map[int]map[string]bool)
+	tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
+	for _, errStr := range splitOutput(out) {
+		colon1 := strings.Index(errStr, ":")
+		if colon1 < 0 || errStr[:colon1] != file {
+			continue
+		}
+		colon2 := strings.Index(errStr[colon1+1:], ":")
+		if colon2 < 0 {
+			continue
+		}
+		colon2 += colon1 + 1
+		line, err := strconv.Atoi(errStr[colon1+1 : colon2])
+		line--
+		if err != nil || line < 0 || line >= len(lines) {
+			continue
+		}
+		msg := errStr[colon2+2:]
+		for _, r := range []string{`\`, `*`, `+`, `[`, `]`, `(`, `)`} {
+			msg = strings.Replace(msg, r, `\`+r, -1)
+		}
+		msg = strings.Replace(msg, `"`, `.`, -1)
+		msg = tmpRe.ReplaceAllLiteralString(msg, `autotmp_[0-9]+`)
+		if errors[line] == nil {
+			errors[line] = make(map[string]bool)
+		}
+		errors[line][msg] = true
+	}
+	// Add new errors.
+	for line, errs := range errors {
+		var sorted []string
+		for e := range errs {
+			sorted = append(sorted, e)
+		}
+		sort.Strings(sorted)
+		lines[line] += " // ERROR"
+		for _, e := range sorted {
+			lines[line] += fmt.Sprintf(` "%s$"`, e)
+		}
+	}
+	// Write new file.
+	err = ioutil.WriteFile(file, []byte(strings.Join(lines, "\n")), 0640)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		return
+	}
+	// Polish.
+	exec.Command("go", "fmt", file).CombinedOutput()
 }
 
 // matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
@@ -884,7 +956,7 @@
 				var err error
 				re, err = regexp.Compile(rx)
 				if err != nil {
-					log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
+					log.Fatalf("%s:%d: invalid regexp \"%s\" in ERROR line: %v", t.goFileName(), lineNum, rx, err)
 				}
 				cache[rx] = re
 			}
diff --git a/test/writebarrier.go b/test/writebarrier.go
new file mode 100644
index 0000000..1f25d91
--- /dev/null
+++ b/test/writebarrier.go
@@ -0,0 +1,110 @@
+// errorcheck -0 -l -d=wb
+
+// 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 where write barriers are and are not emitted.
+
+package p
+
+import "unsafe"
+
+func f(x **byte, y *byte) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f1(x *[]byte, y []byte) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f1a(x *[]byte, y *[]byte) {
+	*x = *y // ERROR "write barrier"
+
+	z := *y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f2(x *interface{}, y interface{}) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f2a(x *interface{}, y *interface{}) {
+	*x = *y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f3(x *string, y string) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f3a(x *string, y *string) {
+	*x = *y // ERROR "write barrier"
+
+	z := *y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f4(x *[2]string, y [2]string) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f4a(x *[2]string, y *[2]string) {
+	*x = *y // ERROR "write barrier"
+
+	z := *y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+type T struct {
+	X *int
+	Y int
+	M map[int]int
+}
+
+func f5(t, u *T) {
+	t.X = &u.Y // ERROR "write barrier"
+}
+
+func f6(t *T) {
+	t.M = map[int]int{1: 2} // ERROR "write barrier"
+}
+
+func f7(x, y *int) []*int {
+	var z [3]*int
+	i := 0
+	z[i] = x // ERROR "write barrier"
+	i++
+	z[i] = y // ERROR "write barrier"
+	i++
+	return z[:i]
+}
+
+func f9(x *interface{}, v *byte) {
+	*x = v // ERROR "write barrier"
+}
+
+func f10(x *byte, f func(interface{})) {
+	f(x)
+}
+
+func f11(x *unsafe.Pointer, y unsafe.Pointer) {
+	*x = unsafe.Pointer(uintptr(y) + 1) // ERROR "write barrier"
+}