Update prebuilts to go1.9rc1 ab/4215840

Test: m -j blueprint_tools
Change-Id: I6e92d224c7b1185c0813593ab11403ef50017916
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
new file mode 100644
index 0000000..2226b77
--- /dev/null
+++ b/src/internal/cpu/cpu.go
@@ -0,0 +1,32 @@
+// Copyright 2017 The Go 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 cpu implements processor feature detection
+// used by the Go standard libary.
+package cpu
+
+var X86 x86
+
+// The booleans in x86 contain the correspondingly named cpuid feature bit.
+// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers
+// in addition to the cpuid feature bit being set.
+// The struct is padded to avoid false sharing.
+type x86 struct {
+	_            [CacheLineSize]byte
+	HasAES       bool
+	HasAVX       bool
+	HasAVX2      bool
+	HasBMI1      bool
+	HasBMI2      bool
+	HasERMS      bool
+	HasOSXSAVE   bool
+	HasPCLMULQDQ bool
+	HasPOPCNT    bool
+	HasSSE2      bool
+	HasSSE3      bool
+	HasSSSE3     bool
+	HasSSE41     bool
+	HasSSE42     bool
+	_            [CacheLineSize]byte
+}
diff --git a/src/internal/cpu/cpu_arm.go b/src/internal/cpu/cpu_arm.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_arm.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_arm64.go b/src/internal/cpu/cpu_arm64.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_arm64.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mips.go b/src/internal/cpu/cpu_mips.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mips.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mips64.go b/src/internal/cpu/cpu_mips64.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mips64.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mips64le.go b/src/internal/cpu/cpu_mips64le.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mips64le.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_mipsle.go b/src/internal/cpu/cpu_mipsle.go
new file mode 100644
index 0000000..078a6c3
--- /dev/null
+++ b/src/internal/cpu/cpu_mipsle.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 32
diff --git a/src/internal/cpu/cpu_ppc64.go b/src/internal/cpu/cpu_ppc64.go
new file mode 100644
index 0000000..5b15150
--- /dev/null
+++ b/src/internal/cpu/cpu_ppc64.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 128
diff --git a/src/internal/cpu/cpu_ppc64le.go b/src/internal/cpu/cpu_ppc64le.go
new file mode 100644
index 0000000..5b15150
--- /dev/null
+++ b/src/internal/cpu/cpu_ppc64le.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 128
diff --git a/src/internal/cpu/cpu_s390x.go b/src/internal/cpu/cpu_s390x.go
new file mode 100644
index 0000000..4455809
--- /dev/null
+++ b/src/internal/cpu/cpu_s390x.go
@@ -0,0 +1,7 @@
+// Copyright 2017 The Go 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 cpu
+
+const CacheLineSize = 256
diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go
new file mode 100644
index 0000000..ab9836a
--- /dev/null
+++ b/src/internal/cpu/cpu_test.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go 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 cpu_test
+
+import (
+	"internal/cpu"
+	"runtime"
+	"testing"
+)
+
+func TestAMD64minimalFeatures(t *testing.T) {
+	if runtime.GOARCH == "amd64" {
+		if !cpu.X86.HasSSE2 {
+			t.Fatalf("HasSSE2 expected true, got false")
+		}
+	}
+}
+
+func TestAVX2hasAVX(t *testing.T) {
+	if runtime.GOARCH == "amd64" {
+		if cpu.X86.HasAVX2 && !cpu.X86.HasAVX {
+			t.Fatalf("HasAVX expected true, got false")
+		}
+	}
+}
diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go
new file mode 100644
index 0000000..31e7084
--- /dev/null
+++ b/src/internal/cpu/cpu_x86.go
@@ -0,0 +1,59 @@
+// Copyright 2017 The Go 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 386 amd64 amd64p32
+
+package cpu
+
+const CacheLineSize = 64
+
+// cpuid is implemented in cpu_x86.s.
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+
+// xgetbv with ecx = 0 is implemented in cpu_x86.s.
+func xgetbv() (eax, edx uint32)
+
+func init() {
+	maxId, _, _, _ := cpuid(0, 0)
+
+	if maxId < 1 {
+		return
+	}
+
+	_, _, ecx1, edx1 := cpuid(1, 0)
+	X86.HasSSE2 = isSet(26, edx1)
+
+	X86.HasSSE3 = isSet(0, ecx1)
+	X86.HasPCLMULQDQ = isSet(1, ecx1)
+	X86.HasSSSE3 = isSet(9, ecx1)
+	X86.HasSSE41 = isSet(19, ecx1)
+	X86.HasSSE42 = isSet(20, ecx1)
+	X86.HasPOPCNT = isSet(23, ecx1)
+	X86.HasAES = isSet(25, ecx1)
+	X86.HasOSXSAVE = isSet(27, ecx1)
+
+	osSupportsAVX := false
+	// For XGETBV, OSXSAVE bit is required and sufficient.
+	if X86.HasOSXSAVE {
+		eax, _ := xgetbv()
+		// Check if XMM and YMM registers have OS support.
+		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
+	}
+
+	X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
+
+	if maxId < 7 {
+		return
+	}
+
+	_, ebx7, _, _ := cpuid(7, 0)
+	X86.HasBMI1 = isSet(3, ebx7)
+	X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
+	X86.HasBMI2 = isSet(8, ebx7)
+	X86.HasERMS = isSet(9, ebx7)
+}
+
+func isSet(bitpos uint, value uint32) bool {
+	return value&(1<<bitpos) != 0
+}
diff --git a/src/internal/cpu/cpu_x86.s b/src/internal/cpu/cpu_x86.s
new file mode 100644
index 0000000..228fbcf
--- /dev/null
+++ b/src/internal/cpu/cpu_x86.s
@@ -0,0 +1,32 @@
+// Copyright 2017 The Go 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 386 amd64 amd64p32
+
+#include "textflag.h"
+
+// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
+TEXT ·cpuid(SB), NOSPLIT, $0-24
+	MOVL eaxArg+0(FP), AX
+	MOVL ecxArg+4(FP), CX
+	CPUID
+	MOVL AX, eax+8(FP)
+	MOVL BX, ebx+12(FP)
+	MOVL CX, ecx+16(FP)
+	MOVL DX, edx+20(FP)
+	RET
+
+// func xgetbv() (eax, edx uint32)
+TEXT ·xgetbv(SB),NOSPLIT,$0-8
+#ifdef GOOS_nacl
+	// nacl does not support XGETBV.
+	MOVL $0, eax+0(FP)
+	MOVL $0, edx+4(FP)
+#else
+	MOVL $0, CX
+	XGETBV
+	MOVL AX, eax+0(FP)
+	MOVL DX, edx+4(FP)
+#endif
+	RET
diff --git a/src/internal/poll/export_posix_test.go b/src/internal/poll/export_posix_test.go
new file mode 100644
index 0000000..73b2c11
--- /dev/null
+++ b/src/internal/poll/export_posix_test.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+// Export guts for testing on posix.
+// Since testing imports os and os imports internal/poll,
+// the internal/poll tests can not be in package poll.
+
+package poll
+
+func (fd *FD) EOFError(n int, err error) error {
+	return fd.eofError(n, err)
+}
diff --git a/src/internal/poll/export_test.go b/src/internal/poll/export_test.go
new file mode 100644
index 0000000..02664d9
--- /dev/null
+++ b/src/internal/poll/export_test.go
@@ -0,0 +1,35 @@
+// 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.
+
+// Export guts for testing.
+// Since testing imports os and os imports internal/poll,
+// the internal/poll tests can not be in package poll.
+
+package poll
+
+var Consume = consume
+
+type FDMutex struct {
+	fdMutex
+}
+
+func (mu *FDMutex) Incref() bool {
+	return mu.incref()
+}
+
+func (mu *FDMutex) IncrefAndClose() bool {
+	return mu.increfAndClose()
+}
+
+func (mu *FDMutex) Decref() bool {
+	return mu.decref()
+}
+
+func (mu *FDMutex) RWLock(read bool) bool {
+	return mu.rwlock(read)
+}
+
+func (mu *FDMutex) RWUnlock(read bool) bool {
+	return mu.rwunlock(read)
+}
diff --git a/src/internal/poll/fd.go b/src/internal/poll/fd.go
new file mode 100644
index 0000000..f1454db
--- /dev/null
+++ b/src/internal/poll/fd.go
@@ -0,0 +1,57 @@
+// Copyright 2017 The Go 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 poll supports non-blocking I/O on file descriptors with polling.
+// This supports I/O operations that block only a goroutine, not a thread.
+// This is used by the net and os packages.
+// It uses a poller built into the runtime, with support from the
+// runtime scheduler.
+package poll
+
+import "errors"
+
+// ErrNetClosing is returned when a network descriptor is used after
+// it has been closed. Keep this string consistent because of issue
+// #4373: since historically programs have not been able to detect
+// this error, they look for the string.
+var ErrNetClosing = errors.New("use of closed network connection")
+
+// ErrFileClosing is returned when a file descriptor is used after it
+// has been closed.
+var ErrFileClosing = errors.New("use of closed file")
+
+// Return the appropriate closing error based on isFile.
+func errClosing(isFile bool) error {
+	if isFile {
+		return ErrFileClosing
+	}
+	return ErrNetClosing
+}
+
+// ErrTimeout is returned for an expired deadline.
+var ErrTimeout error = &TimeoutError{}
+
+// TimeoutError is returned for an expired deadline.
+type TimeoutError struct{}
+
+// Implement the net.Error interface.
+func (e *TimeoutError) Error() string   { return "i/o timeout" }
+func (e *TimeoutError) Timeout() bool   { return true }
+func (e *TimeoutError) Temporary() bool { return true }
+
+// consume removes data from a slice of byte slices, for writev.
+func consume(v *[][]byte, n int64) {
+	for len(*v) > 0 {
+		ln0 := int64(len((*v)[0]))
+		if ln0 > n {
+			(*v)[0] = (*v)[0][n:]
+			return
+		}
+		n -= ln0
+		*v = (*v)[1:]
+	}
+}
+
+// TestHookDidWritev is a hook for testing writev.
+var TestHookDidWritev = func(wrote int) {}
diff --git a/src/internal/poll/fd_io_plan9.go b/src/internal/poll/fd_io_plan9.go
new file mode 100644
index 0000000..287d11b
--- /dev/null
+++ b/src/internal/poll/fd_io_plan9.go
@@ -0,0 +1,91 @@
+// Copyright 2016 The Go 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 poll
+
+import (
+	"runtime"
+	"sync"
+	"syscall"
+)
+
+// asyncIO implements asynchronous cancelable I/O.
+// An asyncIO represents a single asynchronous Read or Write
+// operation. The result is returned on the result channel.
+// The undergoing I/O system call can either complete or be
+// interrupted by a note.
+type asyncIO struct {
+	res chan result
+
+	// mu guards the pid field.
+	mu sync.Mutex
+
+	// pid holds the process id of
+	// the process running the IO operation.
+	pid int
+}
+
+// result is the return value of a Read or Write operation.
+type result struct {
+	n   int
+	err error
+}
+
+// newAsyncIO returns a new asyncIO that performs an I/O
+// operation by calling fn, which must do one and only one
+// interruptible system call.
+func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
+	aio := &asyncIO{
+		res: make(chan result, 0),
+	}
+	aio.mu.Lock()
+	go func() {
+		// Lock the current goroutine to its process
+		// and store the pid in io so that Cancel can
+		// interrupt it. We ignore the "hangup" signal,
+		// so the signal does not take down the entire
+		// Go runtime.
+		runtime.LockOSThread()
+		runtime_ignoreHangup()
+		aio.pid = syscall.Getpid()
+		aio.mu.Unlock()
+
+		n, err := fn(b)
+
+		aio.mu.Lock()
+		aio.pid = -1
+		runtime_unignoreHangup()
+		aio.mu.Unlock()
+
+		aio.res <- result{n, err}
+	}()
+	return aio
+}
+
+// Cancel interrupts the I/O operation, causing
+// the Wait function to return.
+func (aio *asyncIO) Cancel() {
+	aio.mu.Lock()
+	defer aio.mu.Unlock()
+	if aio.pid == -1 {
+		return
+	}
+	f, e := syscall.Open("/proc/"+itoa(aio.pid)+"/note", syscall.O_WRONLY)
+	if e != nil {
+		return
+	}
+	syscall.Write(f, []byte("hangup"))
+	syscall.Close(f)
+}
+
+// Wait for the I/O operation to complete.
+func (aio *asyncIO) Wait() (int, error) {
+	res := <-aio.res
+	return res.n, res.err
+}
+
+// The following functions, provided by the runtime, are used to
+// ignore and unignore the "hangup" signal received by the process.
+func runtime_ignoreHangup()
+func runtime_unignoreHangup()
diff --git a/src/internal/poll/fd_mutex.go b/src/internal/poll/fd_mutex.go
new file mode 100644
index 0000000..76174e5
--- /dev/null
+++ b/src/internal/poll/fd_mutex.go
@@ -0,0 +1,250 @@
+// 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 poll
+
+import "sync/atomic"
+
+// fdMutex is a specialized synchronization primitive that manages
+// lifetime of an fd and serializes access to Read, Write and Close
+// methods on FD.
+type fdMutex struct {
+	state uint64
+	rsema uint32
+	wsema uint32
+}
+
+// fdMutex.state is organized as follows:
+// 1 bit - whether FD is closed, if set all subsequent lock operations will fail.
+// 1 bit - lock for read operations.
+// 1 bit - lock for write operations.
+// 20 bits - total number of references (read+write+misc).
+// 20 bits - number of outstanding read waiters.
+// 20 bits - number of outstanding write waiters.
+const (
+	mutexClosed  = 1 << 0
+	mutexRLock   = 1 << 1
+	mutexWLock   = 1 << 2
+	mutexRef     = 1 << 3
+	mutexRefMask = (1<<20 - 1) << 3
+	mutexRWait   = 1 << 23
+	mutexRMask   = (1<<20 - 1) << 23
+	mutexWWait   = 1 << 43
+	mutexWMask   = (1<<20 - 1) << 43
+)
+
+// Read operations must do rwlock(true)/rwunlock(true).
+//
+// Write operations must do rwlock(false)/rwunlock(false).
+//
+// Misc operations must do incref/decref.
+// Misc operations include functions like setsockopt and setDeadline.
+// They need to use incref/decref to ensure that they operate on the
+// correct fd in presence of a concurrent close call (otherwise fd can
+// be closed under their feet).
+//
+// Close operations must do increfAndClose/decref.
+
+// incref adds a reference to mu.
+// It reports whether mu is available for reading or writing.
+func (mu *fdMutex) incref() bool {
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexClosed != 0 {
+			return false
+		}
+		new := old + mutexRef
+		if new&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			return true
+		}
+	}
+}
+
+// increfAndClose sets the state of mu to closed.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) increfAndClose() bool {
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexClosed != 0 {
+			return false
+		}
+		// Mark as closed and acquire a reference.
+		new := (old | mutexClosed) + mutexRef
+		if new&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		// Remove all read and write waiters.
+		new &^= mutexRMask | mutexWMask
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			// Wake all read and write waiters,
+			// they will observe closed flag after wakeup.
+			for old&mutexRMask != 0 {
+				old -= mutexRWait
+				runtime_Semrelease(&mu.rsema)
+			}
+			for old&mutexWMask != 0 {
+				old -= mutexWWait
+				runtime_Semrelease(&mu.wsema)
+			}
+			return true
+		}
+	}
+}
+
+// decref removes a reference from mu.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) decref() bool {
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		new := old - mutexRef
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			return new&(mutexClosed|mutexRefMask) == mutexClosed
+		}
+	}
+}
+
+// lock adds a reference to mu and locks mu.
+// It reports whether mu is available for reading or writing.
+func (mu *fdMutex) rwlock(read bool) bool {
+	var mutexBit, mutexWait, mutexMask uint64
+	var mutexSema *uint32
+	if read {
+		mutexBit = mutexRLock
+		mutexWait = mutexRWait
+		mutexMask = mutexRMask
+		mutexSema = &mu.rsema
+	} else {
+		mutexBit = mutexWLock
+		mutexWait = mutexWWait
+		mutexMask = mutexWMask
+		mutexSema = &mu.wsema
+	}
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexClosed != 0 {
+			return false
+		}
+		var new uint64
+		if old&mutexBit == 0 {
+			// Lock is free, acquire it.
+			new = (old | mutexBit) + mutexRef
+			if new&mutexRefMask == 0 {
+				panic("inconsistent poll.fdMutex")
+			}
+		} else {
+			// Wait for lock.
+			new = old + mutexWait
+			if new&mutexMask == 0 {
+				panic("inconsistent poll.fdMutex")
+			}
+		}
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			if old&mutexBit == 0 {
+				return true
+			}
+			runtime_Semacquire(mutexSema)
+			// The signaller has subtracted mutexWait.
+		}
+	}
+}
+
+// unlock removes a reference from mu and unlocks mu.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) rwunlock(read bool) bool {
+	var mutexBit, mutexWait, mutexMask uint64
+	var mutexSema *uint32
+	if read {
+		mutexBit = mutexRLock
+		mutexWait = mutexRWait
+		mutexMask = mutexRMask
+		mutexSema = &mu.rsema
+	} else {
+		mutexBit = mutexWLock
+		mutexWait = mutexWWait
+		mutexMask = mutexWMask
+		mutexSema = &mu.wsema
+	}
+	for {
+		old := atomic.LoadUint64(&mu.state)
+		if old&mutexBit == 0 || old&mutexRefMask == 0 {
+			panic("inconsistent poll.fdMutex")
+		}
+		// Drop lock, drop reference and wake read waiter if present.
+		new := (old &^ mutexBit) - mutexRef
+		if old&mutexMask != 0 {
+			new -= mutexWait
+		}
+		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
+			if old&mutexMask != 0 {
+				runtime_Semrelease(mutexSema)
+			}
+			return new&(mutexClosed|mutexRefMask) == mutexClosed
+		}
+	}
+}
+
+// Implemented in runtime package.
+func runtime_Semacquire(sema *uint32)
+func runtime_Semrelease(sema *uint32)
+
+// incref adds a reference to fd.
+// It returns an error when fd cannot be used.
+func (fd *FD) incref() error {
+	if !fd.fdmu.incref() {
+		return errClosing(fd.isFile)
+	}
+	return nil
+}
+
+// decref removes a reference from fd.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *FD) decref() error {
+	if fd.fdmu.decref() {
+		return fd.destroy()
+	}
+	return nil
+}
+
+// readLock adds a reference to fd and locks fd for reading.
+// It returns an error when fd cannot be used for reading.
+func (fd *FD) readLock() error {
+	if !fd.fdmu.rwlock(true) {
+		return errClosing(fd.isFile)
+	}
+	return nil
+}
+
+// readUnlock removes a reference from fd and unlocks fd for reading.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *FD) readUnlock() {
+	if fd.fdmu.rwunlock(true) {
+		fd.destroy()
+	}
+}
+
+// writeLock adds a reference to fd and locks fd for writing.
+// It returns an error when fd cannot be used for writing.
+func (fd *FD) writeLock() error {
+	if !fd.fdmu.rwlock(false) {
+		return errClosing(fd.isFile)
+	}
+	return nil
+}
+
+// writeUnlock removes a reference from fd and unlocks fd for writing.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *FD) writeUnlock() {
+	if fd.fdmu.rwunlock(false) {
+		fd.destroy()
+	}
+}
diff --git a/src/internal/poll/fd_mutex_test.go b/src/internal/poll/fd_mutex_test.go
new file mode 100644
index 0000000..bab81c6
--- /dev/null
+++ b/src/internal/poll/fd_mutex_test.go
@@ -0,0 +1,196 @@
+// 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 poll_test
+
+import (
+	. "internal/poll"
+	"math/rand"
+	"runtime"
+	"testing"
+	"time"
+)
+
+func TestMutexLock(t *testing.T) {
+	var mu FDMutex
+
+	if !mu.Incref() {
+		t.Fatal("broken")
+	}
+	if mu.Decref() {
+		t.Fatal("broken")
+	}
+
+	if !mu.RWLock(true) {
+		t.Fatal("broken")
+	}
+	if mu.RWUnlock(true) {
+		t.Fatal("broken")
+	}
+
+	if !mu.RWLock(false) {
+		t.Fatal("broken")
+	}
+	if mu.RWUnlock(false) {
+		t.Fatal("broken")
+	}
+}
+
+func TestMutexClose(t *testing.T) {
+	var mu FDMutex
+	if !mu.IncrefAndClose() {
+		t.Fatal("broken")
+	}
+
+	if mu.Incref() {
+		t.Fatal("broken")
+	}
+	if mu.RWLock(true) {
+		t.Fatal("broken")
+	}
+	if mu.RWLock(false) {
+		t.Fatal("broken")
+	}
+	if mu.IncrefAndClose() {
+		t.Fatal("broken")
+	}
+}
+
+func TestMutexCloseUnblock(t *testing.T) {
+	c := make(chan bool)
+	var mu FDMutex
+	mu.RWLock(true)
+	for i := 0; i < 4; i++ {
+		go func() {
+			if mu.RWLock(true) {
+				t.Error("broken")
+				return
+			}
+			c <- true
+		}()
+	}
+	// Concurrent goroutines must not be able to read lock the mutex.
+	time.Sleep(time.Millisecond)
+	select {
+	case <-c:
+		t.Fatal("broken")
+	default:
+	}
+	mu.IncrefAndClose() // Must unblock the readers.
+	for i := 0; i < 4; i++ {
+		select {
+		case <-c:
+		case <-time.After(10 * time.Second):
+			t.Fatal("broken")
+		}
+	}
+	if mu.Decref() {
+		t.Fatal("broken")
+	}
+	if !mu.RWUnlock(true) {
+		t.Fatal("broken")
+	}
+}
+
+func TestMutexPanic(t *testing.T) {
+	ensurePanics := func(f func()) {
+		defer func() {
+			if recover() == nil {
+				t.Fatal("does not panic")
+			}
+		}()
+		f()
+	}
+
+	var mu FDMutex
+	ensurePanics(func() { mu.Decref() })
+	ensurePanics(func() { mu.RWUnlock(true) })
+	ensurePanics(func() { mu.RWUnlock(false) })
+
+	ensurePanics(func() { mu.Incref(); mu.Decref(); mu.Decref() })
+	ensurePanics(func() { mu.RWLock(true); mu.RWUnlock(true); mu.RWUnlock(true) })
+	ensurePanics(func() { mu.RWLock(false); mu.RWUnlock(false); mu.RWUnlock(false) })
+
+	// ensure that it's still not broken
+	mu.Incref()
+	mu.Decref()
+	mu.RWLock(true)
+	mu.RWUnlock(true)
+	mu.RWLock(false)
+	mu.RWUnlock(false)
+}
+
+func TestMutexStress(t *testing.T) {
+	P := 8
+	N := int(1e6)
+	if testing.Short() {
+		P = 4
+		N = 1e4
+	}
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
+	done := make(chan bool)
+	var mu FDMutex
+	var readState [2]uint64
+	var writeState [2]uint64
+	for p := 0; p < P; p++ {
+		go func() {
+			r := rand.New(rand.NewSource(rand.Int63()))
+			for i := 0; i < N; i++ {
+				switch r.Intn(3) {
+				case 0:
+					if !mu.Incref() {
+						t.Error("broken")
+						return
+					}
+					if mu.Decref() {
+						t.Error("broken")
+						return
+					}
+				case 1:
+					if !mu.RWLock(true) {
+						t.Error("broken")
+						return
+					}
+					// Ensure that it provides mutual exclusion for readers.
+					if readState[0] != readState[1] {
+						t.Error("broken")
+						return
+					}
+					readState[0]++
+					readState[1]++
+					if mu.RWUnlock(true) {
+						t.Error("broken")
+						return
+					}
+				case 2:
+					if !mu.RWLock(false) {
+						t.Error("broken")
+						return
+					}
+					// Ensure that it provides mutual exclusion for writers.
+					if writeState[0] != writeState[1] {
+						t.Error("broken")
+						return
+					}
+					writeState[0]++
+					writeState[1]++
+					if mu.RWUnlock(false) {
+						t.Error("broken")
+						return
+					}
+				}
+			}
+			done <- true
+		}()
+	}
+	for p := 0; p < P; p++ {
+		<-done
+	}
+	if !mu.IncrefAndClose() {
+		t.Fatal("broken")
+	}
+	if !mu.Decref() {
+		t.Fatal("broken")
+	}
+}
diff --git a/src/internal/poll/fd_plan9.go b/src/internal/poll/fd_plan9.go
new file mode 100644
index 0000000..107f454
--- /dev/null
+++ b/src/internal/poll/fd_plan9.go
@@ -0,0 +1,216 @@
+// 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 poll
+
+import (
+	"errors"
+	"io"
+	"sync/atomic"
+	"time"
+)
+
+type atomicBool int32
+
+func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
+func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
+func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
+
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	Destroy func()
+
+	// deadlines
+	raio      *asyncIO
+	waio      *asyncIO
+	rtimer    *time.Timer
+	wtimer    *time.Timer
+	rtimedout atomicBool // set true when read deadline has been reached
+	wtimedout atomicBool // set true when write deadline has been reached
+
+	// Whether this is a normal file.
+	// On Plan 9 we do not use this package for ordinary files,
+	// so this is always false, but the field is present because
+	// shared code in fd_mutex.go checks it.
+	isFile bool
+}
+
+// We need this to close out a file descriptor when it is unlocked,
+// but the real implementation has to live in the net package because
+// it uses os.File's.
+func (fd *FD) destroy() error {
+	if fd.Destroy != nil {
+		fd.Destroy()
+	}
+	return nil
+}
+
+// Close handles the locking for closing an FD. The real operation
+// is in the net package.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	return nil
+}
+
+// Read implements io.Reader.
+func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
+	if fd.rtimedout.isSet() {
+		return 0, ErrTimeout
+	}
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+	if len(b) == 0 {
+		return 0, nil
+	}
+	fd.raio = newAsyncIO(fn, b)
+	n, err := fd.raio.Wait()
+	fd.raio = nil
+	if isHangup(err) {
+		err = io.EOF
+	}
+	if isInterrupted(err) {
+		err = ErrTimeout
+	}
+	return n, err
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
+	if fd.wtimedout.isSet() {
+		return 0, ErrTimeout
+	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	fd.waio = newAsyncIO(fn, b)
+	n, err := fd.waio.Wait()
+	fd.waio = nil
+	if isInterrupted(err) {
+		err = ErrTimeout
+	}
+	return n, err
+}
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	d := t.Sub(time.Now())
+	if mode == 'r' || mode == 'r'+'w' {
+		fd.rtimedout.setFalse()
+	}
+	if mode == 'w' || mode == 'r'+'w' {
+		fd.wtimedout.setFalse()
+	}
+	if t.IsZero() || d < 0 {
+		// Stop timer
+		if mode == 'r' || mode == 'r'+'w' {
+			if fd.rtimer != nil {
+				fd.rtimer.Stop()
+			}
+			fd.rtimer = nil
+		}
+		if mode == 'w' || mode == 'r'+'w' {
+			if fd.wtimer != nil {
+				fd.wtimer.Stop()
+			}
+			fd.wtimer = nil
+		}
+	} else {
+		// Interrupt I/O operation once timer has expired
+		if mode == 'r' || mode == 'r'+'w' {
+			fd.rtimer = time.AfterFunc(d, func() {
+				fd.rtimedout.setTrue()
+				if fd.raio != nil {
+					fd.raio.Cancel()
+				}
+			})
+		}
+		if mode == 'w' || mode == 'r'+'w' {
+			fd.wtimer = time.AfterFunc(d, func() {
+				fd.wtimedout.setTrue()
+				if fd.waio != nil {
+					fd.waio.Cancel()
+				}
+			})
+		}
+	}
+	if !t.IsZero() && d < 0 {
+		// Interrupt current I/O operation
+		if mode == 'r' || mode == 'r'+'w' {
+			fd.rtimedout.setTrue()
+			if fd.raio != nil {
+				fd.raio.Cancel()
+			}
+		}
+		if mode == 'w' || mode == 'r'+'w' {
+			fd.wtimedout.setTrue()
+			if fd.waio != nil {
+				fd.waio.Cancel()
+			}
+		}
+	}
+	return nil
+}
+
+// On Plan 9 only, expose the locking for the net code.
+
+// ReadLock wraps FD.readLock.
+func (fd *FD) ReadLock() error {
+	return fd.readLock()
+}
+
+// ReadUnlock wraps FD.readUnlock.
+func (fd *FD) ReadUnlock() {
+	fd.readUnlock()
+}
+
+func isHangup(err error) bool {
+	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
+}
+
+func isInterrupted(err error) bool {
+	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return ^uintptr(0)
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	return errors.New("not implemented")
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
diff --git a/src/internal/poll/fd_poll_nacl.go b/src/internal/poll/fd_poll_nacl.go
new file mode 100644
index 0000000..2df3003
--- /dev/null
+++ b/src/internal/poll/fd_poll_nacl.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 poll
+
+import (
+	"syscall"
+	"time"
+)
+
+type pollDesc struct {
+	fd      *FD
+	closing bool
+}
+
+func (pd *pollDesc) init(fd *FD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) close() {}
+
+func (pd *pollDesc) evict() {
+	pd.closing = true
+	if pd.fd != nil {
+		syscall.StopIO(pd.fd.Sysfd)
+	}
+}
+
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
+	if pd.closing {
+		return errClosing(isFile)
+	}
+	return nil
+}
+
+func (pd *pollDesc) prepareRead(isFile bool) error { return pd.prepare('r', isFile) }
+
+func (pd *pollDesc) prepareWrite(isFile bool) error { return pd.prepare('w', isFile) }
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+	if pd.closing {
+		return errClosing(isFile)
+	}
+	return ErrTimeout
+}
+
+func (pd *pollDesc) waitRead(isFile bool) error { return pd.wait('r', isFile) }
+
+func (pd *pollDesc) waitWrite(isFile bool) error { return pd.wait('w', isFile) }
+
+func (pd *pollDesc) waitCanceled(mode int) {}
+
+func (pd *pollDesc) pollable() bool { return true }
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	d := t.UnixNano()
+	if t.IsZero() {
+		d = 0
+	}
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	switch mode {
+	case 'r':
+		syscall.SetReadDeadline(fd.Sysfd, d)
+	case 'w':
+		syscall.SetWriteDeadline(fd.Sysfd, d)
+	case 'r' + 'w':
+		syscall.SetReadDeadline(fd.Sysfd, d)
+		syscall.SetWriteDeadline(fd.Sysfd, d)
+	}
+	fd.decref()
+	return nil
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return ^uintptr(0)
+}
diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go
new file mode 100644
index 0000000..bfbe3c7
--- /dev/null
+++ b/src/internal/poll/fd_poll_runtime.go
@@ -0,0 +1,162 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd windows solaris
+
+package poll
+
+import (
+	"errors"
+	"sync"
+	"syscall"
+	"time"
+)
+
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
+
+func runtime_pollServerInit()
+func runtime_pollServerDescriptor() uintptr
+func runtime_pollOpen(fd uintptr) (uintptr, int)
+func runtime_pollClose(ctx uintptr)
+func runtime_pollWait(ctx uintptr, mode int) int
+func runtime_pollWaitCanceled(ctx uintptr, mode int) int
+func runtime_pollReset(ctx uintptr, mode int) int
+func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
+func runtime_pollUnblock(ctx uintptr)
+
+type pollDesc struct {
+	runtimeCtx uintptr
+}
+
+var serverInit sync.Once
+
+func (pd *pollDesc) init(fd *FD) error {
+	serverInit.Do(runtime_pollServerInit)
+	ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
+	if errno != 0 {
+		if ctx != 0 {
+			runtime_pollUnblock(ctx)
+			runtime_pollClose(ctx)
+		}
+		return syscall.Errno(errno)
+	}
+	pd.runtimeCtx = ctx
+	return nil
+}
+
+func (pd *pollDesc) close() {
+	if pd.runtimeCtx == 0 {
+		return
+	}
+	runtime_pollClose(pd.runtimeCtx)
+	pd.runtimeCtx = 0
+}
+
+// Evict evicts fd from the pending list, unblocking any I/O running on fd.
+func (pd *pollDesc) evict() {
+	if pd.runtimeCtx == 0 {
+		return
+	}
+	runtime_pollUnblock(pd.runtimeCtx)
+}
+
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
+	if pd.runtimeCtx == 0 {
+		return nil
+	}
+	res := runtime_pollReset(pd.runtimeCtx, mode)
+	return convertErr(res, isFile)
+}
+
+func (pd *pollDesc) prepareRead(isFile bool) error {
+	return pd.prepare('r', isFile)
+}
+
+func (pd *pollDesc) prepareWrite(isFile bool) error {
+	return pd.prepare('w', isFile)
+}
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+	if pd.runtimeCtx == 0 {
+		return errors.New("waiting for unsupported file type")
+	}
+	res := runtime_pollWait(pd.runtimeCtx, mode)
+	return convertErr(res, isFile)
+}
+
+func (pd *pollDesc) waitRead(isFile bool) error {
+	return pd.wait('r', isFile)
+}
+
+func (pd *pollDesc) waitWrite(isFile bool) error {
+	return pd.wait('w', isFile)
+}
+
+func (pd *pollDesc) waitCanceled(mode int) {
+	if pd.runtimeCtx == 0 {
+		return
+	}
+	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
+}
+
+func (pd *pollDesc) pollable() bool {
+	return pd.runtimeCtx != 0
+}
+
+func convertErr(res int, isFile bool) error {
+	switch res {
+	case 0:
+		return nil
+	case 1:
+		return errClosing(isFile)
+	case 2:
+		return ErrTimeout
+	}
+	println("unreachable: ", res)
+	panic("unreachable")
+}
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	diff := int64(time.Until(t))
+	d := runtimeNano() + diff
+	if d <= 0 && diff > 0 {
+		// If the user has a deadline in the future, but the delay calculation
+		// overflows, then set the deadline to the maximum possible value.
+		d = 1<<63 - 1
+	}
+	if t.IsZero() {
+		d = 0
+	}
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	if fd.pd.runtimeCtx == 0 {
+		return errors.New("file type does not support deadlines")
+	}
+	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
+	fd.decref()
+	return nil
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return runtime_pollServerDescriptor()
+}
diff --git a/src/internal/poll/fd_posix.go b/src/internal/poll/fd_posix.go
new file mode 100644
index 0000000..e0e634c
--- /dev/null
+++ b/src/internal/poll/fd_posix.go
@@ -0,0 +1,57 @@
+// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package poll
+
+import (
+	"io"
+	"syscall"
+)
+
+// eofError returns io.EOF when fd is available for reading end of
+// file.
+func (fd *FD) eofError(n int, err error) error {
+	if n == 0 && err == nil && fd.ZeroReadIsEOF {
+		return io.EOF
+	}
+	return err
+}
+
+// Fchmod wraps syscall.Fchmod.
+func (fd *FD) Fchmod(mode uint32) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchmod(fd.Sysfd, mode)
+}
+
+// Fchown wraps syscall.Fchown.
+func (fd *FD) Fchown(uid, gid int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchown(fd.Sysfd, uid, gid)
+}
+
+// Ftruncate wraps syscall.Ftruncate.
+func (fd *FD) Ftruncate(size int64) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Ftruncate(fd.Sysfd, size)
+}
+
+// Fsync wraps syscall.Fsync.
+func (fd *FD) Fsync() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fsync(fd.Sysfd)
+}
diff --git a/src/internal/poll/fd_posix_test.go b/src/internal/poll/fd_posix_test.go
new file mode 100644
index 0000000..cbe015e
--- /dev/null
+++ b/src/internal/poll/fd_posix_test.go
@@ -0,0 +1,43 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package poll_test
+
+import (
+	. "internal/poll"
+	"io"
+	"testing"
+)
+
+var eofErrorTests = []struct {
+	n        int
+	err      error
+	fd       *FD
+	expected error
+}{
+	{100, nil, &FD{ZeroReadIsEOF: true}, nil},
+	{100, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
+	{100, ErrNetClosing, &FD{ZeroReadIsEOF: true}, ErrNetClosing},
+	{0, nil, &FD{ZeroReadIsEOF: true}, io.EOF},
+	{0, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
+	{0, ErrNetClosing, &FD{ZeroReadIsEOF: true}, ErrNetClosing},
+
+	{100, nil, &FD{ZeroReadIsEOF: false}, nil},
+	{100, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
+	{100, ErrNetClosing, &FD{ZeroReadIsEOF: false}, ErrNetClosing},
+	{0, nil, &FD{ZeroReadIsEOF: false}, nil},
+	{0, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
+	{0, ErrNetClosing, &FD{ZeroReadIsEOF: false}, ErrNetClosing},
+}
+
+func TestEOFError(t *testing.T) {
+	for _, tt := range eofErrorTests {
+		actual := tt.fd.EOFError(tt.n, tt.err)
+		if actual != tt.expected {
+			t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.ZeroReadIsEOF, tt.expected, actual)
+		}
+	}
+}
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
new file mode 100644
index 0000000..c40c701
--- /dev/null
+++ b/src/internal/poll/fd_unix.go
@@ -0,0 +1,452 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package poll
+
+import (
+	"io"
+	"syscall"
+)
+
+// FD is a file descriptor. The net and os packages use this type as a
+// field of a larger type representing a network connection or OS file.
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	// System file descriptor. Immutable until Close.
+	Sysfd int
+
+	// I/O poller.
+	pd pollDesc
+
+	// Writev cache.
+	iovecs *[]syscall.Iovec
+
+	// Whether this is a streaming descriptor, as opposed to a
+	// packet-based descriptor like a UDP socket. Immutable.
+	IsStream bool
+
+	// Whether a zero byte read indicates EOF. This is false for a
+	// message based socket connection.
+	ZeroReadIsEOF bool
+
+	// Whether this is a file rather than a network socket.
+	isFile bool
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file".
+func (fd *FD) Init(net string, pollable bool) error {
+	// We don't actually care about the various network types.
+	if net == "file" {
+		fd.isFile = true
+	}
+	if !pollable {
+		return nil
+	}
+	return fd.pd.init(fd)
+}
+
+// Destroy closes the file descriptor. This is called when there are
+// no remaining references.
+func (fd *FD) destroy() error {
+	// Poller may want to unregister fd in readiness notification mechanism,
+	// so this must be executed before CloseFunc.
+	fd.pd.close()
+	err := CloseFunc(fd.Sysfd)
+	fd.Sysfd = -1
+	return err
+}
+
+// Close closes the FD. The underlying file descriptor is closed by the
+// destroy method when there are no remaining references.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	// Unblock any I/O.  Once it all unblocks and returns,
+	// so that it cannot be referring to fd.sysfd anymore,
+	// the final decref will close fd.sysfd. This should happen
+	// fairly quickly, since all the I/O is non-blocking, and any
+	// attempts to block in the pollDesc will return errClosing(fd.isFile).
+	fd.pd.evict()
+	// The call to decref will call destroy if there are no other
+	// references.
+	return fd.decref()
+}
+
+// Shutdown wraps the shutdown network call.
+func (fd *FD) Shutdown(how int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Shutdown(fd.Sysfd, how)
+}
+
+// Darwin and FreeBSD can't read or write 2GB+ files at a time,
+// even on 64-bit systems.
+// The same is true of socket implementations on many systems.
+// See golang.org/issue/7812 and golang.org/issue/16266.
+// Use 1GB instead of, say, 2GB-1, to keep subsequent reads aligned.
+const maxRW = 1 << 30
+
+// Read implements io.Reader.
+func (fd *FD) Read(p []byte) (int, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+	if len(p) == 0 {
+		// If the caller wanted a zero byte read, return immediately
+		// without trying (but after acquiring the readLock).
+		// Otherwise syscall.Read returns 0, nil which looks like
+		// io.EOF.
+		// TODO(bradfitz): make it wait for readability? (Issue 15735)
+		return 0, nil
+	}
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, err
+	}
+	if fd.IsStream && len(p) > maxRW {
+		p = p[:maxRW]
+	}
+	for {
+		n, err := syscall.Read(fd.Sysfd, p)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN && fd.pd.pollable() {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		return n, err
+	}
+}
+
+// Pread wraps the pread system call.
+func (fd *FD) Pread(p []byte, off int64) (int, error) {
+	// Call incref, not readLock, because since pread specifies the
+	// offset it is independent from other reads.
+	// Similarly, using the poller doesn't make sense for pread.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	if fd.IsStream && len(p) > maxRW {
+		p = p[:maxRW]
+	}
+	n, err := syscall.Pread(fd.Sysfd, p, off)
+	if err != nil {
+		n = 0
+	}
+	fd.decref()
+	err = fd.eofError(n, err)
+	return n, err
+}
+
+// ReadFrom wraps the recvfrom network call.
+func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, nil, err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, nil, err
+	}
+	for {
+		n, sa, err := syscall.Recvfrom(fd.Sysfd, p, 0)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN && fd.pd.pollable() {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		return n, sa, err
+	}
+}
+
+// ReadMsg wraps the recvmsg network call.
+func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, 0, 0, nil, err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, 0, 0, nil, err
+	}
+	for {
+		n, oobn, flags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, 0)
+		if err != nil {
+			// TODO(dfc) should n and oobn be set to 0
+			if err == syscall.EAGAIN && fd.pd.pollable() {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		return n, oobn, flags, sa, err
+	}
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(p []byte) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+	var nn int
+	for {
+		max := len(p)
+		if fd.IsStream && max-nn > maxRW {
+			max = nn + maxRW
+		}
+		n, err := syscall.Write(fd.Sysfd, p[nn:max])
+		if n > 0 {
+			nn += n
+		}
+		if nn == len(p) {
+			return nn, err
+		}
+		if err == syscall.EAGAIN && fd.pd.pollable() {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		}
+		if err != nil {
+			return nn, err
+		}
+		if n == 0 {
+			return nn, io.ErrUnexpectedEOF
+		}
+	}
+}
+
+// Pwrite wraps the pwrite system call.
+func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
+	// Call incref, not writeLock, because since pwrite specifies the
+	// offset it is independent from other writes.
+	// Similarly, using the poller doesn't make sense for pwrite.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	var nn int
+	for {
+		max := len(p)
+		if fd.IsStream && max-nn > maxRW {
+			max = nn + maxRW
+		}
+		n, err := syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
+		if n > 0 {
+			nn += n
+		}
+		if nn == len(p) {
+			return nn, err
+		}
+		if err != nil {
+			return nn, err
+		}
+		if n == 0 {
+			return nn, io.ErrUnexpectedEOF
+		}
+	}
+}
+
+// WriteTo wraps the sendto network call.
+func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+	for {
+		err := syscall.Sendto(fd.Sysfd, p, 0, sa)
+		if err == syscall.EAGAIN && fd.pd.pollable() {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		}
+		if err != nil {
+			return 0, err
+		}
+		return len(p), nil
+	}
+}
+
+// WriteMsg wraps the sendmsg network call.
+func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, 0, err
+	}
+	for {
+		n, err := syscall.SendmsgN(fd.Sysfd, p, oob, sa, 0)
+		if err == syscall.EAGAIN && fd.pd.pollable() {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		}
+		if err != nil {
+			return n, 0, err
+		}
+		return n, len(oob), err
+	}
+}
+
+// Accept wraps the accept network call.
+func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
+	if err := fd.readLock(); err != nil {
+		return -1, nil, "", err
+	}
+	defer fd.readUnlock()
+
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return -1, nil, "", err
+	}
+	for {
+		s, rsa, errcall, err := accept(fd.Sysfd)
+		if err == nil {
+			return s, rsa, "", err
+		}
+		switch err {
+		case syscall.EAGAIN:
+			if fd.pd.pollable() {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		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 -1, nil, errcall, err
+	}
+}
+
+// Seek wraps syscall.Seek.
+func (fd *FD) Seek(offset int64, whence int) (int64, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// ReadDirent wraps syscall.ReadDirent.
+// We treat this like an ordinary system call rather than a call
+// that tries to fill the buffer.
+func (fd *FD) ReadDirent(buf []byte) (int, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	for {
+		n, err := syscall.ReadDirent(fd.Sysfd, buf)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN && fd.pd.pollable() {
+				if err = fd.pd.waitRead(fd.isFile); err == nil {
+					continue
+				}
+			}
+		}
+		// Do not call eofError; caller does not expect to see io.EOF.
+		return n, err
+	}
+}
+
+// Fchdir wraps syscall.Fchdir.
+func (fd *FD) Fchdir() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchdir(fd.Sysfd)
+}
+
+// Fstat wraps syscall.Fstat
+func (fd *FD) Fstat(s *syscall.Stat_t) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fstat(fd.Sysfd, s)
+}
+
+// On Unix variants only, expose the IO event for the net code.
+
+// WaitWrite waits until data can be read from fd.
+func (fd *FD) WaitWrite() error {
+	return fd.pd.waitWrite(fd.isFile)
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	f(uintptr(fd.Sysfd))
+	return nil
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	if err := fd.readLock(); err != nil {
+		return err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return err
+	}
+	for {
+		if f(uintptr(fd.Sysfd)) {
+			return nil
+		}
+		if err := fd.pd.waitRead(fd.isFile); err != nil {
+			return err
+		}
+	}
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	if err := fd.writeLock(); err != nil {
+		return err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return err
+	}
+	for {
+		if f(uintptr(fd.Sysfd)) {
+			return nil
+		}
+		if err := fd.pd.waitWrite(fd.isFile); err != nil {
+			return err
+		}
+	}
+}
diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go
new file mode 100644
index 0000000..9f40886
--- /dev/null
+++ b/src/internal/poll/fd_windows.go
@@ -0,0 +1,856 @@
+// Copyright 2017 The Go 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 poll
+
+import (
+	"errors"
+	"internal/race"
+	"io"
+	"runtime"
+	"sync"
+	"syscall"
+	"unicode/utf16"
+	"unicode/utf8"
+	"unsafe"
+)
+
+var (
+	initErr error
+	ioSync  uint64
+)
+
+// CancelIo Windows API cancels all outstanding IO for a particular
+// socket on current thread. To overcome that limitation, we run
+// special goroutine, locked to OS single thread, that both starts
+// and cancels IO. It means, there are 2 unavoidable thread switches
+// for every IO.
+// Some newer versions of Windows has new CancelIoEx API, that does
+// not have that limitation and can be used from any thread. This
+// package uses CancelIoEx API, if present, otherwise it fallback
+// to CancelIo.
+
+var (
+	canCancelIO                               bool // determines if CancelIoEx API is present
+	skipSyncNotif                             bool
+	hasLoadSetFileCompletionNotificationModes bool
+)
+
+func init() {
+	var d syscall.WSAData
+	e := syscall.WSAStartup(uint32(0x202), &d)
+	if e != nil {
+		initErr = e
+	}
+	canCancelIO = syscall.LoadCancelIoEx() == nil
+	hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
+	if hasLoadSetFileCompletionNotificationModes {
+		// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
+		// http://support.microsoft.com/kb/2568167
+		skipSyncNotif = true
+		protos := [2]int32{syscall.IPPROTO_TCP, 0}
+		var buf [32]syscall.WSAProtocolInfo
+		len := uint32(unsafe.Sizeof(buf))
+		n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
+		if err != nil {
+			skipSyncNotif = false
+		} else {
+			for i := int32(0); i < n; i++ {
+				if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
+					skipSyncNotif = false
+					break
+				}
+			}
+		}
+	}
+}
+
+// operation contains superset of data necessary to perform all async IO.
+type operation struct {
+	// Used by IOCP interface, it must be first field
+	// of the struct, as our code rely on it.
+	o syscall.Overlapped
+
+	// fields used by runtime.netpoll
+	runtimeCtx uintptr
+	mode       int32
+	errno      int32
+	qty        uint32
+
+	// fields used only by net package
+	fd     *FD
+	errc   chan error
+	buf    syscall.WSABuf
+	sa     syscall.Sockaddr
+	rsa    *syscall.RawSockaddrAny
+	rsan   int32
+	handle syscall.Handle
+	flags  uint32
+	bufs   []syscall.WSABuf
+}
+
+func (o *operation) InitBuf(buf []byte) {
+	o.buf.Len = uint32(len(buf))
+	o.buf.Buf = nil
+	if len(buf) != 0 {
+		o.buf.Buf = &buf[0]
+	}
+}
+
+func (o *operation) InitBufs(buf *[][]byte) {
+	if o.bufs == nil {
+		o.bufs = make([]syscall.WSABuf, 0, len(*buf))
+	} else {
+		o.bufs = o.bufs[:0]
+	}
+	for _, b := range *buf {
+		var p *byte
+		if len(b) > 0 {
+			p = &b[0]
+		}
+		o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
+	}
+}
+
+// ClearBufs clears all pointers to Buffers parameter captured
+// by InitBufs, so it can be released by garbage collector.
+func (o *operation) ClearBufs() {
+	for i := range o.bufs {
+		o.bufs[i].Buf = nil
+	}
+	o.bufs = o.bufs[:0]
+}
+
+// ioSrv executes net IO requests.
+type ioSrv struct {
+	req chan ioSrvReq
+}
+
+type ioSrvReq struct {
+	o      *operation
+	submit func(o *operation) error // if nil, cancel the operation
+}
+
+// ProcessRemoteIO will execute submit IO requests on behalf
+// of other goroutines, all on a single os thread, so it can
+// cancel them later. Results of all operations will be sent
+// back to their requesters via channel supplied in request.
+// It is used only when the CancelIoEx API is unavailable.
+func (s *ioSrv) ProcessRemoteIO() {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+	for r := range s.req {
+		if r.submit != nil {
+			r.o.errc <- r.submit(r.o)
+		} else {
+			r.o.errc <- syscall.CancelIo(r.o.fd.Sysfd)
+		}
+	}
+}
+
+// ExecIO executes a single IO operation o. It submits and cancels
+// IO in the current thread for systems where Windows CancelIoEx API
+// is available. Alternatively, it passes the request onto
+// runtime netpoll and waits for completion or cancels request.
+func (s *ioSrv) ExecIO(o *operation, submit func(o *operation) error) (int, error) {
+	if !canCancelIO {
+		onceStartServer.Do(startServer)
+	}
+
+	fd := o.fd
+	// Notify runtime netpoll about starting IO.
+	err := fd.pd.prepare(int(o.mode), fd.isFile)
+	if err != nil {
+		return 0, err
+	}
+	// Start IO.
+	if canCancelIO {
+		err = submit(o)
+	} else {
+		// Send request to a special dedicated thread,
+		// so it can stop the IO with CancelIO later.
+		s.req <- ioSrvReq{o, submit}
+		err = <-o.errc
+	}
+	switch err {
+	case nil:
+		// IO completed immediately
+		if o.fd.skipSyncNotif {
+			// No completion message will follow, so return immediately.
+			return int(o.qty), nil
+		}
+		// Need to get our completion message anyway.
+	case syscall.ERROR_IO_PENDING:
+		// IO started, and we have to wait for its completion.
+		err = nil
+	default:
+		return 0, err
+	}
+	// Wait for our request to complete.
+	err = fd.pd.wait(int(o.mode), fd.isFile)
+	if err == nil {
+		// All is good. Extract our IO results and return.
+		if o.errno != 0 {
+			err = syscall.Errno(o.errno)
+			return 0, err
+		}
+		return int(o.qty), nil
+	}
+	// IO is interrupted by "close" or "timeout"
+	netpollErr := err
+	switch netpollErr {
+	case ErrNetClosing, ErrFileClosing, ErrTimeout:
+		// will deal with those.
+	default:
+		panic("unexpected runtime.netpoll error: " + netpollErr.Error())
+	}
+	// Cancel our request.
+	if canCancelIO {
+		err := syscall.CancelIoEx(fd.Sysfd, &o.o)
+		// Assuming ERROR_NOT_FOUND is returned, if IO is completed.
+		if err != nil && err != syscall.ERROR_NOT_FOUND {
+			// TODO(brainman): maybe do something else, but panic.
+			panic(err)
+		}
+	} else {
+		s.req <- ioSrvReq{o, nil}
+		<-o.errc
+	}
+	// Wait for cancelation to complete.
+	fd.pd.waitCanceled(int(o.mode))
+	if o.errno != 0 {
+		err = syscall.Errno(o.errno)
+		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
+			err = netpollErr
+		}
+		return 0, err
+	}
+	// We issued a cancelation request. But, it seems, IO operation succeeded
+	// before the cancelation request run. We need to treat the IO operation as
+	// succeeded (the bytes are actually sent/recv from network).
+	return int(o.qty), nil
+}
+
+// Start helper goroutines.
+var rsrv, wsrv ioSrv
+var onceStartServer sync.Once
+
+func startServer() {
+	// This is called, once, when only the CancelIo API is available.
+	// Start two special goroutines, both locked to an OS thread,
+	// that start and cancel IO requests.
+	// One will process read requests, while the other will do writes.
+	rsrv.req = make(chan ioSrvReq)
+	go rsrv.ProcessRemoteIO()
+	wsrv.req = make(chan ioSrvReq)
+	go wsrv.ProcessRemoteIO()
+}
+
+// FD is a file descriptor. The net and os packages embed this type in
+// a larger type representing a network connection or OS file.
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	// System file descriptor. Immutable until Close.
+	Sysfd syscall.Handle
+
+	// Read operation.
+	rop operation
+	// Write operation.
+	wop operation
+
+	// I/O poller.
+	pd pollDesc
+
+	// Used to implement pread/pwrite.
+	l sync.Mutex
+
+	// For console I/O.
+	isConsole      bool
+	lastbits       []byte   // first few bytes of the last incomplete rune in last write
+	readuint16     []uint16 // buffer to hold uint16s obtained with ReadConsole
+	readbyte       []byte   // buffer to hold decoding of readuint16 from utf16 to utf8
+	readbyteOffset int      // readbyte[readOffset:] is yet to be consumed with file.Read
+
+	skipSyncNotif bool
+
+	// Whether this is a streaming descriptor, as opposed to a
+	// packet-based descriptor like a UDP socket.
+	IsStream bool
+
+	// Whether a zero byte read indicates EOF. This is false for a
+	// message based socket connection.
+	ZeroReadIsEOF bool
+
+	// Whether this is a normal file.
+	isFile bool
+
+	// Whether this is a directory.
+	isDir bool
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file" or "console" or "dir".
+func (fd *FD) Init(net string) (string, error) {
+	if initErr != nil {
+		return "", initErr
+	}
+
+	switch net {
+	case "file":
+		fd.isFile = true
+	case "console":
+		fd.isConsole = true
+	case "dir":
+		fd.isDir = true
+	case "tcp", "tcp4", "tcp6":
+	case "udp", "udp4", "udp6":
+	case "ip", "ip4", "ip6":
+	case "unix", "unixgram", "unixpacket":
+	default:
+		return "", errors.New("internal error: unknown network type " + net)
+	}
+
+	if err := fd.pd.init(fd); err != nil {
+		return "", err
+	}
+	if hasLoadSetFileCompletionNotificationModes {
+		// We do not use events, so we can skip them always.
+		flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
+		// It's not safe to skip completion notifications for UDP:
+		// http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
+		if skipSyncNotif && (net == "tcp" || net == "file") {
+			flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+		}
+		err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags)
+		if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 {
+			fd.skipSyncNotif = true
+		}
+	}
+	// Disable SIO_UDP_CONNRESET behavior.
+	// http://support.microsoft.com/kb/263823
+	switch net {
+	case "udp", "udp4", "udp6":
+		ret := uint32(0)
+		flag := uint32(0)
+		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 "wsaioctl", err
+		}
+	}
+	fd.rop.mode = 'r'
+	fd.wop.mode = 'w'
+	fd.rop.fd = fd
+	fd.wop.fd = fd
+	fd.rop.runtimeCtx = fd.pd.runtimeCtx
+	fd.wop.runtimeCtx = fd.pd.runtimeCtx
+	if !canCancelIO {
+		fd.rop.errc = make(chan error)
+		fd.wop.errc = make(chan error)
+	}
+	return "", nil
+}
+
+func (fd *FD) destroy() error {
+	if fd.Sysfd == syscall.InvalidHandle {
+		return syscall.EINVAL
+	}
+	// Poller may want to unregister fd in readiness notification mechanism,
+	// so this must be executed before fd.CloseFunc.
+	fd.pd.close()
+	var err error
+	if fd.isFile || fd.isConsole {
+		err = syscall.CloseHandle(fd.Sysfd)
+	} else if fd.isDir {
+		err = syscall.FindClose(fd.Sysfd)
+	} else {
+		// The net package uses the CloseFunc variable for testing.
+		err = CloseFunc(fd.Sysfd)
+	}
+	fd.Sysfd = syscall.InvalidHandle
+	return err
+}
+
+// Close closes the FD. The underlying file descriptor is closed by
+// the destroy method when there are no remaining references.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	// unblock pending reader and writer
+	fd.pd.evict()
+	return fd.decref()
+}
+
+// Shutdown wraps the shutdown network call.
+func (fd *FD) Shutdown(how int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Shutdown(fd.Sysfd, how)
+}
+
+// Read implements io.Reader.
+func (fd *FD) Read(buf []byte) (int, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+
+	var n int
+	var err error
+	if fd.isFile || fd.isDir || fd.isConsole {
+		fd.l.Lock()
+		defer fd.l.Unlock()
+		if fd.isConsole {
+			n, err = fd.readConsole(buf)
+		} else {
+			n, err = syscall.Read(fd.Sysfd, buf)
+		}
+		if err != nil {
+			n = 0
+		}
+	} else {
+		o := &fd.rop
+		o.InitBuf(buf)
+		n, err = rsrv.ExecIO(o, func(o *operation) error {
+			return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
+		})
+		if race.Enabled {
+			race.Acquire(unsafe.Pointer(&ioSync))
+		}
+	}
+	if len(buf) != 0 {
+		err = fd.eofError(n, err)
+	}
+	return n, err
+}
+
+var ReadConsole = syscall.ReadConsole // changed for testing
+
+// readConsole reads utf16 characters from console File,
+// encodes them into utf8 and stores them in buffer b.
+// It returns the number of utf8 bytes read and an error, if any.
+func (fd *FD) readConsole(b []byte) (int, error) {
+	if len(b) == 0 {
+		return 0, nil
+	}
+
+	if fd.readuint16 == nil {
+		// Note: syscall.ReadConsole fails for very large buffers.
+		// The limit is somewhere around (but not exactly) 16384.
+		// Stay well below.
+		fd.readuint16 = make([]uint16, 0, 10000)
+		fd.readbyte = make([]byte, 0, 4*cap(fd.readuint16))
+	}
+
+	for fd.readbyteOffset >= len(fd.readbyte) {
+		n := cap(fd.readuint16) - len(fd.readuint16)
+		if n > len(b) {
+			n = len(b)
+		}
+		var nw uint32
+		err := ReadConsole(fd.Sysfd, &fd.readuint16[:len(fd.readuint16)+1][len(fd.readuint16)], uint32(n), &nw, nil)
+		if err != nil {
+			return 0, err
+		}
+		uint16s := fd.readuint16[:len(fd.readuint16)+int(nw)]
+		fd.readuint16 = fd.readuint16[:0]
+		buf := fd.readbyte[:0]
+		for i := 0; i < len(uint16s); i++ {
+			r := rune(uint16s[i])
+			if utf16.IsSurrogate(r) {
+				if i+1 == len(uint16s) {
+					if nw > 0 {
+						// Save half surrogate pair for next time.
+						fd.readuint16 = fd.readuint16[:1]
+						fd.readuint16[0] = uint16(r)
+						break
+					}
+					r = utf8.RuneError
+				} else {
+					r = utf16.DecodeRune(r, rune(uint16s[i+1]))
+					if r != utf8.RuneError {
+						i++
+					}
+				}
+			}
+			n := utf8.EncodeRune(buf[len(buf):cap(buf)], r)
+			buf = buf[:len(buf)+n]
+		}
+		fd.readbyte = buf
+		fd.readbyteOffset = 0
+		if nw == 0 {
+			break
+		}
+	}
+
+	src := fd.readbyte[fd.readbyteOffset:]
+	var i int
+	for i = 0; i < len(src) && i < len(b); i++ {
+		x := src[i]
+		if x == 0x1A { // Ctrl-Z
+			if i == 0 {
+				fd.readbyteOffset++
+			}
+			break
+		}
+		b[i] = x
+	}
+	fd.readbyteOffset += i
+	return i, nil
+}
+
+// Pread emulates the Unix pread system call.
+func (fd *FD) Pread(b []byte, off int64) (int, error) {
+	// Call incref, not readLock, because since pread specifies the
+	// offset it is independent from other reads.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+
+	fd.l.Lock()
+	defer fd.l.Unlock()
+	curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
+	if e != nil {
+		return 0, e
+	}
+	defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
+	o := syscall.Overlapped{
+		OffsetHigh: uint32(off >> 32),
+		Offset:     uint32(off),
+	}
+	var done uint32
+	e = syscall.ReadFile(fd.Sysfd, b, &done, &o)
+	if e != nil {
+		done = 0
+		if e == syscall.ERROR_HANDLE_EOF {
+			e = io.EOF
+		}
+	}
+	if len(b) != 0 {
+		e = fd.eofError(int(done), e)
+	}
+	return int(done), e
+}
+
+// ReadFrom wraps the recvfrom network call.
+func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
+	if len(buf) == 0 {
+		return 0, nil, nil
+	}
+	if err := fd.readLock(); err != nil {
+		return 0, nil, err
+	}
+	defer fd.readUnlock()
+	o := &fd.rop
+	o.InitBuf(buf)
+	n, err := rsrv.ExecIO(o, func(o *operation) error {
+		if o.rsa == nil {
+			o.rsa = new(syscall.RawSockaddrAny)
+		}
+		o.rsan = int32(unsafe.Sizeof(*o.rsa))
+		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 n, nil, err
+	}
+	sa, _ := o.rsa.Sockaddr()
+	return n, sa, nil
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(buf []byte) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+
+	var n int
+	var err error
+	if fd.isFile || fd.isDir || fd.isConsole {
+		fd.l.Lock()
+		defer fd.l.Unlock()
+		if fd.isConsole {
+			n, err = fd.writeConsole(buf)
+		} else {
+			n, err = syscall.Write(fd.Sysfd, buf)
+		}
+		if err != nil {
+			n = 0
+		}
+	} else {
+		if race.Enabled {
+			race.ReleaseMerge(unsafe.Pointer(&ioSync))
+		}
+		o := &fd.wop
+		o.InitBuf(buf)
+		n, err = wsrv.ExecIO(o, func(o *operation) error {
+			return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
+		})
+	}
+	return n, err
+}
+
+// writeConsole writes len(b) bytes to the console File.
+// It returns the number of bytes written and an error, if any.
+func (fd *FD) writeConsole(b []byte) (int, error) {
+	n := len(b)
+	runes := make([]rune, 0, 256)
+	if len(fd.lastbits) > 0 {
+		b = append(fd.lastbits, b...)
+		fd.lastbits = nil
+
+	}
+	for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
+		r, l := utf8.DecodeRune(b)
+		runes = append(runes, r)
+		b = b[l:]
+	}
+	if len(b) > 0 {
+		fd.lastbits = make([]byte, len(b))
+		copy(fd.lastbits, b)
+	}
+	// syscall.WriteConsole seems to fail, if given large buffer.
+	// So limit the buffer to 16000 characters. This number was
+	// discovered by experimenting with syscall.WriteConsole.
+	const maxWrite = 16000
+	for len(runes) > 0 {
+		m := len(runes)
+		if m > maxWrite {
+			m = maxWrite
+		}
+		chunk := runes[:m]
+		runes = runes[m:]
+		uint16s := utf16.Encode(chunk)
+		for len(uint16s) > 0 {
+			var written uint32
+			err := syscall.WriteConsole(fd.Sysfd, &uint16s[0], uint32(len(uint16s)), &written, nil)
+			if err != nil {
+				return 0, err
+			}
+			uint16s = uint16s[written:]
+		}
+	}
+	return n, nil
+}
+
+// Pwrite emulates the Unix pwrite system call.
+func (fd *FD) Pwrite(b []byte, off int64) (int, error) {
+	// Call incref, not writeLock, because since pwrite specifies the
+	// offset it is independent from other writes.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+
+	fd.l.Lock()
+	defer fd.l.Unlock()
+	curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
+	if e != nil {
+		return 0, e
+	}
+	defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
+	o := syscall.Overlapped{
+		OffsetHigh: uint32(off >> 32),
+		Offset:     uint32(off),
+	}
+	var done uint32
+	e = syscall.WriteFile(fd.Sysfd, b, &done, &o)
+	if e != nil {
+		return 0, e
+	}
+	return int(done), nil
+}
+
+// Writev emulates the Unix writev system call.
+func (fd *FD) Writev(buf *[][]byte) (int64, error) {
+	if len(*buf) == 0 {
+		return 0, nil
+	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if race.Enabled {
+		race.ReleaseMerge(unsafe.Pointer(&ioSync))
+	}
+	o := &fd.wop
+	o.InitBufs(buf)
+	n, err := wsrv.ExecIO(o, func(o *operation) error {
+		return syscall.WSASend(o.fd.Sysfd, &o.bufs[0], uint32(len(o.bufs)), &o.qty, 0, &o.o, nil)
+	})
+	o.ClearBufs()
+	TestHookDidWritev(n)
+	consume(buf, int64(n))
+	return int64(n), err
+}
+
+// WriteTo wraps the sendto network call.
+func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
+	if len(buf) == 0 {
+		return 0, nil
+	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	o := &fd.wop
+	o.InitBuf(buf)
+	o.sa = sa
+	n, err := wsrv.ExecIO(o, func(o *operation) error {
+		return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
+	})
+	return n, err
+}
+
+// Call ConnectEx. This doesn't need any locking, since it is only
+// called when the descriptor is first created. This is here rather
+// than in the net package so that it can use fd.wop.
+func (fd *FD) ConnectEx(ra syscall.Sockaddr) error {
+	o := &fd.wop
+	o.sa = ra
+	_, err := wsrv.ExecIO(o, func(o *operation) error {
+		return ConnectExFunc(o.fd.Sysfd, o.sa, nil, 0, nil, &o.o)
+	})
+	return err
+}
+
+func (fd *FD) acceptOne(s syscall.Handle, rawsa []syscall.RawSockaddrAny, o *operation) (string, error) {
+	// Submit accept request.
+	o.handle = s
+	o.rsan = int32(unsafe.Sizeof(rawsa[0]))
+	_, err := rsrv.ExecIO(o, func(o *operation) error {
+		return AcceptFunc(o.fd.Sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
+	})
+	if err != nil {
+		CloseFunc(s)
+		return "acceptex", err
+	}
+
+	// Inherit properties of the listening socket.
+	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 {
+		CloseFunc(s)
+		return "setsockopt", err
+	}
+
+	return "", nil
+}
+
+// Accept handles accepting a socket. The sysSocket parameter is used
+// to allocate the net socket.
+func (fd *FD) Accept(sysSocket func() (syscall.Handle, error)) (syscall.Handle, []syscall.RawSockaddrAny, uint32, string, error) {
+	if err := fd.readLock(); err != nil {
+		return syscall.InvalidHandle, nil, 0, "", err
+	}
+	defer fd.readUnlock()
+
+	o := &fd.rop
+	var rawsa [2]syscall.RawSockaddrAny
+	for {
+		s, err := sysSocket()
+		if err != nil {
+			return syscall.InvalidHandle, nil, 0, "", err
+		}
+
+		errcall, err := fd.acceptOne(s, rawsa[:], o)
+		if err == nil {
+			return s, rawsa[:], uint32(o.rsan), "", nil
+		}
+
+		// Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is
+		// returned here. These happen if connection reset is received
+		// before AcceptEx could complete. These errors relate to new
+		// connection, not to AcceptEx, so ignore broken connection and
+		// try AcceptEx again for more connections.
+		errno, ok := err.(syscall.Errno)
+		if !ok {
+			return syscall.InvalidHandle, nil, 0, errcall, err
+		}
+		switch errno {
+		case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET:
+			// ignore these and try again
+		default:
+			return syscall.InvalidHandle, nil, 0, errcall, err
+		}
+	}
+}
+
+// Seek wraps syscall.Seek.
+func (fd *FD) Seek(offset int64, whence int) (int64, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+
+	fd.l.Lock()
+	defer fd.l.Unlock()
+
+	return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// FindNextFile wraps syscall.FindNextFile.
+func (fd *FD) FindNextFile(data *syscall.Win32finddata) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.FindNextFile(fd.Sysfd, data)
+}
+
+// Fchdir wraps syscall.Fchdir.
+func (fd *FD) Fchdir() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fchdir(fd.Sysfd)
+}
+
+// GetFileType wraps syscall.GetFileType.
+func (fd *FD) GetFileType() (uint32, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	return syscall.GetFileType(fd.Sysfd)
+}
+
+// GetFileInformationByHandle wraps GetFileInformationByHandle.
+func (fd *FD) GetFileInformationByHandle(data *syscall.ByHandleFileInformation) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.GetFileInformationByHandle(fd.Sysfd, data)
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	f(uintptr(fd.Sysfd))
+	return nil
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	return errors.New("not implemented")
+}
diff --git a/src/internal/poll/hook_cloexec.go b/src/internal/poll/hook_cloexec.go
new file mode 100644
index 0000000..73df6ed
--- /dev/null
+++ b/src/internal/poll/hook_cloexec.go
@@ -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.
+
+// +build dragonfly freebsd linux
+
+package poll
+
+import "syscall"
+
+// Accept4Func is used to hook the accept4 call.
+var Accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
diff --git a/src/internal/poll/hook_unix.go b/src/internal/poll/hook_unix.go
new file mode 100644
index 0000000..85e102d
--- /dev/null
+++ b/src/internal/poll/hook_unix.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package poll
+
+import "syscall"
+
+// CloseFunc is used to hook the close call.
+var CloseFunc func(int) error = syscall.Close
+
+// AcceptFunc is used to hook the accept call.
+var AcceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept
diff --git a/src/internal/poll/hook_windows.go b/src/internal/poll/hook_windows.go
new file mode 100644
index 0000000..0bd950e
--- /dev/null
+++ b/src/internal/poll/hook_windows.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go 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 poll
+
+import "syscall"
+
+// CloseFunc is used to hook the close call.
+var CloseFunc func(syscall.Handle) error = syscall.Closesocket
+
+// AcceptFunc is used to hook the accept call.
+var AcceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
+
+// ConnectExFunc is used to hook the ConnectEx call.
+var ConnectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go
new file mode 100644
index 0000000..980a75a
--- /dev/null
+++ b/src/internal/poll/sendfile_bsd.go
@@ -0,0 +1,53 @@
+// 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 dragonfly freebsd
+
+package poll
+
+import "syscall"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// SendFile wraps the sendfile system call.
+func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
+	if err := dstFD.writeLock(); err != nil {
+		return 0, err
+	}
+	defer dstFD.writeUnlock()
+	dst := int(dstFD.Sysfd)
+	var written int64
+	var err error
+	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 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
+				continue
+			}
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	return written, err
+}
diff --git a/src/internal/poll/sendfile_linux.go b/src/internal/poll/sendfile_linux.go
new file mode 100644
index 0000000..52955a1
--- /dev/null
+++ b/src/internal/poll/sendfile_linux.go
@@ -0,0 +1,50 @@
+// 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 poll
+
+import "syscall"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// SendFile wraps the sendfile system call.
+func SendFile(dstFD *FD, src int, remain int64) (int64, error) {
+	if err := dstFD.writeLock(); err != nil {
+		return 0, err
+	}
+	defer dstFD.writeUnlock()
+
+	dst := int(dstFD.Sysfd)
+	var written int64
+	var err error
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		n, err1 := syscall.Sendfile(dst, src, nil, n)
+		if n > 0 {
+			written += int64(n)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
+				continue
+			}
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	return written, err
+}
diff --git a/src/internal/poll/sendfile_solaris.go b/src/internal/poll/sendfile_solaris.go
new file mode 100644
index 0000000..9093d46
--- /dev/null
+++ b/src/internal/poll/sendfile_solaris.go
@@ -0,0 +1,63 @@
+// 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 poll
+
+import "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 wraps the sendfile system call.
+func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
+	if err := dstFD.writeLock(); err != nil {
+		return 0, err
+	}
+	defer dstFD.writeUnlock()
+
+	dst := int(dstFD.Sysfd)
+	var written int64
+	var err error
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		pos1 := pos
+		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
+		if err1 == syscall.EAGAIN || err1 == syscall.EINTR {
+			// partial write may have occurred
+			n = int(pos1 - pos)
+		}
+		if n > 0 {
+			pos += int64(n)
+			written += int64(n)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = dstFD.pd.waitWrite(dstFD.isFile); 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
+		}
+	}
+	return written, err
+}
diff --git a/src/internal/poll/sendfile_windows.go b/src/internal/poll/sendfile_windows.go
new file mode 100644
index 0000000..c1a2d6d
--- /dev/null
+++ b/src/internal/poll/sendfile_windows.go
@@ -0,0 +1,23 @@
+// 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 poll
+
+import "syscall"
+
+// SendFile wraps the TransmitFile call.
+func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+
+	o := &fd.wop
+	o.qty = uint32(n)
+	o.handle = src
+	done, err := wsrv.ExecIO(o, func(o *operation) error {
+		return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+	})
+	return int64(done), err
+}
diff --git a/src/internal/poll/sock_cloexec.go b/src/internal/poll/sock_cloexec.go
new file mode 100644
index 0000000..0d5c8bd
--- /dev/null
+++ b/src/internal/poll/sock_cloexec.go
@@ -0,0 +1,50 @@
+// 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 sysSocket and accept for platforms that
+// provide a fast path for setting SetNonblock and CloseOnExec.
+
+// +build dragonfly freebsd linux
+
+package poll
+
+import "syscall"
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(s int) (int, syscall.Sockaddr, string, error) {
+	ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+	// On Linux the accept4 system call was introduced in 2.6.28
+	// kernel and on FreeBSD it was introduced in 10 kernel. If we
+	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
+	// error on Linux, fall back to using accept.
+	switch err {
+	case nil:
+		return ns, sa, "", nil
+	default: // errors other than the ones listed
+		return -1, sa, "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
+	case syscall.EFAULT: // some Linux use this instead of ENOSYS
+	}
+
+	// See ../syscall/exec_unix.go for description of ForkLock.
+	// It is probably okay to hold the lock across syscall.Accept
+	// because we have put fd.sysfd into non-blocking mode.
+	// However, a call to the File method will put it back into
+	// blocking mode. We can't take that risk, so no use of ForkLock here.
+	ns, sa, err = AcceptFunc(s)
+	if err == nil {
+		syscall.CloseOnExec(ns)
+	}
+	if err != nil {
+		return -1, nil, "accept", err
+	}
+	if err = syscall.SetNonblock(ns, true); err != nil {
+		CloseFunc(ns)
+		return -1, nil, "setnonblock", err
+	}
+	return ns, sa, "", nil
+}
diff --git a/src/internal/poll/sockopt.go b/src/internal/poll/sockopt.go
new file mode 100644
index 0000000..f86ce70
--- /dev/null
+++ b/src/internal/poll/sockopt.go
@@ -0,0 +1,36 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+
+package poll
+
+import "syscall"
+
+// SetsockoptInt wraps the setsockopt network call with an int argument.
+func (fd *FD) SetsockoptInt(level, name, arg int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptInt(fd.Sysfd, level, name, arg)
+}
+
+// SetsockoptInet4Addr wraps the setsockopt network call with an IPv4 address.
+func (fd *FD) SetsockoptInet4Addr(level, name int, arg [4]byte) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptInet4Addr(fd.Sysfd, level, name, arg)
+}
+
+// SetsockoptLinger wraps the setsockopt network call with a Linger argument.
+func (fd *FD) SetsockoptLinger(level, name int, l *syscall.Linger) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptLinger(fd.Sysfd, level, name, l)
+}
diff --git a/src/internal/poll/sockopt_linux.go b/src/internal/poll/sockopt_linux.go
new file mode 100644
index 0000000..bc79c35
--- /dev/null
+++ b/src/internal/poll/sockopt_linux.go
@@ -0,0 +1,16 @@
+// 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 poll
+
+import "syscall"
+
+// SetsockoptIPMreqn wraps the setsockopt network call with an IPMreqn argument.
+func (fd *FD) SetsockoptIPMreqn(level, name int, mreq *syscall.IPMreqn) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptIPMreqn(fd.Sysfd, level, name, mreq)
+}
diff --git a/src/internal/poll/sockopt_unix.go b/src/internal/poll/sockopt_unix.go
new file mode 100644
index 0000000..b33644d
--- /dev/null
+++ b/src/internal/poll/sockopt_unix.go
@@ -0,0 +1,18 @@
+// Copyright 2017 The Go 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 poll
+
+import "syscall"
+
+// SetsockoptByte wraps the setsockopt network call with a byte argument.
+func (fd *FD) SetsockoptByte(level, name int, arg byte) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptByte(fd.Sysfd, level, name, arg)
+}
diff --git a/src/internal/poll/sockopt_windows.go b/src/internal/poll/sockopt_windows.go
new file mode 100644
index 0000000..dd5fb70
--- /dev/null
+++ b/src/internal/poll/sockopt_windows.go
@@ -0,0 +1,25 @@
+// 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 poll
+
+import "syscall"
+
+// Setsockopt wraps the setsockopt network call.
+func (fd *FD) Setsockopt(level, optname int32, optval *byte, optlen int32) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Setsockopt(fd.Sysfd, level, optname, optval, optlen)
+}
+
+// WSAIoctl wraps the WSAIoctl network call.
+func (fd *FD) WSAIoctl(iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *syscall.Overlapped, completionRoutine uintptr) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.WSAIoctl(fd.Sysfd, iocc, inbuf, cbif, outbuf, cbob, cbbr, overlapped, completionRoutine)
+}
diff --git a/src/internal/poll/sockoptip.go b/src/internal/poll/sockoptip.go
new file mode 100644
index 0000000..5d5dff6
--- /dev/null
+++ b/src/internal/poll/sockoptip.go
@@ -0,0 +1,27 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd windows
+
+package poll
+
+import "syscall"
+
+// SetsockoptIPMreq wraps the setsockopt network call with an IPMreq argument.
+func (fd *FD) SetsockoptIPMreq(level, name int, mreq *syscall.IPMreq) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptIPMreq(fd.Sysfd, level, name, mreq)
+}
+
+// SetsockoptIPv6Mreq wraps the setsockopt network call with an IPv6Mreq argument.
+func (fd *FD) SetsockoptIPv6Mreq(level, name int, mreq *syscall.IPv6Mreq) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.SetsockoptIPv6Mreq(fd.Sysfd, level, name, mreq)
+}
diff --git a/src/internal/poll/strconv.go b/src/internal/poll/strconv.go
new file mode 100644
index 0000000..21cb40d
--- /dev/null
+++ b/src/internal/poll/strconv.go
@@ -0,0 +1,41 @@
+// 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 plan9
+
+// Simple conversions to avoid depending on strconv.
+
+package poll
+
+// Convert integer to decimal string
+func itoa(val int) string {
+	if val < 0 {
+		return "-" + uitoa(uint(-val))
+	}
+	return uitoa(uint(val))
+}
+
+// Convert unsigned integer to decimal string
+func uitoa(val uint) string {
+	if val == 0 { // avoid string allocation
+		return "0"
+	}
+	var buf [20]byte // big enough for 64bit value base 10
+	i := len(buf) - 1
+	for val >= 10 {
+		q := val / 10
+		buf[i] = byte('0' + val - q*10)
+		i--
+		val = q
+	}
+	// val < 10
+	buf[i] = byte('0' + val)
+	return string(buf[i:])
+}
+
+// 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
+}
diff --git a/src/internal/poll/sys_cloexec.go b/src/internal/poll/sys_cloexec.go
new file mode 100644
index 0000000..9ed35bd
--- /dev/null
+++ b/src/internal/poll/sys_cloexec.go
@@ -0,0 +1,36 @@
+// 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 sysSocket and accept for platforms that do not
+// provide a fast path for setting SetNonblock and CloseOnExec.
+
+// +build darwin nacl netbsd openbsd solaris
+
+package poll
+
+import (
+	"syscall"
+)
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(s int) (int, syscall.Sockaddr, string, error) {
+	// See ../syscall/exec_unix.go for description of ForkLock.
+	// It is probably okay to hold the lock across syscall.Accept
+	// because we have put fd.sysfd into non-blocking mode.
+	// However, a call to the File method will put it back into
+	// blocking mode. We can't take that risk, so no use of ForkLock here.
+	ns, sa, err := AcceptFunc(s)
+	if err == nil {
+		syscall.CloseOnExec(ns)
+	}
+	if err != nil {
+		return -1, nil, "accept", err
+	}
+	if err = syscall.SetNonblock(ns, true); err != nil {
+		CloseFunc(ns)
+		return -1, nil, "setnonblock", err
+	}
+	return ns, sa, "", nil
+}
diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go
new file mode 100644
index 0000000..4bf8804
--- /dev/null
+++ b/src/internal/poll/writev.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go 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
+
+package poll
+
+import (
+	"io"
+	"syscall"
+	"unsafe"
+)
+
+// Writev wraps the writev system call.
+func (fd *FD) Writev(v *[][]byte) (int64, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+
+	var iovecs []syscall.Iovec
+	if fd.iovecs != nil {
+		iovecs = *fd.iovecs
+	}
+	// TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is
+	// 1024 and this seems conservative enough for now. Darwin's
+	// UIO_MAXIOV also seems to be 1024.
+	maxVec := 1024
+
+	var n int64
+	var err error
+	for len(*v) > 0 {
+		iovecs = iovecs[:0]
+		for _, chunk := range *v {
+			if len(chunk) == 0 {
+				continue
+			}
+			iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
+			if fd.IsStream && len(chunk) > 1<<30 {
+				iovecs[len(iovecs)-1].SetLen(1 << 30)
+				break // continue chunk on next writev
+			}
+			iovecs[len(iovecs)-1].SetLen(len(chunk))
+			if len(iovecs) == maxVec {
+				break
+			}
+		}
+		if len(iovecs) == 0 {
+			break
+		}
+		fd.iovecs = &iovecs // cache
+
+		wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
+			uintptr(fd.Sysfd),
+			uintptr(unsafe.Pointer(&iovecs[0])),
+			uintptr(len(iovecs)))
+		if wrote == ^uintptr(0) {
+			wrote = 0
+		}
+		TestHookDidWritev(int(wrote))
+		n += int64(wrote)
+		consume(v, int64(wrote))
+		if e0 == syscall.EAGAIN {
+			if err = fd.pd.waitWrite(fd.isFile); err == nil {
+				continue
+			}
+		} else if e0 != 0 {
+			err = syscall.Errno(e0)
+		}
+		if err != nil {
+			break
+		}
+		if n == 0 {
+			err = io.ErrUnexpectedEOF
+			break
+		}
+	}
+	return n, err
+}
diff --git a/src/internal/poll/writev_test.go b/src/internal/poll/writev_test.go
new file mode 100644
index 0000000..b46657c
--- /dev/null
+++ b/src/internal/poll/writev_test.go
@@ -0,0 +1,62 @@
+// Copyright 2016 The Go 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 poll_test
+
+import (
+	"internal/poll"
+	"reflect"
+	"testing"
+)
+
+func TestConsume(t *testing.T) {
+	tests := []struct {
+		in      [][]byte
+		consume int64
+		want    [][]byte
+	}{
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 0,
+			want:    [][]byte{[]byte("foo"), []byte("bar")},
+		},
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 2,
+			want:    [][]byte{[]byte("o"), []byte("bar")},
+		},
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 3,
+			want:    [][]byte{[]byte("bar")},
+		},
+		{
+			in:      [][]byte{[]byte("foo"), []byte("bar")},
+			consume: 4,
+			want:    [][]byte{[]byte("ar")},
+		},
+		{
+			in:      [][]byte{nil, nil, nil, []byte("bar")},
+			consume: 1,
+			want:    [][]byte{[]byte("ar")},
+		},
+		{
+			in:      [][]byte{nil, nil, nil, []byte("foo")},
+			consume: 0,
+			want:    [][]byte{[]byte("foo")},
+		},
+		{
+			in:      [][]byte{nil, nil, nil},
+			consume: 0,
+			want:    [][]byte{},
+		},
+	}
+	for i, tt := range tests {
+		in := tt.in
+		poll.Consume(&in, tt.consume)
+		if !reflect.DeepEqual(in, tt.want) {
+			t.Errorf("%d. after consume(%d) = %+v, want %+v", i, tt.consume, in, tt.want)
+		}
+	}
+}
diff --git a/src/internal/pprof/profile/encode.go b/src/internal/pprof/profile/encode.go
deleted file mode 100644
index 6b879a8..0000000
--- a/src/internal/pprof/profile/encode.go
+++ /dev/null
@@ -1,470 +0,0 @@
-// 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 profile
-
-import (
-	"errors"
-	"fmt"
-	"sort"
-)
-
-func (p *Profile) decoder() []decoder {
-	return profileDecoder
-}
-
-// preEncode populates the unexported fields to be used by encode
-// (with suffix X) from the corresponding exported fields. The
-// exported fields are cleared up to facilitate testing.
-func (p *Profile) preEncode() {
-	strings := make(map[string]int)
-	addString(strings, "")
-
-	for _, st := range p.SampleType {
-		st.typeX = addString(strings, st.Type)
-		st.unitX = addString(strings, st.Unit)
-	}
-
-	for _, s := range p.Sample {
-		s.labelX = nil
-		var keys []string
-		for k := range s.Label {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
-		for _, k := range keys {
-			vs := s.Label[k]
-			for _, v := range vs {
-				s.labelX = append(s.labelX,
-					Label{
-						keyX: addString(strings, k),
-						strX: addString(strings, v),
-					},
-				)
-			}
-		}
-		var numKeys []string
-		for k := range s.NumLabel {
-			numKeys = append(numKeys, k)
-		}
-		sort.Strings(numKeys)
-		for _, k := range numKeys {
-			vs := s.NumLabel[k]
-			for _, v := range vs {
-				s.labelX = append(s.labelX,
-					Label{
-						keyX: addString(strings, k),
-						numX: v,
-					},
-				)
-			}
-		}
-		s.locationIDX = nil
-		for _, l := range s.Location {
-			s.locationIDX = append(s.locationIDX, l.ID)
-		}
-	}
-
-	for _, m := range p.Mapping {
-		m.fileX = addString(strings, m.File)
-		m.buildIDX = addString(strings, m.BuildID)
-	}
-
-	for _, l := range p.Location {
-		for i, ln := range l.Line {
-			if ln.Function != nil {
-				l.Line[i].functionIDX = ln.Function.ID
-			} else {
-				l.Line[i].functionIDX = 0
-			}
-		}
-		if l.Mapping != nil {
-			l.mappingIDX = l.Mapping.ID
-		} else {
-			l.mappingIDX = 0
-		}
-	}
-	for _, f := range p.Function {
-		f.nameX = addString(strings, f.Name)
-		f.systemNameX = addString(strings, f.SystemName)
-		f.filenameX = addString(strings, f.Filename)
-	}
-
-	p.dropFramesX = addString(strings, p.DropFrames)
-	p.keepFramesX = addString(strings, p.KeepFrames)
-
-	if pt := p.PeriodType; pt != nil {
-		pt.typeX = addString(strings, pt.Type)
-		pt.unitX = addString(strings, pt.Unit)
-	}
-
-	p.stringTable = make([]string, len(strings))
-	for s, i := range strings {
-		p.stringTable[i] = s
-	}
-}
-
-func (p *Profile) encode(b *buffer) {
-	for _, x := range p.SampleType {
-		encodeMessage(b, 1, x)
-	}
-	for _, x := range p.Sample {
-		encodeMessage(b, 2, x)
-	}
-	for _, x := range p.Mapping {
-		encodeMessage(b, 3, x)
-	}
-	for _, x := range p.Location {
-		encodeMessage(b, 4, x)
-	}
-	for _, x := range p.Function {
-		encodeMessage(b, 5, x)
-	}
-	encodeStrings(b, 6, p.stringTable)
-	encodeInt64Opt(b, 7, p.dropFramesX)
-	encodeInt64Opt(b, 8, p.keepFramesX)
-	encodeInt64Opt(b, 9, p.TimeNanos)
-	encodeInt64Opt(b, 10, p.DurationNanos)
-	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
-		encodeMessage(b, 11, p.PeriodType)
-	}
-	encodeInt64Opt(b, 12, p.Period)
-}
-
-var profileDecoder = []decoder{
-	nil, // 0
-	// repeated ValueType sample_type = 1
-	func(b *buffer, m message) error {
-		x := new(ValueType)
-		pp := m.(*Profile)
-		pp.SampleType = append(pp.SampleType, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Sample sample = 2
-	func(b *buffer, m message) error {
-		x := new(Sample)
-		pp := m.(*Profile)
-		pp.Sample = append(pp.Sample, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Mapping mapping = 3
-	func(b *buffer, m message) error {
-		x := new(Mapping)
-		pp := m.(*Profile)
-		pp.Mapping = append(pp.Mapping, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Location location = 4
-	func(b *buffer, m message) error {
-		x := new(Location)
-		pp := m.(*Profile)
-		pp.Location = append(pp.Location, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Function function = 5
-	func(b *buffer, m message) error {
-		x := new(Function)
-		pp := m.(*Profile)
-		pp.Function = append(pp.Function, x)
-		return decodeMessage(b, x)
-	},
-	// repeated string string_table = 6
-	func(b *buffer, m message) error {
-		err := decodeStrings(b, &m.(*Profile).stringTable)
-		if err != nil {
-			return err
-		}
-		if *&m.(*Profile).stringTable[0] != "" {
-			return errors.New("string_table[0] must be ''")
-		}
-		return nil
-	},
-	// repeated int64 drop_frames = 7
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
-	// repeated int64 keep_frames = 8
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
-	// repeated int64 time_nanos = 9
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
-	// repeated int64 duration_nanos = 10
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
-	// optional string period_type = 11
-	func(b *buffer, m message) error {
-		x := new(ValueType)
-		pp := m.(*Profile)
-		pp.PeriodType = x
-		return decodeMessage(b, x)
-	},
-	// repeated int64 period = 12
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
-}
-
-// postDecode takes the unexported fields populated by decode (with
-// suffix X) and populates the corresponding exported fields.
-// The unexported fields are cleared up to facilitate testing.
-func (p *Profile) postDecode() error {
-	var err error
-
-	mappings := make(map[uint64]*Mapping)
-	for _, m := range p.Mapping {
-		m.File, err = getString(p.stringTable, &m.fileX, err)
-		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
-		mappings[m.ID] = m
-	}
-
-	functions := make(map[uint64]*Function)
-	for _, f := range p.Function {
-		f.Name, err = getString(p.stringTable, &f.nameX, err)
-		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
-		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
-		functions[f.ID] = f
-	}
-
-	locations := make(map[uint64]*Location)
-	for _, l := range p.Location {
-		l.Mapping = mappings[l.mappingIDX]
-		l.mappingIDX = 0
-		for i, ln := range l.Line {
-			if id := ln.functionIDX; id != 0 {
-				l.Line[i].Function = functions[id]
-				if l.Line[i].Function == nil {
-					return fmt.Errorf("Function ID %d not found", id)
-				}
-				l.Line[i].functionIDX = 0
-			}
-		}
-		locations[l.ID] = l
-	}
-
-	for _, st := range p.SampleType {
-		st.Type, err = getString(p.stringTable, &st.typeX, err)
-		st.Unit, err = getString(p.stringTable, &st.unitX, err)
-	}
-
-	for _, s := range p.Sample {
-		labels := make(map[string][]string)
-		numLabels := make(map[string][]int64)
-		for _, l := range s.labelX {
-			var key, value string
-			key, err = getString(p.stringTable, &l.keyX, err)
-			if l.strX != 0 {
-				value, err = getString(p.stringTable, &l.strX, err)
-				labels[key] = append(labels[key], value)
-			} else {
-				numLabels[key] = append(numLabels[key], l.numX)
-			}
-		}
-		if len(labels) > 0 {
-			s.Label = labels
-		}
-		if len(numLabels) > 0 {
-			s.NumLabel = numLabels
-		}
-		s.Location = nil
-		for _, lid := range s.locationIDX {
-			s.Location = append(s.Location, locations[lid])
-		}
-		s.locationIDX = nil
-	}
-
-	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
-	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
-
-	if pt := p.PeriodType; pt == nil {
-		p.PeriodType = &ValueType{}
-	}
-
-	if pt := p.PeriodType; pt != nil {
-		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
-		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
-	}
-	p.stringTable = nil
-	return nil
-}
-
-func (p *ValueType) decoder() []decoder {
-	return valueTypeDecoder
-}
-
-func (p *ValueType) encode(b *buffer) {
-	encodeInt64Opt(b, 1, p.typeX)
-	encodeInt64Opt(b, 2, p.unitX)
-}
-
-var valueTypeDecoder = []decoder{
-	nil, // 0
-	// optional int64 type = 1
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
-	// optional int64 unit = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
-}
-
-func (p *Sample) decoder() []decoder {
-	return sampleDecoder
-}
-
-func (p *Sample) encode(b *buffer) {
-	encodeUint64s(b, 1, p.locationIDX)
-	for _, x := range p.Value {
-		encodeInt64(b, 2, x)
-	}
-	for _, x := range p.labelX {
-		encodeMessage(b, 3, x)
-	}
-}
-
-var sampleDecoder = []decoder{
-	nil, // 0
-	// repeated uint64 location = 1
-	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
-	// repeated int64 value = 2
-	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
-	// repeated Label label = 3
-	func(b *buffer, m message) error {
-		s := m.(*Sample)
-		n := len(s.labelX)
-		s.labelX = append(s.labelX, Label{})
-		return decodeMessage(b, &s.labelX[n])
-	},
-}
-
-func (p Label) decoder() []decoder {
-	return labelDecoder
-}
-
-func (p Label) encode(b *buffer) {
-	encodeInt64Opt(b, 1, p.keyX)
-	encodeInt64Opt(b, 2, p.strX)
-	encodeInt64Opt(b, 3, p.numX)
-}
-
-var labelDecoder = []decoder{
-	nil, // 0
-	// optional int64 key = 1
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
-	// optional int64 str = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
-	// optional int64 num = 3
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
-}
-
-func (p *Mapping) decoder() []decoder {
-	return mappingDecoder
-}
-
-func (p *Mapping) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.ID)
-	encodeUint64Opt(b, 2, p.Start)
-	encodeUint64Opt(b, 3, p.Limit)
-	encodeUint64Opt(b, 4, p.Offset)
-	encodeInt64Opt(b, 5, p.fileX)
-	encodeInt64Opt(b, 6, p.buildIDX)
-	encodeBoolOpt(b, 7, p.HasFunctions)
-	encodeBoolOpt(b, 8, p.HasFilenames)
-	encodeBoolOpt(b, 9, p.HasLineNumbers)
-	encodeBoolOpt(b, 10, p.HasInlineFrames)
-}
-
-var mappingDecoder = []decoder{
-	nil, // 0
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
-}
-
-func (p *Location) decoder() []decoder {
-	return locationDecoder
-}
-
-func (p *Location) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.ID)
-	encodeUint64Opt(b, 2, p.mappingIDX)
-	encodeUint64Opt(b, 3, p.Address)
-	for i := range p.Line {
-		encodeMessage(b, 4, &p.Line[i])
-	}
-}
-
-var locationDecoder = []decoder{
-	nil, // 0
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
-	func(b *buffer, m message) error { // repeated Line line = 4
-		pp := m.(*Location)
-		n := len(pp.Line)
-		pp.Line = append(pp.Line, Line{})
-		return decodeMessage(b, &pp.Line[n])
-	},
-}
-
-func (p *Line) decoder() []decoder {
-	return lineDecoder
-}
-
-func (p *Line) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.functionIDX)
-	encodeInt64Opt(b, 2, p.Line)
-}
-
-var lineDecoder = []decoder{
-	nil, // 0
-	// optional uint64 function_id = 1
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
-	// optional int64 line = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
-}
-
-func (p *Function) decoder() []decoder {
-	return functionDecoder
-}
-
-func (p *Function) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.ID)
-	encodeInt64Opt(b, 2, p.nameX)
-	encodeInt64Opt(b, 3, p.systemNameX)
-	encodeInt64Opt(b, 4, p.filenameX)
-	encodeInt64Opt(b, 5, p.StartLine)
-}
-
-var functionDecoder = []decoder{
-	nil, // 0
-	// optional uint64 id = 1
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
-	// optional int64 function_name = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
-	// optional int64 function_system_name = 3
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
-	// repeated int64 filename = 4
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
-	// optional int64 start_line = 5
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
-}
-
-func addString(strings map[string]int, s string) int64 {
-	i, ok := strings[s]
-	if !ok {
-		i = len(strings)
-		strings[s] = i
-	}
-	return int64(i)
-}
-
-func getString(strings []string, strng *int64, err error) (string, error) {
-	if err != nil {
-		return "", err
-	}
-	s := int(*strng)
-	if s < 0 || s >= len(strings) {
-		return "", errMalformed
-	}
-	*strng = 0
-	return strings[s], nil
-}
diff --git a/src/internal/pprof/profile/filter.go b/src/internal/pprof/profile/filter.go
deleted file mode 100644
index 1baa096..0000000
--- a/src/internal/pprof/profile/filter.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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.
-
-// Implements methods to filter samples from profiles.
-
-package profile
-
-import "regexp"
-
-// FilterSamplesByName filters the samples in a profile and only keeps
-// samples where at least one frame matches focus but none match ignore.
-// Returns true is the corresponding regexp matched at least one sample.
-func (p *Profile) FilterSamplesByName(focus, ignore, hide *regexp.Regexp) (fm, im, hm bool) {
-	focusOrIgnore := make(map[uint64]bool)
-	hidden := make(map[uint64]bool)
-	for _, l := range p.Location {
-		if ignore != nil && l.matchesName(ignore) {
-			im = true
-			focusOrIgnore[l.ID] = false
-		} else if focus == nil || l.matchesName(focus) {
-			fm = true
-			focusOrIgnore[l.ID] = true
-		}
-		if hide != nil && l.matchesName(hide) {
-			hm = true
-			l.Line = l.unmatchedLines(hide)
-			if len(l.Line) == 0 {
-				hidden[l.ID] = true
-			}
-		}
-	}
-
-	s := make([]*Sample, 0, len(p.Sample))
-	for _, sample := range p.Sample {
-		if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
-			if len(hidden) > 0 {
-				var locs []*Location
-				for _, loc := range sample.Location {
-					if !hidden[loc.ID] {
-						locs = append(locs, loc)
-					}
-				}
-				if len(locs) == 0 {
-					// Remove sample with no locations (by not adding it to s).
-					continue
-				}
-				sample.Location = locs
-			}
-			s = append(s, sample)
-		}
-	}
-	p.Sample = s
-
-	return
-}
-
-// matchesName returns whether the function name or file in the
-// location matches the regular expression.
-func (loc *Location) matchesName(re *regexp.Regexp) bool {
-	for _, ln := range loc.Line {
-		if fn := ln.Function; fn != nil {
-			if re.MatchString(fn.Name) {
-				return true
-			}
-			if re.MatchString(fn.Filename) {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-// unmatchedLines returns the lines in the location that do not match
-// the regular expression.
-func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
-	var lines []Line
-	for _, ln := range loc.Line {
-		if fn := ln.Function; fn != nil {
-			if re.MatchString(fn.Name) {
-				continue
-			}
-			if re.MatchString(fn.Filename) {
-				continue
-			}
-		}
-		lines = append(lines, ln)
-	}
-	return lines
-}
-
-// focusedAndNotIgnored looks up a slice of ids against a map of
-// focused/ignored locations. The map only contains locations that are
-// explicitly focused or ignored. Returns whether there is at least
-// one focused location but no ignored locations.
-func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
-	var f bool
-	for _, loc := range locs {
-		if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
-			if focus {
-				// Found focused location. Must keep searching in case there
-				// is an ignored one as well.
-				f = true
-			} else {
-				// Found ignored location. Can return false right away.
-				return false
-			}
-		}
-	}
-	return f
-}
-
-// TagMatch selects tags for filtering
-type TagMatch func(key, val string, nval int64) bool
-
-// FilterSamplesByTag removes all samples from the profile, except
-// those that match focus and do not match the ignore regular
-// expression.
-func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
-	samples := make([]*Sample, 0, len(p.Sample))
-	for _, s := range p.Sample {
-		focused, ignored := focusedSample(s, focus, ignore)
-		fm = fm || focused
-		im = im || ignored
-		if focused && !ignored {
-			samples = append(samples, s)
-		}
-	}
-	p.Sample = samples
-	return
-}
-
-// focusedTag checks a sample against focus and ignore regexps.
-// Returns whether the focus/ignore regexps match any tags
-func focusedSample(s *Sample, focus, ignore TagMatch) (fm, im bool) {
-	fm = focus == nil
-	for key, vals := range s.Label {
-		for _, val := range vals {
-			if ignore != nil && ignore(key, val, 0) {
-				im = true
-			}
-			if !fm && focus(key, val, 0) {
-				fm = true
-			}
-		}
-	}
-	for key, vals := range s.NumLabel {
-		for _, val := range vals {
-			if ignore != nil && ignore(key, "", val) {
-				im = true
-			}
-			if !fm && focus(key, "", val) {
-				fm = true
-			}
-		}
-	}
-	return fm, im
-}
diff --git a/src/internal/pprof/profile/legacy_profile.go b/src/internal/pprof/profile/legacy_profile.go
deleted file mode 100644
index d69f8de..0000000
--- a/src/internal/pprof/profile/legacy_profile.go
+++ /dev/null
@@ -1,1266 +0,0 @@
-// 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 parsers to convert legacy profiles into the
-// profile.proto format.
-
-package profile
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"io"
-	"math"
-	"regexp"
-	"strconv"
-	"strings"
-)
-
-var (
-	countStartRE = regexp.MustCompile(`\A(\w+) profile: total \d+\n\z`)
-	countRE      = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\n\z`)
-
-	heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
-	heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
-
-	contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
-
-	hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
-
-	growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz`)
-
-	fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz`)
-
-	threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
-	threadStartRE  = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
-
-	procMapsRE = regexp.MustCompile(`([[:xdigit:]]+)-([[:xdigit:]]+)\s+([-rwxp]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+):([[:xdigit:]]+)\s+([[:digit:]]+)\s*(\S+)?`)
-
-	briefMapsRE = regexp.MustCompile(`\s*([[:xdigit:]]+)-([[:xdigit:]]+):\s*(\S+)(\s.*@)?([[:xdigit:]]+)?`)
-
-	// LegacyHeapAllocated instructs the heapz parsers to use the
-	// allocated memory stats instead of the default in-use memory. Note
-	// that tcmalloc doesn't provide all allocated memory, only in-use
-	// stats.
-	LegacyHeapAllocated bool
-)
-
-func isSpaceOrComment(line string) bool {
-	trimmed := strings.TrimSpace(line)
-	return len(trimmed) == 0 || trimmed[0] == '#'
-}
-
-// parseGoCount parses a Go count profile (e.g., threadcreate or
-// goroutine) and returns a new Profile.
-func parseGoCount(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-
-	var line string
-	var err error
-	for {
-		// Skip past comments and empty lines seeking a real header.
-		line, err = r.ReadString('\n')
-		if err != nil {
-			return nil, err
-		}
-		if !isSpaceOrComment(line) {
-			break
-		}
-	}
-
-	m := countStartRE.FindStringSubmatch(line)
-	if m == nil {
-		return nil, errUnrecognized
-	}
-	profileType := m[1]
-	p := &Profile{
-		PeriodType: &ValueType{Type: profileType, Unit: "count"},
-		Period:     1,
-		SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
-	}
-	locations := make(map[uint64]*Location)
-	for {
-		line, err = r.ReadString('\n')
-		if err != nil {
-			if err == io.EOF {
-				break
-			}
-			return nil, err
-		}
-		if isSpaceOrComment(line) {
-			continue
-		}
-		if strings.HasPrefix(line, "---") {
-			break
-		}
-		m := countRE.FindStringSubmatch(line)
-		if m == nil {
-			return nil, errMalformed
-		}
-		n, err := strconv.ParseInt(m[1], 0, 64)
-		if err != nil {
-			return nil, errMalformed
-		}
-		fields := strings.Fields(m[2])
-		locs := make([]*Location, 0, len(fields))
-		for _, stk := range fields {
-			addr, err := strconv.ParseUint(stk, 0, 64)
-			if err != nil {
-				return nil, errMalformed
-			}
-			// Adjust all frames by -1 to land on the call instruction.
-			addr--
-			loc := locations[addr]
-			if loc == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				locations[addr] = loc
-				p.Location = append(p.Location, loc)
-			}
-			locs = append(locs, loc)
-		}
-		p.Sample = append(p.Sample, &Sample{
-			Location: locs,
-			Value:    []int64{n},
-		})
-	}
-
-	if err = parseAdditionalSections(strings.TrimSpace(line), r, p); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-// remapLocationIDs ensures there is a location for each address
-// referenced by a sample, and remaps the samples to point to the new
-// location ids.
-func (p *Profile) remapLocationIDs() {
-	seen := make(map[*Location]bool, len(p.Location))
-	var locs []*Location
-
-	for _, s := range p.Sample {
-		for _, l := range s.Location {
-			if seen[l] {
-				continue
-			}
-			l.ID = uint64(len(locs) + 1)
-			locs = append(locs, l)
-			seen[l] = true
-		}
-	}
-	p.Location = locs
-}
-
-func (p *Profile) remapFunctionIDs() {
-	seen := make(map[*Function]bool, len(p.Function))
-	var fns []*Function
-
-	for _, l := range p.Location {
-		for _, ln := range l.Line {
-			fn := ln.Function
-			if fn == nil || seen[fn] {
-				continue
-			}
-			fn.ID = uint64(len(fns) + 1)
-			fns = append(fns, fn)
-			seen[fn] = true
-		}
-	}
-	p.Function = fns
-}
-
-// remapMappingIDs matches location addresses with existing mappings
-// and updates them appropriately. This is O(N*M), if this ever shows
-// up as a bottleneck, evaluate sorting the mappings and doing a
-// binary search, which would make it O(N*log(M)).
-func (p *Profile) remapMappingIDs() {
-	if len(p.Mapping) == 0 {
-		return
-	}
-
-	// Some profile handlers will incorrectly set regions for the main
-	// executable if its section is remapped. Fix them through heuristics.
-
-	// Remove the initial mapping if named '/anon_hugepage' and has a
-	// consecutive adjacent mapping.
-	if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
-		if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
-			p.Mapping = p.Mapping[1:]
-		}
-	}
-
-	// Subtract the offset from the start of the main mapping if it
-	// ends up at a recognizable start address.
-	const expectedStart = 0x400000
-	if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
-		m.Start = expectedStart
-		m.Offset = 0
-	}
-
-	for _, l := range p.Location {
-		if a := l.Address; a != 0 {
-			for _, m := range p.Mapping {
-				if m.Start <= a && a < m.Limit {
-					l.Mapping = m
-					break
-				}
-			}
-		}
-	}
-
-	// Reset all mapping IDs.
-	for i, m := range p.Mapping {
-		m.ID = uint64(i + 1)
-	}
-}
-
-var cpuInts = []func([]byte) (uint64, []byte){
-	get32l,
-	get32b,
-	get64l,
-	get64b,
-}
-
-func get32l(b []byte) (uint64, []byte) {
-	if len(b) < 4 {
-		return 0, nil
-	}
-	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
-}
-
-func get32b(b []byte) (uint64, []byte) {
-	if len(b) < 4 {
-		return 0, nil
-	}
-	return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
-}
-
-func get64l(b []byte) (uint64, []byte) {
-	if len(b) < 8 {
-		return 0, nil
-	}
-	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:]
-}
-
-func get64b(b []byte) (uint64, []byte) {
-	if len(b) < 8 {
-		return 0, nil
-	}
-	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:]
-}
-
-// ParseTracebacks parses a set of tracebacks and returns a newly
-// populated profile. It will accept any text file and generate a
-// Profile out of it with any hex addresses it can identify, including
-// a process map if it can recognize one. Each sample will include a
-// tag "source" with the addresses recognized in string format.
-func ParseTracebacks(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-
-	p := &Profile{
-		PeriodType: &ValueType{Type: "trace", Unit: "count"},
-		Period:     1,
-		SampleType: []*ValueType{
-			{Type: "trace", Unit: "count"},
-		},
-	}
-
-	var sources []string
-	var sloc []*Location
-
-	locs := make(map[uint64]*Location)
-	for {
-		l, err := r.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-			if l == "" {
-				break
-			}
-		}
-		if sectionTrigger(l) == memoryMapSection {
-			break
-		}
-		if s, addrs := extractHexAddresses(l); len(s) > 0 {
-			for _, addr := range addrs {
-				// Addresses from stack traces point to the next instruction after
-				// each call. Adjust by -1 to land somewhere on the actual call.
-				addr--
-				loc := locs[addr]
-				if locs[addr] == nil {
-					loc = &Location{
-						Address: addr,
-					}
-					p.Location = append(p.Location, loc)
-					locs[addr] = loc
-				}
-				sloc = append(sloc, loc)
-			}
-
-			sources = append(sources, s...)
-		} else {
-			if len(sources) > 0 || len(sloc) > 0 {
-				addTracebackSample(sloc, sources, p)
-				sloc, sources = nil, nil
-			}
-		}
-	}
-
-	// Add final sample to save any leftover data.
-	if len(sources) > 0 || len(sloc) > 0 {
-		addTracebackSample(sloc, sources, p)
-	}
-
-	if err := p.ParseMemoryMap(r); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-func addTracebackSample(l []*Location, s []string, p *Profile) {
-	p.Sample = append(p.Sample,
-		&Sample{
-			Value:    []int64{1},
-			Location: l,
-			Label:    map[string][]string{"source": s},
-		})
-}
-
-// parseCPU parses a profilez legacy profile and returns a newly
-// populated Profile.
-//
-// The general format for profilez samples is a sequence of words in
-// binary format. The first words are a header with the following data:
-//   1st word -- 0
-//   2nd word -- 3
-//   3rd word -- 0 if a c++ application, 1 if a java application.
-//   4th word -- Sampling period (in microseconds).
-//   5th word -- Padding.
-func parseCPU(b []byte) (*Profile, error) {
-	var parse func([]byte) (uint64, []byte)
-	var n1, n2, n3, n4, n5 uint64
-	for _, parse = range cpuInts {
-		var tmp []byte
-		n1, tmp = parse(b)
-		n2, tmp = parse(tmp)
-		n3, tmp = parse(tmp)
-		n4, tmp = parse(tmp)
-		n5, tmp = parse(tmp)
-
-		if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
-			b = tmp
-			return cpuProfile(b, int64(n4), parse)
-		}
-	}
-	return nil, errUnrecognized
-}
-
-// cpuProfile returns a new Profile from C++ profilez data.
-// b is the profile bytes after the header, period is the profiling
-// period, and parse is a function to parse 8-byte chunks from the
-// profile in its native endianness.
-func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
-	p := &Profile{
-		Period:     period * 1000,
-		PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
-		SampleType: []*ValueType{
-			{Type: "samples", Unit: "count"},
-			{Type: "cpu", Unit: "nanoseconds"},
-		},
-	}
-	var err error
-	if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
-		return nil, err
-	}
-
-	// If all samples have the same second-to-the-bottom frame, it
-	// strongly suggests that it is an uninteresting artifact of
-	// measurement -- a stack frame pushed by the signal handler. The
-	// bottom frame is always correct as it is picked up from the signal
-	// structure, not the stack. Check if this is the case and if so,
-	// remove.
-	if len(p.Sample) > 1 && len(p.Sample[0].Location) > 1 {
-		allSame := true
-		id1 := p.Sample[0].Location[1].Address
-		for _, s := range p.Sample {
-			if len(s.Location) < 2 || id1 != s.Location[1].Address {
-				allSame = false
-				break
-			}
-		}
-		if allSame {
-			for _, s := range p.Sample {
-				s.Location = append(s.Location[:1], s.Location[2:]...)
-			}
-		}
-	}
-
-	if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-// parseCPUSamples parses a collection of profilez samples from a
-// profile.
-//
-// profilez samples are a repeated sequence of stack frames of the
-// form:
-//    1st word -- The number of times this stack was encountered.
-//    2nd word -- The size of the stack (StackSize).
-//    3rd word -- The first address on the stack.
-//    ...
-//    StackSize + 2 -- The last address on the stack
-// The last stack trace is of the form:
-//   1st word -- 0
-//   2nd word -- 1
-//   3rd word -- 0
-//
-// Addresses from stack traces may point to the next instruction after
-// each call. Optionally adjust by -1 to land somewhere on the actual
-// call (except for the leaf, which is not a call).
-func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
-	locs := make(map[uint64]*Location)
-	for len(b) > 0 {
-		var count, nstk uint64
-		count, b = parse(b)
-		nstk, b = parse(b)
-		if b == nil || nstk > uint64(len(b)/4) {
-			return nil, nil, errUnrecognized
-		}
-		var sloc []*Location
-		addrs := make([]uint64, nstk)
-		for i := 0; i < int(nstk); i++ {
-			addrs[i], b = parse(b)
-		}
-
-		if count == 0 && nstk == 1 && addrs[0] == 0 {
-			// End of data marker
-			break
-		}
-		for i, addr := range addrs {
-			if adjust && i > 0 {
-				addr--
-			}
-			loc := locs[addr]
-			if loc == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				locs[addr] = loc
-				p.Location = append(p.Location, loc)
-			}
-			sloc = append(sloc, loc)
-		}
-		p.Sample = append(p.Sample,
-			&Sample{
-				Value:    []int64{int64(count), int64(count) * p.Period},
-				Location: sloc,
-			})
-	}
-	// Reached the end without finding the EOD marker.
-	return b, locs, nil
-}
-
-// parseHeap parses a heapz legacy or a growthz profile and
-// returns a newly populated Profile.
-func parseHeap(b []byte) (p *Profile, err error) {
-	r := bytes.NewBuffer(b)
-	l, err := r.ReadString('\n')
-	if err != nil {
-		return nil, errUnrecognized
-	}
-
-	sampling := ""
-
-	if header := heapHeaderRE.FindStringSubmatch(l); header != nil {
-		p = &Profile{
-			SampleType: []*ValueType{
-				{Type: "objects", Unit: "count"},
-				{Type: "space", Unit: "bytes"},
-			},
-			PeriodType: &ValueType{Type: "objects", Unit: "bytes"},
-		}
-
-		var period int64
-		if len(header[6]) > 0 {
-			if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		}
-
-		switch header[5] {
-		case "heapz_v2", "heap_v2":
-			sampling, p.Period = "v2", period
-		case "heapprofile":
-			sampling, p.Period = "", 1
-		case "heap":
-			sampling, p.Period = "v2", period/2
-		default:
-			return nil, errUnrecognized
-		}
-	} else if header = growthHeaderRE.FindStringSubmatch(l); header != nil {
-		p = &Profile{
-			SampleType: []*ValueType{
-				{Type: "objects", Unit: "count"},
-				{Type: "space", Unit: "bytes"},
-			},
-			PeriodType: &ValueType{Type: "heapgrowth", Unit: "count"},
-			Period:     1,
-		}
-	} else if header = fragmentationHeaderRE.FindStringSubmatch(l); header != nil {
-		p = &Profile{
-			SampleType: []*ValueType{
-				{Type: "objects", Unit: "count"},
-				{Type: "space", Unit: "bytes"},
-			},
-			PeriodType: &ValueType{Type: "allocations", Unit: "count"},
-			Period:     1,
-		}
-	} else {
-		return nil, errUnrecognized
-	}
-
-	if LegacyHeapAllocated {
-		for _, st := range p.SampleType {
-			st.Type = "alloc_" + st.Type
-		}
-	} else {
-		for _, st := range p.SampleType {
-			st.Type = "inuse_" + st.Type
-		}
-	}
-
-	locs := make(map[uint64]*Location)
-	for {
-		l, err = r.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-
-			if l == "" {
-				break
-			}
-		}
-
-		if isSpaceOrComment(l) {
-			continue
-		}
-		l = strings.TrimSpace(l)
-
-		if sectionTrigger(l) != unrecognizedSection {
-			break
-		}
-
-		value, blocksize, addrs, err := parseHeapSample(l, p.Period, sampling)
-		if err != nil {
-			return nil, err
-		}
-		var sloc []*Location
-		for _, addr := range addrs {
-			// Addresses from stack traces point to the next instruction after
-			// each call. Adjust by -1 to land somewhere on the actual call.
-			addr--
-			loc := locs[addr]
-			if locs[addr] == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				p.Location = append(p.Location, loc)
-				locs[addr] = loc
-			}
-			sloc = append(sloc, loc)
-		}
-
-		p.Sample = append(p.Sample, &Sample{
-			Value:    value,
-			Location: sloc,
-			NumLabel: map[string][]int64{"bytes": {blocksize}},
-		})
-	}
-
-	if err = parseAdditionalSections(l, r, p); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-// parseHeapSample parses a single row from a heap profile into a new Sample.
-func parseHeapSample(line string, rate int64, sampling string) (value []int64, blocksize int64, addrs []uint64, err error) {
-	sampleData := heapSampleRE.FindStringSubmatch(line)
-	if len(sampleData) != 6 {
-		return value, blocksize, addrs, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
-	}
-
-	// Use first two values by default; tcmalloc sampling generates the
-	// same value for both, only the older heap-profile collect separate
-	// stats for in-use and allocated objects.
-	valueIndex := 1
-	if LegacyHeapAllocated {
-		valueIndex = 3
-	}
-
-	var v1, v2 int64
-	if v1, err = strconv.ParseInt(sampleData[valueIndex], 10, 64); err != nil {
-		return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-	if v2, err = strconv.ParseInt(sampleData[valueIndex+1], 10, 64); err != nil {
-		return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-
-	if v1 == 0 {
-		if v2 != 0 {
-			return value, blocksize, addrs, fmt.Errorf("allocation count was 0 but allocation bytes was %d", v2)
-		}
-	} else {
-		blocksize = v2 / v1
-		if sampling == "v2" {
-			v1, v2 = scaleHeapSample(v1, v2, rate)
-		}
-	}
-
-	value = []int64{v1, v2}
-	addrs = parseHexAddresses(sampleData[5])
-
-	return value, blocksize, addrs, nil
-}
-
-// extractHexAddresses extracts hex numbers from a string and returns
-// them, together with their numeric value, in a slice.
-func extractHexAddresses(s string) ([]string, []uint64) {
-	hexStrings := hexNumberRE.FindAllString(s, -1)
-	var ids []uint64
-	for _, s := range hexStrings {
-		if id, err := strconv.ParseUint(s, 0, 64); err == nil {
-			ids = append(ids, id)
-		} else {
-			// Do not expect any parsing failures due to the regexp matching.
-			panic("failed to parse hex value:" + s)
-		}
-	}
-	return hexStrings, ids
-}
-
-// parseHexAddresses parses hex numbers from a string and returns them
-// in a slice.
-func parseHexAddresses(s string) []uint64 {
-	_, ids := extractHexAddresses(s)
-	return ids
-}
-
-// scaleHeapSample adjusts the data from a heapz Sample to
-// account for its probability of appearing in the collected
-// data. heapz profiles are a sampling of the memory allocations
-// requests in a program. We estimate the unsampled value by dividing
-// each collected sample by its probability of appearing in the
-// profile. heapz v2 profiles rely on a poisson process to determine
-// which samples to collect, based on the desired average collection
-// rate R. The probability of a sample of size S to appear in that
-// profile is 1-exp(-S/R).
-func scaleHeapSample(count, size, rate int64) (int64, int64) {
-	if count == 0 || size == 0 {
-		return 0, 0
-	}
-
-	if rate <= 1 {
-		// if rate==1 all samples were collected so no adjustment is needed.
-		// if rate<1 treat as unknown and skip scaling.
-		return count, size
-	}
-
-	avgSize := float64(size) / float64(count)
-	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
-
-	return int64(float64(count) * scale), int64(float64(size) * scale)
-}
-
-// parseContention parses a mutex or contention profile. There are 2 cases:
-// "--- contentionz " for legacy C++ profiles (and backwards compatibility)
-// "--- mutex:" or "--- contention:" for profiles generated by the Go runtime.
-// This code converts the text output from runtime into a *Profile. (In the future
-// the runtime might write a serialized Profile directly making this unnecessary.)
-func parseContention(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-	var l string
-	var err error
-	for {
-		// Skip past comments and empty lines seeking a real header.
-		l, err = r.ReadString('\n')
-		if err != nil {
-			return nil, err
-		}
-		if !isSpaceOrComment(l) {
-			break
-		}
-	}
-
-	if strings.HasPrefix(l, "--- contentionz ") {
-		return parseCppContention(r)
-	} else if strings.HasPrefix(l, "--- mutex:") {
-		return parseCppContention(r)
-	} else if strings.HasPrefix(l, "--- contention:") {
-		return parseCppContention(r)
-	}
-	return nil, errUnrecognized
-}
-
-// parseCppContention parses the output from synchronization_profiling.cc
-// for backward compatibility, and the compatible (non-debug) block profile
-// output from the Go runtime.
-func parseCppContention(r *bytes.Buffer) (*Profile, error) {
-	p := &Profile{
-		PeriodType: &ValueType{Type: "contentions", Unit: "count"},
-		Period:     1,
-		SampleType: []*ValueType{
-			{Type: "contentions", Unit: "count"},
-			{Type: "delay", Unit: "nanoseconds"},
-		},
-	}
-
-	var cpuHz int64
-	var l string
-	var err error
-	// Parse text of the form "attribute = value" before the samples.
-	const delimiter = "="
-	for {
-		l, err = r.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-
-			if l == "" {
-				break
-			}
-		}
-		if isSpaceOrComment(l) {
-			continue
-		}
-
-		if l = strings.TrimSpace(l); l == "" {
-			continue
-		}
-
-		if strings.HasPrefix(l, "---") {
-			break
-		}
-
-		attr := strings.SplitN(l, delimiter, 2)
-		if len(attr) != 2 {
-			break
-		}
-		key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
-		var err error
-		switch key {
-		case "cycles/second":
-			if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		case "sampling period":
-			if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		case "ms since reset":
-			ms, err := strconv.ParseInt(val, 0, 64)
-			if err != nil {
-				return nil, errUnrecognized
-			}
-			p.DurationNanos = ms * 1000 * 1000
-		case "format":
-			// CPP contentionz profiles don't have format.
-			return nil, errUnrecognized
-		case "resolution":
-			// CPP contentionz profiles don't have resolution.
-			return nil, errUnrecognized
-		case "discarded samples":
-		default:
-			return nil, errUnrecognized
-		}
-	}
-
-	locs := make(map[uint64]*Location)
-	for {
-		if !isSpaceOrComment(l) {
-			if l = strings.TrimSpace(l); strings.HasPrefix(l, "---") {
-				break
-			}
-			value, addrs, err := parseContentionSample(l, p.Period, cpuHz)
-			if err != nil {
-				return nil, err
-			}
-			var sloc []*Location
-			for _, addr := range addrs {
-				// Addresses from stack traces point to the next instruction after
-				// each call. Adjust by -1 to land somewhere on the actual call.
-				addr--
-				loc := locs[addr]
-				if locs[addr] == nil {
-					loc = &Location{
-						Address: addr,
-					}
-					p.Location = append(p.Location, loc)
-					locs[addr] = loc
-				}
-				sloc = append(sloc, loc)
-			}
-			p.Sample = append(p.Sample, &Sample{
-				Value:    value,
-				Location: sloc,
-			})
-		}
-
-		if l, err = r.ReadString('\n'); err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-			if l == "" {
-				break
-			}
-		}
-	}
-
-	if err = parseAdditionalSections(l, r, p); err != nil {
-		return nil, err
-	}
-
-	return p, nil
-}
-
-// parseContentionSample parses a single row from a contention profile
-// into a new Sample.
-func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
-	sampleData := contentionSampleRE.FindStringSubmatch(line)
-	if sampleData == nil {
-		return value, addrs, errUnrecognized
-	}
-
-	v1, err := strconv.ParseInt(sampleData[1], 10, 64)
-	if err != nil {
-		return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-	v2, err := strconv.ParseInt(sampleData[2], 10, 64)
-	if err != nil {
-		return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-
-	// Unsample values if period and cpuHz are available.
-	// - Delays are scaled to cycles and then to nanoseconds.
-	// - Contentions are scaled to cycles.
-	if period > 0 {
-		if cpuHz > 0 {
-			cpuGHz := float64(cpuHz) / 1e9
-			v1 = int64(float64(v1) * float64(period) / cpuGHz)
-		}
-		v2 = v2 * period
-	}
-
-	value = []int64{v2, v1}
-	addrs = parseHexAddresses(sampleData[3])
-
-	return value, addrs, nil
-}
-
-// parseThread parses a Threadz profile and returns a new Profile.
-func parseThread(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-
-	var line string
-	var err error
-	for {
-		// Skip past comments and empty lines seeking a real header.
-		line, err = r.ReadString('\n')
-		if err != nil {
-			return nil, err
-		}
-		if !isSpaceOrComment(line) {
-			break
-		}
-	}
-
-	if m := threadzStartRE.FindStringSubmatch(line); m != nil {
-		// Advance over initial comments until first stack trace.
-		for {
-			line, err = r.ReadString('\n')
-			if err != nil {
-				if err != io.EOF {
-					return nil, err
-				}
-
-				if line == "" {
-					break
-				}
-			}
-			if sectionTrigger(line) != unrecognizedSection || line[0] == '-' {
-				break
-			}
-		}
-	} else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
-		return nil, errUnrecognized
-	}
-
-	p := &Profile{
-		SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
-		PeriodType: &ValueType{Type: "thread", Unit: "count"},
-		Period:     1,
-	}
-
-	locs := make(map[uint64]*Location)
-	// Recognize each thread and populate profile samples.
-	for sectionTrigger(line) == unrecognizedSection {
-		if strings.HasPrefix(line, "---- no stack trace for") {
-			line = ""
-			break
-		}
-		if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
-			return nil, errUnrecognized
-		}
-
-		var addrs []uint64
-		line, addrs, err = parseThreadSample(r)
-		if err != nil {
-			return nil, errUnrecognized
-		}
-		if len(addrs) == 0 {
-			// We got a --same as previous threads--. Bump counters.
-			if len(p.Sample) > 0 {
-				s := p.Sample[len(p.Sample)-1]
-				s.Value[0]++
-			}
-			continue
-		}
-
-		var sloc []*Location
-		for _, addr := range addrs {
-			// Addresses from stack traces point to the next instruction after
-			// each call. Adjust by -1 to land somewhere on the actual call.
-			addr--
-			loc := locs[addr]
-			if locs[addr] == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				p.Location = append(p.Location, loc)
-				locs[addr] = loc
-			}
-			sloc = append(sloc, loc)
-		}
-
-		p.Sample = append(p.Sample, &Sample{
-			Value:    []int64{1},
-			Location: sloc,
-		})
-	}
-
-	if err = parseAdditionalSections(line, r, p); err != nil {
-		return nil, err
-	}
-
-	return p, nil
-}
-
-// parseThreadSample parses a symbolized or unsymbolized stack trace.
-// Returns the first line after the traceback, the sample (or nil if
-// it hits a 'same-as-previous' marker) and an error.
-func parseThreadSample(b *bytes.Buffer) (nextl string, addrs []uint64, err error) {
-	var l string
-	sameAsPrevious := false
-	for {
-		if l, err = b.ReadString('\n'); err != nil {
-			if err != io.EOF {
-				return "", nil, err
-			}
-			if l == "" {
-				break
-			}
-		}
-		if l = strings.TrimSpace(l); l == "" {
-			continue
-		}
-
-		if strings.HasPrefix(l, "---") {
-			break
-		}
-		if strings.Contains(l, "same as previous thread") {
-			sameAsPrevious = true
-			continue
-		}
-
-		addrs = append(addrs, parseHexAddresses(l)...)
-	}
-
-	if sameAsPrevious {
-		return l, nil, nil
-	}
-	return l, addrs, nil
-}
-
-// parseAdditionalSections parses any additional sections in the
-// profile, ignoring any unrecognized sections.
-func parseAdditionalSections(l string, b *bytes.Buffer, p *Profile) (err error) {
-	for {
-		if sectionTrigger(l) == memoryMapSection {
-			break
-		}
-		// Ignore any unrecognized sections.
-		if l, err := b.ReadString('\n'); err != nil {
-			if err != io.EOF {
-				return err
-			}
-			if l == "" {
-				break
-			}
-		}
-	}
-	return p.ParseMemoryMap(b)
-}
-
-// ParseMemoryMap parses a memory map in the format of
-// /proc/self/maps, and overrides the mappings in the current profile.
-// It renumbers the samples and locations in the profile correspondingly.
-func (p *Profile) ParseMemoryMap(rd io.Reader) error {
-	b := bufio.NewReader(rd)
-
-	var attrs []string
-	var r *strings.Replacer
-	const delimiter = "="
-	for {
-		l, err := b.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return err
-			}
-			if l == "" {
-				break
-			}
-		}
-		if l = strings.TrimSpace(l); l == "" {
-			continue
-		}
-
-		if r != nil {
-			l = r.Replace(l)
-		}
-		m, err := parseMappingEntry(l)
-		if err != nil {
-			if err == errUnrecognized {
-				// Recognize assignments of the form: attr=value, and replace
-				// $attr with value on subsequent mappings.
-				if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
-					attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
-					r = strings.NewReplacer(attrs...)
-				}
-				// Ignore any unrecognized entries
-				continue
-			}
-			return err
-		}
-		if m == nil || (m.File == "" && len(p.Mapping) != 0) {
-			// In some cases the first entry may include the address range
-			// but not the name of the file. It should be followed by
-			// another entry with the name.
-			continue
-		}
-		if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
-			// Update the name if this is the entry following that empty one.
-			p.Mapping[0].File = m.File
-			continue
-		}
-		p.Mapping = append(p.Mapping, m)
-	}
-	p.remapLocationIDs()
-	p.remapFunctionIDs()
-	p.remapMappingIDs()
-	return nil
-}
-
-func parseMappingEntry(l string) (*Mapping, error) {
-	mapping := &Mapping{}
-	var err error
-	if me := procMapsRE.FindStringSubmatch(l); len(me) == 9 {
-		if !strings.Contains(me[3], "x") {
-			// Skip non-executable entries.
-			return nil, nil
-		}
-		if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		if me[4] != "" {
-			if mapping.Offset, err = strconv.ParseUint(me[4], 16, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		}
-		mapping.File = me[8]
-		return mapping, nil
-	}
-
-	if me := briefMapsRE.FindStringSubmatch(l); len(me) == 6 {
-		if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		mapping.File = me[3]
-		if me[5] != "" {
-			if mapping.Offset, err = strconv.ParseUint(me[5], 16, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		}
-		return mapping, nil
-	}
-
-	return nil, errUnrecognized
-}
-
-type sectionType int
-
-const (
-	unrecognizedSection sectionType = iota
-	memoryMapSection
-)
-
-var memoryMapTriggers = []string{
-	"--- Memory map: ---",
-	"MAPPED_LIBRARIES:",
-}
-
-func sectionTrigger(line string) sectionType {
-	for _, trigger := range memoryMapTriggers {
-		if strings.Contains(line, trigger) {
-			return memoryMapSection
-		}
-	}
-	return unrecognizedSection
-}
-
-func (p *Profile) addLegacyFrameInfo() {
-	switch {
-	case isProfileType(p, heapzSampleTypes) ||
-		isProfileType(p, heapzInUseSampleTypes) ||
-		isProfileType(p, heapzAllocSampleTypes):
-		p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
-	case isProfileType(p, contentionzSampleTypes):
-		p.DropFrames, p.KeepFrames = lockRxStr, ""
-	default:
-		p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
-	}
-}
-
-var heapzSampleTypes = []string{"allocations", "size"} // early Go pprof profiles
-var heapzInUseSampleTypes = []string{"inuse_objects", "inuse_space"}
-var heapzAllocSampleTypes = []string{"alloc_objects", "alloc_space"}
-var contentionzSampleTypes = []string{"contentions", "delay"}
-
-func isProfileType(p *Profile, t []string) bool {
-	st := p.SampleType
-	if len(st) != len(t) {
-		return false
-	}
-
-	for i := range st {
-		if st[i].Type != t[i] {
-			return false
-		}
-	}
-	return true
-}
-
-var allocRxStr = strings.Join([]string{
-	// POSIX entry points.
-	`calloc`,
-	`cfree`,
-	`malloc`,
-	`free`,
-	`memalign`,
-	`do_memalign`,
-	`(__)?posix_memalign`,
-	`pvalloc`,
-	`valloc`,
-	`realloc`,
-
-	// TC malloc.
-	`tcmalloc::.*`,
-	`tc_calloc`,
-	`tc_cfree`,
-	`tc_malloc`,
-	`tc_free`,
-	`tc_memalign`,
-	`tc_posix_memalign`,
-	`tc_pvalloc`,
-	`tc_valloc`,
-	`tc_realloc`,
-	`tc_new`,
-	`tc_delete`,
-	`tc_newarray`,
-	`tc_deletearray`,
-	`tc_new_nothrow`,
-	`tc_newarray_nothrow`,
-
-	// Memory-allocation routines on OS X.
-	`malloc_zone_malloc`,
-	`malloc_zone_calloc`,
-	`malloc_zone_valloc`,
-	`malloc_zone_realloc`,
-	`malloc_zone_memalign`,
-	`malloc_zone_free`,
-
-	// Go runtime
-	`runtime\..*`,
-
-	// Other misc. memory allocation routines
-	`BaseArena::.*`,
-	`(::)?do_malloc_no_errno`,
-	`(::)?do_malloc_pages`,
-	`(::)?do_malloc`,
-	`DoSampledAllocation`,
-	`MallocedMemBlock::MallocedMemBlock`,
-	`_M_allocate`,
-	`__builtin_(vec_)?delete`,
-	`__builtin_(vec_)?new`,
-	`__gnu_cxx::new_allocator::allocate`,
-	`__libc_malloc`,
-	`__malloc_alloc_template::allocate`,
-	`allocate`,
-	`cpp_alloc`,
-	`operator new(\[\])?`,
-	`simple_alloc::allocate`,
-}, `|`)
-
-var allocSkipRxStr = strings.Join([]string{
-	// Preserve Go runtime frames that appear in the middle/bottom of
-	// the stack.
-	`runtime\.panic`,
-	`runtime\.reflectcall`,
-	`runtime\.call[0-9]*`,
-}, `|`)
-
-var cpuProfilerRxStr = strings.Join([]string{
-	`ProfileData::Add`,
-	`ProfileData::prof_handler`,
-	`CpuProfiler::prof_handler`,
-	`__pthread_sighandler`,
-	`__restore`,
-}, `|`)
-
-var lockRxStr = strings.Join([]string{
-	`RecordLockProfileData`,
-	`(base::)?RecordLockProfileData.*`,
-	`(base::)?SubmitMutexProfileData.*`,
-	`(base::)?SubmitSpinLockProfileData.*`,
-	`(Mutex::)?AwaitCommon.*`,
-	`(Mutex::)?Unlock.*`,
-	`(Mutex::)?UnlockSlow.*`,
-	`(Mutex::)?ReaderUnlock.*`,
-	`(MutexLock::)?~MutexLock.*`,
-	`(SpinLock::)?Unlock.*`,
-	`(SpinLock::)?SlowUnlock.*`,
-	`(SpinLockHolder::)?~SpinLockHolder.*`,
-}, `|`)
diff --git a/src/internal/pprof/profile/profile.go b/src/internal/pprof/profile/profile.go
deleted file mode 100644
index 28e713d..0000000
--- a/src/internal/pprof/profile/profile.go
+++ /dev/null
@@ -1,572 +0,0 @@
-// 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 profile provides a representation of profile.proto and
-// methods to encode/decode profiles in this format.
-package profile
-
-import (
-	"bytes"
-	"compress/gzip"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"regexp"
-	"strings"
-	"time"
-)
-
-// Profile is an in-memory representation of profile.proto.
-type Profile struct {
-	SampleType []*ValueType
-	Sample     []*Sample
-	Mapping    []*Mapping
-	Location   []*Location
-	Function   []*Function
-
-	DropFrames string
-	KeepFrames string
-
-	TimeNanos     int64
-	DurationNanos int64
-	PeriodType    *ValueType
-	Period        int64
-
-	dropFramesX int64
-	keepFramesX int64
-	stringTable []string
-}
-
-// ValueType corresponds to Profile.ValueType
-type ValueType struct {
-	Type string // cpu, wall, inuse_space, etc
-	Unit string // seconds, nanoseconds, bytes, etc
-
-	typeX int64
-	unitX int64
-}
-
-// Sample corresponds to Profile.Sample
-type Sample struct {
-	Location []*Location
-	Value    []int64
-	Label    map[string][]string
-	NumLabel map[string][]int64
-
-	locationIDX []uint64
-	labelX      []Label
-}
-
-// Label corresponds to Profile.Label
-type Label struct {
-	keyX int64
-	// Exactly one of the two following values must be set
-	strX int64
-	numX int64 // Integer value for this label
-}
-
-// Mapping corresponds to Profile.Mapping
-type Mapping struct {
-	ID              uint64
-	Start           uint64
-	Limit           uint64
-	Offset          uint64
-	File            string
-	BuildID         string
-	HasFunctions    bool
-	HasFilenames    bool
-	HasLineNumbers  bool
-	HasInlineFrames bool
-
-	fileX    int64
-	buildIDX int64
-}
-
-// Location corresponds to Profile.Location
-type Location struct {
-	ID      uint64
-	Mapping *Mapping
-	Address uint64
-	Line    []Line
-
-	mappingIDX uint64
-}
-
-// Line corresponds to Profile.Line
-type Line struct {
-	Function *Function
-	Line     int64
-
-	functionIDX uint64
-}
-
-// Function corresponds to Profile.Function
-type Function struct {
-	ID         uint64
-	Name       string
-	SystemName string
-	Filename   string
-	StartLine  int64
-
-	nameX       int64
-	systemNameX int64
-	filenameX   int64
-}
-
-// Parse parses a profile and checks for its validity. The input
-// may be a gzip-compressed encoded protobuf or one of many legacy
-// profile formats which may be unsupported in the future.
-func Parse(r io.Reader) (*Profile, error) {
-	orig, err := ioutil.ReadAll(r)
-	if err != nil {
-		return nil, err
-	}
-
-	var p *Profile
-	if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
-		gz, err := gzip.NewReader(bytes.NewBuffer(orig))
-		if err != nil {
-			return nil, fmt.Errorf("decompressing profile: %v", err)
-		}
-		data, err := ioutil.ReadAll(gz)
-		if err != nil {
-			return nil, fmt.Errorf("decompressing profile: %v", err)
-		}
-		orig = data
-	}
-	if p, err = parseUncompressed(orig); err != nil {
-		if p, err = parseLegacy(orig); err != nil {
-			return nil, fmt.Errorf("parsing profile: %v", err)
-		}
-	}
-
-	if err := p.CheckValid(); err != nil {
-		return nil, fmt.Errorf("malformed profile: %v", err)
-	}
-	return p, nil
-}
-
-var errUnrecognized = fmt.Errorf("unrecognized profile format")
-var errMalformed = fmt.Errorf("malformed profile format")
-
-func parseLegacy(data []byte) (*Profile, error) {
-	parsers := []func([]byte) (*Profile, error){
-		parseCPU,
-		parseHeap,
-		parseGoCount, // goroutine, threadcreate
-		parseThread,
-		parseContention,
-	}
-
-	for _, parser := range parsers {
-		p, err := parser(data)
-		if err == nil {
-			p.setMain()
-			p.addLegacyFrameInfo()
-			return p, nil
-		}
-		if err != errUnrecognized {
-			return nil, err
-		}
-	}
-	return nil, errUnrecognized
-}
-
-func parseUncompressed(data []byte) (*Profile, error) {
-	p := &Profile{}
-	if err := unmarshal(data, p); err != nil {
-		return nil, err
-	}
-
-	if err := p.postDecode(); err != nil {
-		return nil, err
-	}
-
-	return p, nil
-}
-
-var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)
-
-// setMain scans Mapping entries and guesses which entry is main
-// because legacy profiles don't obey the convention of putting main
-// first.
-func (p *Profile) setMain() {
-	for i := 0; i < len(p.Mapping); i++ {
-		file := strings.TrimSpace(strings.Replace(p.Mapping[i].File, "(deleted)", "", -1))
-		if len(file) == 0 {
-			continue
-		}
-		if len(libRx.FindStringSubmatch(file)) > 0 {
-			continue
-		}
-		if strings.HasPrefix(file, "[") {
-			continue
-		}
-		// Swap what we guess is main to position 0.
-		tmp := p.Mapping[i]
-		p.Mapping[i] = p.Mapping[0]
-		p.Mapping[0] = tmp
-		break
-	}
-}
-
-// Write writes the profile as a gzip-compressed marshaled protobuf.
-func (p *Profile) Write(w io.Writer) error {
-	p.preEncode()
-	b := marshal(p)
-	zw := gzip.NewWriter(w)
-	defer zw.Close()
-	_, err := zw.Write(b)
-	return err
-}
-
-// CheckValid tests whether the profile is valid. Checks include, but are
-// not limited to:
-//   - len(Profile.Sample[n].value) == len(Profile.value_unit)
-//   - Sample.id has a corresponding Profile.Location
-func (p *Profile) CheckValid() error {
-	// Check that sample values are consistent
-	sampleLen := len(p.SampleType)
-	if sampleLen == 0 && len(p.Sample) != 0 {
-		return fmt.Errorf("missing sample type information")
-	}
-	for _, s := range p.Sample {
-		if len(s.Value) != sampleLen {
-			return fmt.Errorf("mismatch: sample has: %d values vs. %d types", len(s.Value), len(p.SampleType))
-		}
-	}
-
-	// Check that all mappings/locations/functions are in the tables
-	// Check that there are no duplicate ids
-	mappings := make(map[uint64]*Mapping, len(p.Mapping))
-	for _, m := range p.Mapping {
-		if m.ID == 0 {
-			return fmt.Errorf("found mapping with reserved ID=0")
-		}
-		if mappings[m.ID] != nil {
-			return fmt.Errorf("multiple mappings with same id: %d", m.ID)
-		}
-		mappings[m.ID] = m
-	}
-	functions := make(map[uint64]*Function, len(p.Function))
-	for _, f := range p.Function {
-		if f.ID == 0 {
-			return fmt.Errorf("found function with reserved ID=0")
-		}
-		if functions[f.ID] != nil {
-			return fmt.Errorf("multiple functions with same id: %d", f.ID)
-		}
-		functions[f.ID] = f
-	}
-	locations := make(map[uint64]*Location, len(p.Location))
-	for _, l := range p.Location {
-		if l.ID == 0 {
-			return fmt.Errorf("found location with reserved id=0")
-		}
-		if locations[l.ID] != nil {
-			return fmt.Errorf("multiple locations with same id: %d", l.ID)
-		}
-		locations[l.ID] = l
-		if m := l.Mapping; m != nil {
-			if m.ID == 0 || mappings[m.ID] != m {
-				return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID)
-			}
-		}
-		for _, ln := range l.Line {
-			if f := ln.Function; f != nil {
-				if f.ID == 0 || functions[f.ID] != f {
-					return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
-				}
-			}
-		}
-	}
-	return nil
-}
-
-// Aggregate merges the locations in the profile into equivalence
-// classes preserving the request attributes. It also updates the
-// samples to point to the merged locations.
-func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error {
-	for _, m := range p.Mapping {
-		m.HasInlineFrames = m.HasInlineFrames && inlineFrame
-		m.HasFunctions = m.HasFunctions && function
-		m.HasFilenames = m.HasFilenames && filename
-		m.HasLineNumbers = m.HasLineNumbers && linenumber
-	}
-
-	// Aggregate functions
-	if !function || !filename {
-		for _, f := range p.Function {
-			if !function {
-				f.Name = ""
-				f.SystemName = ""
-			}
-			if !filename {
-				f.Filename = ""
-			}
-		}
-	}
-
-	// Aggregate locations
-	if !inlineFrame || !address || !linenumber {
-		for _, l := range p.Location {
-			if !inlineFrame && len(l.Line) > 1 {
-				l.Line = l.Line[len(l.Line)-1:]
-			}
-			if !linenumber {
-				for i := range l.Line {
-					l.Line[i].Line = 0
-				}
-			}
-			if !address {
-				l.Address = 0
-			}
-		}
-	}
-
-	return p.CheckValid()
-}
-
-// Print dumps a text representation of a profile. Intended mainly
-// for debugging purposes.
-func (p *Profile) String() string {
-
-	ss := make([]string, 0, len(p.Sample)+len(p.Mapping)+len(p.Location))
-	if pt := p.PeriodType; pt != nil {
-		ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
-	}
-	ss = append(ss, fmt.Sprintf("Period: %d", p.Period))
-	if p.TimeNanos != 0 {
-		ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos)))
-	}
-	if p.DurationNanos != 0 {
-		ss = append(ss, fmt.Sprintf("Duration: %v", time.Duration(p.DurationNanos)))
-	}
-
-	ss = append(ss, "Samples:")
-	var sh1 string
-	for _, s := range p.SampleType {
-		sh1 = sh1 + fmt.Sprintf("%s/%s ", s.Type, s.Unit)
-	}
-	ss = append(ss, strings.TrimSpace(sh1))
-	for _, s := range p.Sample {
-		var sv string
-		for _, v := range s.Value {
-			sv = fmt.Sprintf("%s %10d", sv, v)
-		}
-		sv = sv + ": "
-		for _, l := range s.Location {
-			sv = sv + fmt.Sprintf("%d ", l.ID)
-		}
-		ss = append(ss, sv)
-		const labelHeader = "                "
-		if len(s.Label) > 0 {
-			ls := labelHeader
-			for k, v := range s.Label {
-				ls = ls + fmt.Sprintf("%s:%v ", k, v)
-			}
-			ss = append(ss, ls)
-		}
-		if len(s.NumLabel) > 0 {
-			ls := labelHeader
-			for k, v := range s.NumLabel {
-				ls = ls + fmt.Sprintf("%s:%v ", k, v)
-			}
-			ss = append(ss, ls)
-		}
-	}
-
-	ss = append(ss, "Locations")
-	for _, l := range p.Location {
-		locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address)
-		if m := l.Mapping; m != nil {
-			locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
-		}
-		if len(l.Line) == 0 {
-			ss = append(ss, locStr)
-		}
-		for li := range l.Line {
-			lnStr := "??"
-			if fn := l.Line[li].Function; fn != nil {
-				lnStr = fmt.Sprintf("%s %s:%d s=%d",
-					fn.Name,
-					fn.Filename,
-					l.Line[li].Line,
-					fn.StartLine)
-				if fn.Name != fn.SystemName {
-					lnStr = lnStr + "(" + fn.SystemName + ")"
-				}
-			}
-			ss = append(ss, locStr+lnStr)
-			// Do not print location details past the first line
-			locStr = "             "
-		}
-	}
-
-	ss = append(ss, "Mappings")
-	for _, m := range p.Mapping {
-		bits := ""
-		if m.HasFunctions {
-			bits = bits + "[FN]"
-		}
-		if m.HasFilenames {
-			bits = bits + "[FL]"
-		}
-		if m.HasLineNumbers {
-			bits = bits + "[LN]"
-		}
-		if m.HasInlineFrames {
-			bits = bits + "[IN]"
-		}
-		ss = append(ss, fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
-			m.ID,
-			m.Start, m.Limit, m.Offset,
-			m.File,
-			m.BuildID,
-			bits))
-	}
-
-	return strings.Join(ss, "\n") + "\n"
-}
-
-// Merge adds profile p adjusted by ratio r into profile p. Profiles
-// must be compatible (same Type and SampleType).
-// TODO(rsilvera): consider normalizing the profiles based on the
-// total samples collected.
-func (p *Profile) Merge(pb *Profile, r float64) error {
-	if err := p.Compatible(pb); err != nil {
-		return err
-	}
-
-	pb = pb.Copy()
-
-	// Keep the largest of the two periods.
-	if pb.Period > p.Period {
-		p.Period = pb.Period
-	}
-
-	p.DurationNanos += pb.DurationNanos
-
-	p.Mapping = append(p.Mapping, pb.Mapping...)
-	for i, m := range p.Mapping {
-		m.ID = uint64(i + 1)
-	}
-	p.Location = append(p.Location, pb.Location...)
-	for i, l := range p.Location {
-		l.ID = uint64(i + 1)
-	}
-	p.Function = append(p.Function, pb.Function...)
-	for i, f := range p.Function {
-		f.ID = uint64(i + 1)
-	}
-
-	if r != 1.0 {
-		for _, s := range pb.Sample {
-			for i, v := range s.Value {
-				s.Value[i] = int64((float64(v) * r))
-			}
-		}
-	}
-	p.Sample = append(p.Sample, pb.Sample...)
-	return p.CheckValid()
-}
-
-// Compatible determines if two profiles can be compared/merged.
-// returns nil if the profiles are compatible; otherwise an error with
-// details on the incompatibility.
-func (p *Profile) Compatible(pb *Profile) error {
-	if !compatibleValueTypes(p.PeriodType, pb.PeriodType) {
-		return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType)
-	}
-
-	if len(p.SampleType) != len(pb.SampleType) {
-		return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
-	}
-
-	for i := range p.SampleType {
-		if !compatibleValueTypes(p.SampleType[i], pb.SampleType[i]) {
-			return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
-		}
-	}
-
-	return nil
-}
-
-// HasFunctions determines if all locations in this profile have
-// symbolized function information.
-func (p *Profile) HasFunctions() bool {
-	for _, l := range p.Location {
-		if l.Mapping == nil || !l.Mapping.HasFunctions {
-			return false
-		}
-	}
-	return true
-}
-
-// HasFileLines determines if all locations in this profile have
-// symbolized file and line number information.
-func (p *Profile) HasFileLines() bool {
-	for _, l := range p.Location {
-		if l.Mapping == nil || (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) {
-			return false
-		}
-	}
-	return true
-}
-
-func compatibleValueTypes(v1, v2 *ValueType) bool {
-	if v1 == nil || v2 == nil {
-		return true // No grounds to disqualify.
-	}
-	return v1.Type == v2.Type && v1.Unit == v2.Unit
-}
-
-// Copy makes a fully independent copy of a profile.
-func (p *Profile) Copy() *Profile {
-	p.preEncode()
-	b := marshal(p)
-
-	pp := &Profile{}
-	if err := unmarshal(b, pp); err != nil {
-		panic(err)
-	}
-	if err := pp.postDecode(); err != nil {
-		panic(err)
-	}
-
-	return pp
-}
-
-// Demangler maps symbol names to a human-readable form. This may
-// include C++ demangling and additional simplification. Names that
-// are not demangled may be missing from the resulting map.
-type Demangler func(name []string) (map[string]string, error)
-
-// Demangle attempts to demangle and optionally simplify any function
-// names referenced in the profile. It works on a best-effort basis:
-// it will silently preserve the original names in case of any errors.
-func (p *Profile) Demangle(d Demangler) error {
-	// Collect names to demangle.
-	var names []string
-	for _, fn := range p.Function {
-		names = append(names, fn.SystemName)
-	}
-
-	// Update profile with demangled names.
-	demangled, err := d(names)
-	if err != nil {
-		return err
-	}
-	for _, fn := range p.Function {
-		if dd, ok := demangled[fn.SystemName]; ok {
-			fn.Name = dd
-		}
-	}
-	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/internal/pprof/profile/profile_test.go b/src/internal/pprof/profile/profile_test.go
deleted file mode 100644
index e1963f3..0000000
--- a/src/internal/pprof/profile/profile_test.go
+++ /dev/null
@@ -1,79 +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 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)
-	}
-}
-
-func TestParseContention(t *testing.T) {
-	tests := []struct {
-		name    string
-		in      string
-		wantErr bool
-	}{
-		{
-			name: "valid",
-			in: `--- mutex:
-cycles/second=3491920901
-sampling period=1
-43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31
-34035731690 15760 @ 0x45e851 0x45f764 0x4a2b17 0x44ea31
-`,
-		},
-		{
-			name: "valid with comment",
-			in: `--- mutex:
-cycles/second=3491920901
-sampling period=1
-43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31
-#	0x45e850	sync.(*Mutex).Unlock+0x80	/go/src/sync/mutex.go:126
-#	0x45f763	sync.(*RWMutex).Unlock+0x83	/go/src/sync/rwmutex.go:125
-#	0x4a2be0	main.main.func3+0x70		/go/src/internal/pprof/profile/a_binary.go:58
-
-34035731690 15760 @ 0x45e851 0x45f764 0x4a2b17 0x44ea31
-#	0x45e850	sync.(*Mutex).Unlock+0x80	/go/src/sync/mutex.go:126
-#	0x45f763	sync.(*RWMutex).Unlock+0x83	/go/src/sync/rwmutex.go:125
-#	0x4a2b16	main.main.func2+0xd6		/go/src/internal/pprof/profile/a_binary.go:48
-`,
-		},
-		{
-			name:    "empty",
-			in:      `--- mutex:`,
-			wantErr: true,
-		},
-		{
-			name: "invalid header",
-			in: `--- channel:
-43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31`,
-			wantErr: true,
-		},
-	}
-	for _, tc := range tests {
-		_, err := parseContention([]byte(tc.in))
-		if tc.wantErr && err == nil {
-			t.Errorf("parseContention(%q) succeeded unexpectedly", tc.name)
-		}
-		if !tc.wantErr && err != nil {
-			t.Errorf("parseContention(%q) failed unexpectedly: %v", tc.name, err)
-		}
-	}
-
-}
diff --git a/src/internal/pprof/profile/proto.go b/src/internal/pprof/profile/proto.go
deleted file mode 100644
index 11d7f9f..0000000
--- a/src/internal/pprof/profile/proto.go
+++ /dev/null
@@ -1,360 +0,0 @@
-// 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 is a simple protocol buffer encoder and decoder.
-//
-// A protocol message must implement the message interface:
-//   decoder() []decoder
-//   encode(*buffer)
-//
-// The decode method returns a slice indexed by field number that gives the
-// function to decode that field.
-// The encode method encodes its receiver into the given buffer.
-//
-// The two methods are simple enough to be implemented by hand rather than
-// by using a protocol compiler.
-//
-// See profile.go for examples of messages implementing this interface.
-//
-// There is no support for groups, message sets, or "has" bits.
-
-package profile
-
-import "errors"
-
-type buffer struct {
-	field int
-	typ   int
-	u64   uint64
-	data  []byte
-	tmp   [16]byte
-}
-
-type decoder func(*buffer, message) error
-
-type message interface {
-	decoder() []decoder
-	encode(*buffer)
-}
-
-func marshal(m message) []byte {
-	var b buffer
-	m.encode(&b)
-	return b.data
-}
-
-func encodeVarint(b *buffer, x uint64) {
-	for x >= 128 {
-		b.data = append(b.data, byte(x)|0x80)
-		x >>= 7
-	}
-	b.data = append(b.data, byte(x))
-}
-
-func encodeLength(b *buffer, tag int, len int) {
-	encodeVarint(b, uint64(tag)<<3|2)
-	encodeVarint(b, uint64(len))
-}
-
-func encodeUint64(b *buffer, tag int, x uint64) {
-	// append varint to b.data
-	encodeVarint(b, uint64(tag)<<3|0)
-	encodeVarint(b, x)
-}
-
-func encodeUint64s(b *buffer, tag int, x []uint64) {
-	if len(x) > 2 {
-		// Use packed encoding
-		n1 := len(b.data)
-		for _, u := range x {
-			encodeVarint(b, u)
-		}
-		n2 := len(b.data)
-		encodeLength(b, tag, n2-n1)
-		n3 := len(b.data)
-		copy(b.tmp[:], b.data[n2:n3])
-		copy(b.data[n1+(n3-n2):], b.data[n1:n2])
-		copy(b.data[n1:], b.tmp[:n3-n2])
-		return
-	}
-	for _, u := range x {
-		encodeUint64(b, tag, u)
-	}
-}
-
-func encodeUint64Opt(b *buffer, tag int, x uint64) {
-	if x == 0 {
-		return
-	}
-	encodeUint64(b, tag, x)
-}
-
-func encodeInt64(b *buffer, tag int, x int64) {
-	u := uint64(x)
-	encodeUint64(b, tag, u)
-}
-
-func encodeInt64Opt(b *buffer, tag int, x int64) {
-	if x == 0 {
-		return
-	}
-	encodeInt64(b, tag, x)
-}
-
-func encodeInt64s(b *buffer, tag int, x []int64) {
-	if len(x) > 2 {
-		// Use packed encoding
-		n1 := len(b.data)
-		for _, u := range x {
-			encodeVarint(b, uint64(u))
-		}
-		n2 := len(b.data)
-		encodeLength(b, tag, n2-n1)
-		n3 := len(b.data)
-		copy(b.tmp[:], b.data[n2:n3])
-		copy(b.data[n1+(n3-n2):], b.data[n1:n2])
-		copy(b.data[n1:], b.tmp[:n3-n2])
-		return
-	}
-	for _, u := range x {
-		encodeInt64(b, tag, u)
-	}
-}
-
-func encodeString(b *buffer, tag int, x string) {
-	encodeLength(b, tag, len(x))
-	b.data = append(b.data, x...)
-}
-
-func encodeStrings(b *buffer, tag int, x []string) {
-	for _, s := range x {
-		encodeString(b, tag, s)
-	}
-}
-
-func encodeStringOpt(b *buffer, tag int, x string) {
-	if x == "" {
-		return
-	}
-	encodeString(b, tag, x)
-}
-
-func encodeBool(b *buffer, tag int, x bool) {
-	if x {
-		encodeUint64(b, tag, 1)
-	} else {
-		encodeUint64(b, tag, 0)
-	}
-}
-
-func encodeBoolOpt(b *buffer, tag int, x bool) {
-	if x == false {
-		return
-	}
-	encodeBool(b, tag, x)
-}
-
-func encodeMessage(b *buffer, tag int, m message) {
-	n1 := len(b.data)
-	m.encode(b)
-	n2 := len(b.data)
-	encodeLength(b, tag, n2-n1)
-	n3 := len(b.data)
-	copy(b.tmp[:], b.data[n2:n3])
-	copy(b.data[n1+(n3-n2):], b.data[n1:n2])
-	copy(b.data[n1:], b.tmp[:n3-n2])
-}
-
-func unmarshal(data []byte, m message) (err error) {
-	b := buffer{data: data, typ: 2}
-	return decodeMessage(&b, m)
-}
-
-func le64(p []byte) uint64 {
-	return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
-}
-
-func le32(p []byte) uint32 {
-	return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
-}
-
-func decodeVarint(data []byte) (uint64, []byte, error) {
-	var i int
-	var u uint64
-	for i = 0; ; i++ {
-		if i >= 10 || i >= len(data) {
-			return 0, nil, errors.New("bad varint")
-		}
-		u |= uint64(data[i]&0x7F) << uint(7*i)
-		if data[i]&0x80 == 0 {
-			return u, data[i+1:], nil
-		}
-	}
-}
-
-func decodeField(b *buffer, data []byte) ([]byte, error) {
-	x, data, err := decodeVarint(data)
-	if err != nil {
-		return nil, err
-	}
-	b.field = int(x >> 3)
-	b.typ = int(x & 7)
-	b.data = nil
-	b.u64 = 0
-	switch b.typ {
-	case 0:
-		b.u64, data, err = decodeVarint(data)
-		if err != nil {
-			return nil, err
-		}
-	case 1:
-		if len(data) < 8 {
-			return nil, errors.New("not enough data")
-		}
-		b.u64 = le64(data[:8])
-		data = data[8:]
-	case 2:
-		var n uint64
-		n, data, err = decodeVarint(data)
-		if err != nil {
-			return nil, err
-		}
-		if n > uint64(len(data)) {
-			return nil, errors.New("too much data")
-		}
-		b.data = data[:n]
-		data = data[n:]
-	case 5:
-		if len(data) < 4 {
-			return nil, errors.New("not enough data")
-		}
-		b.u64 = uint64(le32(data[:4]))
-		data = data[4:]
-	default:
-		return nil, errors.New("unknown type: " + string(b.typ))
-	}
-
-	return data, nil
-}
-
-func checkType(b *buffer, typ int) error {
-	if b.typ != typ {
-		return errors.New("type mismatch")
-	}
-	return nil
-}
-
-func decodeMessage(b *buffer, m message) error {
-	if err := checkType(b, 2); err != nil {
-		return err
-	}
-	dec := m.decoder()
-	data := b.data
-	for len(data) > 0 {
-		// pull varint field# + type
-		var err error
-		data, err = decodeField(b, data)
-		if err != nil {
-			return err
-		}
-		if b.field >= len(dec) || dec[b.field] == nil {
-			continue
-		}
-		if err := dec[b.field](b, m); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func decodeInt64(b *buffer, x *int64) error {
-	if err := checkType(b, 0); err != nil {
-		return err
-	}
-	*x = int64(b.u64)
-	return nil
-}
-
-func decodeInt64s(b *buffer, x *[]int64) error {
-	if b.typ == 2 {
-		// Packed encoding
-		data := b.data
-		for len(data) > 0 {
-			var u uint64
-			var err error
-
-			if u, data, err = decodeVarint(data); err != nil {
-				return err
-			}
-			*x = append(*x, int64(u))
-		}
-		return nil
-	}
-	var i int64
-	if err := decodeInt64(b, &i); err != nil {
-		return err
-	}
-	*x = append(*x, i)
-	return nil
-}
-
-func decodeUint64(b *buffer, x *uint64) error {
-	if err := checkType(b, 0); err != nil {
-		return err
-	}
-	*x = b.u64
-	return nil
-}
-
-func decodeUint64s(b *buffer, x *[]uint64) error {
-	if b.typ == 2 {
-		data := b.data
-		// Packed encoding
-		for len(data) > 0 {
-			var u uint64
-			var err error
-
-			if u, data, err = decodeVarint(data); err != nil {
-				return err
-			}
-			*x = append(*x, u)
-		}
-		return nil
-	}
-	var u uint64
-	if err := decodeUint64(b, &u); err != nil {
-		return err
-	}
-	*x = append(*x, u)
-	return nil
-}
-
-func decodeString(b *buffer, x *string) error {
-	if err := checkType(b, 2); err != nil {
-		return err
-	}
-	*x = string(b.data)
-	return nil
-}
-
-func decodeStrings(b *buffer, x *[]string) error {
-	var s string
-	if err := decodeString(b, &s); err != nil {
-		return err
-	}
-	*x = append(*x, s)
-	return nil
-}
-
-func decodeBool(b *buffer, x *bool) error {
-	if err := checkType(b, 0); err != nil {
-		return err
-	}
-	if int64(b.u64) == 0 {
-		*x = false
-	} else {
-		*x = true
-	}
-	return nil
-}
diff --git a/src/internal/pprof/profile/proto_test.go b/src/internal/pprof/profile/proto_test.go
deleted file mode 100644
index c2613fc..0000000
--- a/src/internal/pprof/profile/proto_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package profile
-
-import (
-	"reflect"
-	"testing"
-)
-
-func TestPackedEncoding(t *testing.T) {
-
-	type testcase struct {
-		uint64s []uint64
-		int64s  []int64
-		encoded []byte
-	}
-	for i, tc := range []testcase{
-		{
-			[]uint64{0, 1, 10, 100, 1000, 10000},
-			[]int64{1000, 0, 1000},
-			[]byte{10, 8, 0, 1, 10, 100, 232, 7, 144, 78, 18, 5, 232, 7, 0, 232, 7},
-		},
-		{
-			[]uint64{10000},
-			nil,
-			[]byte{8, 144, 78},
-		},
-		{
-			nil,
-			[]int64{-10000},
-			[]byte{16, 240, 177, 255, 255, 255, 255, 255, 255, 255, 1},
-		},
-	} {
-		source := &packedInts{tc.uint64s, tc.int64s}
-		if got, want := marshal(source), tc.encoded; !reflect.DeepEqual(got, want) {
-			t.Errorf("failed encode %d, got %v, want %v", i, got, want)
-		}
-
-		dest := new(packedInts)
-		if err := unmarshal(tc.encoded, dest); err != nil {
-			t.Errorf("failed decode %d: %v", i, err)
-			continue
-		}
-		if got, want := dest.uint64s, tc.uint64s; !reflect.DeepEqual(got, want) {
-			t.Errorf("failed decode uint64s %d, got %v, want %v", i, got, want)
-		}
-		if got, want := dest.int64s, tc.int64s; !reflect.DeepEqual(got, want) {
-			t.Errorf("failed decode int64s %d, got %v, want %v", i, got, want)
-		}
-	}
-}
-
-type packedInts struct {
-	uint64s []uint64
-	int64s  []int64
-}
-
-func (u *packedInts) decoder() []decoder {
-	return []decoder{
-		nil,
-		func(b *buffer, m message) error { return decodeUint64s(b, &m.(*packedInts).uint64s) },
-		func(b *buffer, m message) error { return decodeInt64s(b, &m.(*packedInts).int64s) },
-	}
-}
-
-func (u *packedInts) encode(b *buffer) {
-	encodeUint64s(b, 1, u.uint64s)
-	encodeInt64s(b, 2, u.int64s)
-}
diff --git a/src/internal/pprof/profile/prune.go b/src/internal/pprof/profile/prune.go
deleted file mode 100644
index 1924fad..0000000
--- a/src/internal/pprof/profile/prune.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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.
-
-// Implements methods to remove frames from profiles.
-
-package profile
-
-import (
-	"fmt"
-	"regexp"
-)
-
-// Prune removes all nodes beneath a node matching dropRx, and not
-// matching keepRx. If the root node of a Sample matches, the sample
-// will have an empty stack.
-func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
-	prune := make(map[uint64]bool)
-	pruneBeneath := make(map[uint64]bool)
-
-	for _, loc := range p.Location {
-		var i int
-		for i = len(loc.Line) - 1; i >= 0; i-- {
-			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
-				funcName := fn.Name
-				// Account for leading '.' on the PPC ELF v1 ABI.
-				if funcName[0] == '.' {
-					funcName = funcName[1:]
-				}
-				if dropRx.MatchString(funcName) {
-					if keepRx == nil || !keepRx.MatchString(funcName) {
-						break
-					}
-				}
-			}
-		}
-
-		if i >= 0 {
-			// Found matching entry to prune.
-			pruneBeneath[loc.ID] = true
-
-			// Remove the matching location.
-			if i == len(loc.Line)-1 {
-				// Matched the top entry: prune the whole location.
-				prune[loc.ID] = true
-			} else {
-				loc.Line = loc.Line[i+1:]
-			}
-		}
-	}
-
-	// Prune locs from each Sample
-	for _, sample := range p.Sample {
-		// Scan from the root to the leaves to find the prune location.
-		// Do not prune frames before the first user frame, to avoid
-		// pruning everything.
-		foundUser := false
-		for i := len(sample.Location) - 1; i >= 0; i-- {
-			id := sample.Location[i].ID
-			if !prune[id] && !pruneBeneath[id] {
-				foundUser = true
-				continue
-			}
-			if !foundUser {
-				continue
-			}
-			if prune[id] {
-				sample.Location = sample.Location[i+1:]
-				break
-			}
-			if pruneBeneath[id] {
-				sample.Location = sample.Location[i:]
-				break
-			}
-		}
-	}
-}
-
-// RemoveUninteresting prunes and elides profiles using built-in
-// tables of uninteresting function names.
-func (p *Profile) RemoveUninteresting() error {
-	var keep, drop *regexp.Regexp
-	var err error
-
-	if p.DropFrames != "" {
-		if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
-			return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
-		}
-		if p.KeepFrames != "" {
-			if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
-				return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
-			}
-		}
-		p.Prune(drop, keep)
-	}
-	return nil
-}
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index 10384b6..1a13ac3 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -114,6 +114,19 @@
 	return true
 }
 
+// HasSrc reports whether the entire source tree is available under GOROOT.
+func HasSrc() bool {
+	switch runtime.GOOS {
+	case "nacl":
+		return false
+	case "darwin":
+		if strings.HasPrefix(runtime.GOARCH, "arm") {
+			return false
+		}
+	}
+	return true
+}
+
 // MustHaveExec checks that the current system can start new processes
 // using os.StartProcess or (more commonly) exec.Command.
 // If not, MustHaveExec calls t.Skip with an explanation.
@@ -138,6 +151,15 @@
 	}
 }
 
+var haveCGO bool
+
+// MustHaveCGO calls t.Skip if cgo is not available.
+func MustHaveCGO(t *testing.T) {
+	if !haveCGO {
+		t.Skipf("skipping test: no cgo")
+	}
+}
+
 // HasSymlink reports whether the current system can use os.Symlink.
 func HasSymlink() bool {
 	ok, _ := hasSymlink()
diff --git a/src/internal/testenv/testenv_cgo.go b/src/internal/testenv/testenv_cgo.go
new file mode 100644
index 0000000..e3d4d16
--- /dev/null
+++ b/src/internal/testenv/testenv_cgo.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go 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
+
+package testenv
+
+func init() {
+	haveCGO = true
+}
diff --git a/src/internal/testenv/testenv_windows.go b/src/internal/testenv/testenv_windows.go
index e593f64..eb8d6ac 100644
--- a/src/internal/testenv/testenv_windows.go
+++ b/src/internal/testenv/testenv_windows.go
@@ -30,7 +30,6 @@
 			winSymlinkErr = err
 		}
 	}
-	os.Remove("target")
 }
 
 func hasSymlink() (ok bool, reason string) {
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index efa8540..1dd3ef1 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -40,6 +40,7 @@
 	// for GoUnblock: the associated GoStart
 	// for blocking GoSysCall: the associated GoSysExit
 	// for GoSysExit: the next GoStart
+	// for GCMarkAssistStart: the associated GCMarkAssistDone
 	Link *Event
 }
 
@@ -127,7 +128,7 @@
 		return
 	}
 	switch ver {
-	case 1005, 1007, 1008:
+	case 1005, 1007, 1008, 1009:
 		// Note: When adding a new version, add canned traces
 		// from the old version to the test suite using mkcanned.bash.
 		break
@@ -501,10 +502,11 @@
 		gWaiting
 	)
 	type gdesc struct {
-		state    int
-		ev       *Event
-		evStart  *Event
-		evCreate *Event
+		state        int
+		ev           *Event
+		evStart      *Event
+		evCreate     *Event
+		evMarkAssist *Event
 	}
 	type pdesc struct {
 		running bool
@@ -579,6 +581,18 @@
 				return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
 			}
 			p.evSweep = ev
+		case EvGCMarkAssistStart:
+			if g.evMarkAssist != nil {
+				return fmt.Errorf("previous mark assist is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			g.evMarkAssist = ev
+		case EvGCMarkAssistDone:
+			// Unlike most events, mark assists can be in progress when a
+			// goroutine starts tracing, so we can't report an error here.
+			if g.evMarkAssist != nil {
+				g.evMarkAssist.Link = ev
+				g.evMarkAssist = nil
+			}
 		case EvGCSweepDone:
 			if p.evSweep == nil {
 				return fmt.Errorf("bogus sweeping end (offset %v, time %v)", ev.Off, ev.Ts)
@@ -835,16 +849,21 @@
 		if ver < 1007 {
 			narg++ // there was an unused arg before 1.7
 		}
+		return narg
+	}
+	narg++ // timestamp
+	if ver < 1007 {
+		narg++ // sequence
+	}
+	switch raw.typ {
+	case EvGCSweepDone:
+		if ver < 1009 {
+			narg -= 2 // 1.9 added two arguments
+		}
 	case EvGCStart, EvGoStart, EvGoUnblock:
 		if ver < 1007 {
 			narg-- // 1.7 added an additional seq arg
 		}
-		fallthrough
-	default:
-		narg++ // timestamp
-		if ver < 1007 {
-			narg++ // sequence
-		}
 	}
 	return narg
 }
@@ -853,52 +872,54 @@
 var BreakTimestampsForTesting bool
 
 // Event types in the trace.
-// Verbatim copy from src/runtime/trace.go.
+// Verbatim copy from src/runtime/trace.go with the "trace" prefix removed.
 const (
-	EvNone           = 0  // unused
-	EvBatch          = 1  // start of per-P batch of events [pid, timestamp]
-	EvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
-	EvStack          = 3  // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
-	EvGomaxprocs     = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
-	EvProcStart      = 5  // start of P [timestamp, thread id]
-	EvProcStop       = 6  // stop of P [timestamp]
-	EvGCStart        = 7  // GC start [timestamp, seq, stack id]
-	EvGCDone         = 8  // GC done [timestamp]
-	EvGCScanStart    = 9  // GC mark termination start [timestamp]
-	EvGCScanDone     = 10 // GC mark termination done [timestamp]
-	EvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
-	EvGCSweepDone    = 12 // GC sweep done [timestamp]
-	EvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
-	EvGoStart        = 14 // goroutine starts running [timestamp, goroutine id, seq]
-	EvGoEnd          = 15 // goroutine ends [timestamp]
-	EvGoStop         = 16 // goroutine stops (like in select{}) [timestamp, stack]
-	EvGoSched        = 17 // goroutine calls Gosched [timestamp, stack]
-	EvGoPreempt      = 18 // goroutine is preempted [timestamp, stack]
-	EvGoSleep        = 19 // goroutine calls Sleep [timestamp, stack]
-	EvGoBlock        = 20 // goroutine blocks [timestamp, stack]
-	EvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack]
-	EvGoBlockSend    = 22 // goroutine blocks on chan send [timestamp, stack]
-	EvGoBlockRecv    = 23 // goroutine blocks on chan recv [timestamp, stack]
-	EvGoBlockSelect  = 24 // goroutine blocks on select [timestamp, stack]
-	EvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
-	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, seq, real timestamp]
-	EvGoSysBlock     = 30 // syscall blocks [timestamp]
-	EvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
-	EvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id]
-	EvHeapAlloc      = 33 // memstats.heap_live change [timestamp, heap_alloc]
-	EvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
-	EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
-	EvFutileWakeup   = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
-	EvString         = 37 // string dictionary entry [ID, length, string]
-	EvGoStartLocal   = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
-	EvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
-	EvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
-	EvGoStartLabel   = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
-	EvGoBlockGC      = 42 // goroutine blocks on GC assist [timestamp, stack]
-	EvCount          = 43
+	EvNone              = 0  // unused
+	EvBatch             = 1  // start of per-P batch of events [pid, timestamp]
+	EvFrequency         = 2  // contains tracer timer frequency [frequency (ticks per second)]
+	EvStack             = 3  // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
+	EvGomaxprocs        = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
+	EvProcStart         = 5  // start of P [timestamp, thread id]
+	EvProcStop          = 6  // stop of P [timestamp]
+	EvGCStart           = 7  // GC start [timestamp, seq, stack id]
+	EvGCDone            = 8  // GC done [timestamp]
+	EvGCScanStart       = 9  // GC mark termination start [timestamp]
+	EvGCScanDone        = 10 // GC mark termination done [timestamp]
+	EvGCSweepStart      = 11 // GC sweep start [timestamp, stack id]
+	EvGCSweepDone       = 12 // GC sweep done [timestamp, swept, reclaimed]
+	EvGoCreate          = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
+	EvGoStart           = 14 // goroutine starts running [timestamp, goroutine id, seq]
+	EvGoEnd             = 15 // goroutine ends [timestamp]
+	EvGoStop            = 16 // goroutine stops (like in select{}) [timestamp, stack]
+	EvGoSched           = 17 // goroutine calls Gosched [timestamp, stack]
+	EvGoPreempt         = 18 // goroutine is preempted [timestamp, stack]
+	EvGoSleep           = 19 // goroutine calls Sleep [timestamp, stack]
+	EvGoBlock           = 20 // goroutine blocks [timestamp, stack]
+	EvGoUnblock         = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack]
+	EvGoBlockSend       = 22 // goroutine blocks on chan send [timestamp, stack]
+	EvGoBlockRecv       = 23 // goroutine blocks on chan recv [timestamp, stack]
+	EvGoBlockSelect     = 24 // goroutine blocks on select [timestamp, stack]
+	EvGoBlockSync       = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+	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, seq, real timestamp]
+	EvGoSysBlock        = 30 // syscall blocks [timestamp]
+	EvGoWaiting         = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
+	EvGoInSyscall       = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id]
+	EvHeapAlloc         = 33 // memstats.heap_live change [timestamp, heap_alloc]
+	EvNextGC            = 34 // memstats.next_gc change [timestamp, next_gc]
+	EvTimerGoroutine    = 35 // denotes timer goroutine [timer goroutine id]
+	EvFutileWakeup      = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
+	EvString            = 37 // string dictionary entry [ID, length, string]
+	EvGoStartLocal      = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
+	EvGoUnblockLocal    = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
+	EvGoSysExitLocal    = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
+	EvGoStartLabel      = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id]
+	EvGoBlockGC         = 42 // goroutine blocks on GC assist [timestamp, stack]
+	EvGCMarkAssistStart = 43 // GC mark assist start [timestamp, stack]
+	EvGCMarkAssistDone  = 44 // GC mark assist done [timestamp]
+	EvCount             = 45
 )
 
 var EventDescriptions = [EvCount]struct {
@@ -907,47 +928,49 @@
 	Stack      bool
 	Args       []string
 }{
-	EvNone:           {"None", 1005, false, []string{}},
-	EvBatch:          {"Batch", 1005, false, []string{"p", "ticks"}}, // in 1.5 format it was {"p", "seq", "ticks"}
-	EvFrequency:      {"Frequency", 1005, false, []string{"freq"}},   // in 1.5 format it was {"freq", "unused"}
-	EvStack:          {"Stack", 1005, false, []string{"id", "siz"}},
-	EvGomaxprocs:     {"Gomaxprocs", 1005, true, []string{"procs"}},
-	EvProcStart:      {"ProcStart", 1005, false, []string{"thread"}},
-	EvProcStop:       {"ProcStop", 1005, false, []string{}},
-	EvGCStart:        {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {}
-	EvGCDone:         {"GCDone", 1005, false, []string{}},
-	EvGCScanStart:    {"GCScanStart", 1005, false, []string{}},
-	EvGCScanDone:     {"GCScanDone", 1005, false, []string{}},
-	EvGCSweepStart:   {"GCSweepStart", 1005, true, []string{}},
-	EvGCSweepDone:    {"GCSweepDone", 1005, false, []string{}},
-	EvGoCreate:       {"GoCreate", 1005, true, []string{"g", "stack"}},
-	EvGoStart:        {"GoStart", 1005, false, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
-	EvGoEnd:          {"GoEnd", 1005, false, []string{}},
-	EvGoStop:         {"GoStop", 1005, true, []string{}},
-	EvGoSched:        {"GoSched", 1005, true, []string{}},
-	EvGoPreempt:      {"GoPreempt", 1005, true, []string{}},
-	EvGoSleep:        {"GoSleep", 1005, true, []string{}},
-	EvGoBlock:        {"GoBlock", 1005, true, []string{}},
-	EvGoUnblock:      {"GoUnblock", 1005, true, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
-	EvGoBlockSend:    {"GoBlockSend", 1005, true, []string{}},
-	EvGoBlockRecv:    {"GoBlockRecv", 1005, true, []string{}},
-	EvGoBlockSelect:  {"GoBlockSelect", 1005, true, []string{}},
-	EvGoBlockSync:    {"GoBlockSync", 1005, true, []string{}},
-	EvGoBlockCond:    {"GoBlockCond", 1005, true, []string{}},
-	EvGoBlockNet:     {"GoBlockNet", 1005, true, []string{}},
-	EvGoSysCall:      {"GoSysCall", 1005, true, []string{}},
-	EvGoSysExit:      {"GoSysExit", 1005, false, []string{"g", "seq", "ts"}},
-	EvGoSysBlock:     {"GoSysBlock", 1005, false, []string{}},
-	EvGoWaiting:      {"GoWaiting", 1005, false, []string{"g"}},
-	EvGoInSyscall:    {"GoInSyscall", 1005, false, []string{"g"}},
-	EvHeapAlloc:      {"HeapAlloc", 1005, false, []string{"mem"}},
-	EvNextGC:         {"NextGC", 1005, false, []string{"mem"}},
-	EvTimerGoroutine: {"TimerGoroutine", 1005, false, []string{"g"}}, // in 1.5 format it was {"g", "unused"}
-	EvFutileWakeup:   {"FutileWakeup", 1005, false, []string{}},
-	EvString:         {"String", 1007, false, []string{}},
-	EvGoStartLocal:   {"GoStartLocal", 1007, false, []string{"g"}},
-	EvGoUnblockLocal: {"GoUnblockLocal", 1007, true, []string{"g"}},
-	EvGoSysExitLocal: {"GoSysExitLocal", 1007, false, []string{"g", "ts"}},
-	EvGoStartLabel:   {"GoStartLabel", 1008, false, []string{"g", "seq", "label"}},
-	EvGoBlockGC:      {"GoBlockGC", 1008, true, []string{}},
+	EvNone:              {"None", 1005, false, []string{}},
+	EvBatch:             {"Batch", 1005, false, []string{"p", "ticks"}}, // in 1.5 format it was {"p", "seq", "ticks"}
+	EvFrequency:         {"Frequency", 1005, false, []string{"freq"}},   // in 1.5 format it was {"freq", "unused"}
+	EvStack:             {"Stack", 1005, false, []string{"id", "siz"}},
+	EvGomaxprocs:        {"Gomaxprocs", 1005, true, []string{"procs"}},
+	EvProcStart:         {"ProcStart", 1005, false, []string{"thread"}},
+	EvProcStop:          {"ProcStop", 1005, false, []string{}},
+	EvGCStart:           {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {}
+	EvGCDone:            {"GCDone", 1005, false, []string{}},
+	EvGCScanStart:       {"GCScanStart", 1005, false, []string{}},
+	EvGCScanDone:        {"GCScanDone", 1005, false, []string{}},
+	EvGCSweepStart:      {"GCSweepStart", 1005, true, []string{}},
+	EvGCSweepDone:       {"GCSweepDone", 1005, false, []string{"swept", "reclaimed"}}, // before 1.9, format was {}
+	EvGoCreate:          {"GoCreate", 1005, true, []string{"g", "stack"}},
+	EvGoStart:           {"GoStart", 1005, false, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+	EvGoEnd:             {"GoEnd", 1005, false, []string{}},
+	EvGoStop:            {"GoStop", 1005, true, []string{}},
+	EvGoSched:           {"GoSched", 1005, true, []string{}},
+	EvGoPreempt:         {"GoPreempt", 1005, true, []string{}},
+	EvGoSleep:           {"GoSleep", 1005, true, []string{}},
+	EvGoBlock:           {"GoBlock", 1005, true, []string{}},
+	EvGoUnblock:         {"GoUnblock", 1005, true, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+	EvGoBlockSend:       {"GoBlockSend", 1005, true, []string{}},
+	EvGoBlockRecv:       {"GoBlockRecv", 1005, true, []string{}},
+	EvGoBlockSelect:     {"GoBlockSelect", 1005, true, []string{}},
+	EvGoBlockSync:       {"GoBlockSync", 1005, true, []string{}},
+	EvGoBlockCond:       {"GoBlockCond", 1005, true, []string{}},
+	EvGoBlockNet:        {"GoBlockNet", 1005, true, []string{}},
+	EvGoSysCall:         {"GoSysCall", 1005, true, []string{}},
+	EvGoSysExit:         {"GoSysExit", 1005, false, []string{"g", "seq", "ts"}},
+	EvGoSysBlock:        {"GoSysBlock", 1005, false, []string{}},
+	EvGoWaiting:         {"GoWaiting", 1005, false, []string{"g"}},
+	EvGoInSyscall:       {"GoInSyscall", 1005, false, []string{"g"}},
+	EvHeapAlloc:         {"HeapAlloc", 1005, false, []string{"mem"}},
+	EvNextGC:            {"NextGC", 1005, false, []string{"mem"}},
+	EvTimerGoroutine:    {"TimerGoroutine", 1005, false, []string{"g"}}, // in 1.5 format it was {"g", "unused"}
+	EvFutileWakeup:      {"FutileWakeup", 1005, false, []string{}},
+	EvString:            {"String", 1007, false, []string{}},
+	EvGoStartLocal:      {"GoStartLocal", 1007, false, []string{"g"}},
+	EvGoUnblockLocal:    {"GoUnblockLocal", 1007, true, []string{"g"}},
+	EvGoSysExitLocal:    {"GoSysExitLocal", 1007, false, []string{"g", "ts"}},
+	EvGoStartLabel:      {"GoStartLabel", 1008, false, []string{"g", "seq", "label"}},
+	EvGoBlockGC:         {"GoBlockGC", 1008, true, []string{}},
+	EvGCMarkAssistStart: {"GCMarkAssistStart", 1009, true, []string{}},
+	EvGCMarkAssistDone:  {"GCMarkAssistDone", 1009, false, []string{}},
 }
diff --git a/src/internal/trace/testdata/http_1_9_good b/src/internal/trace/testdata/http_1_9_good
new file mode 100644
index 0000000..ca89278
--- /dev/null
+++ b/src/internal/trace/testdata/http_1_9_good
Binary files differ
diff --git a/src/internal/trace/testdata/stress_1_9_good b/src/internal/trace/testdata/stress_1_9_good
new file mode 100644
index 0000000..dcf17f1
--- /dev/null
+++ b/src/internal/trace/testdata/stress_1_9_good
Binary files differ
diff --git a/src/internal/trace/testdata/stress_start_stop_1_9_good b/src/internal/trace/testdata/stress_start_stop_1_9_good
new file mode 100644
index 0000000..f00f190
--- /dev/null
+++ b/src/internal/trace/testdata/stress_start_stop_1_9_good
Binary files differ
diff --git a/src/internal/trace/writer.go b/src/internal/trace/writer.go
index a481f50..af5fec8 100644
--- a/src/internal/trace/writer.go
+++ b/src/internal/trace/writer.go
@@ -9,7 +9,7 @@
 
 func NewWriter() *Writer {
 	w := new(Writer)
-	w.Write([]byte("go 1.7 trace\x00\x00\x00\x00"))
+	w.Write([]byte("go 1.9 trace\x00\x00\x00\x00"))
 	return w
 }