[SCM] Packaging for Google Go branch, weekly-debian-sid, updated. debian-weekly/2011.06.09-2-25-gbd93d2f

Ondřej Surý ondrej at sury.org
Wed Aug 10 13:41:09 UTC 2011


The following commit has been merged in the weekly-debian-sid branch:
commit b757d264230d65f988e08158e096a09497d39eb4
Author: Ondřej Surý <ondrej at sury.org>
Date:   Wed Aug 3 17:26:15 2011 +0200

    Imported Upstream version 2011.07.29

diff --git a/AUTHORS b/AUTHORS
index f9af1a7..b507252 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -28,6 +28,7 @@ Aron Nopanen <aron.nopanen at gmail.com>
 Arvindh Rajesh Tamilmani <art at a-30.net>
 Ben Olive <sionide21 at gmail.com>
 Benny Siegert <bsiegert at gmail.com>
+Bobby Powers <bobbypowers at gmail.com>
 Caine Tighe <arctanofyourface at gmail.com>
 Charles L. Dorian <cldorian at gmail.com>
 Chris Dollin <ehog.hedge at gmail.com>
@@ -80,6 +81,7 @@ Jeff Hodges <jeff at somethingsimilar.com>
 Jeff R. Allen <jra at nella.org>
 Jim McGrath <jimmc2 at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
+John Asmuth <jasmuth at gmail.com>
 Jonathan Mark <jhmark at xenops.com>
 Jonathan Wills <runningwild at gmail.com>
 Jose Luis Vázquez González <josvazg at gmail.com>
@@ -100,6 +102,7 @@ Luit van Drongelen <luitvd at gmail.com>
 Markus Duft <markus.duft at salomon.at>
 Martin Neubauer <m.ne at gmx.net>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
+Matthew Horsnell <matthew.horsnell at gmail.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
 Michael Hoisie <hoisie at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 8bb57f9..fe38c03 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -59,6 +59,7 @@ Ben Olive <sionide21 at gmail.com>
 Benny Siegert <bsiegert at gmail.com>
 Berengar Lehr <Berengar.Lehr at gmx.de>
 Bill Neubauer <wcn at golang.org> <wcn at google.com>
+Bobby Powers <bobbypowers at gmail.com>
 Brad Fitzpatrick <bradfitz at golang.org> <bradfitz at gmail.com>
 Brendan O'Dea <bod at golang.org>
 Caine Tighe <arctanofyourface at gmail.com>
@@ -94,6 +95,7 @@ Eivind Uggedal <eivind at uggedal.com>
 Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
 Eric Eisner <eric.d.eisner at gmail.com>
+Evan Martin <evan.martin at gmail.com>
 Evan Shaw <chickencha at gmail.com>
 Fan Hongjian <fan.howard at gmail.com>
 Fazlul Shahriar <fshahriar at gmail.com>
@@ -124,7 +126,9 @@ Jeff Hodges <jeff at somethingsimilar.com>
 Jeff R. Allen <jra at nella.org> <jeff.allen at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
+Joel Sing <jsing at google.com>
 Johan Euphrosine <proppy at google.com>
+John Asmuth <jasmuth at gmail.com>
 John DeNero <denero at google.com>
 Jonathan Allie <jonallie at google.com>
 Jonathan Mark <jhmark at xenops.com> <jhmark000 at gmail.com>
@@ -155,6 +159,7 @@ Markus Duft <markus.duft at salomon.at>
 Martin Neubauer <m.ne at gmx.net>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Matt Jones <mrjones at google.com>
+Matthew Horsnell <matthew.horsnell at gmail.com>
 Maxim Ushakov <ushakov at google.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
@@ -162,6 +167,7 @@ Michael Hoisie <hoisie at gmail.com>
 Michael T. Jones <mtj at google.com> <michael.jones at gmail.com>
 Miek Gieben <miek at miek.nl> <remigius.gieben at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
+Mike Solomon <msolo at gmail.com>
 Mikio Hara <mikioh.mikioh at gmail.com>
 Mikkel Krautz <mikkel at krautz.dk> <krautz at gmail.com>
 Moriyoshi Koizumi <mozo at mozo.jp>
diff --git a/doc/Makefile b/doc/Makefile
index d992a39..e4e3f83 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -4,8 +4,8 @@
 
 include ../src/Make.inc
 
-TARG=htmlgen
+TARG=tmpltohtml
 GOFILES=\
-	htmlgen.go\
+	tmpltohtml.go\
 
 include ../src/Make.cmd
diff --git a/doc/all.css b/doc/all.css
index a985d8f..f8f8c65 100644
--- a/doc/all.css
+++ b/doc/all.css
@@ -135,7 +135,6 @@ h1#title {
   clear: both;
 }
 #content h1 {
-  margin-bottom: -0em;
   padding: 0;
 }
 #content h2 {
diff --git a/doc/devel/release.html b/doc/devel/release.html
index d632200..e1a1cab 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -86,6 +86,14 @@ the Go tree (and avoid writing Makefiles).
 </p>
 
 
+<h3 id="r58.minor">Minor revisions</h3>
+
+<p>r58.1 adds 
+<a href="http://code.google.com/p/go/source/detail?r=293c25943586">build</a> and
+<a href="http://code.google.com/p/go/source/detail?r=bf17e96b6582">runtime</a>
+changes to make Go run on OS X 10.7 Lion.
+</p>
+
 <h2 id="r57">r57 (released 2011/05/03)</h2>
 
 <p>
diff --git a/doc/devel/weekly.html b/doc/devel/weekly.html
index bf16c83..3ee0247 100644
--- a/doc/devel/weekly.html
+++ b/doc/devel/weekly.html
@@ -14,6 +14,171 @@ hg pull
 hg update weekly.<i>YYYY-MM-DD</i>
 </pre>
 
+<h2 id="2011-07-29">2011-07-29</h2>
+
+<pre>
+This weekly contains performance improvements and many bug fixes.
+
+* 6l: OpenBSD support.
+* archive/zip: handle zip files with more than 65535 files,
+	more efficient reader and bug fix.
+* big: refine printf formatting and optimize string conversion.
+* build: fixes for mingw-w64 (thanks Wei Guangjing),
+	miscellaneous fixes.
+* cgo: add GoBytes, fix gmp example.
+* exp/norm: API for normalization library.
+* exp/regexp: implement regexp API using exp/regexp/syntax.
+* exp/template: more tweaks and fixes, convert the tree to use exp/template.
+* fmt: handle precision 0 format strings in standard way.
+* gc: a raft of bug fixes.
+* go/parser: report illegal label declarations at ':'.
+* gob: send empty but non-nil maps.
+* godoc: allow form feed in text files,
+	app engine configuration and updated documentation.
+* goinstall: abort and warn when using any url scheme, not just 'http://',
+	write to goinstall.log in respective GOPATH.
+* html: handle character entities without semicolons (thanks Andrew Balholm),
+	parse misnested formatting tags according to the HTML5 spec,
+	sync html/testdata/webkit with upstream WebKit.
+* http: content-type sniffing,
+	make serveFile redirects relative (thanks Andrew Balholm),
+	other fixes.
+* image/tiff: Do not panic when RowsPerStrip is missing (thanks Benny Siegert).
+* io/ioutil: improve performance of ioutil.Discard (thanks Mike Solomon).
+* ld: detect all import cycles,
+	ldpe fixes (thanks Wei Guangjing),
+	remove cseekend and redo pe writing (thanks Alex Brainman),
+	remove overlap of ELF sections on dynamic binaries (thanks Gustavo Niemeyer).
+* net/textproto: avoid 1 copy in ReadLine, ReadContinuedLine.
+* net: fix memory corruption in windows *netFD.ReadFrom (thanks Alex Brainman).
+* runtime: faster entersyscall/exitsyscall,
+	fix scheduler races (thanks Hector Chu),
+	higher goroutine arg limit, clearer error,
+	parallelism-related performance optimizations and fixes,
+	replace byte-at-a-time zeroing loop with memclr (thanks Quan Yong Zhai).
+* sort: fix Float64Slice sort; NaN smallest value (thanks Florian Uekermann).
+* src: removed some uses of container/vector (thanks John Asmuth).
+* sync: improve Once fast path.
+* unicode: fix case-mapping for roman numerals.
+</pre>
+
+<h2 id="2011-07-19">2011-07-19</h2>
+
+<pre>
+This weekly snapshot includes a language change and a change to the image
+package that may require changes to client code.
+
+The language change is that an "else" block is now required to have braces
+except if the body of the "else" is another "if". Since gofmt always puts those
+braces in anyway, programs will not be affected unless they contain "else for",
+"else switch", or "else select". Run gofmt to fix any such programs.
+
+The image package has had significant changes made to the Pix field of struct
+types such as image.RGBA and image.NRGBA. The image.Image interface type has
+not changed, though, and you should not need to change your code if you don't
+explicitly refer to Pix fields. For example, if you decode a number of images
+using the image/jpeg package, compose them using image/draw, and then encode
+the result using image/png, then your code should still work as before.
+
+If you do explicitly refer to Pix fields, there are two changes.  First, Pix[0]
+now refers to the pixel at Bounds().Min instead of the pixel at (0, 0). Second,
+the element type of the Pix slice is now uint8 instead of image.FooColor. For
+example, for an image.RGBA, the channel values will be packed R, G, B, A, R, G,
+B, A, etc. For 16-bits-per-channel color types, the pixel data will be stored
+as big-endian uint8s.
+
+Most Pix field types have changed, and so if your code still compiles after
+this change, then you probably don't need to make any further changes (unless
+you use an image.Paletted's Pix field). If you do get compiler errors, code
+that used to look like this:
+
+	// Get the R, G, B, A values for the pixel at (x, y).
+	var m *image.RGBA = loadAnImage()
+	c := m.Pix[y*m.Stride + x]
+	r, g, b, a := c.R, c.G, c.B, c.A
+
+should now look like this:
+
+	// Get the R, G, B, A values for the pixel at (x, y).
+	var m *image.RGBA = loadAnImage()
+	i := (y-m.Rect.Min.Y)*m.Stride + (x-m.Rect.Min.X)*4
+	r := m.Pix[i+0]
+	g := m.Pix[i+1]
+	b := m.Pix[i+2]
+	a := m.Pix[i+3]
+
+This image package change will not be fixed by gofix: how best to translate
+code into something efficient and idiomatic depends on the surrounding context,
+and is not easily automatable. Examples of what to do can be found in the
+changes to image/draw/draw.go in http://codereview.appspot.com/4675076/
+
+Other changes:
+* 6l: change default output name to 6.out.exe on windows (thanks Alex Brainman).
+* archive/zip: add Writer,
+	add Mtime_ns function to get modified time in sensible format.
+* cc, ld, gc: fixes for Plan 9 build (thanks Lucio De Re).
+* cgi: close stdout reader pipe when finished.
+* cgo: add missing semicolon in generated struct,
+	windows amd64 port (thanks Wei Guangjing).
+* codereview: fix for Mercurial 1.9.
+* dashboard: list "most installed this week" with rolling count.
+* debug/elf: read ELF Program headers (thanks Matthew Horsnell).
+* debug/pe: fixes ImportedSymbols for Win64 (thanks Wei Guangjing).
+* debug/proc: remove unused package.
+* doc/talks/io2010: update with gofix and handle the errors.
+* exp/eval, exp/ogle: remove packages eval and ogle.
+* exp/regexp/syntax: add Prog.NumCap.
+* exp/template: API changes, bug fixes, and tweaks.
+* flag: make -help nicer.
+* fmt: Scan(&int) was mishandling a lone digit.
+* gc: fix closure bug,
+	fix to build with clang (thanks Dave Cheney),
+	make size of struct{} and [0]byte 0 bytes (thanks Robert Hencke),
+	some enhancements to printing debug info.
+* gif: fix local color map and coordinates.
+* go/build: fixes for windows (thanks Alex Brainman),
+	include processing of .c files for cgo packages (thanks Alex Brainman),
+	less aggressive failure when GOROOT not found.
+* go/printer: changed max. number of newlines from 3 to 2.
+* gob: register more slice types (thanks Bobby Powers).
+* godoc: support for file systems stored in .zip files.
+* goinstall, dashboard: Google Code now supports git (thanks Tarmigan Casebolt).
+* hash/crc32: add SSE4.2 support.
+* html: update section references in comments to the latest HTML5 spec.
+* http: drain the pipe output in TestHandlerPanic to avoid logging deadlock,
+	fix Content-Type of file extension (thanks Yasuhiro Matsumoto),
+	implement http.FileSystem for zip files,
+	let FileServer work when path doesn't begin with a slash,
+	support for periodic flushing in ReverseProxy.
+* image/draw: add benchmarks.
+* json: add omitempty struct tag option,
+	allow using '$' and '-' as the struct field's tag (thanks Mikio Hara),
+	encode \r and \n in strings as e.g. "\n", not "\u000A" (thanks Evan Martin),
+	escape < and > in any JSON string for XSS prevention.
+* ld: allow seek within write buffer<
+	add a PT_LOAD PHDR entry for the PHDR (thanks David Anderson).
+* net: windows/amd64 port (thanks Wei Guangjing).
+* os: plan9: add Process.Signal as a way to send notes (thanks Yuval Pavel Zholkover).
+* os: don't permit Process.Signal after a successful Wait.
+* path/filepath: fixes for windows paths (thanks Alex Brainman).
+* reflect: add Value.NumMethod,
+	panic if Method index is out of range for a type.
+* runtime: faster entersyscall, exitsyscall,
+	fix panic for make(chan [0]byte),
+	fix subtle select bug (thanks Hector Chu),
+	make goc2c build on Plan 9 (thanks Lucio De Re),
+	make TestSideEffectOrder work twice,
+	several parallelism-related optimizations and fixes,
+	stdcall_raw stack 16byte align for Win64 (thanks Wei Guangjing),
+	string-related optimizations (thanks Quan Yong Zhai),
+	track running goroutine count.
+* strconv: handle [-+]Infinity in atof.
+* sync: add fast paths to WaitGroup,
+	improve RWMutex performance.
+* syscall: add Flock on Linux,
+	parse and encode SCM_RIGHTS and SCM_CREDENTIALS (thanks Albert Strasheim).
+</pre>
+
 <h2 id="2011-07-07">2011-07-07</h2>
 
 <pre>
@@ -190,7 +355,7 @@ require changes to client code.
 The sort.IntArray type has been renamed to IntSlice, and similarly for
 StringArray and Float64Array.
 
-The image/draw package’s Draw function now takes an additional argument,
+The image/draw package's Draw function now takes an additional argument,
 a compositing operator. If in doubt, use draw.Over.
 
 Other changes:
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 2ecef44..296939e 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -116,7 +116,7 @@ Some formatting details remain.  Very briefly,
     <dt>Parentheses</dt>
     <dd>
     Go needs fewer parentheses: control structures (<code>if</code>,
-    <code>for</code>, <code>switch</code>) do not require parentheses in
+    <code>for</code>, <code>switch</code>) do not have parentheses in
     their syntax.
     Also, the operator precedence hierarchy is shorter and clearer, so
 <pre>
@@ -405,7 +405,7 @@ break continue fallthrough return ++ -- ) }
 <p>
 the lexer always inserts a semicolon after the token.
 This could be summarized as, “if the newline comes
-after a token that could end a statement, add a semicolon”.
+after a token that could end a statement, insert a semicolon”.
 </p>
 
 <p>
@@ -461,7 +461,7 @@ initialization statement like that of <code>for</code>;
 and there are new control structures including a type switch and a
 multiway communications multiplexer, <code>select</code>.
 The syntax is also slightly different:
-parentheses are not required
+there are no parentheses
 and the bodies must always be brace-delimited.
 </p>
 
@@ -564,7 +564,7 @@ for i := 0; i < 10; i++ {
 <p>
 If you're looping over an array, slice, string, or map,
 or reading from a channel, a <code>range</code> clause can
-manage the loop for you.
+manage the loop.
 </p>
 <pre>
 var m map[string]int
@@ -943,8 +943,11 @@ Go has two allocation primitives, the built-in functions
 They do different things and apply to different types, which can be confusing,
 but the rules are simple.
 Let's talk about <code>new</code> first.
-It's a built-in function essentially the same as its namesakes
-in other languages: <code>new(T)</code> allocates zeroed storage for a new item of type
+It's a built-in function that allocates memory, but unlike its namesakes
+in some other languages it does not <em>initialize</em> the memory,
+it only <em>zeroes</em> it.
+That is,
+<code>new(T)</code> allocates zeroed storage for a new item of type
 <code>T</code> and returns its address, a value of type <code>*T</code>.
 In Go terminology, it returns a pointer to a newly allocated zero value of type
 <code>T</code>.
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 489ad4d..82c7ed4 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,5 +1,5 @@
 <!-- title The Go Programming Language Specification -->
-<!-- subtitle Version of June 17, 2011 -->
+<!-- subtitle Version of July 14, 2011 -->
 
 <!--
 TODO
@@ -3762,7 +3762,7 @@ present, the "else" branch is executed.
 </p>
 
 <pre class="ebnf">
-IfStmt    = "if" [ SimpleStmt ";" ] Expression Block [ "else" Statement ] .
+IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
 </pre>
 
 <pre>
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html
index 822f962..0b366bb 100644
--- a/doc/go_tutorial.html
+++ b/doc/go_tutorial.html
@@ -19,17 +19,14 @@ The presentation here proceeds through a series of modest programs to illustrate
 key features of the language.  All the programs work (at time of writing) and are
 checked into the repository in the directory <a href='/doc/progs'><code>/doc/progs/</code></a>.
 <p>
-Program snippets are annotated with the line number in the original file; for
-cleanliness, blank lines remain blank.
-<p>
 <h2>Hello, World</h2>
 <p>
 Let's start in the usual way:
 <p>
-<pre><!-- progs/helloworld.go /package/ $
+<pre><!--{{code "progs/helloworld.go" `/package/` "$"}}
 -->package main
 
-import fmt "fmt"  // Package implementing formatted I/O.
+import fmt "fmt" // Package implementing formatted I/O.
 
 func main() {
     fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
@@ -116,23 +113,23 @@ $
 <p>
 Next up, here's a version of the Unix utility <code>echo(1)</code>:
 <p>
-<pre><!-- progs/echo.go /package/ $
+<pre><!--{{code "progs/echo.go" `/package/` "$"}}
 -->package main
 
 import (
     "os"
-    "flag"  // command line option parser
+    "flag" // command line option parser
 )
 
 var omitNewline = flag.Bool("n", false, "don't print final newline")
 
 const (
-    Space = " "
+    Space   = " "
     Newline = "\n"
 )
 
 func main() {
-    flag.Parse()   // Scans the arg list and sets up flags
+    flag.Parse() // Scans the arg list and sets up flags
     var s string = ""
     for i := 0; i < flag.NArg(); i++ {
         if i > 0 {
@@ -176,12 +173,13 @@ a naming conflict.
 <p>
 Given <code>os.Stdout</code> we can use its <code>WriteString</code> method to print the string.
 <p>
-Having imported the <code>flag</code> package, line 12 creates a global variable to hold
-the value of echo's <code>-n</code> flag. The variable <code>omitNewline</code> has type <code>*bool</code>, pointer
-to <code>bool</code>.
+After importing the <code>flag</code> package, we use a <code>var</code> declaration
+to create and initialize a global variable, called <code>omitNewline</code>,
+to hold the value of echo's <code>-n</code> flag. 
+The variable  has type <code>*bool</code>, pointer to <code>bool</code>.
 <p>
-In <code>main.main</code>, we parse the arguments (line 20) and then create a local
-string variable we will use to build the output.
+In <code>main.main</code>, we parse the arguments (the call to <code>flag.Parse</code>) and then create a local
+string variable with which to build the output.
 <p>
 The declaration statement has the form
 <p>
@@ -209,7 +207,7 @@ s := ""
 The <code>:=</code> operator is used a lot in Go to represent an initializing declaration.
 There's one in the <code>for</code> clause on the next line:
 <p>
-<pre><!--  progs/echo.go /for/
+<pre><!--{{code "progs/echo.go" `/for/`}}
 -->    for i := 0; i < flag.NArg(); i++ {
 </pre>
 <p>
@@ -259,9 +257,11 @@ Once you've built a string <i>value</i>, you can't change it, although
 of course you can change a string <i>variable</i> simply by
 reassigning it.  This snippet from <code>strings.go</code> is legal code:
 <p>
-<pre><!-- progs/strings.go /hello/ /ciao/
+<pre><!--{{code "progs/strings.go" `/hello/` `/ciao/`}}
 -->    s := "hello"
-    if s[1] != 'e' { os.Exit(1) }
+    if s[1] != 'e' {
+        os.Exit(1)
+    }
     s = "good bye"
     var p *string = &s
     *p = "ciao"
@@ -330,7 +330,7 @@ will slice the whole array.
 <p>
 Using slices one can write this function (from <code>sum.go</code>):
 <p>
-<pre><!-- progs/sum.go /sum/ /^}/
+<pre><!--{{code "progs/sum.go" `/sum/` `/^}/`}}
 -->func sum(a []int) int { // returns an int
     s := 0
     for i := 0; i < len(a); i++ {
@@ -476,7 +476,7 @@ assigned to a variable.
 Next we'll look at a simple package for doing file I/O with an
 open/close/read/write interface.  Here's the start of <code>file.go</code>:
 <p>
-<pre><!-- progs/file.go /package/ /^}/
+<pre><!--{{code "progs/file.go" `/package/` `/^}/`}}
 -->package file
 
 import (
@@ -518,7 +518,7 @@ will soon give it some exported, upper-case methods.
 <p>
 First, though, here is a factory to create a <code>File</code>:
 <p>
-<pre><!-- progs/file.go /newFile/ /^}/
+<pre><!--{{code "progs/file.go" `/newFile/` `/^}/`}}
 -->func newFile(fd int, name string) *File {
     if fd < 0 {
         return nil
@@ -540,11 +540,11 @@ return n
 </pre>
 <p>
 but for simple structures like <code>File</code> it's easier to return the address of a 
-composite literal, as is done here on line 21.
+composite literal, as is done here in the <code>return</code> statement from <code>newFile</code>.
 <p>
 We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
 <p>
-<pre><!-- progs/file.go /var/ /^.$/
+<pre><!--{{code "progs/file.go" `/var/` `/^.$/`}}
 -->var (
     Stdin  = newFile(syscall.Stdin, "/dev/stdin")
     Stdout = newFile(syscall.Stdout, "/dev/stdout")
@@ -556,7 +556,7 @@ We can use the factory to construct some familiar, exported variables of type <c
 The <code>newFile</code> function was not exported because it's internal. The proper,
 exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
 <p>
-<pre><!-- progs/file.go /func.OpenFile/ /^}/
+<pre><!--{{code "progs/file.go" `/func.OpenFile/` `/^}/`}}
 -->func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) {
     r, e := syscall.Open(name, mode, perm)
     if e != 0 {
@@ -573,9 +573,9 @@ multi-value return as a parenthesized list of declarations; syntactically
 they look just like a second parameter list.  The function
 <code>syscall.Open</code>
 also has a multi-value return, which we can grab with the multi-variable
-declaration on line 31; it declares <code>r</code> and <code>e</code> to hold the two values,
+declaration on the first line; it declares <code>r</code> and <code>e</code> to hold the two values,
 both of type <code>int</code> (although you'd have to look at the <code>syscall</code> package
-to see that).  Finally, line 35 returns two values: a pointer to the new <code>File</code>
+to see that).  Finally, <code>OpenFile</code> returns two values: a pointer to the new <code>File</code>
 and the error.  If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
 be negative and <code>newFile</code> will return <code>nil</code>.
 <p>
@@ -594,7 +594,7 @@ the implementation of our <code>Open</code> and <code>Create</code>; they're tri
 wrappers that eliminate common errors by capturing
 the tricky standard arguments to open and, especially, to create a file:
 <p>
-<pre><!-- progs/file.go /^const/ /^}/
+<pre><!--{{code "progs/file.go" `/^const/` `/^}/`}}
 -->const (
     O_RDONLY = syscall.O_RDONLY
     O_RDWR   = syscall.O_RDWR
@@ -607,7 +607,7 @@ func Open(name string) (file *File, err os.Error) {
 }
 </pre>
 <p>
-<pre><!-- progs/file.go /func.Create/ /^}/
+<pre><!--{{code "progs/file.go" `/func.Create/` `/^}/`}}
 -->func Create(name string) (file *File, err os.Error) {
     return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
 }
@@ -620,13 +620,13 @@ of that type, placed
 in parentheses before the function name. Here are some methods for <code>*File</code>,
 each of which declares a receiver variable <code>file</code>.
 <p>
-<pre><!-- progs/file.go /Close/ $
+<pre><!--{{code "progs/file.go" `/Close/` "$"}}
 -->func (file *File) Close() os.Error {
     if file == nil {
         return os.EINVAL
     }
     e := syscall.Close(file.fd)
-    file.fd = -1 // so it can't be closed again
+    file.fd = -1 // so it can't be closed again
     if e != 0 {
         return os.Errno(e)
     }
@@ -675,7 +675,7 @@ set of such error values.
 <p>
 We can now use our new package:
 <p>
-<pre><!-- progs/helloworld3.go /package/ $
+<pre><!--{{code "progs/helloworld3.go" `/package/` "$"}}
 -->package main
 
 import (
@@ -689,7 +689,7 @@ func main() {
     file.Stdout.Write(hello)
     f, err := file.Open("/does/not/exist")
     if f == nil {
-        fmt.Printf("can't open file; err=%s\n",  err.String())
+        fmt.Printf("can't open file; err=%s\n", err.String())
         os.Exit(1)
     }
 }
@@ -718,7 +718,7 @@ $
 Building on the <code>file</code> package, here's a simple version of the Unix utility <code>cat(1)</code>,
 <code>progs/cat.go</code>:
 <p>
-<pre><!-- progs/cat.go /package/ $
+<pre><!--{{code "progs/cat.go" `/package/` "$"}}
 -->package main
 
 import (
@@ -790,7 +790,7 @@ The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>R
 so let's start by defining an interface that has exactly those two methods.
 Here is code from <code>progs/cat_rot13.go</code>:
 <p>
-<pre><!-- progs/cat_rot13.go /type.reader/ /^}/
+<pre><!--{{code "progs/cat_rot13.go" `/type.reader/` `/^}/`}}
 -->type reader interface {
     Read(b []byte) (ret int, err os.Error)
     String() string
@@ -807,7 +807,7 @@ existing <code>reader</code> and does <code>rot13</code> on the data. To do this
 the type and implement the methods and with no other bookkeeping,
 we have a second implementation of the <code>reader</code> interface.
 <p>
-<pre><!-- progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/
+<pre><!--{{code "progs/cat_rot13.go" `/type.rotate13/` `/end.of.rotate13/`}}
 -->type rotate13 struct {
     source reader
 }
@@ -834,13 +834,13 @@ func (r13 *rotate13) String() string {
 <p>
 To use the new feature, we define a flag:
 <p>
-<pre><!-- progs/cat_rot13.go /rot13Flag/
+<pre><!--{{code "progs/cat_rot13.go" `/rot13Flag/`}}
 -->var rot13Flag = flag.Bool("rot13", false, "rot13 the input")
 </pre>
 <p>
 and use it from within a mostly unchanged <code>cat</code> function:
 <p>
-<pre><!-- progs/cat_rot13.go /func.cat/ /^}/
+<pre><!--{{code "progs/cat_rot13.go" `/func.cat/` `/^}/`}}
 -->func cat(r reader) {
     const NBUF = 512
     var buf [NBUF]byte
@@ -911,7 +911,7 @@ same interface variable.
 <p>
 As an example, consider this simple sort algorithm taken from <code>progs/sort.go</code>:
 <p>
-<pre><!-- progs/sort.go /func.Sort/ /^}/
+<pre><!--{{code "progs/sort.go" `/func.Sort/` `/^}/`}}
 -->func Sort(data Interface) {
     for i := 1; i < data.Len(); i++ {
         for j := i; j > 0 && data.Less(j, j-1); j-- {
@@ -923,7 +923,7 @@ As an example, consider this simple sort algorithm taken from <code>progs/sort.g
 <p>
 The code needs only three methods, which we wrap into sort's <code>Interface</code>:
 <p>
-<pre><!-- progs/sort.go /interface/ /^}/
+<pre><!--{{code "progs/sort.go" `/interface/` `/^}/`}}
 -->type Interface interface {
     Len() int
     Less(i, j int) bool
@@ -935,12 +935,12 @@ We can apply <code>Sort</code> to any type that implements <code>Len</code>, <co
 The <code>sort</code> package includes the necessary methods to allow sorting of
 arrays of integers, strings, etc.; here's the code for arrays of <code>int</code>
 <p>
-<pre><!-- progs/sort.go /type.*IntSlice/ /Swap/
+<pre><!--{{code "progs/sort.go" `/type.*IntSlice/` `/Swap/`}}
 -->type IntSlice []int
 
-func (p IntSlice) Len() int            { return len(p) }
-func (p IntSlice) Less(i, j int) bool  { return p[i] < p[j] }
-func (p IntSlice) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
+func (p IntSlice) Len() int           { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 </pre>
 <p>
 Here we see methods defined for non-<code>struct</code> types.  You can define methods
@@ -950,7 +950,7 @@ And now a routine to test it out, from <code>progs/sortmain.go</code>.  This
 uses a function in the <code>sort</code> package, omitted here for brevity,
 to test that the result is sorted.
 <p>
-<pre><!-- progs/sortmain.go /func.ints/ /^}/
+<pre><!--{{code "progs/sortmain.go" `/func.ints/` `/^}/`}}
 -->func ints() {
     data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
     a := sort.IntSlice(data)
@@ -964,20 +964,20 @@ to test that the result is sorted.
 If we have a new type we want to be able to sort, all we need to do is
 to implement the three methods for that type, like this:
 <p>
-<pre><!-- progs/sortmain.go /type.day/ /Swap/
+<pre><!--{{code "progs/sortmain.go" `/type.day/` `/Swap/`}}
 -->type day struct {
-    num        int
-    shortName  string
-    longName   string
+    num       int
+    shortName string
+    longName  string
 }
 
 type dayArray struct {
     data []*day
 }
 
-func (p *dayArray) Len() int            { return len(p.data) }
-func (p *dayArray) Less(i, j int) bool  { return p.data[i].num < p.data[j].num }
-func (p *dayArray) Swap(i, j int)       { p.data[i], p.data[j] = p.data[j], p.data[i] }
+func (p *dayArray) Len() int           { return len(p.data) }
+func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }
+func (p *dayArray) Swap(i, j int)      { p.data[i], p.data[j] = p.data[j], p.data[i] }
 </pre>
 <p>
 <p>
@@ -1012,8 +1012,8 @@ argument.  It's easier in many cases in Go.  Instead of <code>%llud</code> you
 can just say <code>%d</code>; <code>Printf</code> knows the size and signedness of the
 integer and can do the right thing for you.  The snippet
 <p>
-<pre><!-- progs/print.go 10 11
--->    var u64 uint64 = 1<<64-1
+<pre><!--{{code "progs/print.go" 10 11}}
+-->    var u64 uint64 = 1<<64 - 1
     fmt.Printf("%d %d\n", u64, int64(u64))
 </pre>
 <p>
@@ -1026,7 +1026,7 @@ prints
 In fact, if you're lazy the format <code>%v</code> will print, in a simple
 appropriate style, any value, even an array or structure.  The output of
 <p>
-<pre><!-- progs/print.go 14 20
+<pre><!--{{code "progs/print.go" 14 20}}
 -->    type T struct {
         a int
         b string
@@ -1049,7 +1049,7 @@ of <code>%v</code> while <code>Println</code> inserts spaces between arguments
 and adds a newline.  The output of each of these two lines is identical
 to that of the <code>Printf</code> call above.
 <p>
-<pre><!-- progs/print.go 21 22
+<pre><!--{{code "progs/print.go" 21 22}}
 -->    fmt.Print(u64, " ", t, " ", a, "\n")
     fmt.Println(u64, t, a)
 </pre>
@@ -1060,7 +1060,7 @@ routines will examine the value to inquire whether it implements
 the method and if so, use it rather than some other formatting.
 Here's a simple example.
 <p>
-<pre><!-- progs/print_string.go 9 $
+<pre><!--{{code "progs/print_string.go" 9 "$"}}
 -->type testType struct {
     a int
     b string
@@ -1179,11 +1179,11 @@ coordinates the communication; as with maps and slices, use
 <p>
 Here is the first function in <code>progs/sieve.go</code>:
 <p>
-<pre><!-- progs/sieve.go /Send/ /^}/
--->// Send the sequence 2, 3, 4, ... to channel 'ch'.
+<pre><!--{{code "progs/sieve.go" `/Send/` `/^}/`}}
+-->// Send the sequence 2, 3, 4, ... to channel 'ch'.
 func generate(ch chan int) {
     for i := 2; ; i++ {
-        ch <- i  // Send 'i' to channel 'ch'.
+        ch <- i // Send 'i' to channel 'ch'.
     }
 }
 </pre>
@@ -1198,14 +1198,14 @@ channel, and a prime number.  It copies values from the input to the
 output, discarding anything divisible by the prime.  The unary communications
 operator <code><-</code> (receive) retrieves the next value on the channel.
 <p>
-<pre><!-- progs/sieve.go /Copy.the/ /^}/
--->// Copy the values from channel 'in' to channel 'out',
-// removing those divisible by 'prime'.
+<pre><!--{{code "progs/sieve.go" `/Copy.the/` `/^}/`}}
+-->// Copy the values from channel 'in' to channel 'out',
+// removing those divisible by 'prime'.
 func filter(in, out chan int, prime int) {
     for {
-        i := <-in  // Receive value of new variable 'i' from 'in'.
-        if i % prime != 0 {
-            out <- i  // Send 'i' to channel 'out'.
+        i := <-in // Receive value of new variable 'i' from 'in'.
+        if i%prime != 0 {
+            out <- i // Send 'i' to channel 'out'.
         }
     }
 }
@@ -1236,10 +1236,10 @@ result := <-ch  // wait for, and retrieve, result
 Back to our prime sieve.  Here's how the sieve pipeline is stitched
 together:
 <p>
-<pre><!-- progs/sieve.go /func.main/ /^}/
+<pre><!--{{code "progs/sieve.go" `/func.main/` `/^}/`}}
 -->func main() {
-    ch := make(chan int)  // Create a new channel.
-    go generate(ch)  // Start generate() as a goroutine.
+    ch := make(chan int)       // Create a new channel.
+    go generate(ch)            // Start generate() as a goroutine.
     for i := 0; i < 100; i++ { // Print the first hundred primes.
         prime := <-ch
         fmt.Println(prime)
@@ -1259,10 +1259,10 @@ The sieve program can be tweaked to use a pattern common
 in this style of programming.  Here is a variant version
 of <code>generate</code>, from <code>progs/sieve1.go</code>:
 <p>
-<pre><!-- progs/sieve1.go /func.generate/ /^}/
+<pre><!--{{code "progs/sieve1.go" `/func.generate/` `/^}/`}}
 -->func generate() chan int {
     ch := make(chan int)
-    go func(){
+    go func() {
         for i := 2; ; i++ {
             ch <- i
         }
@@ -1283,12 +1283,12 @@ after <code>generate</code> returns.
 <p>
 The same change can be made to <code>filter</code>:
 <p>
-<pre><!-- progs/sieve1.go /func.filter/ /^}/
+<pre><!--{{code "progs/sieve1.go" `/func.filter/` `/^}/`}}
 -->func filter(in chan int, prime int) chan int {
     out := make(chan int)
     go func() {
         for {
-            if i := <-in; i % prime != 0 {
+            if i := <-in; i%prime != 0 {
                 out <- i
             }
         }
@@ -1300,7 +1300,7 @@ The same change can be made to <code>filter</code>:
 The <code>sieve</code> function's main loop becomes simpler and clearer as a
 result, and while we're at it let's turn it into a factory too:
 <p>
-<pre><!-- progs/sieve1.go /func.sieve/ /^}/
+<pre><!--{{code "progs/sieve1.go" `/func.sieve/` `/^}/`}}
 -->func sieve() chan int {
     out := make(chan int)
     go func() {
@@ -1317,7 +1317,7 @@ result, and while we're at it let's turn it into a factory too:
 <p>
 Now <code>main</code>'s interface to the prime sieve is a channel of primes:
 <p>
-<pre><!-- progs/sieve1.go /func.main/ /^}/
+<pre><!--{{code "progs/sieve1.go" `/func.main/` `/^}/`}}
 -->func main() {
     primes := sieve()
     for i := 0; i < 100; i++ { // Print the first hundred primes.
@@ -1335,17 +1335,17 @@ A realistic client-server program is a lot of code, so here is a very simple sub
 to illustrate the idea.  It starts by defining a <code>request</code> type, which embeds a channel
 that will be used for the reply.
 <p>
-<pre><!-- progs/server.go /type.request/ /^}/
+<pre><!--{{code "progs/server.go" `/type.request/` `/^}/`}}
 -->type request struct {
-    a, b    int
-    replyc  chan int
+    a, b   int
+    replyc chan int
 }
 </pre>
 <p>
 The server will be trivial: it will do simple binary operations on integers.  Here's the
 code that invokes the operation and responds to the request:
 <p>
-<pre><!-- progs/server.go /type.binOp/ /^}/
+<pre><!--{{code "progs/server.go" `/type.binOp/` `/^}/`}}
 -->type binOp func(a, b int) int
 
 func run(op binOp, req *request) {
@@ -1360,11 +1360,11 @@ returning a third.
 The <code>server</code> routine loops forever, receiving requests and, to avoid blocking due to
 a long-running operation, starting a goroutine to do the actual work.
 <p>
-<pre><!-- progs/server.go /func.server/ /^}/
+<pre><!--{{code "progs/server.go" `/func.server/` `/^}/`}}
 -->func server(op binOp, service chan *request) {
     for {
         req := <-service
-        go run(op, req)  // don't wait for it
+        go run(op, req) // don't wait for it
     }
 }
 </pre>
@@ -1372,7 +1372,7 @@ a long-running operation, starting a goroutine to do the actual work.
 We construct a server in a familiar way, starting it and returning a channel
 connected to it:
 <p>
-<pre><!-- progs/server.go /func.startServer/ /^}/
+<pre><!--{{code "progs/server.go" `/func.startServer/` `/^}/`}}
 -->func startServer(op binOp) chan *request {
     req := make(chan *request)
     go server(op, req)
@@ -1384,7 +1384,7 @@ Here's a simple test.  It starts a server with an addition operator and sends ou
 <code>N</code> requests without waiting for the replies.  Only after all the requests are sent
 does it check the results.
 <p>
-<pre><!-- progs/server.go /func.main/ /^}/
+<pre><!--{{code "progs/server.go" `/func.main/` `/^}/`}}
 -->func main() {
     adder := startServer(func(a, b int) int { return a + b })
     const N = 100
@@ -1396,8 +1396,8 @@ does it check the results.
         req.replyc = make(chan int)
         adder <- req
     }
-    for i := N-1; i >= 0; i-- {   // doesn't matter what order
-        if <-reqs[i].replyc != N + 2*i {
+    for i := N - 1; i >= 0; i-- { // doesn't matter what order
+        if <-reqs[i].replyc != N+2*i {
             fmt.Println("fail at", i)
         }
     }
@@ -1409,7 +1409,7 @@ One annoyance with this program is that it doesn't shut down the server cleanly;
 there are a number of lingering goroutines blocked on communication.  To solve this,
 we can provide a second, <code>quit</code> channel to the server:
 <p>
-<pre><!-- progs/server1.go /func.startServer/ /^}/
+<pre><!--{{code "progs/server1.go" `/func.startServer/` `/^}/`}}
 -->func startServer(op binOp) (service chan *request, quit chan bool) {
     service = make(chan *request)
     quit = make(chan bool)
@@ -1420,12 +1420,12 @@ we can provide a second, <code>quit</code> channel to the server:
 <p>
 It passes the quit channel to the <code>server</code> function, which uses it like this:
 <p>
-<pre><!-- progs/server1.go /func.server/ /^}/
+<pre><!--{{code "progs/server1.go" `/func.server/` `/^}/`}}
 -->func server(op binOp, service chan *request, quit chan bool) {
     for {
         select {
         case req := <-service:
-            go run(op, req)  // don't wait for it
+            go run(op, req) // don't wait for it
         case <-quit:
             return
         }
@@ -1443,11 +1443,11 @@ returns, terminating its execution.
 All that's left is to strobe the <code>quit</code> channel
 at the end of main:
 <p>
-<pre><!-- progs/server1.go /adder,.quit/
+<pre><!--{{code "progs/server1.go" `/adder,.quit/`}}
 -->    adder, quit := startServer(func(a, b int) int { return a + b })
 </pre>
 ...
-<pre><!-- progs/server1.go /quit....true/
+<pre><!--{{code "progs/server1.go" `/quit....true/`}}
 -->    quit <- true
 </pre>
 <p>
diff --git a/doc/go_tutorial.tmpl b/doc/go_tutorial.tmpl
new file mode 100644
index 0000000..c170c25
--- /dev/null
+++ b/doc/go_tutorial.tmpl
@@ -0,0 +1,990 @@
+<!-- A Tutorial for the Go Programming Language -->
+<h2>Introduction</h2>
+<p>
+This document is a tutorial introduction to the basics of the Go programming
+language, intended for programmers familiar with C or C++. It is not a comprehensive
+guide to the language; at the moment the document closest to that is the
+<a href='/doc/go_spec.html'>language specification</a>.
+After you've read this tutorial, you should look at
+<a href='/doc/effective_go.html'>Effective Go</a>,
+which digs deeper into how the language is used and
+talks about the style and idioms of programming in Go.
+Also, slides from a 3-day course about Go are available.
+They provide some background and a lot of examples:
+<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
+<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
+<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
+<p>
+The presentation here proceeds through a series of modest programs to illustrate
+key features of the language.  All the programs work (at time of writing) and are
+checked into the repository in the directory <a href='/doc/progs'><code>/doc/progs/</code></a>.
+<p>
+<h2>Hello, World</h2>
+<p>
+Let's start in the usual way:
+<p>
+{{code "progs/helloworld.go" `/package/` "$"}}
+<p>
+Every Go source file declares, using a <code>package</code> statement, which package it's part of.
+It may also import other packages to use their facilities.
+This program imports the package <code>fmt</code> to gain access to
+our old, now capitalized and package-qualified, friend, <code>fmt.Printf</code>.
+<p>
+Functions are introduced with the <code>func</code> keyword.
+The <code>main</code> package's <code>main</code> function is where the program starts running (after
+any initialization).
+<p>
+String constants can contain Unicode characters, encoded in UTF-8.
+(In fact, Go source files are defined to be encoded in UTF-8.)
+<p>
+The comment convention is the same as in C++:
+<p>
+<pre>
+/* ... */
+// ...
+</pre>
+<p>
+Later we'll have much more to say about printing.
+<p>
+<h2>Semicolons</h2>
+<p>
+You might have noticed that our program has no semicolons.  In Go
+code, the only place you typically see semicolons is separating the
+clauses of <code>for</code> loops and the like; they are not necessary after
+every statement.
+<p>
+In fact, what happens is that the formal language uses semicolons,
+much as in C or Java, but they are inserted automatically
+at the end of every line that looks like the end of a statement. You
+don't need to type them yourself.
+<p>
+For details about how this is done you can see the language
+specification, but in practice all you need to know is that you
+never need to put a semicolon at the end of a line.  (You can put
+them in if you want to write multiple statements per line.) As an
+extra help, you can also leave out a semicolon immediately before
+a closing brace.
+<p>
+This approach makes for clean-looking, semicolon-free code.  The
+one surprise is that it's important to put the opening
+brace of a construct such as an <code>if</code> statement on the same line as
+the <code>if</code>; if you don't, there are situations that may not compile
+or may give the wrong result.  The language forces the brace style
+to some extent.
+<p>
+<h2>Compiling</h2>
+<p>
+Go is a compiled language.  At the moment there are two compilers.
+<code>Gccgo</code> is a Go compiler that uses the GCC back end.  There is also a
+suite of compilers with different (and odd) names for each architecture:
+<code>6g</code> for the 64-bit x86, <code>8g</code> for the 32-bit x86, and more.  These
+compilers run significantly faster but generate less efficient code
+than <code>gccgo</code>.  At the time of writing (late 2009), they also have
+a more robust run-time system although <code>gccgo</code> is catching up.
+<p>
+Here's how to compile and run our program.  With <code>6g</code>, say,
+<p>
+<pre>
+$ 6g helloworld.go  # compile; object goes into helloworld.6
+$ 6l helloworld.6   # link; output goes into 6.out
+$ 6.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
+</pre>
+<p>
+With <code>gccgo</code> it looks a little more traditional.
+<p>
+<pre>
+$ gccgo helloworld.go
+$ a.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
+</pre>
+<p>
+<h2>Echo</h2>
+<p>
+Next up, here's a version of the Unix utility <code>echo(1)</code>:
+<p>
+{{code "progs/echo.go" `/package/` "$"}}
+<p>
+This program is small but it's doing a number of new things.  In the last example,
+we saw <code>func</code> introduce a function.  The keywords <code>var</code>, <code>const</code>, and <code>type</code>
+(not used yet) also introduce declarations, as does <code>import</code>.
+Notice that we can group declarations of the same sort into
+parenthesized lists, one item per line, as in the <code>import</code> and <code>const</code> clauses here.
+But it's not necessary to do so; we could have said
+<p>
+<pre>
+const Space = " "
+const Newline = "\n"
+</pre>
+<p>
+This program imports the <code>"os"</code> package to access its <code>Stdout</code> variable, of type
+<code>*os.File</code>.  The <code>import</code> statement is actually a declaration: in its general form,
+as used in our ``hello world'' program,
+it names the identifier (<code>fmt</code>)
+that will be used to access members of the package imported from the file (<code>"fmt"</code>),
+found in the current directory or in a standard location.
+In this program, though, we've dropped the explicit name from the imports; by default,
+packages are imported using the name defined by the imported package,
+which by convention is of course the file name itself.  Our ``hello world'' program
+could have said just <code>import "fmt"</code>.
+<p>
+You can specify your
+own import names if you want but it's only necessary if you need to resolve
+a naming conflict.
+<p>
+Given <code>os.Stdout</code> we can use its <code>WriteString</code> method to print the string.
+<p>
+After importing the <code>flag</code> package, we use a <code>var</code> declaration
+to create and initialize a global variable, called <code>omitNewline</code>,
+to hold the value of echo's <code>-n</code> flag. 
+The variable  has type <code>*bool</code>, pointer to <code>bool</code>.
+<p>
+In <code>main.main</code>, we parse the arguments (the call to <code>flag.Parse</code>) and then create a local
+string variable with which to build the output.
+<p>
+The declaration statement has the form
+<p>
+<pre>
+var s string = ""
+</pre>
+<p>
+This is the <code>var</code> keyword, followed by the name of the variable, followed by
+its type, followed by an equals sign and an initial value for the variable.
+<p>
+Go tries to be terse, and this declaration could be shortened.  Since the
+string constant is of type string, we don't have to tell the compiler that.
+We could write
+<p>
+<pre>
+var s = ""
+</pre>
+<p>
+or we could go even shorter and write the idiom
+<p>
+<pre>
+s := ""
+</pre>
+<p>
+The <code>:=</code> operator is used a lot in Go to represent an initializing declaration.
+There's one in the <code>for</code> clause on the next line:
+<p>
+{{code  "progs/echo.go" `/for/`}}
+<p>
+The <code>flag</code> package has parsed the arguments and left the non-flag arguments
+in a list that can be iterated over in the obvious way.
+<p>
+The Go <code>for</code> statement differs from that of C in a number of ways.  First,
+it's the only looping construct; there is no <code>while</code> or <code>do</code>.  Second,
+there are no parentheses on the clause, but the braces on the body
+are mandatory.  The same applies to the <code>if</code> and <code>switch</code> statements.
+Later examples will show some other ways <code>for</code> can be written.
+<p>
+The body of the loop builds up the string <code>s</code> by appending (using <code>+=</code>)
+the arguments and separating spaces. After the loop, if the <code>-n</code> flag is not
+set, the program appends a newline. Finally, it writes the result.
+<p>
+Notice that <code>main.main</code> is a niladic function with no return type.
+It's defined that way.  Falling off the end of <code>main.main</code> means
+''success''; if you want to signal an erroneous return, call
+<p>
+<pre>
+os.Exit(1)
+</pre>
+<p>
+The <code>os</code> package contains other essentials for getting
+started; for instance, <code>os.Args</code> is a slice used by the
+<code>flag</code> package to access the command-line arguments.
+<p>
+<h2>An Interlude about Types</h2>
+<p>
+Go has some familiar types such as <code>int</code> and <code>uint</code> (unsigned <code>int</code>), which represent
+values of the ''appropriate'' size for the machine. It also defines
+explicitly-sized types such as <code>int8</code>, <code>float64</code>, and so on, plus
+unsigned integer types such as <code>uint</code>, <code>uint32</code>, etc.
+These are distinct types; even if <code>int</code> and <code>int32</code> are both 32 bits in size,
+they are not the same type.  There is also a <code>byte</code> synonym for
+<code>uint8</code>, which is the element type for strings.
+<p>
+Floating-point types are always sized: <code>float32</code> and <code>float64</code>,
+plus <code>complex64</code> (two <code>float32s</code>) and <code>complex128</code>
+(two <code>float64s</code>).  Complex numbers are outside the
+scope of this tutorial.
+<p>
+Speaking of <code>string</code>, that's a built-in type as well.  Strings are
+<i>immutable values</i>—they are not just arrays of <code>byte</code> values.
+Once you've built a string <i>value</i>, you can't change it, although
+of course you can change a string <i>variable</i> simply by
+reassigning it.  This snippet from <code>strings.go</code> is legal code:
+<p>
+{{code "progs/strings.go" `/hello/` `/ciao/`}}
+<p>
+However the following statements are illegal because they would modify
+a <code>string</code> value:
+<p>
+<pre>
+s[0] = 'x'
+(*p)[1] = 'y'
+</pre>
+<p>
+In C++ terms, Go strings are a bit like <code>const strings</code>, while pointers
+to strings are analogous to <code>const string</code> references.
+<p>
+Yes, there are pointers.  However, Go simplifies their use a little;
+read on.
+<p>
+Arrays are declared like this:
+<p>
+<pre>
+var arrayOfInt [10]int
+</pre>
+<p>
+Arrays, like strings, are values, but they are mutable. This differs
+from C, in which <code>arrayOfInt</code> would be usable as a pointer to <code>int</code>.
+In Go, since arrays are values, it's meaningful (and useful) to talk
+about pointers to arrays.
+<p>
+The size of the array is part of its type; however, one can declare
+a <i>slice</i> variable to hold a reference to any array, of any size,
+with the same element type.
+A <i>slice
+expression</i> has the form <code>a[low : high]</code>, representing
+the internal array indexed from <code>low</code> through <code>high-1</code>; the resulting
+slice is indexed from <code>0</code> through <code>high-low-1</code>.
+In short, slices look a lot like arrays but with
+no explicit size (<code>[]</code> vs. <code>[10]</code>) and they reference a segment of
+an underlying, usually anonymous, regular array.  Multiple slices
+can share data if they represent pieces of the same array;
+multiple arrays can never share data.
+<p>
+Slices are much more common in Go programs than
+regular arrays; they're more flexible, have reference semantics,
+and are efficient.  What they lack is the precise control of storage
+layout of a regular array; if you want to have a hundred elements
+of an array stored within your structure, you should use a regular
+array. To create one, use a compound value <i>constructor</i>—an
+expression formed
+from a type followed by a brace-bounded expression like this:
+<p>
+<pre>
+[3]int{1,2,3}
+</pre>
+<p>
+In this case the constructor builds an array of 3 <code>ints</code>.
+<p>
+When passing an array to a function, you almost always want
+to declare the formal parameter to be a slice.  When you call
+the function, slice the array to create
+(efficiently) a slice reference and pass that.
+By default, the lower and upper bounds of a slice match the
+ends of the existing object, so the concise notation <code>[:]</code>
+will slice the whole array.
+<p>
+Using slices one can write this function (from <code>sum.go</code>):
+<p>
+{{code "progs/sum.go" `/sum/` `/^}/`}}
+<p>
+Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
+after the parameter list.
+<p>
+To call the function, we slice the array.  This intricate call (we'll show
+a simpler way in a moment) constructs
+an array and slices it:
+<p>
+<pre>
+s := sum([3]int{1,2,3}[:])
+</pre>
+<p>
+If you are creating a regular array but want the compiler to count the
+elements for you, use <code>...</code> as the array size:
+<p>
+<pre>
+s := sum([...]int{1,2,3}[:])
+</pre>
+<p>
+That's fussier than necessary, though.
+In practice, unless you're meticulous about storage layout within a
+data structure, a slice itself—using empty brackets with no size—is all you need:
+<p>
+<pre>
+s := sum([]int{1,2,3})
+</pre>
+<p>
+There are also maps, which you can initialize like this:
+<p>
+<pre>
+m := map[string]int{"one":1 , "two":2}
+</pre>
+<p>
+The built-in function <code>len</code>, which returns number of elements,
+makes its first appearance in <code>sum</code>.  It works on strings, arrays,
+slices, maps, and channels.
+<p>
+By the way, another thing that works on strings, arrays, slices, maps
+and channels is the <code>range</code> clause on <code>for</code> loops.  Instead of writing
+<p>
+<pre>
+for i := 0; i < len(a); i++ { ... }
+</pre>
+<p>
+to loop over the elements of a slice (or map or ...) , we could write
+<p>
+<pre>
+for i, v := range a { ... }
+</pre>
+<p>
+This assigns <code>i</code> to the index and <code>v</code> to the value of the successive
+elements of the target of the range.   See
+<a href='/doc/effective_go.html'>Effective Go</a>
+for more examples of its use.
+<p>
+<p>
+<h2>An Interlude about Allocation</h2>
+<p>
+Most types in Go are values. If you have an <code>int</code> or a <code>struct</code>
+or an array, assignment
+copies the contents of the object.
+To allocate a new variable, use the built-in function <code>new</code>, which
+returns a pointer to the allocated storage.
+<p>
+<pre>
+type T struct { a, b int }
+var t *T = new(T)
+</pre>
+<p>
+or the more idiomatic
+<p>
+<pre>
+t := new(T)
+</pre>
+<p>
+Some types—maps, slices, and channels (see below)—have reference semantics.
+If you're holding a slice or a map and you modify its contents, other variables
+referencing the same underlying data will see the modification.  For these three
+types you want to use the built-in function <code>make</code>:
+<p>
+<pre>
+m := make(map[string]int)
+</pre>
+<p>
+This statement initializes a new map ready to store entries.
+If you just declare the map, as in
+<p>
+<pre>
+var m map[string]int
+</pre>
+<p>
+it creates a <code>nil</code> reference that cannot hold anything. To use the map,
+you must first initialize the reference using <code>make</code> or by assignment from an
+existing map.
+<p>
+Note that <code>new(T)</code> returns type <code>*T</code> while <code>make(T)</code> returns type
+<code>T</code>.  If you (mistakenly) allocate a reference object with <code>new</code> rather than <code>make</code>,
+you receive a pointer to a nil reference, equivalent to
+declaring an uninitialized variable and taking its address.
+<p>
+<h2>An Interlude about Constants</h2>
+<p>
+Although integers come in lots of sizes in Go, integer constants do not.
+There are no constants like <code>0LL</code> or <code>0x0UL</code>.   Instead, integer
+constants are evaluated as large-precision values that
+can overflow only when they are assigned to an integer variable with
+too little precision to represent the value.
+<p>
+<pre>
+const hardEight = (1 << 100) >> 97  // legal
+</pre>
+<p>
+There are nuances that deserve redirection to the legalese of the
+language specification but here are some illustrative examples:
+<p>
+<pre>
+var a uint64 = 0  // a has type uint64, value 0
+a := uint64(0)    // equivalent; uses a "conversion"
+i := 0x1234       // i gets default type: int
+var j int = 1e6   // legal - 1000000 is representable in an int
+x := 1.5          // a float64, the default type for floating constants
+i3div2 := 3/2     // integer division - result is 1
+f3div2 := 3./2.   // floating-point division - result is 1.5
+</pre>
+<p>
+Conversions only work for simple cases such as converting <code>ints</code> of one
+sign or size to another and between integers and floating-point numbers,
+plus a couple of other instances outside the scope of a tutorial.
+There are no automatic numeric conversions of any kind in Go,
+other than that of making constants have concrete size and type when
+assigned to a variable.
+<p>
+<h2>An I/O Package</h2>
+<p>
+Next we'll look at a simple package for doing file I/O with an
+open/close/read/write interface.  Here's the start of <code>file.go</code>:
+<p>
+{{code "progs/file.go" `/package/` `/^}/`}}
+<p>
+The first few lines declare the name of the
+package—<code>file</code>—and then import two packages.  The <code>os</code>
+package hides the differences
+between various operating systems to give a consistent view of files and
+so on; here we're going to use its error handling utilities
+and reproduce the rudiments of its file I/O.
+<p>
+The other item is the low-level, external <code>syscall</code> package, which provides
+a primitive interface to the underlying operating system's calls.
+<p>
+Next is a type definition: the <code>type</code> keyword introduces a type declaration,
+in this case a data structure called <code>File</code>.
+To make things a little more interesting, our <code>File</code> includes the name of the file
+that the file descriptor refers to.
+<p>
+Because <code>File</code> starts with a capital letter, the type is available outside the package,
+that is, by users of the package.   In Go the rule about visibility of information is
+simple: if a name (of a top-level type, function, method, constant or variable, or of
+a structure field or method) is capitalized, users of the package may see it. Otherwise, the
+name and hence the thing being named is visible only inside the package in which
+it is declared.  This is more than a convention; the rule is enforced by the compiler.
+In Go, the term for publicly visible names is ''exported''.
+<p>
+In the case of <code>File</code>, all its fields are lower case and so invisible to users, but we
+will soon give it some exported, upper-case methods.
+<p>
+First, though, here is a factory to create a <code>File</code>:
+<p>
+{{code "progs/file.go" `/newFile/` `/^}/`}}
+<p>
+This returns a pointer to a new <code>File</code> structure with the file descriptor and name
+filled in.  This code uses Go's notion of a ''composite literal'', analogous to
+the ones used to build maps and arrays, to construct a new heap-allocated
+object.  We could write
+<p>
+<pre>
+n := new(File)
+n.fd = fd
+n.name = name
+return n
+</pre>
+<p>
+but for simple structures like <code>File</code> it's easier to return the address of a 
+composite literal, as is done here in the <code>return</code> statement from <code>newFile</code>.
+<p>
+We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
+<p>
+{{code "progs/file.go" `/var/` `/^.$/`}}
+<p>
+The <code>newFile</code> function was not exported because it's internal. The proper,
+exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
+<p>
+{{code "progs/file.go" `/func.OpenFile/` `/^}/`}}
+<p>
+There are a number of new things in these few lines.  First, <code>OpenFile</code> returns
+multiple values, a <code>File</code> and an error (more about errors in a moment).
+We declare the
+multi-value return as a parenthesized list of declarations; syntactically
+they look just like a second parameter list.  The function
+<code>syscall.Open</code>
+also has a multi-value return, which we can grab with the multi-variable
+declaration on the first line; it declares <code>r</code> and <code>e</code> to hold the two values,
+both of type <code>int</code> (although you'd have to look at the <code>syscall</code> package
+to see that).  Finally, <code>OpenFile</code> returns two values: a pointer to the new <code>File</code>
+and the error.  If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
+be negative and <code>newFile</code> will return <code>nil</code>.
+<p>
+About those errors:  The <code>os</code> library includes a general notion of an error.
+It's a good idea to use its facility in your own interfaces, as we do here, for
+consistent error handling throughout Go code.   In <code>Open</code> we use a
+conversion to translate Unix's integer <code>errno</code> value into the integer type
+<code>os.Errno</code>, which implements <code>os.Error</code>.
+<p>
+Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
+our exercise is emulating. The <code>os</code> package takes the opportunity
+to make the two commonest cases - open for read and create for
+write - the simplest, just <code>Open</code> and <code>Create</code>.  <code>OpenFile</code> is the
+general case, analogous to the Unix system call <code>Open</code>.  Here is
+the implementation of our <code>Open</code> and <code>Create</code>; they're trivial
+wrappers that eliminate common errors by capturing
+the tricky standard arguments to open and, especially, to create a file:
+<p>
+{{code "progs/file.go" `/^const/` `/^}/`}}
+<p>
+{{code "progs/file.go" `/func.Create/` `/^}/`}}
+<p>
+Back to our main story.
+Now that we can build <code>Files</code>, we can write methods for them. To declare
+a method of a type, we define a function to have an explicit receiver
+of that type, placed
+in parentheses before the function name. Here are some methods for <code>*File</code>,
+each of which declares a receiver variable <code>file</code>.
+<p>
+{{code "progs/file.go" `/Close/` "$"}}
+<p>
+There is no implicit <code>this</code> and the receiver variable must be used to access
+members of the structure.  Methods are not declared within
+the <code>struct</code> declaration itself.  The <code>struct</code> declaration defines only data members.
+In fact, methods can be created for almost any type you name, such as an integer or
+array, not just for <code>structs</code>.   We'll see an example with arrays later.
+<p>
+The <code>String</code> method is so called because of a printing convention we'll
+describe later.
+<p>
+The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code>
+version of the) Unix error code <code>EINVAL</code>.  The <code>os</code> library defines a standard
+set of such error values.
+<p>
+We can now use our new package:
+<p>
+{{code "progs/helloworld3.go" `/package/` "$"}}
+<p>
+The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler
+to use our own package rather than
+something from the directory of installed packages.
+(Also, ''<code>file.go</code>'' must be compiled before we can import the
+package.)
+<p>
+Now we can compile and run the program. On Unix, this would be the result:
+<p>
+<pre>
+$ 6g file.go                       # compile file package
+$ 6g helloworld3.go                # compile main package
+$ 6l -o helloworld3 helloworld3.6  # link - no need to mention "file"
+$ helloworld3
+hello, world
+can't open file; err=No such file or directory
+$
+</pre>
+<p>
+<h2>Rotting cats</h2>
+<p>
+Building on the <code>file</code> package, here's a simple version of the Unix utility <code>cat(1)</code>,
+<code>progs/cat.go</code>:
+<p>
+{{code "progs/cat.go" `/package/` "$"}}
+<p>
+By now this should be easy to follow, but the <code>switch</code> statement introduces some
+new features.  Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
+initialization statement.  The <code>switch</code> statement in <code>cat</code> uses one to create variables
+<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>.  (The <code>if</code> a few lines later
+has the same idea.)  The <code>switch</code> statement is general: it evaluates the cases
+from  top to bottom looking for the first case that matches the value; the
+case expressions don't need to be constants or even integers, as long as
+they all have the same type.
+<p>
+Since the <code>switch</code> value is just <code>true</code>, we could leave it off—as is also
+the situation
+in a <code>for</code> statement, a missing value means <code>true</code>.  In fact, such a <code>switch</code>
+is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in
+<code>switch</code> statements each <code>case</code> has an implicit <code>break</code>.
+<p>
+The argument to <code>file.Stdout.Write</code> is created by slicing the array <code>buf</code>.
+Slices provide the standard Go way to handle I/O buffers.
+<p>
+Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input.
+It's easy to do by just processing the bytes, but instead we will exploit
+Go's notion of an <i>interface</i>.
+<p>
+The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>Read</code> and <code>String</code>,
+so let's start by defining an interface that has exactly those two methods.
+Here is code from <code>progs/cat_rot13.go</code>:
+<p>
+{{code "progs/cat_rot13.go" `/type.reader/` `/^}/`}}
+<p>
+Any type that has the two methods of <code>reader</code>—regardless of whatever
+other methods the type may also have—is said to <i>implement</i> the
+interface.  Since <code>file.File</code> implements these methods, it implements the
+<code>reader</code> interface.  We could tweak the <code>cat</code> subroutine to accept a <code>reader</code>
+instead of a <code>*file.File</code> and it would work just fine, but let's embellish a little
+first by writing a second type that implements <code>reader</code>, one that wraps an
+existing <code>reader</code> and does <code>rot13</code> on the data. To do this, we just define
+the type and implement the methods and with no other bookkeeping,
+we have a second implementation of the <code>reader</code> interface.
+<p>
+{{code "progs/cat_rot13.go" `/type.rotate13/` `/end.of.rotate13/`}}
+<p>
+(The <code>rot13</code> function called in <code>Read</code> is trivial and not worth reproducing here.)
+<p>
+To use the new feature, we define a flag:
+<p>
+{{code "progs/cat_rot13.go" `/rot13Flag/`}}
+<p>
+and use it from within a mostly unchanged <code>cat</code> function:
+<p>
+{{code "progs/cat_rot13.go" `/func.cat/` `/^}/`}}
+<p>
+(We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
+for changing the type of the argument; consider that an exercise.)
+The <code>if</code> at the top of <code>cat</code> sets it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code>
+we received into a <code>rotate13</code> and proceed.  Note that the interface variables
+are values, not pointers: the argument is of type <code>reader</code>, not <code>*reader</code>,
+even though under the covers it holds a pointer to a <code>struct</code>.
+<p>
+Here it is in action:
+<p>
+<pre>
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat
+abcdefghijklmnopqrstuvwxyz
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
+nopqrstuvwxyzabcdefghijklm
+$
+</pre>
+<p>
+Fans of dependency injection may take cheer from how easily interfaces
+allow us to substitute the implementation of a file descriptor.
+<p>
+Interfaces are a distinctive feature of Go.  An interface is implemented by a
+type if the type implements all the methods declared in the interface.
+This means
+that a type may implement an arbitrary number of different interfaces.
+There is no type hierarchy; things can be much more <i>ad hoc</i>,
+as we saw with <code>rot13</code>.  The type <code>file.File</code> implements <code>reader</code>; it could also
+implement a <code>writer</code>, or any other interface built from its methods that
+fits the current situation. Consider the <i>empty interface</i>
+<p>
+<pre>
+type Empty interface {}
+</pre>
+<p>
+<i>Every</i> type implements the empty interface, which makes it
+useful for things like containers.
+<p>
+<h2>Sorting</h2>
+<p>
+Interfaces provide a simple form of polymorphism.  They completely
+separate the definition of what an object does from how it does it, allowing
+distinct implementations to be represented at different times by the
+same interface variable.
+<p>
+As an example, consider this simple sort algorithm taken from <code>progs/sort.go</code>:
+<p>
+{{code "progs/sort.go" `/func.Sort/` `/^}/`}}
+<p>
+The code needs only three methods, which we wrap into sort's <code>Interface</code>:
+<p>
+{{code "progs/sort.go" `/interface/` `/^}/`}}
+<p>
+We can apply <code>Sort</code> to any type that implements <code>Len</code>, <code>Less</code>, and <code>Swap</code>.
+The <code>sort</code> package includes the necessary methods to allow sorting of
+arrays of integers, strings, etc.; here's the code for arrays of <code>int</code>
+<p>
+{{code "progs/sort.go" `/type.*IntSlice/` `/Swap/`}}
+<p>
+Here we see methods defined for non-<code>struct</code> types.  You can define methods
+for any type you define and name in your package.
+<p>
+And now a routine to test it out, from <code>progs/sortmain.go</code>.  This
+uses a function in the <code>sort</code> package, omitted here for brevity,
+to test that the result is sorted.
+<p>
+{{code "progs/sortmain.go" `/func.ints/` `/^}/`}}
+<p>
+If we have a new type we want to be able to sort, all we need to do is
+to implement the three methods for that type, like this:
+<p>
+{{code "progs/sortmain.go" `/type.day/` `/Swap/`}}
+<p>
+<p>
+<h2>Printing</h2>
+<p>
+The examples of formatted printing so far have been modest.  In this section
+we'll talk about how formatted I/O can be done well in Go.
+<p>
+We've seen simple uses of the package <code>fmt</code>, which
+implements <code>Printf</code>, <code>Fprintf</code>, and so on.
+Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
+<p>
+<pre>
+Printf(format string, v ...interface{}) (n int, errno os.Error)
+</pre>
+<p>
+The token <code>...</code> introduces a variable-length argument list that in C would
+be handled using the <code>stdarg.h</code> macros.
+In Go, variadic functions are passed a slice of the arguments of the
+specified type.  In <code>Printf</code>'s case, the declaration says <code>...interface{}</code>
+so the actual type is a slice of empty interface values, <code>[]interface{}</code>.
+<code>Printf</code> can examine the arguments by iterating over the slice
+and, for each element, using a type switch or the reflection library
+to interpret the value.
+It's off topic here but such run-time type analysis
+helps explain some of the nice properties of Go's <code>Printf</code>,
+due to the ability of <code>Printf</code> to discover the type of its arguments
+dynamically.
+<p>
+For example, in C each format must correspond to the type of its
+argument.  It's easier in many cases in Go.  Instead of <code>%llud</code> you
+can just say <code>%d</code>; <code>Printf</code> knows the size and signedness of the
+integer and can do the right thing for you.  The snippet
+<p>
+{{code "progs/print.go" 10 11}}
+<p>
+prints
+<p>
+<pre>
+18446744073709551615 -1
+</pre>
+<p>
+In fact, if you're lazy the format <code>%v</code> will print, in a simple
+appropriate style, any value, even an array or structure.  The output of
+<p>
+{{code "progs/print.go" 14 20}}
+<p>
+is
+<p>
+<pre>
+18446744073709551615 {77 Sunset Strip} [1 2 3 4]
+</pre>
+<p>
+You can drop the formatting altogether if you use <code>Print</code> or <code>Println</code>
+instead of <code>Printf</code>.  Those routines do fully automatic formatting.
+The <code>Print</code> function just prints its elements out using the equivalent
+of <code>%v</code> while <code>Println</code> inserts spaces between arguments
+and adds a newline.  The output of each of these two lines is identical
+to that of the <code>Printf</code> call above.
+<p>
+{{code "progs/print.go" 21 22}}
+<p>
+If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
+just give it a <code>String</code> method that returns a string.  The print
+routines will examine the value to inquire whether it implements
+the method and if so, use it rather than some other formatting.
+Here's a simple example.
+<p>
+{{code "progs/print_string.go" 9 "$"}}
+<p>
+Since <code>*testType</code> has a <code>String</code> method, the
+default formatter for that type will use it and produce the output
+<p>
+<pre>
+77 Sunset Strip
+</pre>
+<p>
+Observe that the <code>String</code> method calls <code>Sprint</code> (the obvious Go
+variant that returns a string) to do its formatting; special formatters
+can use the <code>fmt</code> library recursively.
+<p>
+Another feature of <code>Printf</code> is that the format <code>%T</code> will print a string
+representation of the type of a value, which can be handy when debugging
+polymorphic code.
+<p>
+It's possible to write full custom print formats with flags and precisions
+and such, but that's getting a little off the main thread so we'll leave it
+as an exploration exercise.
+<p>
+You might ask, though, how <code>Printf</code> can tell whether a type implements
+the <code>String</code> method.  Actually what it does is ask if the value can
+be converted to an interface variable that implements the method.
+Schematically, given a value <code>v</code>, it does this:
+<p>
+<p>
+<pre>
+type Stringer interface {
+    String() string
+}
+</pre>
+<p>
+<pre>
+s, ok := v.(Stringer)  // Test whether v implements "String()"
+if ok {
+    result = s.String()
+} else {
+    result = defaultOutput(v)
+}
+</pre>
+<p>
+The code uses a ``type assertion'' (<code>v.(Stringer)</code>) to test if the value stored in
+<code>v</code> satisfies the <code>Stringer</code> interface; if it does, <code>s</code>
+will become an interface variable implementing the method and <code>ok</code> will
+be <code>true</code>.  We then use the interface variable to call the method.
+(The ''comma, ok'' pattern is a Go idiom used to test the success of
+operations such as type conversion, map update, communications, and so on,
+although this is the only appearance in this tutorial.)
+If the value does not satisfy the interface, <code>ok</code> will be false.
+<p>
+In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
+to interfaces describing simple method sets like this.
+<p>
+One last wrinkle.  To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
+etc., there are also <code>Fprintf</code> etc.  Unlike in C, <code>Fprintf</code>'s first argument is
+not a file.  Instead, it is a variable of type <code>io.Writer</code>, which is an
+interface type defined in the <code>io</code> library:
+<p>
+<pre>
+type Writer interface {
+    Write(p []byte) (n int, err os.Error)
+}
+</pre>
+<p>
+(This interface is another conventional name, this time for <code>Write</code>; there are also
+<code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.)
+Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write</code>
+method, not just files but also network channels, buffers, whatever
+you want.
+<p>
+<h2>Prime numbers</h2>
+<p>
+Now we come to processes and communication—concurrent programming.
+It's a big subject so to be brief we assume some familiarity with the topic.
+<p>
+A classic program in the style is a prime sieve.
+(The sieve of Eratosthenes is computationally more efficient than
+the algorithm presented here, but we are more interested in concurrency than
+algorithmics at the moment.)
+It works by taking a stream of all the natural numbers and introducing
+a sequence of filters, one for each prime, to winnow the multiples of
+that prime.  At each step we have a sequence of filters of the primes
+so far, and the next number to pop out is the next prime, which triggers
+the creation of the next filter in the chain.
+<p>
+Here's a flow diagram; each box represents a filter element whose
+creation is triggered by the first number that flowed from the
+elements before it.
+<p>
+<br>
+<p>
+     <img src='sieve.gif'>
+<p>
+<br>
+<p>
+To create a stream of integers, we use a Go <i>channel</i>, which,
+borrowing from CSP's descendants, represents a communications
+channel that can connect two concurrent computations.
+In Go, channel variables are references to a run-time object that
+coordinates the communication; as with maps and slices, use
+<code>make</code> to create a new channel.
+<p>
+Here is the first function in <code>progs/sieve.go</code>:
+<p>
+{{code "progs/sieve.go" `/Send/` `/^}/`}}
+<p>
+The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its
+argument channel, <code>ch</code>, using the binary communications operator <code><-</code>.
+Channel operations block, so if there's no recipient for the value on <code>ch</code>,
+the send operation will wait until one becomes available.
+<p>
+The <code>filter</code> function has three arguments: an input channel, an output
+channel, and a prime number.  It copies values from the input to the
+output, discarding anything divisible by the prime.  The unary communications
+operator <code><-</code> (receive) retrieves the next value on the channel.
+<p>
+{{code "progs/sieve.go" `/Copy.the/` `/^}/`}}
+<p>
+The generator and filters execute concurrently.  Go has
+its own model of process/threads/light-weight processes/coroutines,
+so to avoid notational confusion we call concurrently executing
+computations in Go <i>goroutines</i>.  To start a goroutine,
+invoke the function, prefixing the call with the keyword <code>go</code>;
+this starts the function running in parallel with the current
+computation but in the same address space:
+<p>
+<pre>
+go sum(hugeArray) // calculate sum in the background
+</pre>
+<p>
+If you want to know when the calculation is done, pass a channel
+on which it can report back:
+<p>
+<pre>
+ch := make(chan int)
+go sum(hugeArray, ch)
+// ... do something else for a while
+result := <-ch  // wait for, and retrieve, result
+</pre>
+<p>
+Back to our prime sieve.  Here's how the sieve pipeline is stitched
+together:
+<p>
+{{code "progs/sieve.go" `/func.main/` `/^}/`}}
+<p>
+The first line of <code>main</code> creates the initial channel to pass to <code>generate</code>, which it
+then starts up.  As each prime pops out of the channel, a new <code>filter</code>
+is added to the pipeline and <i>its</i> output becomes the new value
+of <code>ch</code>.
+<p>
+The sieve program can be tweaked to use a pattern common
+in this style of programming.  Here is a variant version
+of <code>generate</code>, from <code>progs/sieve1.go</code>:
+<p>
+{{code "progs/sieve1.go" `/func.generate/` `/^}/`}}
+<p>
+This version does all the setup internally. It creates the output
+channel, launches a goroutine running a function literal, and
+returns the channel to the caller.  It is a factory for concurrent
+execution, starting the goroutine and returning its connection.
+<p>
+The function literal notation used in the <code>go</code> statement allows us to construct an
+anonymous function and invoke it on the spot. Notice that the local
+variable <code>ch</code> is available to the function literal and lives on even
+after <code>generate</code> returns.
+<p>
+The same change can be made to <code>filter</code>:
+<p>
+{{code "progs/sieve1.go" `/func.filter/` `/^}/`}}
+<p>
+The <code>sieve</code> function's main loop becomes simpler and clearer as a
+result, and while we're at it let's turn it into a factory too:
+<p>
+{{code "progs/sieve1.go" `/func.sieve/` `/^}/`}}
+<p>
+Now <code>main</code>'s interface to the prime sieve is a channel of primes:
+<p>
+{{code "progs/sieve1.go" `/func.main/` `/^}/`}}
+<p>
+<h2>Multiplexing</h2>
+<p>
+With channels, it's possible to serve multiple independent client goroutines without
+writing an explicit multiplexer.  The trick is to send the server a channel in the message,
+which it will then use to reply to the original sender.
+A realistic client-server program is a lot of code, so here is a very simple substitute
+to illustrate the idea.  It starts by defining a <code>request</code> type, which embeds a channel
+that will be used for the reply.
+<p>
+{{code "progs/server.go" `/type.request/` `/^}/`}}
+<p>
+The server will be trivial: it will do simple binary operations on integers.  Here's the
+code that invokes the operation and responds to the request:
+<p>
+{{code "progs/server.go" `/type.binOp/` `/^}/`}}
+<p>
+The type declaration makes <code>binOp</code> represent a function taking two integers and
+returning a third.
+<p>
+The <code>server</code> routine loops forever, receiving requests and, to avoid blocking due to
+a long-running operation, starting a goroutine to do the actual work.
+<p>
+{{code "progs/server.go" `/func.server/` `/^}/`}}
+<p>
+We construct a server in a familiar way, starting it and returning a channel
+connected to it:
+<p>
+{{code "progs/server.go" `/func.startServer/` `/^}/`}}
+<p>
+Here's a simple test.  It starts a server with an addition operator and sends out
+<code>N</code> requests without waiting for the replies.  Only after all the requests are sent
+does it check the results.
+<p>
+{{code "progs/server.go" `/func.main/` `/^}/`}}
+<p>
+One annoyance with this program is that it doesn't shut down the server cleanly; when <code>main</code> returns
+there are a number of lingering goroutines blocked on communication.  To solve this,
+we can provide a second, <code>quit</code> channel to the server:
+<p>
+{{code "progs/server1.go" `/func.startServer/` `/^}/`}}
+<p>
+It passes the quit channel to the <code>server</code> function, which uses it like this:
+<p>
+{{code "progs/server1.go" `/func.server/` `/^}/`}}
+<p>
+Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications
+listed by its cases can proceed.  If all are blocked, it waits until one can proceed; if
+multiple can proceed, it chooses one at random.  In this instance, the <code>select</code> allows
+the server to honor requests until it receives a quit message, at which point it
+returns, terminating its execution.
+<p>
+<p>
+All that's left is to strobe the <code>quit</code> channel
+at the end of main:
+<p>
+{{code "progs/server1.go" `/adder,.quit/`}}
+...
+{{code "progs/server1.go" `/quit....true/`}}
+<p>
+There's a lot more to Go programming and concurrent programming in general but this
+quick tour should give you some of the basics.
diff --git a/doc/go_tutorial.txt b/doc/go_tutorial.txt
deleted file mode 100644
index 17ef6ee..0000000
--- a/doc/go_tutorial.txt
+++ /dev/null
@@ -1,934 +0,0 @@
-<!-- A Tutorial for the Go Programming Language -->
-Introduction
-----
-
-This document is a tutorial introduction to the basics of the Go programming
-language, intended for programmers familiar with C or C++. It is not a comprehensive
-guide to the language; at the moment the document closest to that is the
-<a href='/doc/go_spec.html'>language specification</a>.
-After you've read this tutorial, you should look at
-<a href='/doc/effective_go.html'>Effective Go</a>,
-which digs deeper into how the language is used and
-talks about the style and idioms of programming in Go.
-Also, slides from a 3-day course about Go are available.
-They provide some background and a lot of examples:
-<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
-<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
-<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
-
-The presentation here proceeds through a series of modest programs to illustrate
-key features of the language.  All the programs work (at time of writing) and are
-checked into the repository in the directory <a href='/doc/progs'>"/doc/progs/"</a>.
-
-Program snippets are annotated with the line number in the original file; for
-cleanliness, blank lines remain blank.
-
-Hello, World
-----
-
-Let's start in the usual way:
-
-!src progs/helloworld.go /package/ $
-
-Every Go source file declares, using a "package" statement, which package it's part of.
-It may also import other packages to use their facilities.
-This program imports the package "fmt" to gain access to
-our old, now capitalized and package-qualified, friend, "fmt.Printf".
-
-Functions are introduced with the "func" keyword.
-The "main" package's "main" function is where the program starts running (after
-any initialization).
-
-String constants can contain Unicode characters, encoded in UTF-8.
-(In fact, Go source files are defined to be encoded in UTF-8.)
-
-The comment convention is the same as in C++:
-
-	/* ... */
-	// ...
-
-Later we'll have much more to say about printing.
-
-Semicolons
-----
-
-You might have noticed that our program has no semicolons.  In Go
-code, the only place you typically see semicolons is separating the
-clauses of "for" loops and the like; they are not necessary after
-every statement.
-
-In fact, what happens is that the formal language uses semicolons,
-much as in C or Java, but they are inserted automatically
-at the end of every line that looks like the end of a statement. You
-don't need to type them yourself.
-
-For details about how this is done you can see the language
-specification, but in practice all you need to know is that you
-never need to put a semicolon at the end of a line.  (You can put
-them in if you want to write multiple statements per line.) As an
-extra help, you can also leave out a semicolon immediately before
-a closing brace.
-
-This approach makes for clean-looking, semicolon-free code.  The
-one surprise is that it's important to put the opening
-brace of a construct such as an "if" statement on the same line as
-the "if"; if you don't, there are situations that may not compile
-or may give the wrong result.  The language forces the brace style
-to some extent.
-
-Compiling
-----
-
-Go is a compiled language.  At the moment there are two compilers.
-"Gccgo" is a Go compiler that uses the GCC back end.  There is also a
-suite of compilers with different (and odd) names for each architecture:
-"6g" for the 64-bit x86, "8g" for the 32-bit x86, and more.  These
-compilers run significantly faster but generate less efficient code
-than "gccgo".  At the time of writing (late 2009), they also have
-a more robust run-time system although "gccgo" is catching up.
-
-Here's how to compile and run our program.  With "6g", say,
-
-	$ 6g helloworld.go  # compile; object goes into helloworld.6
-	$ 6l helloworld.6   # link; output goes into 6.out
-	$ 6.out
-	Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
-	$
-
-With "gccgo" it looks a little more traditional.
-
-	$ gccgo helloworld.go
-	$ a.out
-	Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
-	$
-
-Echo
-----
-
-Next up, here's a version of the Unix utility "echo(1)":
-
-!src progs/echo.go /package/ $
-
-This program is small but it's doing a number of new things.  In the last example,
-we saw "func" introduce a function.  The keywords "var", "const", and "type"
-(not used yet) also introduce declarations, as does "import".
-Notice that we can group declarations of the same sort into
-parenthesized lists, one item per line, as in the "import" and "const" clauses here.
-But it's not necessary to do so; we could have said
-
-	const Space = " "
-	const Newline = "\n"
-
-This program imports the ""os"" package to access its "Stdout" variable, of type
-"*os.File".  The "import" statement is actually a declaration: in its general form,
-as used in our ``hello world'' program,
-it names the identifier ("fmt")
-that will be used to access members of the package imported from the file (""fmt""),
-found in the current directory or in a standard location.
-In this program, though, we've dropped the explicit name from the imports; by default,
-packages are imported using the name defined by the imported package,
-which by convention is of course the file name itself.  Our ``hello world'' program
-could have said just "import "fmt"".
-
-You can specify your
-own import names if you want but it's only necessary if you need to resolve
-a naming conflict.
-
-Given "os.Stdout" we can use its "WriteString" method to print the string.
-
-Having imported the "flag" package, line 12 creates a global variable to hold
-the value of echo's "-n" flag. The variable "omitNewline" has type "*bool", pointer
-to "bool".
-
-In "main.main", we parse the arguments (line 20) and then create a local
-string variable we will use to build the output.
-
-The declaration statement has the form
-
-	var s string = ""
-
-This is the "var" keyword, followed by the name of the variable, followed by
-its type, followed by an equals sign and an initial value for the variable.
-
-Go tries to be terse, and this declaration could be shortened.  Since the
-string constant is of type string, we don't have to tell the compiler that.
-We could write
-
-	var s = ""
-
-or we could go even shorter and write the idiom
-
-	s := ""
-
-The ":=" operator is used a lot in Go to represent an initializing declaration.
-There's one in the "for" clause on the next line:
-
-!src  progs/echo.go /for/
-
-The "flag" package has parsed the arguments and left the non-flag arguments
-in a list that can be iterated over in the obvious way.
-
-The Go "for" statement differs from that of C in a number of ways.  First,
-it's the only looping construct; there is no "while" or "do".  Second,
-there are no parentheses on the clause, but the braces on the body
-are mandatory.  The same applies to the "if" and "switch" statements.
-Later examples will show some other ways "for" can be written.
-
-The body of the loop builds up the string "s" by appending (using "+=")
-the arguments and separating spaces. After the loop, if the "-n" flag is not
-set, the program appends a newline. Finally, it writes the result.
-
-Notice that "main.main" is a niladic function with no return type.
-It's defined that way.  Falling off the end of "main.main" means
-''success''; if you want to signal an erroneous return, call
-
-	os.Exit(1)
-
-The "os" package contains other essentials for getting
-started; for instance, "os.Args" is a slice used by the
-"flag" package to access the command-line arguments.
-
-An Interlude about Types
-----
-
-Go has some familiar types such as "int" and "uint" (unsigned "int"), which represent
-values of the ''appropriate'' size for the machine. It also defines
-explicitly-sized types such as "int8", "float64", and so on, plus
-unsigned integer types such as "uint", "uint32", etc.
-These are distinct types; even if "int" and "int32" are both 32 bits in size,
-they are not the same type.  There is also a "byte" synonym for
-"uint8", which is the element type for strings.
-
-Floating-point types are always sized: "float32" and "float64",
-plus "complex64" (two "float32s") and "complex128"
-(two "float64s").  Complex numbers are outside the
-scope of this tutorial.
-
-Speaking of "string", that's a built-in type as well.  Strings are
-<i>immutable values</i>—they are not just arrays of "byte" values.
-Once you've built a string <i>value</i>, you can't change it, although
-of course you can change a string <i>variable</i> simply by
-reassigning it.  This snippet from "strings.go" is legal code:
-
-!src progs/strings.go /hello/ /ciao/
-
-However the following statements are illegal because they would modify
-a "string" value:
-
-	s[0] = 'x'
-	(*p)[1] = 'y'
-
-In C++ terms, Go strings are a bit like "const strings", while pointers
-to strings are analogous to "const string" references.
-
-Yes, there are pointers.  However, Go simplifies their use a little;
-read on.
-
-Arrays are declared like this:
-
-	var arrayOfInt [10]int
-
-Arrays, like strings, are values, but they are mutable. This differs
-from C, in which "arrayOfInt" would be usable as a pointer to "int".
-In Go, since arrays are values, it's meaningful (and useful) to talk
-about pointers to arrays.
-
-The size of the array is part of its type; however, one can declare
-a <i>slice</i> variable to hold a reference to any array, of any size,
-with the same element type.
-A <i>slice
-expression</i> has the form "a[low : high]", representing
-the internal array indexed from "low" through "high-1"; the resulting
-slice is indexed from "0" through "high-low-1".
-In short, slices look a lot like arrays but with
-no explicit size ("[]" vs. "[10]") and they reference a segment of
-an underlying, usually anonymous, regular array.  Multiple slices
-can share data if they represent pieces of the same array;
-multiple arrays can never share data.
-
-Slices are much more common in Go programs than
-regular arrays; they're more flexible, have reference semantics,
-and are efficient.  What they lack is the precise control of storage
-layout of a regular array; if you want to have a hundred elements
-of an array stored within your structure, you should use a regular
-array. To create one, use a compound value <i>constructor</i>—an
-expression formed
-from a type followed by a brace-bounded expression like this:
-
-	[3]int{1,2,3}
-
-In this case the constructor builds an array of 3 "ints".
-
-When passing an array to a function, you almost always want
-to declare the formal parameter to be a slice.  When you call
-the function, slice the array to create
-(efficiently) a slice reference and pass that.
-By default, the lower and upper bounds of a slice match the
-ends of the existing object, so the concise notation "[:]"
-will slice the whole array.
-
-Using slices one can write this function (from "sum.go"):
-
-!src progs/sum.go /sum/ /^}/
-
-Note how the return type ("int") is defined for "sum" by stating it
-after the parameter list.
-
-To call the function, we slice the array.  This intricate call (we'll show
-a simpler way in a moment) constructs
-an array and slices it:
-
-	s := sum([3]int{1,2,3}[:])
-
-If you are creating a regular array but want the compiler to count the
-elements for you, use "..." as the array size:
-
-	s := sum([...]int{1,2,3}[:])
-
-That's fussier than necessary, though.
-In practice, unless you're meticulous about storage layout within a
-data structure, a slice itself—using empty brackets with no size—is all you need:
-
-	s := sum([]int{1,2,3})
-
-There are also maps, which you can initialize like this:
-
-	m := map[string]int{"one":1 , "two":2}
-
-The built-in function "len", which returns number of elements,
-makes its first appearance in "sum".  It works on strings, arrays,
-slices, maps, and channels.
-
-By the way, another thing that works on strings, arrays, slices, maps
-and channels is the "range" clause on "for" loops.  Instead of writing
-
-	for i := 0; i < len(a); i++ { ... }
-
-to loop over the elements of a slice (or map or ...) , we could write
-
-	for i, v := range a { ... }
-
-This assigns "i" to the index and "v" to the value of the successive
-elements of the target of the range.   See
-<a href='/doc/effective_go.html'>Effective Go</a>
-for more examples of its use.
-
-
-An Interlude about Allocation
-----
-
-Most types in Go are values. If you have an "int" or a "struct"
-or an array, assignment
-copies the contents of the object.
-To allocate a new variable, use the built-in function "new", which
-returns a pointer to the allocated storage.
-
-	type T struct { a, b int }
-	var t *T = new(T)
-
-or the more idiomatic
-
-	t := new(T)
-
-Some types—maps, slices, and channels (see below)—have reference semantics.
-If you're holding a slice or a map and you modify its contents, other variables
-referencing the same underlying data will see the modification.  For these three
-types you want to use the built-in function "make":
-
-	m := make(map[string]int)
-
-This statement initializes a new map ready to store entries.
-If you just declare the map, as in
-
-	var m map[string]int
-
-it creates a "nil" reference that cannot hold anything. To use the map,
-you must first initialize the reference using "make" or by assignment from an
-existing map.
-
-Note that "new(T)" returns type "*T" while "make(T)" returns type
-"T".  If you (mistakenly) allocate a reference object with "new" rather than "make",
-you receive a pointer to a nil reference, equivalent to
-declaring an uninitialized variable and taking its address.
-
-An Interlude about Constants
-----
-
-Although integers come in lots of sizes in Go, integer constants do not.
-There are no constants like "0LL" or "0x0UL".   Instead, integer
-constants are evaluated as large-precision values that
-can overflow only when they are assigned to an integer variable with
-too little precision to represent the value.
-
-	const hardEight = (1 << 100) >> 97  // legal
-
-There are nuances that deserve redirection to the legalese of the
-language specification but here are some illustrative examples:
-
-	var a uint64 = 0  // a has type uint64, value 0
-	a := uint64(0)    // equivalent; uses a "conversion"
-	i := 0x1234       // i gets default type: int
-	var j int = 1e6   // legal - 1000000 is representable in an int
-	x := 1.5          // a float64, the default type for floating constants
-	i3div2 := 3/2     // integer division - result is 1
-	f3div2 := 3./2.   // floating-point division - result is 1.5
-
-Conversions only work for simple cases such as converting "ints" of one
-sign or size to another and between integers and floating-point numbers,
-plus a couple of other instances outside the scope of a tutorial.
-There are no automatic numeric conversions of any kind in Go,
-other than that of making constants have concrete size and type when
-assigned to a variable.
-
-An I/O Package
-----
-
-Next we'll look at a simple package for doing file I/O with an
-open/close/read/write interface.  Here's the start of "file.go":
-
-!src progs/file.go /package/ /^}/
-
-The first few lines declare the name of the
-package—"file"—and then import two packages.  The "os"
-package hides the differences
-between various operating systems to give a consistent view of files and
-so on; here we're going to use its error handling utilities
-and reproduce the rudiments of its file I/O.
-
-The other item is the low-level, external "syscall" package, which provides
-a primitive interface to the underlying operating system's calls.
-
-Next is a type definition: the "type" keyword introduces a type declaration,
-in this case a data structure called "File".
-To make things a little more interesting, our "File" includes the name of the file
-that the file descriptor refers to.
-
-Because "File" starts with a capital letter, the type is available outside the package,
-that is, by users of the package.   In Go the rule about visibility of information is
-simple: if a name (of a top-level type, function, method, constant or variable, or of
-a structure field or method) is capitalized, users of the package may see it. Otherwise, the
-name and hence the thing being named is visible only inside the package in which
-it is declared.  This is more than a convention; the rule is enforced by the compiler.
-In Go, the term for publicly visible names is ''exported''.
-
-In the case of "File", all its fields are lower case and so invisible to users, but we
-will soon give it some exported, upper-case methods.
-
-First, though, here is a factory to create a "File":
-
-!src progs/file.go /newFile/ /^}/
-
-This returns a pointer to a new "File" structure with the file descriptor and name
-filled in.  This code uses Go's notion of a ''composite literal'', analogous to
-the ones used to build maps and arrays, to construct a new heap-allocated
-object.  We could write
-
-	n := new(File)
-	n.fd = fd
-	n.name = name
-	return n
-
-but for simple structures like "File" it's easier to return the address of a 
-composite literal, as is done here on line 21.
-
-We can use the factory to construct some familiar, exported variables of type "*File":
-
-!src progs/file.go /var/ /^.$/
-
-The "newFile" function was not exported because it's internal. The proper,
-exported factory to use is "OpenFile" (we'll explain that name in a moment):
-
-!src progs/file.go /func.OpenFile/ /^}/
-
-There are a number of new things in these few lines.  First, "OpenFile" returns
-multiple values, a "File" and an error (more about errors in a moment).
-We declare the
-multi-value return as a parenthesized list of declarations; syntactically
-they look just like a second parameter list.  The function
-"syscall.Open"
-also has a multi-value return, which we can grab with the multi-variable
-declaration on line 31; it declares "r" and "e" to hold the two values,
-both of type "int" (although you'd have to look at the "syscall" package
-to see that).  Finally, line 35 returns two values: a pointer to the new "File"
-and the error.  If "syscall.Open" fails, the file descriptor "r" will
-be negative and "newFile" will return "nil".
-
-About those errors:  The "os" library includes a general notion of an error.
-It's a good idea to use its facility in your own interfaces, as we do here, for
-consistent error handling throughout Go code.   In "Open" we use a
-conversion to translate Unix's integer "errno" value into the integer type
-"os.Errno", which implements "os.Error".
-
-Why "OpenFile" and not "Open"? To mimic Go's "os" package, which
-our exercise is emulating. The "os" package takes the opportunity
-to make the two commonest cases - open for read and create for
-write - the simplest, just "Open" and "Create".  "OpenFile" is the
-general case, analogous to the Unix system call "Open".  Here is
-the implementation of our "Open" and "Create"; they're trivial
-wrappers that eliminate common errors by capturing
-the tricky standard arguments to open and, especially, to create a file:
-
-!src progs/file.go /^const/ /^}/
-
-!src progs/file.go /func.Create/ /^}/
-
-Back to our main story.
-Now that we can build "Files", we can write methods for them. To declare
-a method of a type, we define a function to have an explicit receiver
-of that type, placed
-in parentheses before the function name. Here are some methods for "*File",
-each of which declares a receiver variable "file".
-
-!src progs/file.go /Close/ $
-
-There is no implicit "this" and the receiver variable must be used to access
-members of the structure.  Methods are not declared within
-the "struct" declaration itself.  The "struct" declaration defines only data members.
-In fact, methods can be created for almost any type you name, such as an integer or
-array, not just for "structs".   We'll see an example with arrays later.
-
-The "String" method is so called because of a printing convention we'll
-describe later.
-
-The methods use the public variable "os.EINVAL" to return the ("os.Error"
-version of the) Unix error code "EINVAL".  The "os" library defines a standard
-set of such error values.
-
-We can now use our new package:
-
-!src progs/helloworld3.go /package/ $
-
-The ''"./"'' in the import of ''"./file"'' tells the compiler
-to use our own package rather than
-something from the directory of installed packages.
-(Also, ''"file.go"'' must be compiled before we can import the
-package.)
-
-Now we can compile and run the program. On Unix, this would be the result:
-
-	$ 6g file.go                       # compile file package
-	$ 6g helloworld3.go                # compile main package
-	$ 6l -o helloworld3 helloworld3.6  # link - no need to mention "file"
-	$ helloworld3
-	hello, world
-	can't open file; err=No such file or directory
-	$
-
-Rotting cats
-----
-
-Building on the "file" package, here's a simple version of the Unix utility "cat(1)",
-"progs/cat.go":
-
-!src progs/cat.go /package/ $
-
-By now this should be easy to follow, but the "switch" statement introduces some
-new features.  Like a "for" loop, an "if" or "switch" can include an
-initialization statement.  The "switch" statement in "cat" uses one to create variables
-"nr" and "er" to hold the return values from the call to "f.Read".  (The "if" a few lines later
-has the same idea.)  The "switch" statement is general: it evaluates the cases
-from  top to bottom looking for the first case that matches the value; the
-case expressions don't need to be constants or even integers, as long as
-they all have the same type.
-
-Since the "switch" value is just "true", we could leave it off—as is also
-the situation
-in a "for" statement, a missing value means "true".  In fact, such a "switch"
-is a form of "if-else" chain. While we're here, it should be mentioned that in
-"switch" statements each "case" has an implicit "break".
-
-The argument to "file.Stdout.Write" is created by slicing the array "buf".
-Slices provide the standard Go way to handle I/O buffers.
-
-Now let's make a variant of "cat" that optionally does "rot13" on its input.
-It's easy to do by just processing the bytes, but instead we will exploit
-Go's notion of an <i>interface</i>.
-
-The "cat" subroutine uses only two methods of "f": "Read" and "String",
-so let's start by defining an interface that has exactly those two methods.
-Here is code from "progs/cat_rot13.go":
-
-!src progs/cat_rot13.go /type.reader/ /^}/
-
-Any type that has the two methods of "reader"—regardless of whatever
-other methods the type may also have—is said to <i>implement</i> the
-interface.  Since "file.File" implements these methods, it implements the
-"reader" interface.  We could tweak the "cat" subroutine to accept a "reader"
-instead of a "*file.File" and it would work just fine, but let's embellish a little
-first by writing a second type that implements "reader", one that wraps an
-existing "reader" and does "rot13" on the data. To do this, we just define
-the type and implement the methods and with no other bookkeeping,
-we have a second implementation of the "reader" interface.
-
-!src progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/
-
-(The "rot13" function called in "Read" is trivial and not worth reproducing here.)
-
-To use the new feature, we define a flag:
-
-!src progs/cat_rot13.go /rot13Flag/
-
-and use it from within a mostly unchanged "cat" function:
-
-!src progs/cat_rot13.go /func.cat/ /^}/
-
-(We could also do the wrapping in "main" and leave "cat" mostly alone, except
-for changing the type of the argument; consider that an exercise.)
-The "if" at the top of "cat" sets it all up: If the "rot13" flag is true, wrap the "reader"
-we received into a "rotate13" and proceed.  Note that the interface variables
-are values, not pointers: the argument is of type "reader", not "*reader",
-even though under the covers it holds a pointer to a "struct".
-
-Here it is in action:
-
-	$ echo abcdefghijklmnopqrstuvwxyz | ./cat
-	abcdefghijklmnopqrstuvwxyz
-	$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
-	nopqrstuvwxyzabcdefghijklm
-	$
-
-Fans of dependency injection may take cheer from how easily interfaces
-allow us to substitute the implementation of a file descriptor.
-
-Interfaces are a distinctive feature of Go.  An interface is implemented by a
-type if the type implements all the methods declared in the interface.
-This means
-that a type may implement an arbitrary number of different interfaces.
-There is no type hierarchy; things can be much more <i>ad hoc</i>,
-as we saw with "rot13".  The type "file.File" implements "reader"; it could also
-implement a "writer", or any other interface built from its methods that
-fits the current situation. Consider the <i>empty interface</i>
-
-	type Empty interface {}
-
-<i>Every</i> type implements the empty interface, which makes it
-useful for things like containers.
-
-Sorting
-----
-
-Interfaces provide a simple form of polymorphism.  They completely
-separate the definition of what an object does from how it does it, allowing
-distinct implementations to be represented at different times by the
-same interface variable.
-
-As an example, consider this simple sort algorithm taken from "progs/sort.go":
-
-!src progs/sort.go /func.Sort/ /^}/
-
-The code needs only three methods, which we wrap into sort's "Interface":
-
-!src progs/sort.go /interface/ /^}/
-
-We can apply "Sort" to any type that implements "Len", "Less", and "Swap".
-The "sort" package includes the necessary methods to allow sorting of
-arrays of integers, strings, etc.; here's the code for arrays of "int"
-
-!src progs/sort.go /type.*IntSlice/ /Swap/
-
-Here we see methods defined for non-"struct" types.  You can define methods
-for any type you define and name in your package.
-
-And now a routine to test it out, from "progs/sortmain.go".  This
-uses a function in the "sort" package, omitted here for brevity,
-to test that the result is sorted.
-
-!src progs/sortmain.go /func.ints/ /^}/
-
-If we have a new type we want to be able to sort, all we need to do is
-to implement the three methods for that type, like this:
-
-!src progs/sortmain.go /type.day/ /Swap/
-
-
-Printing
-----
-
-The examples of formatted printing so far have been modest.  In this section
-we'll talk about how formatted I/O can be done well in Go.
-
-We've seen simple uses of the package "fmt", which
-implements "Printf", "Fprintf", and so on.
-Within the "fmt" package, "Printf" is declared with this signature:
-
-	Printf(format string, v ...interface{}) (n int, errno os.Error)
-
-The token "..." introduces a variable-length argument list that in C would
-be handled using the "stdarg.h" macros.
-In Go, variadic functions are passed a slice of the arguments of the
-specified type.  In "Printf"'s case, the declaration says "...interface{}"
-so the actual type is a slice of empty interface values, "[]interface{}".
-"Printf" can examine the arguments by iterating over the slice
-and, for each element, using a type switch or the reflection library
-to interpret the value.
-It's off topic here but such run-time type analysis
-helps explain some of the nice properties of Go's "Printf",
-due to the ability of "Printf" to discover the type of its arguments
-dynamically.
-
-For example, in C each format must correspond to the type of its
-argument.  It's easier in many cases in Go.  Instead of "%llud" you
-can just say "%d"; "Printf" knows the size and signedness of the
-integer and can do the right thing for you.  The snippet
-
-!src progs/print.go 10 11
-
-prints
-
-	18446744073709551615 -1
-
-In fact, if you're lazy the format "%v" will print, in a simple
-appropriate style, any value, even an array or structure.  The output of
-
-!src progs/print.go 14 20
-
-is
-
-	18446744073709551615 {77 Sunset Strip} [1 2 3 4]
-
-You can drop the formatting altogether if you use "Print" or "Println"
-instead of "Printf".  Those routines do fully automatic formatting.
-The "Print" function just prints its elements out using the equivalent
-of "%v" while "Println" inserts spaces between arguments
-and adds a newline.  The output of each of these two lines is identical
-to that of the "Printf" call above.
-
-!src progs/print.go 21 22
-
-If you have your own type you'd like "Printf" or "Print" to format,
-just give it a "String" method that returns a string.  The print
-routines will examine the value to inquire whether it implements
-the method and if so, use it rather than some other formatting.
-Here's a simple example.
-
-!src progs/print_string.go 9 $
-
-Since "*testType" has a "String" method, the
-default formatter for that type will use it and produce the output
-
-	77 Sunset Strip
-
-Observe that the "String" method calls "Sprint" (the obvious Go
-variant that returns a string) to do its formatting; special formatters
-can use the "fmt" library recursively.
-
-Another feature of "Printf" is that the format "%T" will print a string
-representation of the type of a value, which can be handy when debugging
-polymorphic code.
-
-It's possible to write full custom print formats with flags and precisions
-and such, but that's getting a little off the main thread so we'll leave it
-as an exploration exercise.
-
-You might ask, though, how "Printf" can tell whether a type implements
-the "String" method.  Actually what it does is ask if the value can
-be converted to an interface variable that implements the method.
-Schematically, given a value "v", it does this:
-
-
-	type Stringer interface {
-		String() string
-	}
-
-	s, ok := v.(Stringer)  // Test whether v implements "String()"
-	if ok {
-		result = s.String()
-	} else {
-		result = defaultOutput(v)
-	}
-
-The code uses a ``type assertion'' ("v.(Stringer)") to test if the value stored in
-"v" satisfies the "Stringer" interface; if it does, "s"
-will become an interface variable implementing the method and "ok" will
-be "true".  We then use the interface variable to call the method.
-(The ''comma, ok'' pattern is a Go idiom used to test the success of
-operations such as type conversion, map update, communications, and so on,
-although this is the only appearance in this tutorial.)
-If the value does not satisfy the interface, "ok" will be false.
-
-In this snippet the name "Stringer" follows the convention that we add ''[e]r''
-to interfaces describing simple method sets like this.
-
-One last wrinkle.  To complete the suite, besides "Printf" etc. and "Sprintf"
-etc., there are also "Fprintf" etc.  Unlike in C, "Fprintf"'s first argument is
-not a file.  Instead, it is a variable of type "io.Writer", which is an
-interface type defined in the "io" library:
-
-	type Writer interface {
-		Write(p []byte) (n int, err os.Error)
-	}
-
-(This interface is another conventional name, this time for "Write"; there are also
-"io.Reader", "io.ReadWriter", and so on.)
-Thus you can call "Fprintf" on any type that implements a standard "Write"
-method, not just files but also network channels, buffers, whatever
-you want.
-
-Prime numbers
-----
-
-Now we come to processes and communication—concurrent programming.
-It's a big subject so to be brief we assume some familiarity with the topic.
-
-A classic program in the style is a prime sieve.
-(The sieve of Eratosthenes is computationally more efficient than
-the algorithm presented here, but we are more interested in concurrency than
-algorithmics at the moment.)
-It works by taking a stream of all the natural numbers and introducing
-a sequence of filters, one for each prime, to winnow the multiples of
-that prime.  At each step we have a sequence of filters of the primes
-so far, and the next number to pop out is the next prime, which triggers
-the creation of the next filter in the chain.
-
-Here's a flow diagram; each box represents a filter element whose
-creation is triggered by the first number that flowed from the
-elements before it.
-
-<br>
-
-     <img src='sieve.gif'>
-
-<br>
-
-To create a stream of integers, we use a Go <i>channel</i>, which,
-borrowing from CSP's descendants, represents a communications
-channel that can connect two concurrent computations.
-In Go, channel variables are references to a run-time object that
-coordinates the communication; as with maps and slices, use
-"make" to create a new channel.
-
-Here is the first function in "progs/sieve.go":
-
-!src progs/sieve.go /Send/ /^}/
-
-The "generate" function sends the sequence 2, 3, 4, 5, ... to its
-argument channel, "ch", using the binary communications operator "<-".
-Channel operations block, so if there's no recipient for the value on "ch",
-the send operation will wait until one becomes available.
-
-The "filter" function has three arguments: an input channel, an output
-channel, and a prime number.  It copies values from the input to the
-output, discarding anything divisible by the prime.  The unary communications
-operator "<-" (receive) retrieves the next value on the channel.
-
-!src progs/sieve.go /Copy.the/ /^}/
-
-The generator and filters execute concurrently.  Go has
-its own model of process/threads/light-weight processes/coroutines,
-so to avoid notational confusion we call concurrently executing
-computations in Go <i>goroutines</i>.  To start a goroutine,
-invoke the function, prefixing the call with the keyword "go";
-this starts the function running in parallel with the current
-computation but in the same address space:
-
-	go sum(hugeArray) // calculate sum in the background
-
-If you want to know when the calculation is done, pass a channel
-on which it can report back:
-
-	ch := make(chan int)
-	go sum(hugeArray, ch)
-	// ... do something else for a while
-	result := <-ch  // wait for, and retrieve, result
-
-Back to our prime sieve.  Here's how the sieve pipeline is stitched
-together:
-
-!src progs/sieve.go /func.main/ /^}/
-
-The first line of "main" creates the initial channel to pass to "generate", which it
-then starts up.  As each prime pops out of the channel, a new "filter"
-is added to the pipeline and <i>its</i> output becomes the new value
-of "ch".
-
-The sieve program can be tweaked to use a pattern common
-in this style of programming.  Here is a variant version
-of "generate", from "progs/sieve1.go":
-
-!src progs/sieve1.go /func.generate/ /^}/
-
-This version does all the setup internally. It creates the output
-channel, launches a goroutine running a function literal, and
-returns the channel to the caller.  It is a factory for concurrent
-execution, starting the goroutine and returning its connection.
-
-The function literal notation used in the "go" statement allows us to construct an
-anonymous function and invoke it on the spot. Notice that the local
-variable "ch" is available to the function literal and lives on even
-after "generate" returns.
-
-The same change can be made to "filter":
-
-!src progs/sieve1.go /func.filter/ /^}/
-
-The "sieve" function's main loop becomes simpler and clearer as a
-result, and while we're at it let's turn it into a factory too:
-
-!src progs/sieve1.go /func.sieve/ /^}/
-
-Now "main"'s interface to the prime sieve is a channel of primes:
-
-!src progs/sieve1.go /func.main/ /^}/
-
-Multiplexing
-----
-
-With channels, it's possible to serve multiple independent client goroutines without
-writing an explicit multiplexer.  The trick is to send the server a channel in the message,
-which it will then use to reply to the original sender.
-A realistic client-server program is a lot of code, so here is a very simple substitute
-to illustrate the idea.  It starts by defining a "request" type, which embeds a channel
-that will be used for the reply.
-
-!src progs/server.go /type.request/ /^}/
-
-The server will be trivial: it will do simple binary operations on integers.  Here's the
-code that invokes the operation and responds to the request:
-
-!src progs/server.go /type.binOp/ /^}/
-
-The type declaration makes "binOp" represent a function taking two integers and
-returning a third.
-
-The "server" routine loops forever, receiving requests and, to avoid blocking due to
-a long-running operation, starting a goroutine to do the actual work.
-
-!src progs/server.go /func.server/ /^}/
-
-We construct a server in a familiar way, starting it and returning a channel
-connected to it:
-
-!src progs/server.go /func.startServer/ /^}/
-
-Here's a simple test.  It starts a server with an addition operator and sends out
-"N" requests without waiting for the replies.  Only after all the requests are sent
-does it check the results.
-
-!src progs/server.go /func.main/ /^}/
-
-One annoyance with this program is that it doesn't shut down the server cleanly; when "main" returns
-there are a number of lingering goroutines blocked on communication.  To solve this,
-we can provide a second, "quit" channel to the server:
-
-!src progs/server1.go /func.startServer/ /^}/
-
-It passes the quit channel to the "server" function, which uses it like this:
-
-!src progs/server1.go /func.server/ /^}/
-
-Inside "server", the "select" statement chooses which of the multiple communications
-listed by its cases can proceed.  If all are blocked, it waits until one can proceed; if
-multiple can proceed, it chooses one at random.  In this instance, the "select" allows
-the server to honor requests until it receives a quit message, at which point it
-returns, terminating its execution.
-
-
-All that's left is to strobe the "quit" channel
-at the end of main:
-
-!src progs/server1.go /adder,.quit/
-...
-!src progs/server1.go /quit....true/
-
-There's a lot more to Go programming and concurrent programming in general but this
-quick tour should give you some of the basics.
diff --git a/doc/htmlgen.go b/doc/htmlgen.go
deleted file mode 100644
index 5318a07..0000000
--- a/doc/htmlgen.go
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// If --html is set, process plain text into HTML.
-//	- h2's are made from lines followed by a line "----\n"
-//	- tab-indented blocks become <pre> blocks with the first tab deleted
-//	- blank lines become <p> marks (except inside <pre> tags)
-//	- "quoted strings" become <code>quoted strings</code>
-
-// Lines beginning !src define pieces of program source to be
-// extracted from other files and injected as <pre> blocks.
-// The syntax is simple: 1, 2, or 3 space-separated arguments:
-//
-// Whole file:
-//	!src foo.go
-// One line (here the signature of main):
-//	!src foo.go /^func.main/
-// Block of text, determined by start and end (here the body of main):
-// !src foo.go /^func.main/ /^}/
-//
-// Patterns can be /regular.expression/, a decimal number, or $
-// to signify the end of the file.
-// TODO: the regular expression cannot contain spaces; does this matter?
-
-package main
-
-import (
-	"bufio"
-	"bytes"
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"os"
-	"regexp"
-	"strconv"
-	"strings"
-	"template"
-)
-
-var (
-	html = flag.Bool("html", true, "process text into HTML")
-)
-
-var (
-	// lines holds the input and is reworked in place during processing.
-	lines = make([][]byte, 0, 20000)
-
-	empty   = []byte("")
-	newline = []byte("\n")
-	tab     = []byte("\t")
-	quote   = []byte(`"`)
-	indent  = []byte("    ")
-
-	sectionMarker = []byte("----\n")
-	preStart      = []byte("<pre>")
-	preEnd        = []byte("</pre>\n")
-	pp            = []byte("<p>\n")
-
-	srcPrefix = []byte("!src")
-)
-
-func main() {
-	flag.Parse()
-	read()
-	programs()
-	if *html {
-		headings()
-		coalesce(preStart, foldPre)
-		coalesce(tab, foldTabs)
-		paragraphs()
-		quotes()
-	}
-	write()
-}
-
-// read turns standard input into a slice of lines.
-func read() {
-	b := bufio.NewReader(os.Stdin)
-	for {
-		line, err := b.ReadBytes('\n')
-		if err == os.EOF {
-			break
-		}
-		if err != nil {
-			log.Fatal(err)
-		}
-		lines = append(lines, line)
-	}
-}
-
-// write puts the result on standard output.
-func write() {
-	b := bufio.NewWriter(os.Stdout)
-	for _, line := range lines {
-		b.Write(expandTabs(line))
-	}
-	b.Flush()
-}
-
-// programs injects source code from !src invocations.
-func programs() {
-	nlines := make([][]byte, 0, len(lines)*3/2)
-	for _, line := range lines {
-		if bytes.HasPrefix(line, srcPrefix) {
-			line = trim(line)[len(srcPrefix):]
-			prog := srcCommand(string(line))
-			if *html {
-				nlines = append(nlines, []byte(fmt.Sprintf("<pre><!--%s\n-->", line)))
-			}
-			for _, l := range prog {
-				nlines = append(nlines, htmlEscape(l))
-			}
-			if *html {
-				nlines = append(nlines, preEnd)
-			}
-		} else {
-			nlines = append(nlines, line)
-		}
-	}
-	lines = nlines
-}
-
-// srcCommand processes one !src invocation.
-func srcCommand(command string) [][]byte {
-	// TODO: quoted args so we can have 'a b'?
-	args := strings.Fields(command)
-	if len(args) == 0 || len(args) > 3 {
-		log.Fatal("bad syntax for src command: %s", command)
-	}
-	file := args[0]
-	lines := bytes.SplitAfter(readFile(file), newline)
-	// File plus zero args: whole file:
-	//	!src file.go
-	if len(args) == 1 {
-		return lines
-	}
-	start := match(file, 0, lines, string(args[1]))
-	// File plus one arg: one line:
-	//	!src file.go /foo/
-	if len(args) == 2 {
-		return [][]byte{lines[start]}
-	}
-	// File plus two args: range:
-	//	!src file.go /foo/ /^}/
-	end := match(file, start, lines, string(args[2]))
-	return lines[start : end+1] // +1 to include matched line.
-}
-
-// htmlEscape makes sure input is HTML clean, if necessary.
-func htmlEscape(input []byte) []byte {
-	if !*html || bytes.IndexAny(input, `&"<>`) < 0 {
-		return input
-	}
-	var b bytes.Buffer
-	template.HTMLEscape(&b, input)
-	return b.Bytes()
-}
-
-// readFile reads and returns a file as part of !src processing.
-func readFile(name string) []byte {
-	file, err := ioutil.ReadFile(name)
-	if err != nil {
-		log.Fatal(err)
-	}
-	return file
-}
-
-// match identifies the input line that matches the pattern in a !src invocation.
-// If start>0, match lines starting there rather than at the beginning.
-func match(file string, start int, lines [][]byte, pattern string) int {
-	// $ matches the end of the file.
-	if pattern == "$" {
-		return len(lines) - 1
-	}
-	// Number matches the line.
-	if i, err := strconv.Atoi(pattern); err == nil {
-		return i - 1 // Lines are 1-indexed.
-	}
-	// /regexp/ matches the line that matches the regexp.
-	if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
-		re, err := regexp.Compile(pattern[1 : len(pattern)-1])
-		if err != nil {
-			log.Fatal(err)
-		}
-		for i := start; i < len(lines); i++ {
-			if re.Match(lines[i]) {
-				return i
-			}
-		}
-		log.Fatalf("%s: no match for %s", file, pattern)
-	}
-	log.Fatalf("unrecognized pattern: %s", pattern)
-	return 0
-}
-
-// coalesce combines lines. Each time prefix is found on a line,
-// it calls fold and replaces the line with return value from fold.
-func coalesce(prefix []byte, fold func(i int) (n int, line []byte)) {
-	j := 0 // output line number goes up by one each loop
-	for i := 0; i < len(lines); {
-		if bytes.HasPrefix(lines[i], prefix) {
-			nlines, block := fold(i)
-			lines[j] = block
-			i += nlines
-		} else {
-			lines[j] = lines[i]
-			i++
-		}
-		j++
-	}
-	lines = lines[0:j]
-}
-
-// foldPre returns the <pre> block as a single slice.
-func foldPre(i int) (n int, line []byte) {
-	buf := new(bytes.Buffer)
-	for i < len(lines) {
-		buf.Write(lines[i])
-		n++
-		if bytes.Equal(lines[i], preEnd) {
-			break
-		}
-		i++
-	}
-	return n, buf.Bytes()
-}
-
-// foldTabs returns the tab-indented block as a single <pre>-bounded slice.
-func foldTabs(i int) (n int, line []byte) {
-	buf := new(bytes.Buffer)
-	buf.WriteString("<pre>\n")
-	for i < len(lines) {
-		if !bytes.HasPrefix(lines[i], tab) {
-			break
-		}
-		buf.Write(lines[i][1:]) // delete leading tab.
-		n++
-		i++
-	}
-	buf.WriteString("</pre>\n")
-	return n, buf.Bytes()
-}
-
-// headings turns sections into HTML sections.
-func headings() {
-	b := bufio.NewWriter(os.Stdout)
-	for i, l := range lines {
-		if i > 0 && bytes.Equal(l, sectionMarker) {
-			lines[i-1] = []byte("<h2>" + string(trim(lines[i-1])) + "</h2>\n")
-			lines[i] = empty
-		}
-	}
-	b.Flush()
-}
-
-// paragraphs turns blank lines into paragraph marks.
-func paragraphs() {
-	for i, l := range lines {
-		if bytes.Equal(l, newline) {
-			lines[i] = pp
-		}
-	}
-}
-
-// quotes turns "x" in the file into <code>x</code>.
-func quotes() {
-	for i, l := range lines {
-		lines[i] = codeQuotes(l)
-	}
-}
-
-// quotes turns "x" in the line into <code>x</code>.
-func codeQuotes(l []byte) []byte {
-	if bytes.HasPrefix(l, preStart) {
-		return l
-	}
-	n := bytes.Index(l, quote)
-	if n < 0 {
-		return l
-	}
-	buf := new(bytes.Buffer)
-	inQuote := false
-	for _, c := range l {
-		if c == '"' {
-			if inQuote {
-				buf.WriteString("</code>")
-			} else {
-				buf.WriteString("<code>")
-			}
-			inQuote = !inQuote
-		} else {
-			buf.WriteByte(c)
-		}
-	}
-	return buf.Bytes()
-}
-
-// trim drops the trailing newline, if present.
-func trim(l []byte) []byte {
-	n := len(l)
-	if n > 0 && l[n-1] == '\n' {
-		return l[0 : n-1]
-	}
-	return l
-}
-
-// expandTabs expands tabs to spaces. It doesn't worry about columns.
-func expandTabs(l []byte) []byte {
-	return bytes.Replace(l, tab, indent, -1)
-}
diff --git a/doc/makehtml b/doc/makehtml
index 1b8caed..2418c68 100755
--- a/doc/makehtml
+++ b/doc/makehtml
@@ -5,8 +5,8 @@
 
 set -e
 
-TXT=${1:-go_tutorial.txt}		# input file
-HTML=$(basename $TXT .txt).html		# output file (basename)
+TMPL=${1:-go_tutorial.tmpl}		# input file
+HTML=$(basename $TMPL .tmpl).html		# output file (basename)
 
 if ! test -w $HTML
 then
@@ -14,4 +14,4 @@ then
 	exit 1
 fi
 
-make htmlgen && ./htmlgen < $TXT > $HTML
+make && ./tmpltohtml $TMPL > $HTML
diff --git a/doc/progs/echo.go b/doc/progs/echo.go
index 84470dd..3260edd 100644
--- a/doc/progs/echo.go
+++ b/doc/progs/echo.go
@@ -6,18 +6,18 @@ package main
 
 import (
 	"os"
-	"flag"  // command line option parser
+	"flag" // command line option parser
 )
 
 var omitNewline = flag.Bool("n", false, "don't print final newline")
 
 const (
-	Space = " "
+	Space   = " "
 	Newline = "\n"
 )
 
 func main() {
-	flag.Parse()   // Scans the arg list and sets up flags
+	flag.Parse() // Scans the arg list and sets up flags
 	var s string = ""
 	for i := 0; i < flag.NArg(); i++ {
 		if i > 0 {
diff --git a/doc/progs/file_windows.go b/doc/progs/file_windows.go
index d5e7c00..03003a3 100644
--- a/doc/progs/file_windows.go
+++ b/doc/progs/file_windows.go
@@ -10,8 +10,8 @@ import (
 )
 
 type File struct {
-	fd   syscall.Handle    // file descriptor number
-	name string // file name at Open time
+	fd   syscall.Handle // file descriptor number
+	name string         // file name at Open time
 }
 
 func newFile(fd syscall.Handle, name string) *File {
diff --git a/doc/progs/helloworld.go b/doc/progs/helloworld.go
index 637a095..8185038 100644
--- a/doc/progs/helloworld.go
+++ b/doc/progs/helloworld.go
@@ -4,7 +4,7 @@
 
 package main
 
-import fmt "fmt"  // Package implementing formatted I/O.
+import fmt "fmt" // Package implementing formatted I/O.
 
 func main() {
 	fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
diff --git a/doc/progs/helloworld3.go b/doc/progs/helloworld3.go
index 5bb0be2..2011513 100644
--- a/doc/progs/helloworld3.go
+++ b/doc/progs/helloworld3.go
@@ -15,7 +15,7 @@ func main() {
 	file.Stdout.Write(hello)
 	f, err := file.Open("/does/not/exist")
 	if f == nil {
-		fmt.Printf("can't open file; err=%s\n",  err.String())
+		fmt.Printf("can't open file; err=%s\n", err.String())
 		os.Exit(1)
 	}
 }
diff --git a/doc/progs/print.go b/doc/progs/print.go
index 69c35a5..8f44ba8 100644
--- a/doc/progs/print.go
+++ b/doc/progs/print.go
@@ -7,7 +7,7 @@ package main
 import "fmt"
 
 func main() {
-	var u64 uint64 = 1<<64-1
+	var u64 uint64 = 1<<64 - 1
 	fmt.Printf("%d %d\n", u64, int64(u64))
 
 	// harder stuff
diff --git a/doc/progs/server.go b/doc/progs/server.go
index f3a6b18..b498b53 100644
--- a/doc/progs/server.go
+++ b/doc/progs/server.go
@@ -7,8 +7,8 @@ package main
 import "fmt"
 
 type request struct {
-	a, b    int
-	replyc  chan int
+	a, b   int
+	replyc chan int
 }
 
 type binOp func(a, b int) int
@@ -21,7 +21,7 @@ func run(op binOp, req *request) {
 func server(op binOp, service chan *request) {
 	for {
 		req := <-service
-		go run(op, req)  // don't wait for it
+		go run(op, req) // don't wait for it
 	}
 }
 
@@ -42,8 +42,8 @@ func main() {
 		req.replyc = make(chan int)
 		adder <- req
 	}
-	for i := N-1; i >= 0; i-- {   // doesn't matter what order
-		if <-reqs[i].replyc != N + 2*i {
+	for i := N - 1; i >= 0; i-- { // doesn't matter what order
+		if <-reqs[i].replyc != N+2*i {
 			fmt.Println("fail at", i)
 		}
 	}
diff --git a/doc/progs/server1.go b/doc/progs/server1.go
index b8c0926..a409392 100644
--- a/doc/progs/server1.go
+++ b/doc/progs/server1.go
@@ -7,8 +7,8 @@ package main
 import "fmt"
 
 type request struct {
-	a, b	int
-	replyc	chan int
+	a, b   int
+	replyc chan int
 }
 
 type binOp func(a, b int) int
@@ -22,7 +22,7 @@ func server(op binOp, service chan *request, quit chan bool) {
 	for {
 		select {
 		case req := <-service:
-			go run(op, req)  // don't wait for it
+			go run(op, req) // don't wait for it
 		case <-quit:
 			return
 		}
@@ -47,8 +47,8 @@ func main() {
 		req.replyc = make(chan int)
 		adder <- req
 	}
-	for i := N-1; i >= 0; i-- {   // doesn't matter what order
-		if <-reqs[i].replyc != N + 2*i {
+	for i := N - 1; i >= 0; i-- { // doesn't matter what order
+		if <-reqs[i].replyc != N+2*i {
 			fmt.Println("fail at", i)
 		}
 	}
diff --git a/doc/progs/sieve.go b/doc/progs/sieve.go
index c7c3e78..b315309 100644
--- a/doc/progs/sieve.go
+++ b/doc/progs/sieve.go
@@ -9,7 +9,7 @@ import "fmt"
 // Send the sequence 2, 3, 4, ... to channel 'ch'.
 func generate(ch chan int) {
 	for i := 2; ; i++ {
-		ch <- i  // Send 'i' to channel 'ch'.
+		ch <- i // Send 'i' to channel 'ch'.
 	}
 }
 
@@ -17,17 +17,17 @@ func generate(ch chan int) {
 // removing those divisible by 'prime'.
 func filter(in, out chan int, prime int) {
 	for {
-		i := <-in  // Receive value of new variable 'i' from 'in'.
-		if i % prime != 0 {
-			out <- i  // Send 'i' to channel 'out'.
+		i := <-in // Receive value of new variable 'i' from 'in'.
+		if i%prime != 0 {
+			out <- i // Send 'i' to channel 'out'.
 		}
 	}
 }
 
 // The prime sieve: Daisy-chain filter processes together.
 func main() {
-	ch := make(chan int)  // Create a new channel.
-	go generate(ch)  // Start generate() as a goroutine.
+	ch := make(chan int)       // Create a new channel.
+	go generate(ch)            // Start generate() as a goroutine.
 	for i := 0; i < 100; i++ { // Print the first hundred primes.
 		prime := <-ch
 		fmt.Println(prime)
diff --git a/doc/progs/sieve1.go b/doc/progs/sieve1.go
index e785e20..e1411a3 100644
--- a/doc/progs/sieve1.go
+++ b/doc/progs/sieve1.go
@@ -9,7 +9,7 @@ import "fmt"
 // Send the sequence 2, 3, 4, ... to returned channel 
 func generate() chan int {
 	ch := make(chan int)
-	go func(){
+	go func() {
 		for i := 2; ; i++ {
 			ch <- i
 		}
@@ -22,7 +22,7 @@ func filter(in chan int, prime int) chan int {
 	out := make(chan int)
 	go func() {
 		for {
-			if i := <-in; i % prime != 0 {
+			if i := <-in; i%prime != 0 {
 				out <- i
 			}
 		}
diff --git a/doc/progs/sort.go b/doc/progs/sort.go
index 47df9b3..894693f 100644
--- a/doc/progs/sort.go
+++ b/doc/progs/sort.go
@@ -21,7 +21,7 @@ func Sort(data Interface) {
 func IsSorted(data Interface) bool {
 	n := data.Len()
 	for i := n - 1; i > 0; i-- {
-		if data.Less(i, i - 1) {
+		if data.Less(i, i-1) {
 			return false
 		}
 	}
@@ -32,32 +32,28 @@ func IsSorted(data Interface) bool {
 
 type IntSlice []int
 
-func (p IntSlice) Len() int            { return len(p) }
-func (p IntSlice) Less(i, j int) bool  { return p[i] < p[j] }
-func (p IntSlice) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
-
+func (p IntSlice) Len() int           { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 
 type Float64Slice []float64
 
-func (p Float64Slice) Len() int            { return len(p) }
-func (p Float64Slice) Less(i, j int) bool  { return p[i] < p[j] }
-func (p Float64Slice) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
-
+func (p Float64Slice) Len() int           { return len(p) }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] }
+func (p Float64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 
 type StringSlice []string
 
-func (p StringSlice) Len() int            { return len(p) }
-func (p StringSlice) Less(i, j int) bool  { return p[i] < p[j] }
-func (p StringSlice) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
-
+func (p StringSlice) Len() int           { return len(p) }
+func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 
 // Convenience wrappers for common cases
 
-func SortInts(a []int)        { Sort(IntSlice(a)) }
-func SortFloat64s(a []float64)    { Sort(Float64Slice(a)) }
-func SortStrings(a []string)  { Sort(StringSlice(a)) }
-
+func SortInts(a []int)         { Sort(IntSlice(a)) }
+func SortFloat64s(a []float64) { Sort(Float64Slice(a)) }
+func SortStrings(a []string)   { Sort(StringSlice(a)) }
 
-func IntsAreSorted(a []int) bool       { return IsSorted(IntSlice(a)) }
-func Float64sAreSorted(a []float64) bool   { return IsSorted(Float64Slice(a)) }
-func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
+func IntsAreSorted(a []int) bool         { return IsSorted(IntSlice(a)) }
+func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+func StringsAreSorted(a []string) bool   { return IsSorted(StringSlice(a)) }
diff --git a/doc/progs/sortmain.go b/doc/progs/sortmain.go
index 28eec8d..c1babb0 100644
--- a/doc/progs/sortmain.go
+++ b/doc/progs/sortmain.go
@@ -28,27 +28,27 @@ func strings() {
 }
 
 type day struct {
-	num        int
-	shortName  string
-	longName   string
+	num       int
+	shortName string
+	longName  string
 }
 
 type dayArray struct {
 	data []*day
 }
 
-func (p *dayArray) Len() int            { return len(p.data) }
-func (p *dayArray) Less(i, j int) bool  { return p.data[i].num < p.data[j].num }
-func (p *dayArray) Swap(i, j int)       { p.data[i], p.data[j] = p.data[j], p.data[i] }
+func (p *dayArray) Len() int           { return len(p.data) }
+func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }
+func (p *dayArray) Swap(i, j int)      { p.data[i], p.data[j] = p.data[j], p.data[i] }
 
 func days() {
-	Sunday :=    day{0, "SUN", "Sunday"}
-	Monday :=    day{1, "MON", "Monday"}
-	Tuesday :=   day{2, "TUE", "Tuesday"}
+	Sunday := day{0, "SUN", "Sunday"}
+	Monday := day{1, "MON", "Monday"}
+	Tuesday := day{2, "TUE", "Tuesday"}
 	Wednesday := day{3, "WED", "Wednesday"}
-	Thursday :=  day{4, "THU", "Thursday"}
-	Friday :=    day{5, "FRI", "Friday"}
-	Saturday :=  day{6, "SAT", "Saturday"}
+	Thursday := day{4, "THU", "Thursday"}
+	Friday := day{5, "FRI", "Friday"}
+	Saturday := day{6, "SAT", "Saturday"}
 	data := []*day{&Tuesday, &Thursday, &Wednesday, &Sunday, &Monday, &Friday, &Saturday}
 	a := dayArray{data}
 	sort.Sort(&a)
diff --git a/doc/progs/strings.go b/doc/progs/strings.go
index 2cdb610..e6739b3 100644
--- a/doc/progs/strings.go
+++ b/doc/progs/strings.go
@@ -8,7 +8,9 @@ import "os"
 
 func main() {
 	s := "hello"
-	if s[1] != 'e' { os.Exit(1) }
+	if s[1] != 'e' {
+		os.Exit(1)
+	}
 	s = "good bye"
 	var p *string = &s
 	*p = "ciao"
diff --git a/doc/progs/sum.go b/doc/progs/sum.go
index 9caa799..e022195 100644
--- a/doc/progs/sum.go
+++ b/doc/progs/sum.go
@@ -14,7 +14,6 @@ func sum(a []int) int { // returns an int
 	return s
 }
 
-
 func main() {
 	s := sum([3]int{1, 2, 3}[:]) // a slice of the array is passed to sum
 	fmt.Print(s, "\n")
diff --git a/doc/talks/io2010/decrypt.go b/doc/talks/io2010/decrypt.go
index 3292c30..0a6c006 100644
--- a/doc/talks/io2010/decrypt.go
+++ b/doc/talks/io2010/decrypt.go
@@ -2,39 +2,84 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This code differs from the slides in that it handles errors.
+
 package main
 
 import (
 	"crypto/aes"
-	"crypto/block"
+	"crypto/cipher"
 	"compress/gzip"
 	"io"
+	"log"
 	"os"
 )
 
-func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) {
-	r, _ := os.Open(srcfile, os.O_RDONLY, 0)
+func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) os.Error {
+	r, err := os.Open(srcfile)
+	if err != nil {
+		return err
+	}
 	var w io.Writer
-	w, _ = os.Open(dstfile, os.O_WRONLY|os.O_CREATE, 0666)
-	c, _ := aes.NewCipher(key)
-	w = block.NewOFBWriter(c, iv, w)
-	w2, _ := gzip.NewDeflater(w)
-	io.Copy(w2, r)
-	w2.Close()
+	w, err = os.Create(dstfile)
+	if err != nil {
+		return err
+	}
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return err
+	}
+	w = cipher.StreamWriter{S: cipher.NewOFB(c, iv), W: w}
+	w2, err := gzip.NewWriter(w)
+	if err != nil {
+		return err
+	}
+	defer w2.Close()
+	_, err = io.Copy(w2, r)
+	return err
 }
 
-func DecryptAndGunzip(dstfile, srcfile string, key, iv []byte) {
-	f, _ := os.Open(srcfile, os.O_RDONLY, 0)
+func DecryptAndGunzip(dstfile, srcfile string, key, iv []byte) os.Error {
+	f, err := os.Open(srcfile)
+	if err != nil {
+		return err
+	}
 	defer f.Close()
-	c, _ := aes.NewCipher(key)
-	r := block.NewOFBReader(c, iv, f)
-	r, _ = gzip.NewInflater(r)
-	w, _ := os.Open(dstfile, os.O_WRONLY|os.O_CREATE, 0666)
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return err
+	}
+	r := cipher.StreamReader{S: cipher.NewOFB(c, iv), R: f}
+	r2, err := gzip.NewReader(r)
+	if err != nil {
+		return err
+	}
+	w, err := os.Create(dstfile)
+	if err != nil {
+		return err
+	}
 	defer w.Close()
-	io.Copy(w, r)
+	_, err = io.Copy(w, r2)
+	return err
 }
 
 func main() {
-	EncryptAndGzip("/tmp/passwd.gz", "/etc/passwd", make([]byte, 16), make([]byte, 16))
-	DecryptAndGunzip("/dev/stdout", "/tmp/passwd.gz", make([]byte, 16), make([]byte, 16))
+	err := EncryptAndGzip(
+		"/tmp/passwd.gz",
+		"/etc/passwd",
+		make([]byte, 16),
+		make([]byte, 16),
+	)
+	if err != nil {
+		log.Fatal(err)
+	}
+	err = DecryptAndGunzip(
+		"/dev/stdout",
+		"/tmp/passwd.gz",
+		make([]byte, 16),
+		make([]byte, 16),
+	)
+	if err != nil {
+		log.Fatal(err)
+	}
 }
diff --git a/doc/talks/io2010/encrypt.go b/doc/talks/io2010/encrypt.go
index e5ab3fc..c6508bb 100644
--- a/doc/talks/io2010/encrypt.go
+++ b/doc/talks/io2010/encrypt.go
@@ -2,27 +2,51 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This code differs from the slides in that it handles errors.
+
 package main
 
 import (
 	"crypto/aes"
-	"crypto/block"
+	"crypto/cipher"
 	"compress/gzip"
 	"io"
+	"log"
 	"os"
 )
 
-func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) {
-	r, _ := os.Open(srcfile, os.O_RDONLY, 0)
+func EncryptAndGzip(dstfile, srcfile string, key, iv []byte) os.Error {
+	r, err := os.Open(srcfile)
+	if err != nil {
+		return err
+	}
 	var w io.WriteCloser
-	w, _ = os.Open(dstfile, os.O_WRONLY|os.O_CREATE, 0666)
+	w, err = os.Create(dstfile)
+	if err != nil {
+		return err
+	}
 	defer w.Close()
-	w, _ = gzip.NewDeflater(w)
+	w, err = gzip.NewWriter(w)
+	if err != nil {
+		return err
+	}
 	defer w.Close()
-	c, _ := aes.NewCipher(key)
-	io.Copy(block.NewCBCEncrypter(c, iv, w), r)
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return err
+	}
+	_, err = io.Copy(cipher.StreamWriter{S: cipher.NewOFB(c, iv), W: w}, r)
+	return err
 }
 
 func main() {
-	EncryptAndGzip("/tmp/passwd.gz", "/etc/passwd", make([]byte, 16), make([]byte, 16))
+	err := EncryptAndGzip(
+		"/tmp/passwd.gz",
+		"/etc/passwd",
+		make([]byte, 16),
+		make([]byte, 16),
+	)
+	if err != nil {
+		log.Fatal(err)
+	}
 }
diff --git a/doc/tmpltohtml.go b/doc/tmpltohtml.go
new file mode 100644
index 0000000..0a509d9
--- /dev/null
+++ b/doc/tmpltohtml.go
@@ -0,0 +1,176 @@
+// 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.
+
+
+// The template uses the function "code" to inject program
+// source into the output by extracting code from files and
+// injecting them as HTML-escaped <pre> blocks.
+//
+// The syntax is simple: 1, 2, or 3 space-separated arguments:
+//
+// Whole file:
+//	{{code "foo.go"}}
+// One line (here the signature of main):
+//	{{code "foo.go" `/^func.main/`}}
+// Block of text, determined by start and end (here the body of main):
+//	{{code "foo.go" `/^func.main/` `/^}/`
+//
+// Patterns can be `/regular expression/`, a decimal number, or "$"
+// to signify the end of the file.
+package main
+
+import (
+	"exp/template"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"regexp"
+	"strings"
+)
+
+func Usage() {
+	fmt.Fprintf(os.Stderr, "usage: tmpltohtml file\n")
+	os.Exit(2)
+}
+
+func main() {
+	flag.Usage = Usage
+	flag.Parse()
+	if len(flag.Args()) != 1 {
+		Usage()
+	}
+
+	// Read and parse the input.
+	name := flag.Args()[0]
+	tmpl := template.New(name).Funcs(template.FuncMap{"code": code})
+	if err := tmpl.ParseFile(name); err != nil {
+		log.Fatal(err)
+	}
+
+	// Execute the template.
+	if err := tmpl.Execute(os.Stdout, 0); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// contents reads a file by name and returns its contents as a string.
+func contents(name string) string {
+	file, err := ioutil.ReadFile(name)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return string(file)
+}
+
+// format returns a textual representation of the arg, formatted according to its nature.
+func format(arg interface{}) string {
+	switch arg := arg.(type) {
+	case int:
+		return fmt.Sprintf("%d", arg)
+	case string:
+		if len(arg) > 2 && arg[0] == '/' && arg[len(arg)-1] == '/' {
+			return fmt.Sprintf("%#q", arg)
+		}
+		return fmt.Sprintf("%q", arg)
+	default:
+		log.Fatalf("unrecognized argument: %v type %T", arg, arg)
+	}
+	return ""
+}
+
+func code(file string, arg ...interface{}) (string, os.Error) {
+	text := contents(file)
+	var command string
+	switch len(arg) {
+	case 0:
+		// text is already whole file.
+		command = fmt.Sprintf("code %q", file)
+	case 1:
+		command = fmt.Sprintf("code %q %s", file, format(arg[0]))
+		text = oneLine(file, text, arg[0])
+	case 2:
+		command = fmt.Sprintf("code %q %s %s", file, format(arg[0]), format(arg[1]))
+		text = multipleLines(file, text, arg[0], arg[1])
+	default:
+		return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
+	}
+	// Replace tabs by spaces, which work better in HTML.
+	text = strings.Replace(text, "\t", "    ", -1)
+	// Escape the program text for HTML.
+	text = template.HTMLEscapeString(text)
+	// Include the command as a comment.
+	text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, text)
+	return text, nil
+}
+
+// parseArg returns the integer or string value of the argument and tells which it is.
+func parseArg(arg interface{}, file string, max int) (ival int, sval string, isInt bool) {
+	switch n := arg.(type) {
+	case int:
+		if n <= 0 || n > max {
+			log.Fatalf("%q:%d is out of range", file, n)
+		}
+		return n, "", true
+	case string:
+		return 0, n, false
+	}
+	log.Fatalf("unrecognized argument %v type %T", arg, arg)
+	return
+}
+
+// oneLine returns the single line generated by a two-argument code invocation.
+func oneLine(file, text string, arg interface{}) string {
+	lines := strings.SplitAfter(contents(file), "\n")
+	line, pattern, isInt := parseArg(arg, file, len(lines))
+	if isInt {
+		return lines[line-1]
+	}
+	return lines[match(file, 0, lines, pattern)-1]
+}
+
+// multipleLines returns the text generated by a three-argument code invocation.
+func multipleLines(file, text string, arg1, arg2 interface{}) string {
+	lines := strings.SplitAfter(contents(file), "\n")
+	line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
+	line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
+	if !isInt1 {
+		line1 = match(file, 0, lines, pattern1)
+	}
+	if !isInt2 {
+		line2 = match(file, line1, lines, pattern2)
+	} else if line2 < line1 {
+		log.Fatal("lines out of order for %q: %d %d", line1, line2)
+	}
+	return strings.Join(lines[line1-1:line2], "")
+}
+
+// match identifies the input line that matches the pattern in a code invocation.
+// If start>0, match lines starting there rather than at the beginning.
+// The return value is 1-indexed.
+func match(file string, start int, lines []string, pattern string) int {
+	// $ matches the end of the file.
+	if pattern == "$" {
+		if len(lines) == 0 {
+			log.Fatal("%q: empty file", file)
+		}
+		return len(lines)
+	}
+	// /regexp/ matches the line that matches the regexp.
+	if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+		re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+		if err != nil {
+			log.Fatal(err)
+		}
+		for i := start; i < len(lines); i++ {
+			if re.MatchString(lines[i]) {
+				return i + 1
+			}
+		}
+		log.Fatalf("%s: no match for %#q", file, pattern)
+	}
+	log.Fatalf("unrecognized pattern: %q", pattern)
+	return 0
+}
diff --git a/include/libc.h b/include/libc.h
index a91039d..03e247f 100644
--- a/include/libc.h
+++ b/include/libc.h
@@ -292,16 +292,20 @@ extern	char*	getgoroot(void);
 extern	char*	getgoversion(void);
 
 #ifdef _WIN32
+
+#ifndef _WIN64
 struct timespec {
 	int tv_sec;
 	long tv_nsec;
 };
+#define execv(prog, argv) execv(prog, (const char* const*)(argv))
+#define execvp(prog, argv) execvp(prog, (const char**)(argv))
+#endif
+
 extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
 extern int fork(void);
 extern int pread(int fd, void *buf, int n, int off);
 extern int pwrite(int fd, void *buf, int n, int off);
-#define execv(prog, argv) execv(prog, (const char* const*)(argv))
-#define execvp(prog, argv) execvp(prog, (const char**)(argv))
 #define lseek(fd, n, base) _lseeki64(fd, n, base)
 #define mkdir(path, perm) mkdir(path)
 #define pipe(fd) _pipe(fd, 512, O_BINARY)
diff --git a/include/u.h b/include/u.h
index 9ee7493..44bfcd6 100644
--- a/include/u.h
+++ b/include/u.h
@@ -194,6 +194,8 @@ typedef u64int uint64;
 #undef _NEEDUINT
 #undef _NEEDULONG
 
+#define getcallerpc(x)	__builtin_return_address(0)
+
 #ifndef SIGBUS
 #define SIGBUS SIGSEGV /* close enough */
 #endif
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index 385ac2c..adaff32 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -75,6 +75,12 @@ except:
 	def findcommonincoming(repo, remote):
 		return repo.findcommonincoming(remote)
 
+# in Mercurial 1.9 the cmdutil.match and cmdutil.revpair moved to scmutil
+if hgversion >= '1.9':
+    from mercurial import scmutil
+else:
+    scmutil = cmdutil
+
 oldMessage = """
 The code review extension requires Mercurial 1.3 or newer.
 
@@ -713,14 +719,14 @@ _change_prolog = """# Change list.
 # Get effective change nodes taking into account applied MQ patches
 def effective_revpair(repo):
     try:
-	return cmdutil.revpair(repo, ['qparent'])
+	return scmutil.revpair(repo, ['qparent'])
     except:
-	return cmdutil.revpair(repo, None)
+	return scmutil.revpair(repo, None)
 
 # Return list of changed files in repository that match pats.
 # Warn about patterns that did not match.
 def matchpats(ui, repo, pats, opts):
-	matcher = cmdutil.match(repo, pats, opts)
+	matcher = scmutil.match(repo, pats, opts)
 	node1, node2 = effective_revpair(repo)
 	modified, added, removed, deleted, unknown, ignored, clean = repo.status(node1, node2, matcher, ignored=True, clean=True, unknown=True)
 	return (modified, added, removed, deleted, unknown, ignored, clean)
@@ -827,7 +833,6 @@ Examples:
 
 '''
 
-	
 
 def promptremove(ui, repo, f):
 	if promptyesno(ui, "hg remove %s (y/n)?" % (f,)):
@@ -959,6 +964,11 @@ def ReplacementForCmdutilMatch(repo, pats=None, opts=None, globbed=False, defaul
 				raise util.Abort("no files in CL " + clname)
 			files = Add(files, cl.files)
 	pats = Sub(pats, taken) + ['path:'+f for f in files]
+
+	# work-around for http://selenic.com/hg/rev/785bbc8634f8
+	if hgversion >= '1.9' and not hasattr(repo, 'match'):
+		repo = repo[None]
+
 	return original_match(repo, pats=pats, opts=opts, globbed=globbed, default=default)
 
 def RelativePath(path, cwd):
@@ -1292,7 +1302,7 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
 		# sequence numbers get to be 7 digits long.
 		if re.match('^[0-9]{7,}$', clname):
 			found = False
-			matchfn = cmdutil.match(repo, [], {'rev': None})
+			matchfn = scmutil.match(repo, [], {'rev': None})
 			def prep(ctx, fns):
 				pass
 			for ctx in cmdutil.walkchangerevs(repo, matchfn, {'rev': None}, prep):
@@ -1607,8 +1617,8 @@ def reposetup(ui, repo):
 	global original_match
 	if original_match is None:
 		start_status_thread()
-		original_match = cmdutil.match
-		cmdutil.match = ReplacementForCmdutilMatch
+		original_match = scmutil.match
+		scmutil.match = ReplacementForCmdutilMatch
 		RietveldSetup(ui, repo)
 
 def CheckContributor(ui, repo, user=None):
@@ -1828,7 +1838,7 @@ def sync_changes(ui, repo):
 				break
 			Rev(rev)
 	else:
-		matchfn = cmdutil.match(repo, [], {'rev': None})
+		matchfn = scmutil.match(repo, [], {'rev': None})
 		def prep(ctx, fns):
 			pass
 		for ctx in cmdutil.walkchangerevs(repo, matchfn, {'rev': None}, prep):
diff --git a/lib/godoc/dirlist.html b/lib/godoc/dirlist.html
index 3c1e3aa..29b4b24 100644
--- a/lib/godoc/dirlist.html
+++ b/lib/godoc/dirlist.html
@@ -18,11 +18,11 @@
 </tr>
 {.repeated section @}
 <tr>
-	<td align="left"><a href="{Name|html-esc}{@|dir/}">{Name|html-esc}{@|dir/}</a></td>
+	<td align="left"><a href="{@|fileInfoName}">{@|fileInfoName}</a></td>
 	<td></td>
-	<td align="right">{Size|html-esc}</td>
+	<td align="right">{@|fileInfoSize}</td>
 	<td></td>
-	<td align="left">{Mtime_ns|time}</td>
+	<td align="left">{@|fileInfoTime}</td>
 </tr>
 {.end}
 </table>
diff --git a/misc/cgo/gmp/gmp.go b/misc/cgo/gmp/gmp.go
index 7faa71b..3dbc022 100644
--- a/misc/cgo/gmp/gmp.go
+++ b/misc/cgo/gmp/gmp.go
@@ -211,7 +211,6 @@ func (z *Int) destroy() {
 	z.init = false
 }
 
-
 /*
  * arithmetic
  */
@@ -266,7 +265,7 @@ func (z *Int) Mod(x, y *Int) *Int {
 func (z *Int) Lsh(x *Int, s uint) *Int {
 	x.doinit()
 	z.doinit()
-	C.mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s))
+	C.mpz_mul_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s))
 	return z
 }
 
@@ -274,7 +273,7 @@ func (z *Int) Lsh(x *Int, s uint) *Int {
 func (z *Int) Rsh(x *Int, s uint) *Int {
 	x.doinit()
 	z.doinit()
-	C.mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s))
+	C.mpz_div_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s))
 	return z
 }
 
@@ -300,7 +299,6 @@ func (z *Int) Int64() int64 {
 	return int64(C.mpz_get_si(&z.i[0]))
 }
 
-
 // Neg sets z = -x and returns z.
 func (z *Int) Neg(x *Int) *Int {
 	x.doinit()
@@ -317,7 +315,6 @@ func (z *Int) Abs(x *Int) *Int {
 	return z
 }
 
-
 /*
  * functions without a clear receiver
  */
diff --git a/misc/cgo/stdio/file.go b/misc/cgo/stdio/file.go
index 021cbf9..ab1e884 100644
--- a/misc/cgo/stdio/file.go
+++ b/misc/cgo/stdio/file.go
@@ -42,3 +42,4 @@ func (f *File) Flush() {
 }
 
 var Greeting = C.GoString(C.greeting)
+var Gbytes = C.GoBytes(unsafe.Pointer(C.greeting), C.int(len(Greeting)))
diff --git a/misc/cgo/test/Makefile b/misc/cgo/test/Makefile
index 43c45f4..f26f972 100644
--- a/misc/cgo/test/Makefile
+++ b/misc/cgo/test/Makefile
@@ -11,6 +11,7 @@ CGOFILES=\
 	basic.go\
 	callback.go\
 	env.go\
+	exports.go\
 	issue1222.go\
 	issue1328.go\
 	issue1560.go\
diff --git a/misc/cgo/test/exports.go b/misc/cgo/test/exports.go
new file mode 100644
index 0000000..f96c60b
--- /dev/null
+++ b/misc/cgo/test/exports.go
@@ -0,0 +1,12 @@
+// 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 cgotest
+
+import "C"
+
+//export ReturnIntLong
+func ReturnIntLong() (int, C.long) {
+	return 1, 2
+}
diff --git a/misc/dashboard/builder/package.go b/misc/dashboard/builder/package.go
index b667442..b2a83fa 100644
--- a/misc/dashboard/builder/package.go
+++ b/misc/dashboard/builder/package.go
@@ -38,7 +38,7 @@ func (b *Builder) buildPackages(workpath string, hash string) os.Error {
 		}
 
 		// goinstall
-		buildLog, code, err := runLog(envv, "", goroot, goinstall, "-log=false", p)
+		buildLog, code, err := runLog(envv, "", goroot, goinstall, "-dashboard=false", p)
 		if err != nil {
 			log.Printf("goinstall %v: %v", p, err)
 		}
diff --git a/misc/dashboard/godashboard/app.yaml b/misc/dashboard/godashboard/app.yaml
index 83611cf..7b77a85 100644
--- a/misc/dashboard/godashboard/app.yaml
+++ b/misc/dashboard/godashboard/app.yaml
@@ -11,9 +11,13 @@ handlers:
 - url: /static
   static_dir: static
 
-- url: /package.*
+- url: /package
   script: package.py
 
+- url: /package/daily
+  script: package.py
+  login: admin
+
 - url: /project.*
   script: package.py
 
diff --git a/misc/dashboard/godashboard/cron.yaml b/misc/dashboard/godashboard/cron.yaml
new file mode 100644
index 0000000..953b6a1
--- /dev/null
+++ b/misc/dashboard/godashboard/cron.yaml
@@ -0,0 +1,4 @@
+cron:
+- description: daily package maintenance
+  url: /package/daily
+  schedule: every 24 hours
diff --git a/misc/dashboard/godashboard/package.html b/misc/dashboard/godashboard/package.html
index 043080b..8a9d0a3 100644
--- a/misc/dashboard/godashboard/package.html
+++ b/misc/dashboard/godashboard/package.html
@@ -32,6 +32,20 @@
     <a href="http://blog.golang.org/2011/03/godoc-documenting-go-code.html">package doc comment</a>.
     </p>
     
+    <h2>Most Installed Packages (this week)</h2>
+    <table class="alternate" cellpadding="0" cellspacing="0">
+      <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
+      {% for r in by_week_count %}
+        <tr>
+          <td class="time">{{r.last_install|date:"Y-M-d H:i"}}</td>
+          <td class="count">{{r.week_count}}</td>
+          <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %} {% endif %}</td>
+          <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
+          <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
+        </tr>
+      {% endfor %}
+    </table>
+    
     <h2>Recently Installed Packages</h2>
     <table class="alternate" cellpadding="0" cellspacing="0">
       <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
@@ -41,12 +55,12 @@
           <td class="count">{{r.count}}</td>
           <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %} {% endif %}</td>
           <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
-	      <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
+          <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
         </tr>
       {% endfor %}
     </table>
 
-    <h2>Most Installed Packages</h2>
+    <h2>Most Installed Packages (all time)</h2>
     <table class="alternate" cellpadding="0" cellspacing="0">
       <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
       {% for r in by_count %}
@@ -55,7 +69,7 @@
           <td class="count">{{r.count}}</td>
           <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %} {% endif %}</td>
           <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
-	      <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
+          <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
         </tr>
       {% endfor %}
     </table>
diff --git a/misc/dashboard/godashboard/package.py b/misc/dashboard/godashboard/package.py
index 316f386..5cc2d24 100644
--- a/misc/dashboard/godashboard/package.py
+++ b/misc/dashboard/godashboard/package.py
@@ -5,34 +5,36 @@
 # This is the server part of the package dashboard.
 # It must be run by App Engine.
 
+from google.appengine.api import mail
 from google.appengine.api import memcache
+from google.appengine.api import taskqueue
+from google.appengine.api import urlfetch
+from google.appengine.api import users
 from google.appengine.ext import db
 from google.appengine.ext import webapp
 from google.appengine.ext.webapp import template
 from google.appengine.ext.webapp.util import run_wsgi_app
-from google.appengine.api import users
-from google.appengine.api import mail
-from google.appengine.api import urlfetch
 import datetime
 import logging
 import os
 import re
-import urllib2
 import sets
+import urllib2
 
 # local imports
+from auth import auth
 import toutf8
 import const
-from auth import auth
 
 template.register_template_library('toutf8')
 
 # Storage model for package info recorded on server.
-# Just path, count, and time of last install.
 class Package(db.Model):
     path = db.StringProperty()
-    web_url = db.StringProperty()  # derived from path
-    count = db.IntegerProperty()
+    web_url = db.StringProperty()           # derived from path
+    count = db.IntegerProperty()            # grand total
+    week_count = db.IntegerProperty()       # rolling weekly count
+    day_count = db.TextProperty(default='') # daily count
     last_install = db.DateTimeProperty()
 
     # data contributed by gobuilder
@@ -40,6 +42,67 @@ class Package(db.Model):
     ok = db.BooleanProperty()
     last_ok = db.DateTimeProperty()
 
+    def get_day_count(self):
+        counts = {}
+        if not self.day_count:
+            return counts
+        for d in str(self.day_count).split('\n'):
+            date, count = d.split(' ')
+            counts[date] = int(count)
+        return counts
+
+    def set_day_count(self, count):
+        days = []
+        for day, count in count.items():
+            days.append('%s %d' % (day, count))
+        days.sort(reverse=True)
+        days = days[:28]
+        self.day_count = '\n'.join(days)
+
+    def inc(self):
+        count = self.get_day_count()
+        today = str(datetime.date.today())
+        count[today] = count.get(today, 0) + 1
+        self.set_day_count(count)
+        self.update_week_count(count)
+        self.count += 1
+
+    def update_week_count(self, count=None):
+        if count is None:
+            count = self.get_day_count()
+        total = 0
+        today = datetime.date.today()
+        for i in range(7):
+            day = str(today - datetime.timedelta(days=i))
+            if day in count:
+                total += count[day]
+        self.week_count = total
+
+
+# PackageDaily kicks off the daily package maintenance cron job
+# and serves the associated task queue.
+class PackageDaily(webapp.RequestHandler):
+
+    def get(self):
+        # queue a task to update each package with a week_count > 0
+        keys = Package.all(keys_only=True).filter('week_count >', 0)
+        for key in keys:
+            taskqueue.add(url='/package/daily', params={'key': key.name()})
+
+    def post(self):
+        # update a single package (in a task queue)
+        def update(key):
+            p = Package.get_by_key_name(key)
+            if not p:
+                return
+            p.update_week_count()
+            p.put()
+        key = self.request.get('key')
+        if not key:
+            return
+        db.run_in_transaction(update, key)
+ 
+
 class Project(db.Model):
     name = db.StringProperty(indexed=True)
     descr = db.StringProperty()
@@ -49,8 +112,9 @@ class Project(db.Model):
     tags = db.ListProperty(str)
     approved = db.BooleanProperty(indexed=True)
 
+
 re_bitbucket = re.compile(r'^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-zA-Z0-9_.\-]+)(/[a-z0-9A-Z_.\-/]+)?$')
-re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg)(/[a-z0-9A-Z_.\-/]+)?$')
+re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg|git)(/[a-z0-9A-Z_.\-/]+)?$')
 re_github = re.compile(r'^github\.com/[a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)+$')
 re_launchpad = re.compile(r'^launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]+)?$')
 
@@ -66,7 +130,7 @@ def vc_to_web(path):
     elif re_googlecode.match(path):
         m = re_googlecode.match(path)
         check_url = 'http://'+path
-        if not m.group(2):  # append / after bare '/hg'
+        if not m.group(2):  # append / after bare '/hg' or '/git'
             check_url += '/'
         web = 'http://code.google.com/p/' + path[:path.index('.')]
     elif re_launchpad.match(path):
@@ -81,6 +145,17 @@ re_github_web = re.compile(r'github\.com/([a-z0-9A-Z_.\-]+)/([a-z0-9A-Z_.\-]+)')
 re_launchpad_web = re.compile(r'launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]+)?')
 re_striphttp = re.compile(r'https?://(www\.)?')
 
+def find_googlecode_vcs(path):
+    # Perform http request to path/hg or path/git to check if they're
+    # using mercurial or git.  Otherwise, assume svn.
+    for vcs in ['git', 'hg']:
+        try:
+            response = urlfetch.fetch('http://'+path+vcs, deadline=1)
+            if response.status_code == 200:
+                return vcs
+        except: pass
+    return 'svn'
+
 def web_to_vc(url):
     url = re_striphttp.sub('', url)
     m = re_bitbucket_web.match(url)
@@ -92,13 +167,7 @@ def web_to_vc(url):
     m = re_googlecode_web.match(url)
     if m:
         path = m.group(1)+'.googlecode.com/'
-        # perform http request to path/hg to check if they're using mercurial
-        vcs = 'svn'
-        try:
-            response = urlfetch.fetch('http://'+path+'hg', deadline=1)
-            if response.status_code == 200:
-                vcs = 'hg'
-        except: pass
+        vcs = find_googlecode_vcs(path)
         return path + vcs
     m = re_launchpad_web.match(url)
     if m:
@@ -115,29 +184,30 @@ class PackagePage(webapp.RequestHandler):
 
         html = memcache.get('view-package')
         if not html:
+            tdata = {}
+
+            q = Package.all().filter('week_count >', 0)
+            q.order('-week_count')
+            tdata['by_week_count'] = q.fetch(50)
+
             q = Package.all()
             q.order('-last_install')
-            by_time = q.fetch(100)
+            tdata['by_time'] = q.fetch(20)
 
             q = Package.all()
             q.order('-count')
-            by_count = q.fetch(100)
+            tdata['by_count'] = q.fetch(100)
 
-            self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
             path = os.path.join(os.path.dirname(__file__), 'package.html')
-            html = template.render(
-                path, 
-                {"by_time": by_time, "by_count": by_count}
-            )
+            html = template.render(path, tdata)
             memcache.set('view-package', html, time=CacheTimeout)
 
+        self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
         self.response.out.write(html)
 
     def json(self):
         json = memcache.get('view-package-json')
         if not json:
-            self.response.set_status(200)
-            self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
             q = Package.all()
             s = '{"packages": ['
             sep = ''
@@ -147,6 +217,8 @@ class PackagePage(webapp.RequestHandler):
             s += '\n]}\n'
             json = s
             memcache.set('view-package-json', json, time=CacheTimeout)
+        self.response.set_status(200)
+        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
         self.response.out.write(json)
 
     def can_get_url(self, url):
@@ -181,14 +253,15 @@ class PackagePage(webapp.RequestHandler):
                 return False
             p = Package(key_name = key, path = path, count = 0, web_url = web)
 
-        # is this the builder updating package metadata?
         if auth(self.request):
+            # builder updating package metadata
             p.info = self.request.get('info')
             p.ok = self.request.get('ok') == "true"
             if p.ok:
                 p.last_ok = datetime.datetime.utcnow()
         else:
-            p.count += 1
+            # goinstall reporting an install
+            p.inc()
             p.last_install = datetime.datetime.utcnow()
 
         # update package object
@@ -197,7 +270,7 @@ class PackagePage(webapp.RequestHandler):
 
     def post(self):
         path = self.request.get('path')
-        ok = db.run_in_transaction(self.record_pkg,  path)
+        ok = db.run_in_transaction(self.record_pkg, path)
         if ok:
             self.response.set_status(200)
             self.response.out.write('ok')
@@ -347,6 +420,7 @@ class ProjectPage(webapp.RequestHandler):
 def main():
     app = webapp.WSGIApplication([
         ('/package', PackagePage),
+        ('/package/daily', PackageDaily),
         ('/project.*', ProjectPage),
         ], debug=True)
     run_wsgi_app(app)
diff --git a/misc/dashboard/godashboard/static/style.css b/misc/dashboard/godashboard/static/style.css
index a7e61dd..d6d23b5 100644
--- a/misc/dashboard/godashboard/static/style.css
+++ b/misc/dashboard/godashboard/static/style.css
@@ -54,6 +54,9 @@ table.alternate tr td:last-child {
 table.alternate tr:nth-child(2n) {
 	background-color: #f0f0f0;
 }
+td.result {
+	text-align: center;
+}
 span.hash {
 	font-family: monospace;
 	font-size: small;
diff --git a/src/Make.pkg b/src/Make.pkg
index 86a2e9f..fc80cf6 100644
--- a/src/Make.pkg
+++ b/src/Make.pkg
@@ -59,7 +59,7 @@ coverage:
 	gotest
 	6cov -g $(shell pwd) $O.out | grep -v '_test\.go:'
 
-CLEANFILES+=*.so _obj _test _testmain.go *.exe _cgo* *.cgo[12].* test.out build.out
+CLEANFILES+=*.so _obj _test _testmain.go *.exe _cgo* test.out build.out
 
 test:
 	gotest
diff --git a/src/all-qemu.bash b/src/all-qemu.bash
index c7079ba..6a659d6 100755
--- a/src/all-qemu.bash
+++ b/src/all-qemu.bash
@@ -6,11 +6,11 @@
 # Run all.bash but exclude tests that depend on functionality
 # missing in QEMU's system call emulation.
 
+export GOARCH=arm
 export NOTEST=""
-
 NOTEST="$NOTEST big" # just slow
 NOTEST="$NOTEST go/build" # wants to run cgo
-NOTEST="$NOTEST http net rpc syslog websocket"  # no localhost network
+NOTEST="$NOTEST http http/cgi net rpc syslog websocket"  # no localhost network
 NOTEST="$NOTEST os"  # 64-bit seek fails
 
 ./all.bash
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
index 550b61d..a2c87cf 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -28,8 +28,6 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include <u.h>
-#include <libc.h>
 #include <bio.h>
 #include "../5l/5.out.h"
 
@@ -54,7 +52,9 @@ typedef	struct	Hist	Hist;
 #define	NSYMB		8192
 #define	BUFSIZ		8192
 #define	HISTSZ		20
+#ifndef	EOF
 #define	EOF		(-1)
+#endif
 #define	IGN		(-2)
 #define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
 #define	NHASH		503
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index b39c916..9a0efd5 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -29,7 +29,9 @@
 // THE SOFTWARE.
 
 %{
+#include <u.h>
 #include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
 #include "a.h"
 %}
 %union
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index 3978f1a..ad7ed05 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -29,9 +29,10 @@
 // THE SOFTWARE.
 
 #define	EXTERN
+#include <u.h>
+#include <libc.h>
 #include "a.h"
 #include "y.tab.h"
-#include <ctype.h>
 
 enum
 {
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
index c15bf0f..3a905f0 100644
--- a/src/cmd/5c/peep.c
+++ b/src/cmd/5c/peep.c
@@ -1122,7 +1122,6 @@ copyu(Prog *p, Adr *v, Adr *s)
 				return 3;
 		return 0;
 	}
-	return 0;
 }
 
 int
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
index 8c97944..50b8145 100644
--- a/src/cmd/5c/reg.c
+++ b/src/cmd/5c/reg.c
@@ -66,6 +66,11 @@ rcmp(const void *a1, const void *a2)
 void
 regopt(Prog *p)
 {
+	// TODO(kaib): optimizer disabled because it smashes R8 when running out of registers
+	// the disable is unconventionally here because the call is in common code shared by 5c/6c/8c
+	return;
+
+#ifdef	NOTDEF
 	Reg *r, *r1, *r2;
 	Prog *p1;
 	int i, z;
@@ -79,10 +84,6 @@ regopt(Prog *p)
 		Reg*	p;
 	} log5[6], *lp;
 
-	// TODO(kaib): optimizer disabled because it smashes R8 when running out of registers
-	// the disable is unconventionally here because the call is in common code shared by 5c/6c/8c
-	return;
-
 	firstr = R;
 	lastr = R;
 	nvar = 0;
@@ -490,6 +491,7 @@ brk:
 		r1->link = freer;
 		freer = firstr;
 	}
+#endif
 }
 
 void
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index 431f048..7cbaadb 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -380,10 +380,10 @@ outcode(void)
 		Bprint(&outbuf, "\n");
 		Bprint(&outbuf, "$$  // exports\n\n");
 		Bprint(&outbuf, "$$  // local types\n\n");
-		Bprint(&outbuf, "$$  // dynimport\n", thestring);
+		Bprint(&outbuf, "$$  // dynimport\n");
 		for(i=0; i<ndynimp; i++)
 			Bprint(&outbuf, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
-		Bprint(&outbuf, "\n$$  // dynexport\n", thestring);
+		Bprint(&outbuf, "\n$$  // dynexport\n");
 		for(i=0; i<ndynexp; i++)
 			Bprint(&outbuf, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
 		Bprint(&outbuf, "\n$$\n\n");
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 76e2707..6e2fbe2 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -595,9 +595,6 @@ agen(Node *n, Node *res)
 		// i is in &n1 (if not constant)
 		// w is width
 
-		if(w == 0)
-			fatal("index is zero width");
-
 		// constant index
 		if(isconst(nr, CTINT)) {
 			if(isconst(nl, CTSTR))
@@ -683,7 +680,9 @@ agen(Node *n, Node *res)
 			gmove(&n1, &n3);
 		}
 
-		if(w == 1 || w == 2 || w == 4 || w == 8) {
+		if(w == 0) {
+			// nothing to do
+		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
 			memset(&n4, 0, sizeof n4);
 			n4.op = OADDR;
 			n4.left = &n2;
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index 4da8db2..b56df76 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -158,7 +158,7 @@ cgen64(Node *n, Node *res)
 		gins(AMOVW, &hi2, &ch);
 		gins(AMOVW, &lo2, &cl);
 
-		// bl * cl
+		// bl * cl -> ah al
 		p1 = gins(AMULLU, N, N);
 		p1->from.type = D_REG;
 		p1->from.reg = bl.val.u.reg;
@@ -168,7 +168,7 @@ cgen64(Node *n, Node *res)
 		p1->to.offset = al.val.u.reg;
 //print("%P\n", p1);
 
-		// bl * ch
+		// bl * ch + ah -> ah
 		p1 = gins(AMULA, N, N);
 		p1->from.type = D_REG;
 		p1->from.reg = bl.val.u.reg;
@@ -178,7 +178,7 @@ cgen64(Node *n, Node *res)
 		p1->to.offset = ah.val.u.reg;
 //print("%P\n", p1);
 
-		// bh * cl
+		// bh * cl + ah -> ah
 		p1 = gins(AMULA, N, N);
 		p1->from.type = D_REG;
 		p1->from.reg = bh.val.u.reg;
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 0fece9a..1276610 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -7,6 +7,7 @@
 int	thechar	= '5';
 char*	thestring	= "arm";
 
+vlong MAXWIDTH = (1LL<<32) - 1;
 
 /*
  * go declares several platform-specific type aliases:
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index d5b00b3..e2f0e6b 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -470,9 +470,10 @@ samereg(Node *a, Node *b)
 void
 cgen_shift(int op, Node *nl, Node *nr, Node *res)
 {
-	Node n1, n2, n3, t;
+	Node n1, n2, n3, nt, t, lo, hi;
 	int w;
-	Prog *p1, *p2, *p3;
+	Prog *p1, *p2, *p3, *pbig;
+	Type *tr;
 	uvlong sc;
 
 	if(nl->type->width > 4)
@@ -504,16 +505,43 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
 		return;
 	}
 
-	if(nl->ullman >= nr->ullman) {
-		regalloc(&n2, nl->type, res);
-		cgen(nl, &n2);
-		regalloc(&n1, nr->type, N);
-		cgen(nr, &n1);
+	pbig = P;
+	tr = nr->type;
+	if(tr->width > 4) {
+		tempname(&nt, nr->type);
+		if(nl->ullman >= nr->ullman) {
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+			cgen(nr, &nt);
+			n1 = nt;
+		} else {
+			cgen(nr, &nt);
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+		}
+		split64(&nt, &lo, &hi);
+		regalloc(&n1, types[TUINT32], N);
+		regalloc(&n3, types[TUINT32], N);
+		gmove(&lo, &n1);
+		gmove(&hi, &n3);
+		gins(ATST, &n3, N);
+		nodconst(&t, types[TUINT32], w);
+		p1 = gins(AMOVW, &t, &n1);
+		p1->scond = C_SCOND_NE;
+		tr = types[TUINT32];
+		regfree(&n3);
 	} else {
-		regalloc(&n1, nr->type, N);
-		cgen(nr, &n1);
-		regalloc(&n2, nl->type, res);
-		cgen(nl, &n2);
+		if(nl->ullman >= nr->ullman) {
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+			regalloc(&n1, nr->type, N);
+			cgen(nr, &n1);
+		} else {
+			regalloc(&n1, nr->type, N);
+			cgen(nr, &n1);
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+		}
 	}
 
 	// test for shift being 0
@@ -521,7 +549,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
 	p3 = gbranch(ABEQ, T);
 
 	// test and fix up large shifts
-	regalloc(&n3, nr->type, N);
+	regalloc(&n3, tr, N);
 	nodconst(&t, types[TUINT32], w);
 	gmove(&t, &n3);
 	gcmp(ACMP, &n1, &n3);
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 2d92184..ddaf52a 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -497,6 +497,7 @@ fp:
 		n->class = PPARAM;
 		break;
 	}
+	n->typecheck = 1;
 	return n;
 }
 
@@ -1173,6 +1174,7 @@ naddr(Node *n, Addr *a, int canemitcode)
 	a->name = D_NONE;
 	a->reg = NREG;
 	a->node = N;
+	a->etype = 0;
 	if(n == N)
 		return;
 
@@ -1308,6 +1310,7 @@ naddr(Node *n, Addr *a, int canemitcode)
 	case OLEN:
 		// len of string or slice
 		naddr(n->left, a, canemitcode);
+		a->etype = TINT32;
 		if(a->type == D_CONST && a->offset == 0)
 			break;	// len(nil)
 		a->offset += Array_nel;
@@ -1318,6 +1321,7 @@ naddr(Node *n, Addr *a, int canemitcode)
 	case OCAP:
 		// cap of string or slice
 		naddr(n->left, a, canemitcode);
+		a->etype = TINT32;
 		if(a->type == D_CONST && a->offset == 0)
 			break;	// cap(nil)
 		a->offset += Array_cap;
@@ -1327,6 +1331,7 @@ naddr(Node *n, Addr *a, int canemitcode)
 
 	case OADDR:
 		naddr(n->left, a, canemitcode);
+		a->etype = tptr;
 		switch(a->type) {
 		case D_OREG:
 			a->type = D_CONST;
@@ -1819,6 +1824,7 @@ odot:
 
 	a->type = D_NONE;
 	a->name = D_NONE;
+	n1.type = n->type;
 	naddr(&n1, a, 1);
 	goto yes;
 
@@ -1946,7 +1952,6 @@ oindex:
 	a->type = D_OREG;
 	a->reg = reg->val.u.reg;
 	a->offset = 0;
-
 	goto yes;
 
 oindex_const:
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index 6f36e12..6cc93db 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -933,7 +933,6 @@ xtramodes(Reg *r, Adr *a)
 int
 copyu(Prog *p, Adr *v, Adr *s)
 {
-
 	switch(p->as) {
 
 	default:
@@ -1011,6 +1010,8 @@ copyu(Prog *p, Adr *v, Adr *s)
 			return 0;
 		}
 		if(copyas(&p->to, v)) {
+			if(p->scond != C_SCOND_NONE)
+				return 2;
 			if(copyau(&p->from, v))
 				return 4;
 			return 3;
@@ -1069,6 +1070,8 @@ copyu(Prog *p, Adr *v, Adr *s)
 			return 0;
 		}
 		if(copyas(&p->to, v)) {
+			if(p->scond != C_SCOND_NONE)
+				return 2;
 			if(p->reg == NREG)
 				p->reg = p->to.reg;
 			if(copyau(&p->from, v))
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 77d0a87..2d2a6d0 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -336,6 +336,7 @@ regopt(Prog *firstp)
 		case AMULD:
 		case ADIVF:
 		case ADIVD:
+		case AMULA:
 		case AMULAL:
 		case AMULALU:
 			for(z=0; z<BITS; z++) {
@@ -728,13 +729,19 @@ addsplits(void)
 void
 addmove(Reg *r, int bn, int rn, int f)
 {
-	Prog *p, *p1;
+	Prog *p, *p1, *p2;
 	Adr *a;
 	Var *v;
 
 	p1 = mal(sizeof(*p1));
 	*p1 = zprog;
 	p = r->prog;
+	
+	// If there's a stack fixup coming (after BL newproc or BL deferproc),
+	// delay the load until after the fixup.
+	p2 = p->link;
+	if(p2 && p2->as == AMOVW && p2->from.type == D_CONST && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == D_REG)
+		p = p2;
 
 	p1->link = p->link;
 	p->link = p1;
@@ -764,6 +771,7 @@ addmove(Reg *r, int bn, int rn, int f)
 		break;
 	case TBOOL:
 	case TUINT8:
+//print("movbu %E %d %S\n", v->etype, bn, v->sym);
 		p1->as = AMOVBU;
 		break;
 	case TINT16:
@@ -837,9 +845,6 @@ mkvar(Reg *r, Adr *a)
 	n = D_NONE;
 
 	flag = 0;
-	if(a->pun)
-		flag = 1;
-
 	switch(t) {
 	default:
 		print("type %d %d %D\n", t, a->name, a);
@@ -922,7 +927,7 @@ mkvar(Reg *r, Adr *a)
 				if(!flag)
 					return blsh(i);
 
-			// if they overlaps, disable both
+			// if they overlap, disable both
 			if(overlap(v->offset, v->width, o, w)) {
 				v->addr = 1;
 				flag = 1;
@@ -946,6 +951,7 @@ mkvar(Reg *r, Adr *a)
 
 	i = nvar;
 	nvar++;
+//print("var %d %E %D %S\n", i, et, a, s);
 	v = var+i;
 	v->sym = s;
 	v->offset = o;
@@ -957,7 +963,7 @@ mkvar(Reg *r, Adr *a)
 	v->node = a->node;
 	
 	if(debug['R'])
-		print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
+		print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
 
 	bit = blsh(i);
 	if(n == D_EXTERN || n == D_STATIC)
@@ -1447,10 +1453,6 @@ paint3(Reg *r, int bn, int32 rb, int rn)
 void
 addreg(Adr *a, int rn)
 {
-
-	if(a->type == D_CONST)
-		fatal("addreg: cant do this %D %d\n", a, rn);
-
 	a->sym = 0;
 	a->name = D_NONE;
 	a->type = D_REG;
@@ -1471,8 +1473,7 @@ addreg(Adr *a, int rn)
 int32
 RtoB(int r)
 {
-
-	if(r < 2 || r >= REGTMP-2)	// excluded R9 and R10 for m and g
+	if(r >= REGTMP-2)	// excluded R9 and R10 for m and g
 		return 0;
 	return 1L << r;
 }
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index 9f4a192..8489abc 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -29,7 +29,7 @@ OFILES=\
 
 HFILES=\
 	l.h\
-	../5l/5.out.h\
+	5.out.h\
 	../ld/elf.h\
 
 include ../../Make.ccmd
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 2c9e50d..5b7f6f1 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -102,12 +102,15 @@ int	nelfsym = 1;
 void
 adddynrel(Sym *s, Reloc *r)
 {
+	USED(s);
+	USED(r);
 	diag("adddynrel: unsupported binary format");
 }
 
 void
 adddynsym(Sym *s)
 {
+	USED(s);
 	diag("adddynsym: not implemented");
 }
 
@@ -120,6 +123,9 @@ elfsetupplt(void)
 int
 archreloc(Reloc *r, Sym *s, vlong *val)
 {
+	USED(r);
+	USED(s);
+	USED(val);
 	return -1;
 }
 
@@ -151,7 +157,7 @@ doelf(void)
 
 	/* predefine strings we need for section headers */
 	shstrtab = lookup(".shstrtab", 0);
-	shstrtab->type = SELFDATA;
+	shstrtab->type = SELFROSECT;
 	shstrtab->reachable = 1;
 
 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
@@ -179,20 +185,15 @@ doelf(void)
 		elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
 		elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
 
-		/* interpreter string */
-		s = lookup(".interp", 0);
-		s->reachable = 1;
-		s->type = SELFDATA;	// TODO: rodata
-
 		/* dynamic symbol table - first entry all zeros */
 		s = lookup(".dynsym", 0);
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		s->reachable = 1;
 		s->value += ELF32SYMSIZE;
 
 		/* dynamic string table */
 		s = lookup(".dynstr", 0);
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		s->reachable = 1;
 		if(s->size == 0)
 			addstring(s, "");
@@ -201,37 +202,37 @@ doelf(void)
 		/* relocation table */
 		s = lookup(".rel", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/* global offset table */
 		s = lookup(".got", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFSECT; // writable
 		
 		/* hash */
 		s = lookup(".hash", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/* got.plt */
 		s = lookup(".got.plt", 0);
 		s->reachable = 1;
-		s->type = SDATA;	// writable, so not SELFDATA
+		s->type = SELFSECT; // writable
 		
 		s = lookup(".plt", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		s = lookup(".rel.plt", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		
 		elfsetupplt();
 
 		/* define dynamic elf table */
 		s = lookup(".dynamic", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/*
 		 * .dynamic table
@@ -268,8 +269,11 @@ datoff(vlong addr)
 void
 shsym(Elf64_Shdr *sh, Sym *s)
 {
-	sh->addr = symaddr(s);
-	sh->off = datoff(sh->addr);
+	vlong addr;
+	addr = symaddr(s);
+	if(sh->flags&SHF_ALLOC)
+		sh->addr = addr;
+	sh->off = datoff(addr);
 	sh->size = s->size;
 }
 
@@ -294,18 +298,19 @@ asmb(void)
 	ElfPhdr *ph, *pph;
 	ElfShdr *sh;
 	Section *sect;
+	int o;
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f asmb\n", cputime());
 	Bflush(&bso);
 
 	sect = segtext.sect;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 	codeblk(sect->vaddr, sect->len);
 
 	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
 	for(sect = sect->next; sect != nil; sect = sect->next) {
-		seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 		datblk(sect->vaddr, sect->len);
 	}
 
@@ -313,18 +318,18 @@ asmb(void)
 		Bprint(&bso, "%5.2f datblk\n", cputime());
 	Bflush(&bso);
 
-	seek(cout, segdata.fileoff, 0);
+	cseek(segdata.fileoff);
 	datblk(segdata.vaddr, segdata.filelen);
 
 	/* output read-only data in text segment */
 	sect = segtext.sect->next;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 	datblk(sect->vaddr, sect->len);
 
 	if(iself) {
 		/* index of elf text section; needed by asmelfsym, double-checked below */
 		/* !debug['d'] causes extra sections before the .text section */
-		elftextsh = 1;
+		elftextsh = 2;
 		if(!debug['d']) {
 			elftextsh += 10;
 			if(elfverneed)
@@ -362,13 +367,13 @@ asmb(void)
 			symo = rnd(symo, INITRND);
 			break;
 		}
-		seek(cout, symo, 0);
+		cseek(symo);
 		if(iself) {
 			if(debug['v'])
 			       Bprint(&bso, "%5.2f elfsym\n", cputime());
 			asmelfsym();
 			cflush();
-			ewrite(cout, elfstrdat, elfstrsize);
+			cwrite(elfstrdat, elfstrsize);
 
 			// if(debug['v'])
 			// 	Bprint(&bso, "%5.2f dwarf\n", cputime());
@@ -382,7 +387,7 @@ asmb(void)
 	if(debug['v'])
 		Bprint(&bso, "%5.2f header\n", cputime());
 	Bflush(&bso);
-	seek(cout, 0L, 0);
+	cseek(0L);
 	switch(HEADTYPE) {
 	case Hnoheader:	/* no header */
 		break;
@@ -451,7 +456,7 @@ asmb(void)
 		startva = INITTEXT - fo;	/* va of byte 0 of file */
 		
 		/* This null SHdr must appear before all others */
-		sh = newElfShdr(elfstr[ElfStrEmpty]);
+		newElfShdr(elfstr[ElfStrEmpty]);
 
 		/* program header info */
 		pph = newElfPhdr();
@@ -462,6 +467,17 @@ asmb(void)
 		pph->paddr = INITTEXT - HEADR + pph->off;
 		pph->align = INITRND;
 
+		/*
+		 * PHDR must be in a loaded segment. Adjust the text
+		 * segment boundaries downwards to include it.
+		 */
+		o = segtext.vaddr - pph->vaddr;
+		segtext.vaddr -= o;
+		segtext.len += o;
+		o = segtext.fileoff - pph->off;
+		segtext.fileoff -= o;
+		segtext.filelen += o;
+
 		if(!debug['d']) {
 			/* interpreter for dynamic linking */
 			sh = newElfShdr(elfstr[ElfStrInterp]);
@@ -561,6 +577,11 @@ asmb(void)
 		ph->flags = PF_W+PF_R;
 		ph->align = 4;
 
+		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
+		sh->type = SHT_STRTAB;
+		sh->addralign = 1;
+		shsym(sh, lookup(".shstrtab", 0));
+
 		if(elftextsh != eh->shnum)
 			diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
 		for(sect=segtext.sect; sect!=nil; sect=sect->next)
@@ -586,11 +607,6 @@ asmb(void)
 			// dwarfaddelfheaders();
 		}
 
-		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
-		sh->type = SHT_STRTAB;
-		sh->addralign = 1;
-		shsym(sh, lookup(".shstrtab", 0));
-
 		/* Main header */
 		eh->ident[EI_MAG0] = '\177';
 		eh->ident[EI_MAG1] = 'E';
@@ -610,37 +626,27 @@ asmb(void)
 			pph->memsz = pph->filesz;
 		}
 
-		seek(cout, 0, 0);
+		cseek(0);
 		a = 0;
 		a += elfwritehdr();
 		a += elfwritephdrs();
 		a += elfwriteshdrs();
 		cflush();
-		if(a+elfwriteinterp() > ELFRESERVE)
+		if(a+elfwriteinterp() > ELFRESERVE)	
 			diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
 		break;
 	}
 	cflush();
 	if(debug['c']){
 		print("textsize=%d\n", textsize);
-		print("datsize=%d\n", segdata.filelen);
-		print("bsssize=%d\n", segdata.len - segdata.filelen);
+		print("datsize=%ulld\n", segdata.filelen);
+		print("bsssize=%ulld\n", segdata.len - segdata.filelen);
 		print("symsize=%d\n", symsize);
 		print("lcsize=%d\n", lcsize);
-		print("total=%d\n", textsize+segdata.len+symsize+lcsize);
+		print("total=%lld\n", textsize+segdata.len+symsize+lcsize);
 	}
 }
 
-void
-cput(int c)
-{
-	cbp[0] = c;
-	cbp++;
-	cbc--;
-	if(cbc <= 0)
-		cflush();
-}
-
 /*
 void
 cput(int32 c)
@@ -691,19 +697,6 @@ lput(int32 l)
 }
 
 void
-cflush(void)
-{
-	int n;
-
-	/* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */
-	n = sizeof(buf.cbuf) - cbc;
-	if(n)
-		ewrite(cout, buf.cbuf, n);
-	cbp = buf.cbuf;
-	cbc = sizeof(buf.cbuf);
-}
-
-void
 nopstat(char *f, Count *c)
 {
 	if(c->outof)
@@ -1424,6 +1417,7 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
 	out[5] = o6;
 	return;
 
+#ifdef NOTDEF
 	v = p->pc;
 	switch(o->size) {
 	default:
@@ -1479,6 +1473,7 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
 		lputl(o6);
 		break;
 	}
+#endif
 }
 
 int32
@@ -1828,7 +1823,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
 			case SCONST:
 			case SRODATA:
 			case SDATA:
-			case SELFDATA:
+			case SELFROSECT:
 			case STYPE:
 			case SSTRING:
 			case SGOSTRING:
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index 182f3e7..e00f536 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -31,7 +31,7 @@
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
-#include	"../5l/5.out.h"
+#include	"5.out.h"
 
 enum
 {
@@ -264,19 +264,6 @@ enum
 	MINLC	= 4,
 };
 
-EXTERN union
-{
-	struct
-	{
-		uchar	obuf[MAXIO];			/* output buffer */
-		uchar	ibuf[MAXIO];			/* input buffer */
-	} u;
-	char	dbuf[1];
-} buf;
-
-#define	cbuf	u.obuf
-#define	xbuf	u.ibuf
-
 #ifndef COFFCVT
 
 EXTERN	int32	HEADR;			/* length of header */
@@ -286,10 +273,6 @@ EXTERN	int32	INITRND;		/* data round above text location */
 EXTERN	int32	INITTEXT;		/* text location */
 EXTERN	char*	INITENTRY;		/* entry point */
 EXTERN	int32	autosize;
-EXTERN	Biobuf	bso;
-EXTERN	int	cbc;
-EXTERN	uchar*	cbp;
-EXTERN	int	cout;
 EXTERN	Auto*	curauto;
 EXTERN	Auto*	curhist;
 EXTERN	Prog*	curp;
@@ -337,9 +320,11 @@ EXTERN	Prog*	prog_modu;
 #pragma	varargck	type	"A"	int
 #pragma	varargck	type	"C"	int
 #pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"I"	uchar*
 #pragma	varargck	type	"N"	Adr*
 #pragma	varargck	type	"P"	Prog*
 #pragma	varargck	type	"S"	char*
+#pragma	varargck	type	"i"	char*
 
 int	Aconv(Fmt*);
 int	Cconv(Fmt*);
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index dd3a732..fc5806a 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -84,7 +84,6 @@ main(int argc, char *argv[])
 	char *p;
 
 	Binit(&bso, 1, OWRITE);
-	cout = -1;
 	listinit();
 	nerrors = 0;
 	outfile = "5.out";
@@ -146,17 +145,8 @@ main(int argc, char *argv[])
 
 	libinit();
 
-	if(!debug['9'] && !debug['U'] && !debug['B'])
-		debug[DEFAULT] = 1;
-	if(HEADTYPE == -1) {
-		if(debug['U'])
-			HEADTYPE = Hnoheader;
-		if(debug['B'])
-			HEADTYPE = Hrisc;
-		if(debug['9'])
-			HEADTYPE = Hplan9x32;
+	if(HEADTYPE == -1)
 		HEADTYPE = Hlinux;
-	}
 	switch(HEADTYPE) {
 	default:
 		diag("unknown -H option");
@@ -347,7 +337,6 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
 
 	case D_REGREG:
 		a->offset = Bgetc(f);
-		c++;
 		break;
 
 	case D_CONST2:
@@ -363,7 +352,6 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
 	case D_SCONST:
 		a->sval = mal(NSNAME);
 		Bread(f, a->sval, NSNAME);
-		c += NSNAME;
 		break;
 
 	case D_FCONST:
@@ -462,7 +450,6 @@ loop:
 		s = lookup(x, r);
 		if(x != name)
 			free(x);
-		name = nil;
 
 		if(sig != 0){
 			if(s->sig != 0 && s->sig != sig)
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index 194a1ed..c430494 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -246,7 +246,6 @@ patch(void)
 
 	for(cursym = textp; cursym != nil; cursym = cursym->next) {
 		for(p = cursym->text; p != P; p = p->link) {
-			a = p->as;
 			if(p->cond != P) {
 				p->cond = brloop(p->cond);
 				if(p->cond != P)
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
index 48ad2dc..225a524 100644
--- a/src/cmd/5l/prof.c
+++ b/src/cmd/5l/prof.c
@@ -36,7 +36,7 @@
 void
 doprof1(void)
 {
-#if 0	// TODO(rsc)
+#ifdef	NOTDEF	// TODO(rsc)
 	Sym *s;
 	int32 n;
 	Prog *p, *q;
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index eb79f6b..2e1232a 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -97,8 +97,6 @@ span(void)
 
 	bflag = 0;
 	c = INITTEXT;
-	op = nil;
-	p = nil;
 	otxt = c;
 	for(cursym = textp; cursym != nil; cursym = cursym->next) {
 		p = cursym->text;
@@ -224,7 +222,6 @@ span(void)
 	
 		bp = cursym->p;
 		for(p = p->link; p != P; p = p->link) {
-			curp = p;
 			pc = p->pc;
 			curp = p;
 			o = oplook(p);
@@ -419,7 +416,7 @@ symaddr(Sym *s)
 		return 0;
 	
 	case STEXT:
-	case SELFDATA:
+	case SELFROSECT:
 	case SRODATA:
 	case SDATA:
 	case SBSS:
@@ -463,8 +460,6 @@ aclass(Adr *a)
 				print("%D\n", a);
 				return C_GOK;
 			}
-			s = a->sym;
-			t = s->type;
 			instoffset = 0;	// s.b. unused but just in case
 			return C_ADDR;
 
@@ -520,8 +515,6 @@ aclass(Adr *a)
 		switch(a->name) {
 		case D_EXTERN:
 		case D_STATIC:
-			s = a->sym;
-			t = s->type;
 			instoffset = 0;	// s.b. unused but just in case
 			return C_ADDR;
 		}
@@ -556,7 +549,6 @@ aclass(Adr *a)
 			s = a->sym;
 			if(s == S)
 				break;
-			t = s->type;
 			instoffset = 0;	// s.b. unused but just in case
 			return C_LCON;
 
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
index 2d42726..5c78680 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -28,8 +28,6 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include <u.h>
-#include <libc.h>
 #include <bio.h>
 #include "../6l/6.out.h"
 
@@ -57,7 +55,9 @@ typedef	struct	Gen2	Gen2;
 #define	NSYMB		500
 #define	BUFSIZ		8192
 #define	HISTSZ		20
+#ifndef	EOF
 #define	EOF		(-1)
+#endif
 #define	IGN		(-2)
 #define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
 #define	NHASH		503
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index 770f676..c0fa410 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -29,7 +29,9 @@
 // THE SOFTWARE.
 
 %{
+#include <u.h>
 #include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
 #include "a.h"
 %}
 %union	{
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index b4c7d0c..42f4b1d 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -29,9 +29,10 @@
 // THE SOFTWARE.
 
 #define	EXTERN
+#include <u.h>
+#include <libc.h>
 #include "a.h"
 #include "y.tab.h"
-#include <ctype.h>
 
 enum
 {
@@ -169,6 +170,13 @@ assemble(char *file)
 struct
 {
 	char	*name;
+	/*
+	 * type is the lexical type to return.  It dictates what kind of
+	 * operands 6a allows to follow it (in a.y) as the possible operand
+	 * types are handled by a grammar.  How do you know which LTYPE?
+	 * Either read a.y or think of an instruction that has the same
+	 * possible operands and look up what it takes.
+	 */
 	ushort	type;
 	ushort	value;
 } itab[] =
@@ -519,6 +527,7 @@ struct
 	"OUTSB",	LTYPE0,	AOUTSB,
 	"OUTSL",	LTYPE0,	AOUTSL,
 	"OUTSW",	LTYPE0,	AOUTSW,
+	"PAUSE",	LTYPEN,	APAUSE,
 	"POPAL",	LTYPE0,	APOPAL,
 	"POPAW",	LTYPE0,	APOPAW,
 	"POPFL",	LTYPE0,	APOPFL,
@@ -985,6 +994,8 @@ struct
 	"UNPCKLPS",	LTYPE3,	AUNPCKLPS,
 	"XORPD",	LTYPE3,	AXORPD,
 	"XORPS",	LTYPE3,	AXORPS,
+	"CRC32B",	LTYPE4, ACRC32B,
+	"CRC32Q",	LTYPE4, ACRC32Q,
 
 	0
 };
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
index 775d972..0c23b11 100644
--- a/src/cmd/6c/gc.h
+++ b/src/cmd/6c/gc.h
@@ -398,6 +398,7 @@ void	shiftit(Type*, Node*, Node*);
 #pragma	varargck	type	"A"	int
 #pragma	varargck	type	"B"	Bits
 #pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"lD"	Adr*
 #pragma	varargck	type	"P"	Prog*
 #pragma	varargck	type	"R"	int
 #pragma	varargck	type	"S"	char*
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index 6d886f4..d7a9170 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -238,10 +238,10 @@ outcode(void)
 		Bprint(&b, "\n");
 		Bprint(&b, "$$  // exports\n\n");
 		Bprint(&b, "$$  // local types\n\n");
-		Bprint(&b, "$$  // dynimport\n", thestring);
+		Bprint(&b, "$$  // dynimport\n");
 		for(i=0; i<ndynimp; i++)
 			Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
-		Bprint(&b, "\n$$  // dynexport\n", thestring);
+		Bprint(&b, "\n$$  // dynexport\n");
 		for(i=0; i<ndynexp; i++)
 			Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
 		Bprint(&b, "\n$$\n\n");
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index fca4b64..24f88a4 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -510,9 +510,6 @@ agen(Node *n, Node *res)
 			regfree(&n4);
 		}
 
-		if(w == 0)
-			fatal("index is zero width");
-
 		// constant index
 		if(isconst(nr, CTINT)) {
 			if(isconst(nl, CTSTR))
@@ -600,7 +597,9 @@ agen(Node *n, Node *res)
 			gmove(&n1, &n3);
 		}
 
-		if(w == 1 || w == 2 || w == 4 || w == 8) {
+		if(w == 0) {
+			// nothing to do
+		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
 			p1 = gins(ALEAQ, &n2, &n3);
 			p1->from.scale = w;
 			p1->from.index = p1->from.type;
@@ -608,7 +607,6 @@ agen(Node *n, Node *res)
 		} else {
 			ginscon(optoas(OMUL, t), w, &n2);
 			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			gmove(&n3, res);
 		}
 
 	indexdone:
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 97bfb58..e366362 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -7,6 +7,7 @@
 int	thechar	= '6';
 char*	thestring	= "amd64";
 
+vlong MAXWIDTH = 1LL<<50;
 
 /*
  * go declares several platform-specific type aliases:
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 9e7fbab..a5f2783 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -436,9 +436,6 @@ samereg(Node *a, Node *b)
 
 /*
  * generate division.
- * caller must set:
- *	ax = allocated AX register
- *	dx = allocated DX register
  * generates one of:
  *	res = nl / nr
  *	res = nl % nr
@@ -447,17 +444,35 @@ samereg(Node *a, Node *b)
 void
 dodiv(int op, Node *nl, Node *nr, Node *res)
 {
-	int a;
-	Node n3, n4;
+	int a, check;
+	Node n3, n4, n5;
 	Type *t;
 	Node ax, dx, oldax, olddx;
-
+	Prog *p1, *p2, *p3;
+
+	// Have to be careful about handling
+	// most negative int divided by -1 correctly.
+	// The hardware will trap.
+	// Also the byte divide instruction needs AH,
+	// which we otherwise don't have to deal with.
+	// Easiest way to avoid for int8, int16: use int32.
+	// For int32 and int64, use explicit test.
+	// Could use int64 hw for int32.
 	t = nl->type;
-	if(t->width == 1) {
+	check = 0;
+	if(issigned[t->etype]) {
+		check = 1;
+		if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
+			check = 0;
+		else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+			check = 0;
+	}
+	if(t->width < 4) {
 		if(issigned[t->etype])
 			t = types[TINT32];
 		else
 			t = types[TUINT32];
+		check = 0;
 	}
 	a = optoas(op, t);
 
@@ -473,6 +488,31 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
 		savex(D_AX, &ax, &oldax, res, t);
 		cgen(nl, &ax);
 	}
+	p3 = P;
+	if(check) {
+		nodconst(&n4, t, -1);
+		gins(optoas(OCMP, t), &n3, &n4);
+		p1 = gbranch(optoas(ONE, t), T);
+		nodconst(&n4, t, -1LL<<(t->width*8-1));
+		if(t->width == 8) {
+			n5 = n4;
+			regalloc(&n4, t, N);
+			gins(AMOVQ, &n5, &n4);
+		}
+		gins(optoas(OCMP, t), &ax, &n4);
+		p2 = gbranch(optoas(ONE, t), T);
+		if(op == ODIV)
+			gmove(&n4, res);
+		if(t->width == 8)
+			regfree(&n4);
+		if(op == OMOD) {
+			nodconst(&n4, t, 0);
+			gmove(&n4, res);
+		}
+		p3 = gbranch(AJMP, T);
+		patch(p1, pc);
+		patch(p2, pc);
+	}
 	savex(D_DX, &dx, &olddx, res, t);
 	if(!issigned[t->etype]) {
 		nodconst(&n4, t, 0);
@@ -481,13 +521,14 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
 		gins(optoas(OEXTEND, t), N, N);
 	gins(a, &n3, N);
 	regfree(&n3);
-
 	if(op == ODIV)
 		gmove(&ax, res);
 	else
 		gmove(&dx, res);
-	restx(&ax, &oldax);
 	restx(&dx, &olddx);
+	if(check)
+		patch(p3, pc);
+	restx(&ax, &oldax);
 }
 
 /*
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 211915f..d0d6d0c 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -473,6 +473,7 @@ fatal("shouldnt be used");
 		n->xoffset += types[tptr]->width;
 		break;
 	}
+	n->typecheck = 1;
 	return n;
 }
 
@@ -987,7 +988,6 @@ gins(int as, Node *f, Node *t)
 	if(debug['g'])
 		print("%P\n", p);
 
-
 	w = 0;
 	switch(as) {
 	case AMOVB:
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index 709f82c..262da02 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -190,6 +190,7 @@ enum	as
 	AOUTSB,
 	AOUTSL,
 	AOUTSW,
+	APAUSE,
 	APOPAL,
 	APOPAW,
 	APOPFL,
@@ -730,6 +731,8 @@ enum	as
 	ASWAPGS,
 
 	AMODE,
+	ACRC32B,
+	ACRC32Q,
 
 	ALAST
 };
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
index abe204d..8ed3e14 100644
--- a/src/cmd/6l/Makefile
+++ b/src/cmd/6l/Makefile
@@ -30,7 +30,7 @@ OFILES=\
 
 HFILES=\
 	l.h\
-	../6l/6.out.h\
+	6.out.h\
 	../ld/lib.h\
 	../ld/elf.h\
 	../ld/macho.h\
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 9136e03..f59a59e 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -43,6 +43,7 @@
 
 char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
 char freebsddynld[] = "/libexec/ld-elf.so.1";
+char openbsddynld[] = "/usr/libexec/ld.so";
 
 char	zeroes[32];
 
@@ -524,7 +525,7 @@ adddynsym(Sym *s)
 			adduint64(d, 0);	// value
 		else
 			addaddr(d, s);
-	} else {
+	} else if(HEADTYPE != Hwindows) {
 		diag("adddynsym: unsupported binary format");
 	}
 }
@@ -554,12 +555,12 @@ doelf(void)
 {
 	Sym *s, *shstrtab, *dynstr;
 
-	if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd)
+	if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd)
 		return;
 
 	/* predefine strings we need for section headers */
 	shstrtab = lookup(".shstrtab", 0);
-	shstrtab->type = SELFDATA;
+	shstrtab->type = SELFROSECT;
 	shstrtab->reachable = 1;
 
 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
@@ -593,13 +594,13 @@ doelf(void)
 
 		/* dynamic symbol table - first entry all zeros */
 		s = lookup(".dynsym", 0);
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		s->reachable = 1;
 		s->size += ELF64SYMSIZE;
 
 		/* dynamic string table */
 		s = lookup(".dynstr", 0);
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		s->reachable = 1;
 		if(s->size == 0)
 			addstring(s, "");
@@ -608,44 +609,44 @@ doelf(void)
 		/* relocation table */
 		s = lookup(".rela", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/* global offset table */
 		s = lookup(".got", 0);
 		s->reachable = 1;
-		s->type = SDATA;	// writable, so not SELFDATA
+		s->type = SELFSECT; // writable
 
 		/* hash */
 		s = lookup(".hash", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		s = lookup(".got.plt", 0);
 		s->reachable = 1;
-		s->type = SDATA;	// writable, not SELFDATA
+		s->type = SELFSECT; // writable
 
 		s = lookup(".plt", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		
 		elfsetupplt();
 		
 		s = lookup(".rela.plt", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		
 		s = lookup(".gnu.version", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		
 		s = lookup(".gnu.version_r", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/* define dynamic elf table */
 		s = lookup(".dynamic", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/*
 		 * .dynamic table
@@ -673,8 +674,11 @@ doelf(void)
 void
 shsym(ElfShdr *sh, Sym *s)
 {
-	sh->addr = symaddr(s);
-	sh->off = datoff(sh->addr);
+	vlong addr;
+	addr = symaddr(s);
+	if(sh->flags&SHF_ALLOC)
+		sh->addr = addr;
+	sh->off = datoff(addr);
 	sh->size = s->size;
 }
 
@@ -699,6 +703,7 @@ asmb(void)
 	ElfPhdr *ph, *pph;
 	ElfShdr *sh;
 	Section *sect;
+	int o;
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -711,12 +716,12 @@ asmb(void)
 	Bflush(&bso);
 
 	sect = segtext.sect;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 	codeblk(sect->vaddr, sect->len);
 
 	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
 	for(sect = sect->next; sect != nil; sect = sect->next) {
-		seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 		datblk(sect->vaddr, sect->len);
 	}
 
@@ -724,7 +729,7 @@ asmb(void)
 		Bprint(&bso, "%5.2f datblk\n", cputime());
 	Bflush(&bso);
 
-	seek(cout, segdata.fileoff, 0);
+	cseek(segdata.fileoff);
 	datblk(segdata.vaddr, segdata.filelen);
 
 	machlink = 0;
@@ -742,10 +747,11 @@ asmb(void)
 		break;
 	case Hlinux:
 	case Hfreebsd:
+	case Hopenbsd:
 		debug['8'] = 1;	/* 64-bit addresses */
 		/* index of elf text section; needed by asmelfsym, double-checked below */
 		/* !debug['d'] causes extra sections before the .text section */
-		elftextsh = 1;
+		elftextsh = 2;
 		if(!debug['d']) {
 			elftextsh += 10;
 			if(elfverneed)
@@ -776,6 +782,7 @@ asmb(void)
 			break;
 		case Hlinux:
 		case Hfreebsd:
+		case Hopenbsd:
 			symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
 			symo = rnd(symo, INITRND);
 			break;
@@ -784,14 +791,14 @@ asmb(void)
 			symo = rnd(symo, PEFILEALIGN);
 			break;
 		}
-		seek(cout, symo, 0);
+		cseek(symo);
 		switch(HEADTYPE) {
 		default:
 			if(iself) {
-				seek(cout, symo, 0);
+				cseek(symo);
 				asmelfsym();
 				cflush();
-				ewrite(cout, elfstrdat, elfstrsize);
+				cwrite(elfstrdat, elfstrsize);
 
 				if(debug['v'])
 				       Bprint(&bso, "%5.2f dwarf\n", cputime());
@@ -812,7 +819,7 @@ asmb(void)
 	if(debug['v'])
 		Bprint(&bso, "%5.2f headr\n", cputime());
 	Bflush(&bso);
-	seek(cout, 0L, 0);
+	cseek(0L);
 	switch(HEADTYPE) {
 	default:
 	case Hplan9x32:	/* plan9 */
@@ -845,6 +852,7 @@ asmb(void)
 		break;
 	case Hlinux:
 	case Hfreebsd:
+	case Hopenbsd:
 		/* elf amd-64 */
 
 		eh = getElfEhdr();
@@ -862,6 +870,17 @@ asmb(void)
 		pph->paddr = INITTEXT - HEADR + pph->off;
 		pph->align = INITRND;
 
+		/*
+		 * PHDR must be in a loaded segment. Adjust the text
+		 * segment boundaries downwards to include it.
+		 */
+		o = segtext.vaddr - pph->vaddr;
+		segtext.vaddr -= o;
+		segtext.len += o;
+		o = segtext.fileoff - pph->off;
+		segtext.fileoff -= o;
+		segtext.filelen += o;
+
 		if(!debug['d']) {
 			/* interpreter */
 			sh = newElfShdr(elfstr[ElfStrInterp]);
@@ -876,6 +895,9 @@ asmb(void)
 				case Hfreebsd:
 					interpreter = freebsddynld;
 					break;
+				case Hopenbsd:
+					interpreter = openbsddynld;
+					break;
 				}
 			}
 			elfinterp(sh, startva, interpreter);
@@ -1002,6 +1024,11 @@ asmb(void)
 		ph->flags = PF_W+PF_R;
 		ph->align = 8;
 
+		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
+		sh->type = SHT_STRTAB;
+		sh->addralign = 1;
+		shsym(sh, lookup(".shstrtab", 0));
+
 		if(elftextsh != eh->shnum)
 			diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
 		for(sect=segtext.sect; sect!=nil; sect=sect->next)
@@ -1027,18 +1054,15 @@ asmb(void)
 			dwarfaddelfheaders();
 		}
 
-		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
-		sh->type = SHT_STRTAB;
-		sh->addralign = 1;
-		shsym(sh, lookup(".shstrtab", 0));
-
 		/* Main header */
 		eh->ident[EI_MAG0] = '\177';
 		eh->ident[EI_MAG1] = 'E';
 		eh->ident[EI_MAG2] = 'L';
 		eh->ident[EI_MAG3] = 'F';
 		if(HEADTYPE == Hfreebsd)
-			eh->ident[EI_OSABI] = 9;
+			eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
+		else if(HEADTYPE == Hopenbsd)
+			eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
 		eh->ident[EI_CLASS] = ELFCLASS64;
 		eh->ident[EI_DATA] = ELFDATA2LSB;
 		eh->ident[EI_VERSION] = EV_CURRENT;
@@ -1051,13 +1075,13 @@ asmb(void)
 		pph->filesz = eh->phnum * eh->phentsize;
 		pph->memsz = pph->filesz;
 
-		seek(cout, 0, 0);
+		cseek(0);
 		a = 0;
 		a += elfwritehdr();
 		a += elfwritephdrs();
 		a += elfwriteshdrs();
 		cflush();
-		if(a+elfwriteinterp() > ELFRESERVE)
+		if(a+elfwriteinterp() > ELFRESERVE)	
 			diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
 		break;
 	case Hwindows:
@@ -1067,25 +1091,6 @@ asmb(void)
 	cflush();
 }
 
-void
-cflush(void)
-{
-	int n;
-
-	n = sizeof(buf.cbuf) - cbc;
-	if(n)
-		ewrite(cout, buf.cbuf, n);
-	cbp = buf.cbuf;
-	cbc = sizeof(buf.cbuf);
-}
-
-/* Current position in file */
-vlong
-cpos(void)
-{
-	return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
-}
-
 vlong
 rnd(vlong v, vlong r)
 {
@@ -1118,7 +1123,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
 		case SCONST:
 		case SRODATA:
 		case SDATA:
-		case SELFDATA:
+		case SELFROSECT:
 		case SMACHOGOT:
 		case STYPE:
 		case SSTRING:
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
index cc7782c..b8a6013 100644
--- a/src/cmd/6l/doc.go
+++ b/src/cmd/6l/doc.go
@@ -34,6 +34,8 @@ Options new in this version:
 	Write Linux ELF binaries (default when $GOOS is linux)
 -Hfreebsd
 	Write FreeBSD ELF binaries (default when $GOOS is freebsd)
+-Hopenbsd
+	Write OpenBSD ELF binaries (default when $GOOS is openbsd)
 -Hwindows
 	Write Windows PE32+ binaries (default when $GOOS is windows)
 -I interpreter
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index f4ee6aa..0435685 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -31,7 +31,7 @@
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
-#include	"../6l/6.out.h"
+#include	"6.out.h"
 
 #ifndef	EXTERN
 #define	EXTERN	extern
@@ -46,10 +46,6 @@ enum
 #define	P		((Prog*)0)
 #define	S		((Sym*)0)
 #define	TNAME		(cursym?cursym->name:noname)
-#define	cput(c)\
-	{ *cbp++ = c;\
-	if(--cbc <= 0)\
-		cflush(); }
 
 typedef	struct	Adr	Adr;
 typedef	struct	Prog	Prog;
@@ -222,6 +218,7 @@ enum
 	Zxxx		= 0,
 
 	Zlit,
+	Zlitm_r,
 	Z_rp,
 	Zbr,
 	Zcall,
@@ -285,24 +282,13 @@ enum
 	Maxand	= 10,		/* in -a output width of the byte codes */
 };
 
-EXTERN union
-{
-	struct
-	{
-		char	obuf[MAXIO];			/* output buffer */
-		uchar	ibuf[MAXIO];			/* input buffer */
-	} u;
-	char	dbuf[1];
-} buf;
-
-#define	cbuf	u.obuf
-#define	xbuf	u.ibuf
-
 #pragma	varargck	type	"A"	uint
 #pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"I"	uchar*
 #pragma	varargck	type	"P"	Prog*
 #pragma	varargck	type	"R"	int
 #pragma	varargck	type	"S"	char*
+#pragma	varargck	type	"i"	char*
 
 EXTERN	int32	HEADR;
 EXTERN	int32	HEADTYPE;
@@ -310,9 +296,6 @@ EXTERN	int32	INITRND;
 EXTERN	vlong	INITTEXT;
 EXTERN	vlong	INITDAT;
 EXTERN	char*	INITENTRY;		/* entry point */
-EXTERN	Biobuf	bso;
-EXTERN	int	cbc;
-EXTERN	char*	cbp;
 EXTERN	char*	pcstr;
 EXTERN	Auto*	curauto;
 EXTERN	Auto*	curhist;
@@ -373,9 +356,7 @@ vlong	atolwhex(char*);
 Prog*	brchain(Prog*);
 Prog*	brloop(Prog*);
 void	buildop(void);
-void	cflush(void);
 Prog*	copyp(Prog*);
-vlong	cpos(void);
 double	cputime(void);
 void	datblk(int32, int32);
 void	deadcode(void);
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index e3191bb..a7ef58d 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -50,6 +50,7 @@ Header headers[] = {
    "darwin", Hdarwin,
    "linux", Hlinux,
    "freebsd", Hfreebsd,
+   "openbsd", Hopenbsd,
    "windows", Hwindows,
    "windowsgui", Hwindows,
    0, 0
@@ -62,6 +63,7 @@ Header headers[] = {
  *	-Hdarwin -Tx -Rx		is apple MH-exec
  *	-Hlinux -Tx -Rx			is linux elf-exec
  *	-Hfreebsd -Tx -Rx		is FreeBSD elf-exec
+ *	-Hopenbsd -Tx -Rx		is OpenBSD elf-exec
  *	-Hwindows -Tx -Rx		is MS Windows PE32+
  *
  *	options used: 189BLQSWabcjlnpsvz
@@ -80,11 +82,10 @@ main(int argc, char *argv[])
 	int c;
 
 	Binit(&bso, 1, OWRITE);
-	cout = -1;
 	listinit();
 	memset(debug, 0, sizeof(debug));
 	nerrors = 0;
-	outfile = "6.out";
+	outfile = nil;
 	HEADTYPE = -1;
 	INITTEXT = -1;
 	INITDAT = -1;
@@ -134,11 +135,20 @@ main(int argc, char *argv[])
 	if(argc != 1)
 		usage();
 
-	libinit();
+	mywhatsys();	// get goos
 
 	if(HEADTYPE == -1)
 		HEADTYPE = headtype(goos);
 
+	if(outfile == nil) {
+		if(HEADTYPE == Hwindows)
+			outfile = "6.out.exe";
+		else
+			outfile = "6.out";
+	}
+
+	libinit();
+
 	switch(HEADTYPE) {
 	default:
 		diag("unknown -H option");
@@ -186,7 +196,8 @@ main(int argc, char *argv[])
 			INITDAT = 0;
 		break;
 	case Hlinux:	/* elf64 executable */
-	case Hfreebsd: /* freebsd */
+	case Hfreebsd:	/* freebsd */
+	case Hopenbsd:	/* openbsd */
 		/*
 		 * ELF uses TLS offset negative from FS.
 		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
@@ -446,7 +457,6 @@ loop:
 		s = lookup(x, r);
 		if(x != name)
 			free(x);
-		name = nil;
 
 		if(debug['S'] && r == 0)
 			sig = 1729;
@@ -715,7 +725,6 @@ loop:
 		lastp = p;
 		goto loop;
 	}
-	goto loop;
 
 eof:
 	diag("truncated object file: %s", pn);
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
index 6cc5031..36806ec 100644
--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -529,7 +529,69 @@ uchar	ymskb[] =
 	Ymr,	Yrl,	Zm_r_xm,	1,
 	0
 };
+uchar	ycrc32l[] =
+{
+	Yml,	Yrl,	Zlitm_r,	0,
+};
 
+/*
+ * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
+ * and p->from and p->to as operands (Adr*).  The linker scans optab to find
+ * the entry with the given p->as and then looks through the ytable for that
+ * instruction (the second field in the optab struct) for a line whose first
+ * two values match the Ytypes of the p->from and p->to operands.  The function
+ * oclass in span.c computes the specific Ytype of an operand and then the set
+ * of more general Ytypes that it satisfies is implied by the ycover table, set
+ * up in instinit.  For example, oclass distinguishes the constants 0 and 1
+ * from the more general 8-bit constants, but instinit says
+ *
+ *        ycover[Yi0*Ymax + Ys32] = 1;
+ *        ycover[Yi1*Ymax + Ys32] = 1;
+ *        ycover[Yi8*Ymax + Ys32] = 1;
+ *
+ * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
+ * if that's what an instruction can handle.
+ *
+ * In parallel with the scan through the ytable for the appropriate line, there
+ * is a z pointer that starts out pointing at the strange magic byte list in
+ * the Optab struct.  With each step past a non-matching ytable line, z
+ * advances by the 4th entry in the line.  When a matching line is found, that
+ * z pointer has the extra data to use in laying down the instruction bytes.
+ * The actual bytes laid down are a function of the 3rd entry in the line (that
+ * is, the Ztype) and the z bytes.
+ *
+ * For example, let's look at AADDL.  The optab line says:
+ *        { AADDL,        yaddl,  Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ *
+ * and yaddl says
+ *        uchar   yaddl[] =
+ *        {
+ *                Yi8,    Yml,    Zibo_m, 2,
+ *                Yi32,   Yax,    Zil_,   1,
+ *                Yi32,   Yml,    Zilo_m, 2,
+ *                Yrl,    Yml,    Zr_m,   1,
+ *                Yml,    Yrl,    Zm_r,   1,
+ *                0
+ *        };
+ *
+ * so there are 5 possible types of ADDL instruction that can be laid down, and
+ * possible states used to lay them down (Ztype and z pointer, assuming z
+ * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
+ *
+ *        Yi8, Yml -> Zibo_m, z (0x83, 00)
+ *        Yi32, Yax -> Zil_, z+2 (0x05)
+ *        Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
+ *        Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
+ *        Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
+ *
+ * The Pconstant in the optab line controls the prefix bytes to emit.  That's
+ * relatively straightforward as this program goes.
+ *
+ * The switch on t[2] in doasm implements the various Z cases.  Zibo_m, for
+ * example, is an opcode byte (z[0]) then an asmando (which is some kind of
+ * encoded addressing mode for the Yml arg), and then a single immediate byte.
+ * Zilo_m is the same but a long (32-bit) immediate.
+ */
 Optab optab[] =
 /*	as, ytab, andproto, opcode */
 {
@@ -857,6 +919,7 @@ Optab optab[] =
 	{ APADDW,	ymm,	Py, 0xfd,Pe,0xfd },
 	{ APAND,	ymm,	Py, 0xdb,Pe,0xdb },
 	{ APANDN,	ymm,	Py, 0xdf,Pe,0xdf },
+	{ APAUSE,	ynone,	Px, 0xf3,0x90 },
 	{ APAVGB,	ymm,	Py, 0xe0,Pe,0xe0 },
 	{ APAVGW,	ymm,	Py, 0xe3,Pe,0xe3 },
 	{ APCMPEQB,	ymm,	Py, 0x74,Pe,0x74 },
@@ -1199,6 +1262,9 @@ Optab optab[] =
 	{ AXADDQ,	yrl_ml,	Pw, 0x0f,0xc1 },
 	{ AXADDW,	yrl_ml,	Pe, 0x0f,0xc1 },
 
+	{ ACRC32B,       ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0},
+	{ ACRC32Q,       ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0},
+
 	{ AEND },
 	0
 };
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index 0b0ee12..d9e0b2f 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -294,7 +294,8 @@ patch(void)
 				p->from.offset = 0x58;
 			}
 		}
-		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd) {
+		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
+		|| HEADTYPE == Hopenbsd) {
 			// ELF uses FS instead of GS.
 			if(p->from.type == D_INDIR+D_GS)
 				p->from.type = D_INDIR+D_FS;
@@ -402,8 +403,6 @@ dostkoff(void)
 		pmorestack[i] = symmorestack[i]->text;
 	}
 
-	autoffset = 0;
-	deltasp = 0;
 	for(cursym = textp; cursym != nil; cursym = cursym->next) {
 		if(cursym->text == nil || cursym->text->link == nil)
 			continue;
@@ -415,14 +414,14 @@ dostkoff(void)
 			autoffset = 0;
 
 		q = P;
-		q1 = P;
 		if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
 			diag("nosplit func likely to overflow stack");
 
 		if(!(p->from.scale & NOSPLIT)) {
 			p = appendp(p);	// load g into CX
 			p->as = AMOVQ;
-			if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd)	// ELF uses FS
+			if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
+			|| HEADTYPE == Hopenbsd)	// ELF uses FS
 				p->from.type = D_INDIR+D_FS;
 			else
 				p->from.type = D_INDIR+D_GS;
@@ -471,7 +470,6 @@ dostkoff(void)
 				p = appendp(p);
 				p->as = ANOP;
 				q1->pcond = p;
-				q1 = P;
 			}
 
 			if(autoffset < StackBig) {  // do we need to call morestack?
@@ -611,7 +609,6 @@ dostkoff(void)
 			p = appendp(p);
 			p->as = ANOP;
 			q1->pcond = p;
-			q1 = P;
 		}
 		
 		for(; p != P; p = p->link) {
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
index 25992a4..862ce08 100644
--- a/src/cmd/6l/prof.c
+++ b/src/cmd/6l/prof.c
@@ -36,7 +36,7 @@
 void
 doprof1(void)
 {
-#if 0
+#ifdef	NOTDEF
 	Sym *s;
 	int32 n;
 	Prog *p, *q;
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 5251f19..5d13ad4 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -94,7 +94,7 @@ span1(Sym *s)
 					*bp++ = v;
 					*bp++ = v>>8;
 					*bp++ = v>>16;
-					*bp++ = v>>24;
+					*bp = v>>24;
 				}	
 			}
 			p->comefrom = P;
@@ -706,6 +706,7 @@ asmandsz(Adr *a, int r, int rex, int m64)
 	int t, scale;
 	Reloc rel;
 
+	USED(m64);
 	rex &= (0x40 | Rxr);
 	v = a->offset;
 	t = a->type;
@@ -732,7 +733,6 @@ asmandsz(Adr *a, int r, int rex, int m64)
 			*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
 			asmidx(a->scale, a->index, t);
 			goto putrelv;
-			return;
 		}
 		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
 			*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
@@ -1166,6 +1166,12 @@ found:
 			*andptr++ = op;
 		break;
 
+	case Zlitm_r:
+		for(; op = o->op[z]; z++)
+			*andptr++ = op;
+		asmand(&p->from, &p->to);
+		break;
+
 	case Zmb_r:
 		bytereg(&p->from, &p->ft);
 		/* fall through */
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index ab4de41..e56460e 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -421,6 +421,7 @@ struct
 	"OUTSB",	LTYPE0,	AOUTSB,
 	"OUTSL",	LTYPE0,	AOUTSL,
 	"OUTSW",	LTYPE0,	AOUTSW,
+	"PAUSE",	LTYPEN,	APAUSE,
 	"POPAL",	LTYPE0,	APOPAL,
 	"POPAW",	LTYPE0,	APOPAW,
 	"POPFL",	LTYPE0,	APOPFL,
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 1614a2d..b316e6e 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -562,9 +562,6 @@ agen(Node *n, Node *res)
 			regfree(&n4);
 		}
 
-		if(w == 0)
-			fatal("index is zero width");
-
 		// constant index
 		if(isconst(nr, CTINT)) {
 			if(isconst(nl, CTSTR))
@@ -639,7 +636,9 @@ agen(Node *n, Node *res)
 			gmove(&n1, &n3);
 		}
 
-		if(w == 1 || w == 2 || w == 4 || w == 8) {
+		if(w == 0) {
+			// nothing to do
+		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
 			p1 = gins(ALEAL, &n2, &n3);
 			p1->from.scale = w;
 			p1->from.index = p1->from.type;
@@ -648,7 +647,6 @@ agen(Node *n, Node *res)
 			nodconst(&n1, types[TUINT32], w);
 			gins(optoas(OMUL, types[TUINT32]), &n1, &n2);
 			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			gmove(&n3, res);
 		}
 
 	indexdone:
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 48edfdf..7734603 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -7,6 +7,7 @@
 int	thechar	= '8';
 char*	thestring	= "386";
 
+vlong MAXWIDTH = (1LL<<32) - 1;
 
 /*
  * go declares several platform-specific type aliases:
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 7da60d7..9f7a66a 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -9,7 +9,7 @@
 #include "../8l/8.out.h"
 
 #ifndef	EXTERN
-#define EXTERN	extern
+#define	EXTERN	extern
 #endif
 
 typedef	struct	Addr	Addr;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 6db0474..108c493 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -480,12 +480,40 @@ samereg(Node *a, Node *b)
  * according to op.
  */
 void
-dodiv(int op, Type *t, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
+dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
 {
-	Node n1, t1, t2, nz;
+	int check;
+	Node n1, t1, t2, n4, nz;
+	Type *t;
+	Prog *p1, *p2, *p3;
+
+	// Have to be careful about handling
+	// most negative int divided by -1 correctly.
+	// The hardware will trap.
+	// Also the byte divide instruction needs AH,
+	// which we otherwise don't have to deal with.
+	// Easiest way to avoid for int8, int16: use int32.
+	// For int32 and int64, use explicit test.
+	// Could use int64 hw for int32.
+	t = nl->type;
+	check = 0;
+	if(issigned[t->etype]) {
+		check = 1;
+		if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
+			check = 0;
+		else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+			check = 0;
+	}
+	if(t->width < 4) {
+		if(issigned[t->etype])
+			t = types[TINT32];
+		else
+			t = types[TUINT32];
+		check = 0;
+	}
 
-	tempname(&t1, nl->type);
-	tempname(&t2, nr->type);
+	tempname(&t1, t);
+	tempname(&t2, t);
 	cgen(nl, &t1);
 	cgen(nr, &t2);
 
@@ -495,6 +523,24 @@ dodiv(int op, Type *t, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
 		regalloc(&n1, t, N);
 	gmove(&t2, &n1);
 	gmove(&t1, ax);
+	p3 = P;
+	if(check) {
+		nodconst(&n4, t, -1);
+		gins(optoas(OCMP, t), &n1, &n4);
+		p1 = gbranch(optoas(ONE, t), T);
+		nodconst(&n4, t, -1LL<<(t->width*8-1));
+		gins(optoas(OCMP, t), ax, &n4);
+		p2 = gbranch(optoas(ONE, t), T);
+		if(op == ODIV)
+			gmove(&n4, res);
+		if(op == OMOD) {
+			nodconst(&n4, t, 0);
+			gmove(&n4, res);
+		}
+		p3 = gbranch(AJMP, T);
+		patch(p1, pc);
+		patch(p2, pc);
+	}
 	if(!issigned[t->etype]) {
 		nodconst(&nz, t, 0);
 		gmove(&nz, dx);
@@ -507,6 +553,8 @@ dodiv(int op, Type *t, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
 		gmove(ax, res);
 	else
 		gmove(dx, res);
+	if(check)
+		patch(p3, pc);
 }
 
 static void
@@ -553,13 +601,13 @@ cgen_div(int op, Node *nl, Node *nr, Node *res)
 	if(is64(nl->type))
 		fatal("cgen_div %T", nl->type);
 
-	t = nl->type;
-	if(t->width == 1)
-		t = types[t->etype+2];	// int8 -> int16, uint8 -> uint16
-
+	if(issigned[nl->type->etype])
+		t = types[TINT32];
+	else
+		t = types[TUINT32];
 	savex(D_AX, &ax, &oldax, res, t);
 	savex(D_DX, &dx, &olddx, res, t);
-	dodiv(op, t, nl, nr, res, &ax, &dx);
+	dodiv(op, nl, nr, res, &ax, &dx);
 	restx(&dx, &olddx);
 	restx(&ax, &oldax);
 }
@@ -572,9 +620,9 @@ cgen_div(int op, Node *nl, Node *nr, Node *res)
 void
 cgen_shift(int op, Node *nl, Node *nr, Node *res)
 {
-	Node n1, n2, cx, oldcx;
+	Node n1, n2, nt, cx, oldcx, hi, lo;
 	int a, w;
-	Prog *p1;
+	Prog *p1, *p2;
 	uvlong sc;
 
 	if(nl->type->width > 4)
@@ -608,8 +656,13 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
 		gmove(&cx, &oldcx);
 	}
 
-	nodreg(&n1, types[TUINT32], D_CX);
-	regalloc(&n1, nr->type, &n1);		// to hold the shift type in CX
+	if(nr->type->width > 4) {
+		tempname(&nt, nr->type);
+		n1 = nt;
+	} else {
+		nodreg(&n1, types[TUINT32], D_CX);
+		regalloc(&n1, nr->type, &n1);		// to hold the shift type in CX
+	}
 
 	if(samereg(&cx, res))
 		regalloc(&n2, nl->type, N);
@@ -624,8 +677,21 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
 	}
 
 	// test and fix up large shifts
-	gins(optoas(OCMP, nr->type), &n1, ncon(w));
-	p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+	if(nr->type->width > 4) {
+		// delayed reg alloc
+		nodreg(&n1, types[TUINT32], D_CX);
+		regalloc(&n1, types[TUINT32], &n1);		// to hold the shift type in CX
+		split64(&nt, &lo, &hi);
+		gmove(&lo, &n1);
+		gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
+		p2 = gbranch(optoas(ONE, types[TUINT32]), T);
+		gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
+		p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+		patch(p2, pc);
+	} else {
+		gins(optoas(OCMP, nr->type), &n1, ncon(w));
+		p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+	}
 	if(op == ORSH && issigned[nl->type->etype]) {
 		gins(a, ncon(w-1), &n2);
 	} else {
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index a4828c3..2b878f6 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -865,7 +865,7 @@ mkvar(Reg *r, Adr *a)
 			if(v->width == w)
 				return blsh(i);
 
-			// if they overlaps, disable both
+			// if they overlap, disable both
 			if(overlap(v->offset, v->width, o, w)) {
 				if(debug['R'])
 					print("disable %s\n", v->sym->name);
@@ -874,8 +874,6 @@ mkvar(Reg *r, Adr *a)
 			}
 		}
 	}
-	if(a->pun)
-		flag = 1;
 
 	switch(et) {
 	case 0:
@@ -902,7 +900,7 @@ mkvar(Reg *r, Adr *a)
 	v->node = a->node;
 
 	if(debug['R'])
-		print("bit=%2d et=%2d w=%d %S %D flag=%d\n", i, et, w, s, a, v->addr);
+		print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
 	ostats.nvar++;
 
 	bit = blsh(i);
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index 03db001..9a8483a 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -180,6 +180,7 @@ enum	as
 	AOUTSB,
 	AOUTSL,
 	AOUTSW,
+	APAUSE,
 	APOPAL,
 	APOPAW,
 	APOPFL,
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
index a85e3ff..7d34e17 100644
--- a/src/cmd/8l/Makefile
+++ b/src/cmd/8l/Makefile
@@ -31,7 +31,7 @@ OFILES=\
 
 HFILES=\
 	l.h\
-	../8l/8.out.h\
+	8.out.h\
 	../ld/dwarf.h\
 	../ld/elf.h\
 	../ld/macho.h\
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index e1ccfb8..22abd80 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -519,7 +519,7 @@ doelf(void)
 
 	/* predefine strings we need for section headers */
 	shstrtab = lookup(".shstrtab", 0);
-	shstrtab->type = SELFDATA;
+	shstrtab->type = SELFROSECT;
 	shstrtab->reachable = 1;
 
 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
@@ -551,21 +551,16 @@ doelf(void)
 		elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
 		elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
 
-		/* interpreter string */
-		s = lookup(".interp", 0);
-		s->reachable = 1;
-		s->type = SELFDATA;
-
 		/* dynamic symbol table - first entry all zeros */
 		s = lookup(".dynsym", 0);
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		s->reachable = 1;
 		s->size += ELF32SYMSIZE;
 
 		/* dynamic string table */
 		s = lookup(".dynstr", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		if(s->size == 0)
 			addstring(s, "");
 		dynstr = s;
@@ -573,45 +568,45 @@ doelf(void)
 		/* relocation table */
 		s = lookup(".rel", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/* global offset table */
 		s = lookup(".got", 0);
 		s->reachable = 1;
-		s->type = SDATA;	// writable, so not SELFDATA
+		s->type = SELFSECT; // writable
 		
 		/* hash */
 		s = lookup(".hash", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/* got.plt */
 		s = lookup(".got.plt", 0);
 		s->reachable = 1;
-		s->type = SDATA;	// writable, so not SELFDATA
+		s->type = SELFSECT; // writable
 		
 		s = lookup(".plt", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		s = lookup(".rel.plt", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		
 		s = lookup(".gnu.version", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 		
 		s = lookup(".gnu.version_r", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		elfsetupplt();
 
 		/* define dynamic elf table */
 		s = lookup(".dynamic", 0);
 		s->reachable = 1;
-		s->type = SELFDATA;
+		s->type = SELFROSECT;
 
 		/*
 		 * .dynamic table
@@ -638,8 +633,11 @@ doelf(void)
 void
 shsym(Elf64_Shdr *sh, Sym *s)
 {
-	sh->addr = symaddr(s);
-	sh->off = datoff(sh->addr);
+	vlong addr;
+	addr = symaddr(s);
+	if(sh->flags&SHF_ALLOC)
+		sh->addr = addr;
+	sh->off = datoff(addr);
 	sh->size = s->size;
 }
 
@@ -665,6 +663,7 @@ asmb(void)
 	ElfShdr *sh;
 	Section *sect;
 	Sym *sym;
+	int o;
 	int i;
 
 	if(debug['v'])
@@ -672,12 +671,12 @@ asmb(void)
 	Bflush(&bso);
 
 	sect = segtext.sect;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 	codeblk(sect->vaddr, sect->len);
 
 	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
 	for(sect = sect->next; sect != nil; sect = sect->next) {
-		seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
 		datblk(sect->vaddr, sect->len);
 	}
 
@@ -685,7 +684,7 @@ asmb(void)
 		Bprint(&bso, "%5.2f datblk\n", cputime());
 	Bflush(&bso);
 
-	seek(cout, segdata.fileoff, 0);
+	cseek(segdata.fileoff);
 	datblk(segdata.vaddr, segdata.filelen);
 
 	machlink = 0;
@@ -695,7 +694,7 @@ asmb(void)
 	if(iself) {
 		/* index of elf text section; needed by asmelfsym, double-checked below */
 		/* !debug['d'] causes extra sections before the .text section */
-		elftextsh = 1;
+		elftextsh = 2;
 		if(!debug['d']) {
 			elftextsh += 10;
 			if(elfverneed)
@@ -742,7 +741,7 @@ asmb(void)
 			symo = rnd(symo, PEFILEALIGN);
 			break;
 		}
-		seek(cout, symo, 0);
+		cseek(symo);
 		switch(HEADTYPE) {
 		default:
 			if(iself) {
@@ -750,7 +749,7 @@ asmb(void)
 				       Bprint(&bso, "%5.2f elfsym\n", cputime());
 				asmelfsym();
 				cflush();
-				ewrite(cout, elfstrdat, elfstrsize);
+				cwrite(elfstrdat, elfstrsize);
 
 				if(debug['v'])
 					Bprint(&bso, "%5.2f dwarf\n", cputime());
@@ -781,7 +780,7 @@ asmb(void)
 	if(debug['v'])
 		Bprint(&bso, "%5.2f headr\n", cputime());
 	Bflush(&bso);
-	seek(cout, 0L, 0);
+	cseek(0L);
 	switch(HEADTYPE) {
 	default:
 		if(iself)
@@ -932,6 +931,17 @@ asmb(void)
 		pph->paddr = INITTEXT - HEADR + pph->off;
 		pph->align = INITRND;
 
+		/*
+		 * PHDR must be in a loaded segment. Adjust the text
+		 * segment boundaries downwards to include it.
+		 */
+		o = segtext.vaddr - pph->vaddr;
+		segtext.vaddr -= o;
+		segtext.len += o;
+		o = segtext.fileoff - pph->off;
+		segtext.fileoff -= o;
+		segtext.filelen += o;
+
 		if(!debug['d']) {
 			/* interpreter */
 			sh = newElfShdr(elfstr[ElfStrInterp]);
@@ -1072,6 +1082,11 @@ asmb(void)
 		ph->flags = PF_W+PF_R;
 		ph->align = 4;
 
+		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
+		sh->type = SHT_STRTAB;
+		sh->addralign = 1;
+		shsym(sh, lookup(".shstrtab", 0));
+
 		if(elftextsh != eh->shnum)
 			diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
 		for(sect=segtext.sect; sect!=nil; sect=sect->next)
@@ -1097,11 +1112,6 @@ asmb(void)
 			dwarfaddelfheaders();
 		}
 
-		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
-		sh->type = SHT_STRTAB;
-		sh->addralign = 1;
-		shsym(sh, lookup(".shstrtab", 0));
-
 		/* Main header */
 		eh->ident[EI_MAG0] = '\177';
 		eh->ident[EI_MAG1] = 'E';
@@ -1126,13 +1136,13 @@ asmb(void)
 			pph->memsz = pph->filesz;
 		}
 
-		seek(cout, 0, 0);
+		cseek(0);
 		a = 0;
 		a += elfwritehdr();
 		a += elfwritephdrs();
 		a += elfwriteshdrs();
 		cflush();
-		if(a+elfwriteinterp() > ELFRESERVE)
+		if(a+elfwriteinterp() > ELFRESERVE)	
 			diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
 		break;
 
@@ -1154,25 +1164,6 @@ s8put(char *n)
 		cput(name[i]);
 }
 
-void
-cflush(void)
-{
-	int n;
-
-	n = sizeof(buf.cbuf) - cbc;
-	if(n)
-		ewrite(cout, buf.cbuf, n);
-	cbp = buf.cbuf;
-	cbc = sizeof(buf.cbuf);
-}
-
-/* Current position in file */
-vlong
-cpos(void)
-{
-	return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
-}
-
 int32
 rnd(int32 v, int32 r)
 {
@@ -1207,7 +1198,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
 			case SCONST:
 			case SRODATA:
 			case SDATA:
-			case SELFDATA:
+			case SELFROSECT:
 			case SMACHO:
 			case SMACHOGOT:
 			case STYPE:
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 7e7cd5d..94cbfc2 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -31,7 +31,7 @@
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
-#include	"../8l/8.out.h"
+#include	"8.out.h"
 
 #ifndef	EXTERN
 #define	EXTERN	extern
@@ -247,22 +247,8 @@ enum
 	Pb		= 0xfe,	/* byte operands */
 };
 
-EXTERN union
-{
-	struct
-	{
-		char	obuf[MAXIO];			/* output buffer */
-		uchar	ibuf[MAXIO];			/* input buffer */
-	} u;
-	char	dbuf[1];
-} buf;
-
-#define	cbuf	u.obuf
-#define	xbuf	u.ibuf
-
 #pragma	varargck	type	"A"	int
 #pragma	varargck	type	"D"	Adr*
-#pragma	varargck	type	"I"	int
 #pragma	varargck	type	"I"	uchar*
 #pragma	varargck	type	"P"	Prog*
 #pragma	varargck	type	"R"	int
@@ -276,10 +262,7 @@ EXTERN	int32	INITRND;
 EXTERN	int32	INITTEXT;
 EXTERN	int32	INITDAT;
 EXTERN	char*	INITENTRY;		/* entry point */
-EXTERN	Biobuf	bso;
 EXTERN	int32	casepc;
-EXTERN	int	cbc;
-EXTERN	char*	cbp;
 EXTERN	char*	pcstr;
 EXTERN	Auto*	curauto;
 EXTERN	Auto*	curhist;
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index ce7b595..a8e1c34 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -85,7 +85,6 @@ main(int argc, char *argv[])
 	int c;
 
 	Binit(&bso, 1, OWRITE);
-	cout = -1;
 	listinit();
 	memset(debug, 0, sizeof(debug));
 	nerrors = 0;
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
index 1e89a21..f5c195d 100644
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -495,6 +495,7 @@ Optab optab[] =
 	{ AOUTSB,	ynone,	Pb, 0x6e },
 	{ AOUTSL,	ynone,	Px, 0x6f },
 	{ AOUTSW,	ynone,	Pe, 0x6f },
+	{ APAUSE,	ynone,	Px, 0xf3,0x90 },
 	{ APOPAL,	ynone,	Px, 0x61 },
 	{ APOPAW,	ynone,	Pe, 0x61 },
 	{ APOPFL,	ynone,	Px, 0x9d },
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 42c245b..084aa04 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -29,7 +29,6 @@
 // THE SOFTWARE.
 
 #include	<u.h>
-#include	<ctype.h>
 #include	"cc.h"
 #include	"y.tab.h"
 
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index 15f2d37..9fb2f9e 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -29,7 +29,6 @@
 // THE SOFTWARE.
 
 #include	<u.h>
-#include	<ctype.h>
 #include	"cc.h"
 #include	"y.tab.h"
 
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
index 43ae214..b969662 100644
--- a/src/cmd/cc/mac.c
+++ b/src/cmd/cc/mac.c
@@ -29,7 +29,6 @@
 // THE SOFTWARE.
 
 #include	<u.h>
-#include	<ctype.h>
 #include	"cc.h"
 
 #include	"macbody"
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 46e3368..73b7313 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -189,6 +189,10 @@ func (f *File) saveExport(x interface{}, context string) {
 			error(c.Pos(), "export missing name")
 		}
 
+		if name != n.Name.Name {
+			error(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
+		}
+
 		f.ExpFunc = append(f.ExpFunc, &ExpFunc{
 			Func:    n,
 			ExpName: name,
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 064725c..6341382 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -52,6 +52,7 @@ C.char, C.schar (signed char), C.uchar (unsigned char),
 C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
 C.long, C.ulong (unsigned long), C.longlong (long long),
 C.ulonglong (unsigned long long), C.float, C.double.
+The C type void* is represented by Go's unsafe.Pointer.
 
 To access a struct, union, or enum type directly, prefix it with
 struct_, union_, or enum_, as in C.struct_stat.
@@ -68,6 +69,21 @@ C compilers are aware of this calling convention and adjust
 the call accordingly, but Go cannot.  In Go, you must pass
 the pointer to the first element explicitly: C.f(&x[0]).
 
+A few special functions convert between Go and C types
+by making copies of the data.  In pseudo-Go definitions:
+
+	// Go string to C string
+	func C.CString(string) *C.char
+
+	// C string to Go string
+	func C.GoString(*C.char) string
+
+	// C string, length to Go string
+	func C.GoStringN(*C.char, C.int) string
+
+	// C pointer, length to Go []byte
+	func C.GoBytes(unsafe.Pointer, C.int) []byte
+
 Cgo transforms the input file into four output files: two Go source
 files, a C file for 6c (or 8c or 5c), and a C file for gcc.
 
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index a4d83f1..7ec4d8c 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1140,6 +1140,14 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
 			t.Align = c.ptrSize
 			break
 		}
+		if dt.Name == "_GoBytes_" {
+			// Special C name for Go []byte type.
+			// Knows slice layout used by compilers: pointer, length, cap.
+			t.Go = c.Ident("[]byte")
+			t.Size = c.ptrSize + 4 + 4
+			t.Align = c.ptrSize
+			break
+		}
 		name := c.Ident("_Ctypedef_" + dt.Name)
 		t.Go = name // publish before recursive call
 		sub := c.Type(dt.Type)
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 6802dd1..9c962b8 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -236,7 +236,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
 	printer.Fprint(fgo2, fset, d)
 	fmt.Fprintf(fgo2, "\n")
 
-	if name == "CString" || name == "GoString" || name == "GoStringN" {
+	if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" {
 		// The builtins are already defined in the C prolog.
 		return
 	}
@@ -316,7 +316,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
 
 func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 	name := n.Mangle
-	if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] {
+	if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] {
 		// The builtins are already defined in the C prolog, and we don't
 		// want to duplicate function definitions we've already done.
 		return
@@ -412,7 +412,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
 				t := p.cgoType(atype)
 				if off%t.Align != 0 {
 					pad := t.Align - off%t.Align
-					ctype += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
+					ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
 					off += pad
 					npad++
 				}
@@ -646,6 +646,8 @@ func (p *Package) cgoType(e ast.Expr) *Type {
 			}
 			return r
 		}
+		error(e.Pos(), "unrecognized Go type %s", t.Name)
+		return &Type{Size: 4, Align: 4, C: c("int")}
 	case *ast.SelectorExpr:
 		id, ok := t.X.(*ast.Ident)
 		if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
@@ -679,8 +681,10 @@ __cgo_size_assert(double, 8)
 
 const builtinProlog = `
 typedef struct { char *p; int n; } _GoString_;
+typedef struct { char *p; int n; int c; } _GoBytes_;
 _GoString_ GoString(char *p);
 _GoString_ GoStringN(char *p, int l);
+_GoBytes_ GoBytes(void *p, int n);
 char *CString(_GoString_);
 `
 
@@ -705,10 +709,17 @@ void
 }
 
 void
+·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
+{
+	s = runtime·gobytes((byte*)p, l);
+	FLUSH(&s);
+}
+
+void
 ·_Cfunc_CString(String s, int8 *p)
 {
 	p = runtime·cmalloc(s.len+1);
-	runtime·mcpy((byte*)p, s.str, s.len);
+	runtime·memmove((byte*)p, s.str, s.len);
 	p[s.len] = 0;
 	FLUSH(&p);
 }
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
index 0b04431..009b336 100644
--- a/src/cmd/ebnflint/ebnflint.go
+++ b/src/cmd/ebnflint/ebnflint.go
@@ -16,31 +16,26 @@ import (
 	"path/filepath"
 )
 
-
 var fset = token.NewFileSet()
 var start = flag.String("start", "Start", "name of start production")
 
-
 func usage() {
 	fmt.Fprintf(os.Stderr, "usage: ebnflint [flags] [filename]\n")
 	flag.PrintDefaults()
 	os.Exit(1)
 }
 
-
 // Markers around EBNF sections in .html files
 var (
 	open  = []byte(`<pre class="ebnf">`)
 	close = []byte(`</pre>`)
 )
 
-
 func report(err os.Error) {
 	scanner.PrintError(os.Stderr, err)
 	os.Exit(1)
 }
 
-
 func extractEBNF(src []byte) []byte {
 	var buf bytes.Buffer
 
@@ -77,7 +72,6 @@ func extractEBNF(src []byte) []byte {
 	return buf.Bytes()
 }
 
-
 func main() {
 	flag.Parse()
 
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 7fcac48..14c1c4a 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -30,14 +30,18 @@ offmod(Type *t)
 	o = 0;
 	for(f=t->type; f!=T; f=f->down) {
 		if(f->etype != TFIELD)
-			fatal("widstruct: not TFIELD: %lT", f);
+			fatal("offmod: not TFIELD: %lT", f);
 		f->width = o;
 		o += widthptr;
+		if(o >= MAXWIDTH) {
+			yyerror("interface too large");
+			o = widthptr;
+		}
 	}
 }
 
-static uint32
-widstruct(Type *t, uint32 o, int flag)
+static vlong
+widstruct(Type *errtype, Type *t, vlong o, int flag)
 {
 	Type *f;
 	int32 w, maxalign;
@@ -69,6 +73,10 @@ widstruct(Type *t, uint32 o, int flag)
 				f->nname->xoffset = o;
 		}
 		o += w;
+		if(o >= MAXWIDTH) {
+			yyerror("type %lT too large", errtype);
+			o = 8;  // small but nonzero
+		}
 	}
 	// final width is rounded
 	if(flag)
@@ -225,20 +233,13 @@ dowidth(Type *t)
 			uint64 cap;
 
 			dowidth(t->type);
-			if(t->type->width == 0)
-				fatal("no width for type %T", t->type);
-			if(tptr == TPTR32)
-				cap = ((uint32)-1) / t->type->width;
-			else
-				cap = ((uint64)-1) / t->type->width;
-			if(t->bound > cap)
-				yyerror("type %lT larger than address space", t);
+			if(t->type->width != 0) {
+				cap = (MAXWIDTH-1) / t->type->width;
+				if(t->bound > cap)
+					yyerror("type %lT larger than address space", t);
+			}
 			w = t->bound * t->type->width;
 			t->align = t->type->align;
-			if(w == 0) {
-				w = 1;
-				t->align = 1;
-			}
 		}
 		else if(t->bound == -1) {
 			w = sizeof_Array;
@@ -254,11 +255,7 @@ dowidth(Type *t)
 	case TSTRUCT:
 		if(t->funarg)
 			fatal("dowidth fn struct %T", t);
-		w = widstruct(t, 0, 1);
-		if(w == 0) {
-			w = 1;
-			t->align = 1;
-		}
+		w = widstruct(t, t, 0, 1);
 		break;
 
 	case TFUNC:
@@ -276,9 +273,9 @@ dowidth(Type *t)
 		// function is 3 cated structures;
 		// compute their widths as side-effect.
 		t1 = t->type;
-		w = widstruct(*getthis(t1), 0, 0);
-		w = widstruct(*getinarg(t1), w, widthptr);
-		w = widstruct(*getoutarg(t1), w, widthptr);
+		w = widstruct(t->type, *getthis(t1), 0, 0);
+		w = widstruct(t->type, *getinarg(t1), w, widthptr);
+		w = widstruct(t->type, *getoutarg(t1), w, widthptr);
 		t1->argwid = w;
 		if(w%widthptr)
 			warn("bad type %T %d\n", t1, w);
@@ -286,9 +283,6 @@ dowidth(Type *t)
 		break;
 	}
 
-	// catch all for error cases; avoid divide by zero later
-	if(w == 0)
-		w = 1;
 	t->width = w;
 	if(t->align == 0) {
 		if(w > 8 || (w&(w-1)) != 0)
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
index 1f2a776..7188ac4 100644
--- a/src/cmd/gc/bits.c
+++ b/src/cmd/gc/bits.c
@@ -150,8 +150,11 @@ Qconv(Fmt *fp)
 			fmtprint(fp, " ");
 		if(var[i].sym == S)
 			fmtprint(fp, "$%lld", var[i].offset);
-		else
+		else {
 			fmtprint(fp, var[i].sym->name);
+			if(var[i].offset != 0)
+				fmtprint(fp, "%+d", var[i].offset);
+		}
 		bits.b[i/32] &= ~(1L << (i%32));
 	}
 	return 0;
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 95098c8..6419873 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -76,7 +76,7 @@ char *runtimeimport =
 	"func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
 	"func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n"
 	"func \"\".newselect (size int) *uint8\n"
-	"func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n"
+	"func \"\".selectsend (sel *uint8, hchan chan<- any, elem *any) bool\n"
 	"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
 	"func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
 	"func \"\".selectdefault (sel *uint8) bool\n"
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 906dadb..1261eef 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -84,6 +84,11 @@ typecheckclosure(Node *func, int top)
 	oldfn = curfn;
 	typecheck(&func->ntype, Etype);
 	func->type = func->ntype->type;
+	if(curfn == nil) {
+		xtop = list(xtop, func);
+		return;
+	}
+
 	if(func->type != T) {
 		curfn = func;
 		typechecklist(func->nbody, Etop);
@@ -116,12 +121,11 @@ typecheckclosure(Node *func, int top)
 	}
 }
 
-Node*
-walkclosure(Node *func, NodeList **init)
+static Node*
+makeclosure(Node *func, NodeList **init, int nowrap)
 {
-	int narg;
-	Node *xtype, *v, *addr, *xfunc, *call, *clos;
-	NodeList *l, *in;
+	Node *xtype, *v, *addr, *xfunc;
+	NodeList *l;
 	static int closgen;
 	char *p;
 
@@ -133,7 +137,6 @@ walkclosure(Node *func, NodeList **init)
 
 	// each closure variable has a corresponding
 	// address parameter.
-	narg = 0;
 	for(l=func->cvars; l; l=l->next) {
 		v = l->n;
 		if(v->op == 0)
@@ -146,7 +149,6 @@ walkclosure(Node *func, NodeList **init)
 		addr->class = PPARAM;
 		addr->addable = 1;
 		addr->ullman = 1;
-		narg++;
 
 		v->heapaddr = addr;
 
@@ -154,7 +156,8 @@ walkclosure(Node *func, NodeList **init)
 	}
 
 	// then a dummy arg where the closure's caller pc sits
-	xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	if (!nowrap)
+		xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
 
 	// then the function arguments
 	xtype->list = concat(xtype->list, func->list);
@@ -176,15 +179,36 @@ walkclosure(Node *func, NodeList **init)
 	typecheck(&xfunc, Etop);
 	closures = list(closures, xfunc);
 
+	return xfunc;
+}
+
+Node*
+walkclosure(Node *func, NodeList **init)
+{
+	int narg;
+	Node *xtype, *xfunc, *call, *clos;
+	NodeList *l, *in;
+
+	/*
+	 * wrap body in external function
+	 * with extra closure parameters.
+	 */
+
+	// create the function
+	xfunc = makeclosure(func, init, 0);
+	xtype = xfunc->nname->ntype;
+
 	// prepare call of sys.closure that turns external func into func literal value.
 	clos = syslook("closure", 1);
 	clos->type = T;
 	clos->ntype = nod(OTFUNC, N, N);
 	in = list1(nod(ODCLFIELD, N, typenod(types[TINT])));	// siz
 	in = list(in, nod(ODCLFIELD, N, xtype));
+	narg = 0;
 	for(l=func->cvars; l; l=l->next) {
 		if(l->n->op == 0)
 			continue;
+		narg++;
 		in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
 	}
 	clos->ntype->list = in;
@@ -211,33 +235,18 @@ walkclosure(Node *func, NodeList **init)
 void
 walkcallclosure(Node *n, NodeList **init)
 {
-	Node *z;
-	NodeList *ll, *cargs;
-
-	walkexpr(&n->left, init);
-	cargs =	n->left    // FUNC runtime.closure
-		->list     // arguments
-		->next     // skip first
-		->next;    // skip second
-
-	n->left = n->left  // FUNC runtime.closure
-		->list     // arguments
-		->next     // skip first
-		->n        // AS (to indreg) 
-		->right;   // argument  == the generated function 
-
-	// New arg list for n. First the closure-args, stolen from
-	// runtime.closure's 3rd and following,
-	ll = nil;
-	for (; cargs; cargs = cargs->next)
-		ll = list(ll, cargs->n->right);  // cargs->n is the OAS(INDREG, arg)
-
-	// then an extra zero, to fill the dummy return pointer slot,
-	z = nod(OXXX, N, N);
-	nodconst(z, types[TUINTPTR], 0);
-	z->typecheck = 1;
-	ll = list(ll, z);
-
-	// and finally the original parameter list.
-	n->list = concat(ll, n->list);
+	if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
+		dump("walkcallclosure", n);
+		fatal("abuse of walkcallclosure");
+	}
+
+	// New arg list for n. First the closure-args
+	// and then the original parameter list.
+	n->list = concat(n->left->enter, n->list);
+	n->left = makeclosure(n->left, init, 1)->nname;
+	dowidth(n->left->type);
+	n->type = getoutargx(n->left->type);
+	// for a single valued function, pull the field type out of the struct
+	if (n->type && n->type->type && !n->type->type->down)
+		n->type = n->type->type->type;
 }
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 8fe9072..36a64cb 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -947,8 +947,24 @@ defaultlit(Node **np, Type *t)
 			dump("defaultlit", n);
 			fatal("defaultlit");
 		}
-		defaultlit(&n->left, t);
-		defaultlit(&n->right, t);
+		// n is ideal, so left and right must both be ideal.
+		// n has not been computed as a constant value,
+		// so either left or right must not be constant.
+		// The only 'ideal' non-constant expressions are shifts.  Ugh.
+		// If one of these is a shift and the other is not, use that type.
+		// When compiling x := 1<<i + 3.14, this means we try to push
+		// the float64 down into the 1<<i, producing the correct error
+		// (cannot shift float64).
+		if(t == T && (n->right->op == OLSH || n->right->op == ORSH)) {
+			defaultlit(&n->left, T);
+			defaultlit(&n->right, n->left->type);
+		} else if(t == T && (n->left->op == OLSH || n->left->op == ORSH)) {
+			defaultlit(&n->right, T);
+			defaultlit(&n->left, n->right->type);
+		} else {
+			defaultlit(&n->left, t);
+			defaultlit(&n->right, t);
+		}
 		if(n->type == idealbool || n->type == idealstring)
 			n->type = types[n->type->etype];
 		else
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 7290f9d..5bfeeb9 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -457,17 +457,19 @@ colasname(Node *n)
 void
 colasdefn(NodeList *left, Node *defn)
 {
-	int nnew;
+	int nnew, nerr;
 	NodeList *l;
 	Node *n;
 
 	nnew = 0;
+	nerr = 0;
 	for(l=left; l; l=l->next) {
 		n = l->n;
 		if(isblank(n))
 			continue;
 		if(!colasname(n)) {
 			yyerror("non-name %#N on left side of :=", n);
+			nerr++;
 			continue;
 		}
 		if(n->sym->block == block)
@@ -480,7 +482,7 @@ colasdefn(NodeList *left, Node *defn)
 		defn->ninit = list(defn->ninit, nod(ODCL, n, N));
 		l->n = n;
 	}
-	if(nnew == 0)
+	if(nnew == 0 && nerr == 0)
 		yyerror("no new variables on left side of :=");
 }
 
@@ -744,10 +746,8 @@ stotype(NodeList *l, int et, Type **t, int funarg)
 			} else {
 				typecheck(&n->right, Etype);
 				n->type = n->right->type;
-				if(n->type == T) {
-					*t0 = T;
-					return t0;
-				}
+				if(n->type == T)
+					continue;
 				if(left != N)
 					left->type = n->type;
 				n->right = N;
@@ -1077,7 +1077,10 @@ methodsym(Sym *nsym, Type *t0, int iface)
 		if(t0->width < types[tptr]->width)
 			suffix = "·i";
 	}
-	p = smprint("%#hT·%s%s", t0, nsym->name, suffix);
+	if(t0->sym == S && isptr[t0->etype])
+		p = smprint("(%#hT).%s%s", t0, nsym->name, suffix);
+	else
+		p = smprint("%#hT.%s%s", t0, nsym->name, suffix);
 	s = pkglookup(p, s->pkg);
 	free(p);
 	return s;
@@ -1104,14 +1107,17 @@ methodname1(Node *n, Node *t)
 	char *star;
 	char *p;
 
-	star = "";
+	star = nil;
 	if(t->op == OIND) {
 		star = "*";
 		t = t->left;
 	}
 	if(t->sym == S || isblank(n))
 		return newname(n->sym);
-	p = smprint("%s%S·%S", star, t->sym, n->sym);
+	if(star)
+		p = smprint("(%s%S).%S", star, t->sym, n->sym);
+	else
+		p = smprint("%S.%S", t->sym, n->sym);
 	n = newname(pkglookup(p, t->sym->pkg));
 	free(p);
 	return n;
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 8ca086e..4491272 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -43,9 +43,10 @@ enum
 	AMEMWORD,
 
 	BADWIDTH	= -1000000000,
-	MAXWIDTH	= 1<<30
 };
 
+extern vlong	MAXWIDTH;
+
 /*
  * note this is the representation
  * of the compilers string literals,
@@ -392,6 +393,7 @@ enum
 	ONOT, OCOM, OPLUS, OMINUS,
 	OOROR,
 	OPANIC, OPRINT, OPRINTN,
+	OPAREN,
 	OSEND,
 	OSLICE, OSLICEARR, OSLICESTR,
 	ORECOVER,
@@ -531,6 +533,7 @@ enum
 	Eindir = 1<<8,		// indirecting through expression
 	Eaddr = 1<<9,		// taking address of expression
 	Eproc = 1<<10,		// inside a go statement
+	Ecomplit = 1<<11,	// type in composite literal
 };
 
 #define	BITS	5
@@ -697,6 +700,7 @@ EXTERN	int	nsyntaxerrors;
 EXTERN	int	safemode;
 EXTERN	char	namebuf[NSYMB];
 EXTERN	char	lexbuf[NSYMB];
+EXTERN	char	litbuf[NSYMB];
 EXTERN	char	debug[256];
 EXTERN	Sym*	hash[NHASH];
 EXTERN	Sym*	importmyname;	// my name for package
@@ -1106,7 +1110,6 @@ int	isinter(Type *t);
 int	isnil(Node *n);
 int	isnilinter(Type *t);
 int	isptrto(Type *t, int et);
-int	isselect(Node *n);
 int	isslice(Type *t);
 int	istype(Type *t, int et);
 void	linehist(char *file, int32 off, int relative);
@@ -1137,6 +1140,7 @@ Sym*	restrictlookup(char *name, Pkg *pkg);
 Node*	safeexpr(Node *n, NodeList **init);
 void	saveerrors(void);
 Node*	cheapexpr(Node *n, NodeList **init);
+Node*	localexpr(Node *n, Type *t, NodeList **init);
 int32	setlineno(Node *n);
 void	setmaxarg(Type *t);
 Type*	shallow(Type *t);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 01a4e82..4c7fe60 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -685,6 +685,7 @@ select_stmt:
 	LBODY caseblock_list '}'
 	{
 		$$ = nod(OSELECT, N, N);
+		$$->lineno = typesw->lineno;
 		$$->list = $4;
 		typesw = typesw->left;
 	}
@@ -915,6 +916,18 @@ pexpr:
 |	'(' expr_or_type ')'
 	{
 		$$ = $2;
+		
+		// Need to know on lhs of := whether there are ( ).
+		// Don't bother with the OPAREN in other cases:
+		// it's just a waste of memory and time.
+		switch($$->op) {
+		case ONAME:
+		case ONONAME:
+		case OPACK:
+		case OTYPE:
+		case OLITERAL:
+			$$ = nod(OPAREN, $$, N);
+		}
 	}
 
 expr_or_type:
@@ -1236,7 +1249,10 @@ fnliteral:
 		$$ = closurebody($3);
 		fixlbrace($2);
 	}
-
+|	fnlitdcl error
+	{
+		$$ = closurebody(nil);
+	}
 
 /*
  * lists of things
@@ -1462,6 +1478,9 @@ non_dcl_stmt:
 	}
 |	if_stmt LELSE stmt
 	{
+		if($3->op != OIF && $3->op != OBLOCK)
+			yyerror("missing { } after else");
+
 		popdcl();
 		$$ = $1;
 		$$->nelse = list1($3);
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 5c64237..29b6d27 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -218,6 +218,7 @@ main(int argc, char *argv[])
 		curio.nlsemi = 0;
 
 		block = 1;
+		iota = -1000000;
 
 		yyparse();
 		if(nsyntaxerrors != 0)
@@ -253,15 +254,20 @@ main(int argc, char *argv[])
 	resumetypecopy();
 	resumecheckwidth();
 
-	for(l=xtop; l; l=l->next)
-		if(l->n->op == ODCLFUNC) {
+	for(l=xtop; l; l=l->next) {
+		if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
 			curfn = l->n;
 			saveerrors();
 			typechecklist(l->n->nbody, Etop);
 			if(nerrors != 0)
 				l->n->nbody = nil;  // type errors; do not compile
 		}
+	}
+
 	curfn = nil;
+	
+	if(nsavederrors+nerrors)
+		errorexit();
 
 	for(l=xtop; l; l=l->next)
 		if(l->n->op == ODCLFUNC)
@@ -273,8 +279,9 @@ main(int argc, char *argv[])
 	while(closures) {
 		l = closures;
 		closures = nil;
-		for(; l; l=l->next)
+		for(; l; l=l->next) {
 			funccompile(l->n, 1);
+		}
 	}
 
 	for(l=externdcl; l; l=l->next)
@@ -728,6 +735,7 @@ l0:
 		yylval.val.u.sval = (Strlit*)cp;
 		yylval.val.ctype = CTSTR;
 		DBG("lex: string literal\n");
+		strcpy(litbuf, "string literal");
 		return LLITERAL;
 
 	case '\'':
@@ -744,6 +752,7 @@ l0:
 		mpmovecfix(yylval.val.u.xval, v);
 		yylval.val.ctype = CTINT;
 		DBG("lex: codepoint literal\n");
+		strcpy(litbuf, "string literal");
 		return LLITERAL;
 
 	case '/':
@@ -1133,6 +1142,8 @@ ncu:
 	}
 	yylval.val.ctype = CTINT;
 	DBG("lex: integer literal\n");
+	strcpy(litbuf, "literal ");
+	strcat(litbuf, lexbuf);
 	return LLITERAL;
 
 casedot:
@@ -1205,6 +1216,8 @@ casei:
 	}
 	yylval.val.ctype = CTCPLX;
 	DBG("lex: imaginary literal\n");
+	strcpy(litbuf, "literal ");
+	strcat(litbuf, lexbuf);
 	return LLITERAL;
 
 caseout:
@@ -1219,6 +1232,8 @@ caseout:
 	}
 	yylval.val.ctype = CTFLT;
 	DBG("lex: floating literal\n");
+	strcpy(litbuf, "literal ");
+	strcat(litbuf, lexbuf);
 	return LLITERAL;
 }
 
@@ -1859,6 +1874,12 @@ yytinit(void)
 	for(i=0; yytname[i] != nil; i++) {
 		s = yytname[i];
 		
+		if(strcmp(s, "LLITERAL") == 0) {
+			strcpy(litbuf, "literal");
+			yytname[i] = litbuf;
+			goto loop;
+		}
+		
 		// apply yytfix if possible
 		for(j=0; j<nelem(yytfix); j++) {
 			if(strcmp(s, yytfix[j].have) == 0) {
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
index aa28e29..baa87fe 100644
--- a/src/cmd/gc/mkbuiltin1.c
+++ b/src/cmd/gc/mkbuiltin1.c
@@ -4,11 +4,9 @@
 
 // Compile .go file, import data from .6 file, and generate C string version.
 
+#include <u.h>
+#include <libc.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
 
 void esc(char*);
 
@@ -21,8 +19,7 @@ main(int argc, char **argv)
 
 	if(argc != 2) {
 		fprintf(stderr, "usage: mkbuiltin1 sys\n");
-		fprintf(stderr, "in file $1.6 s/PACKAGE/$1/\n");
-		exit(1);
+		sysfatal("in file $1.6 s/PACKAGE/$1/\n");
 	}
 
 	name = argv[1];
@@ -30,16 +27,14 @@ main(int argc, char **argv)
 
 	snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
 	if((fin = fopen(buf, "r")) == NULL) {
-		fprintf(stderr, "open %s: %s\n", buf, strerror(errno));
-		exit(1);
+		sysfatal("open %s: %r\n", buf);
 	}
 
 	// look for $$ that introduces imports
 	while(fgets(buf, sizeof buf, fin) != NULL)
 		if(strstr(buf, "$$"))
 			goto begin;
-	fprintf(stderr, "did not find beginning of imports\n");
-	exit(1);
+	sysfatal("did not find beginning of imports\n");
 
 begin:
 	printf("char *%simport =\n", name);
@@ -71,8 +66,7 @@ begin:
 		esc(p);
 		printf("\\n\"\n", p);
 	}
-	fprintf(stderr, "did not find end of imports\n");
-	exit(1);
+	sysfatal("did not find end of imports\n");
 
 end:
 	printf("\t\"$$\\n\";\n");
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 552e405..abe8ea8 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -149,7 +149,7 @@ compactframe(Prog* ptxt)
 {
 	NodeList *ll;
 	Node* n;
-	uint32 w;
+	vlong w;
 
 	if (stksize == 0)
 		return;
@@ -189,7 +189,7 @@ compactframe(Prog* ptxt)
 			continue;
 
 		w = n->type->width;
-		if((w >= MAXWIDTH) || (w < 1))
+		if(w >= MAXWIDTH || w < 0)
 			fatal("bad width");
 		stksize += w;
 		stksize = rnd(stksize, n->type->align);
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index e88e0f8..5913e84 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -78,6 +78,7 @@ exprfmt(Fmt *f, Node *n, int prec)
 	case OTPAREN:
 	case OINDEX:
 	case OINDEXMAP:
+	case OPAREN:
 		nprec = 7;
 		break;
 
@@ -134,6 +135,10 @@ exprfmt(Fmt *f, Node *n, int prec)
 		fmtprint(f, "(node %O)", n->op);
 		break;
 
+	case OPAREN:
+		fmtprint(f, "(%#N)", n->left);
+		break;
+
 	case OREGISTER:
 		fmtprint(f, "%R", n->val.u.reg);
 		break;
@@ -404,6 +409,7 @@ exprfmt(Fmt *f, Node *n, int prec)
 	case OCONVIFACE:
 	case OCONVNOP:
 	case OARRAYBYTESTR:
+	case OSTRARRAYBYTE:
 	case ORUNESTR:
 		if(n->type == T || n->type->sym == S)
 			fmtprint(f, "(%T)(", n->type);
@@ -445,8 +451,28 @@ exprfmt(Fmt *f, Node *n, int prec)
 		break;
 
 	case OMAKEMAP:
+	case OMAKECHAN:
 		fmtprint(f, "make(%#T)", n->type);
 		break;
+
+	// Some statements
+
+	case ODCL:
+		fmtprint(f, "var %S %#T", n->left->sym, n->left->type);
+		break;
+
+	case ORETURN:
+		fmtprint(f, "return ");
+		exprlistfmt(f, n->list);
+		break;
+
+	case OPROC:
+		fmtprint(f, "go %#N", n->left);
+		break;
+
+	case ODEFER:
+		fmtprint(f, "defer %#N", n->left);
+		break;
 	}
 
 	if(prec > nprec)
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index dfb2b8e..fb33e4e 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -98,11 +98,13 @@ walkrange(Node *n)
 	Node *fn, *tmp;
 	NodeList *body, *init;
 	Type *th, *t;
+	int lno;
 
 	t = n->type;
 	init = nil;
 
 	a = n->right;
+	lno = setlineno(a);
 	if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
 		a = nod(OCONV, n->right, N);
 		a->type = types[TSTRING];
@@ -248,5 +250,7 @@ walkrange(Node *n)
 	typechecklist(body, Etop);
 	n->nbody = concat(body, n->nbody);
 	walkstmt(&n);
+	
+	lineno = lno;
 }
 
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index e13c95d..7254f87 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -103,7 +103,7 @@ func selectnbrecv(elem *any, hchan <-chan any) bool
 func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
 
 func newselect(size int) (sel *byte)
-func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool)
+func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
 func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
 func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
 func selectdefault(sel *byte) (selected bool)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 91d4ebf..8395dda 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -108,6 +108,7 @@ walkselect(Node *sel)
 	// optimization: one-case select: single op.
 	if(i == 1) {
 		cas = sel->list->n;
+		setlineno(cas);
 		l = cas->ninit;
 		if(cas->left != N) {  // not default:
 			n = cas->left;
@@ -165,6 +166,7 @@ walkselect(Node *sel)
 	// this rewrite is used by both the general code and the next optimization.
 	for(l=sel->list; l; l=l->next) {
 		cas = l->n;
+		setlineno(cas);
 		n = cas->left;
 		if(n == N)
 			continue;
@@ -238,6 +240,7 @@ walkselect(Node *sel)
 		}
 		
 		n = cas->left;
+		setlineno(n);
 		r = nod(OIF, N, N);
 		r->ninit = cas->ninit;
 		switch(n->op) {
@@ -283,6 +286,7 @@ walkselect(Node *sel)
 	sel->ninit = nil;
 
 	// generate sel-struct
+	setlineno(sel);
 	var = nod(OXXX, N, N);
 	tempname(var, ptrto(types[TUINT8]));
 	r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
@@ -292,6 +296,7 @@ walkselect(Node *sel)
 	// register cases
 	for(l=sel->list; l; l=l->next) {
 		cas = l->n;
+		setlineno(cas);
 		n = cas->left;
 		r = nod(OIF, N, N);
 		r->nbody = cas->ninit;
@@ -309,7 +314,12 @@ walkselect(Node *sel)
 				fatal("select %O", n->op);
 	
 			case OSEND:
-				// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
+				n->left = safeexpr(n->left, &r->ninit);
+				n->right = localexpr(n->right, n->left->type->type, &r->ninit);
+				n->right = nod(OADDR, n->right, N);
+				n->right->etype = 1;  // pointer does not escape
+				typecheck(&n->right, Erv);
 				r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
 					&init, var, n->left, n->right);
 				break;
@@ -333,6 +343,7 @@ walkselect(Node *sel)
 	}
 
 	// run the select
+	setlineno(sel);
 	init = list(init, mkcall("selectgo", T, nil, var));
 	sel->nbody = init;
 
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index eb7ef31..917e2ae 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -686,7 +686,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
 			if(ctxt == 0) {
 				// lay out static data
 				vstat = staticname(t, ctxt);
-				structlit(1, 1, n, vstat, init);
+				structlit(ctxt, 1, n, vstat, init);
 
 				// copy static to var
 				a = nod(OAS, var, vstat);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 40b0c4f..96675be 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -1049,21 +1049,25 @@ Jconv(Fmt *fp)
 {
 	Node *n;
 	char *s;
+	int c;
 
 	n = va_arg(fp->args, Node*);
-	if(n->ullman != 0)
+
+	c = fp->flags&FmtShort;
+
+	if(!c && n->ullman != 0)
 		fmtprint(fp, " u(%d)", n->ullman);
 
-	if(n->addable != 0)
+	if(!c && n->addable != 0)
 		fmtprint(fp, " a(%d)", n->addable);
 
-	if(n->vargen != 0)
+	if(!c && n->vargen != 0)
 		fmtprint(fp, " g(%d)", n->vargen);
 
 	if(n->lineno != 0)
 		fmtprint(fp, " l(%d)", n->lineno);
 
-	if(n->xoffset != BADWIDTH)
+	if(!c && n->xoffset != BADWIDTH)
 		fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
 
 	if(n->class != 0) {
@@ -1081,10 +1085,13 @@ Jconv(Fmt *fp)
 	if(n->funcdepth != 0)
 		fmtprint(fp, " f(%d)", n->funcdepth);
 
-	if(n->typecheck != 0)
+	if(n->noescape != 0)
+		fmtprint(fp, " ne(%d)", n->noescape);
+
+	if(!c && n->typecheck != 0)
 		fmtprint(fp, " tc(%d)", n->typecheck);
 
-	if(n->dodata != 0)
+	if(!c && n->dodata != 0)
 		fmtprint(fp, " dd(%d)", n->dodata);
 
 	if(n->isddd != 0)
@@ -1093,10 +1100,10 @@ Jconv(Fmt *fp)
 	if(n->implicit != 0)
 		fmtprint(fp, " implicit(%d)", n->implicit);
 
-	if(n->pun != 0)
+	if(!c && n->pun != 0)
 		fmtprint(fp, " pun(%d)", n->pun);
 
-	if(n->used != 0)
+	if(!c && n->used != 0)
 		fmtprint(fp, " used(%d)", n->used);
 	return 0;
 }
@@ -1494,17 +1501,25 @@ Nconv(Fmt *fp)
 
 	switch(n->op) {
 	default:
-		fmtprint(fp, "%O%J", n->op, n);
+		if (fp->flags & FmtShort)
+			fmtprint(fp, "%O%hJ", n->op, n);
+		else
+			fmtprint(fp, "%O%J", n->op, n);
 		break;
 
 	case ONAME:
 	case ONONAME:
 		if(n->sym == S) {
-			fmtprint(fp, "%O%J", n->op, n);
+			if (fp->flags & FmtShort)
+				fmtprint(fp, "%O%hJ", n->op, n);
+			else
+				fmtprint(fp, "%O%J", n->op, n);
 			break;
 		}
-		fmtprint(fp, "%O-%S G%d%J", n->op,
-			n->sym, n->vargen, n);
+		if (fp->flags & FmtShort)
+			fmtprint(fp, "%O-%S%hJ", n->op, n->sym, n);
+		else
+			fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
 		goto ptyp;
 
 	case OREGISTER:
@@ -1705,29 +1720,6 @@ isblank(Node *n)
 }
 
 int
-isselect(Node *n)
-{
-	Sym *s;
-
-	if(n == N)
-		return 0;
-	n = n->left;
-	s = pkglookup("selectsend", runtimepkg);
-	if(s == n->sym)
-		return 1;
-	s = pkglookup("selectrecv", runtimepkg);
-	if(s == n->sym)
-		return 1;
-	s = pkglookup("selectrecv2", runtimepkg);
-	if(s == n->sym)
-		return 1;
-	s = pkglookup("selectdefault", runtimepkg);
-	if(s == n->sym)
-		return 1;
-	return 0;
-}
-
-int
 isinter(Type *t)
 {
 	return t != T && t->etype == TINTER;
@@ -2735,6 +2727,20 @@ safeexpr(Node *n, NodeList **init)
 	return cheapexpr(n, init);
 }
 
+static Node*
+copyexpr(Node *n, Type *t, NodeList **init)
+{
+	Node *a, *l;
+	
+	l = nod(OXXX, N, N);
+	tempname(l, t);
+	a = nod(OAS, l, n);
+	typecheck(&a, Etop);
+	walkexpr(&a, init);
+	*init = list(*init, a);
+	return l;
+}
+
 /*
  * return side-effect free and cheap n, appending side effects to init.
  * result may not be assignable.
@@ -2742,21 +2748,27 @@ safeexpr(Node *n, NodeList **init)
 Node*
 cheapexpr(Node *n, NodeList **init)
 {
-	Node *a, *l;
-
 	switch(n->op) {
 	case ONAME:
 	case OLITERAL:
 		return n;
 	}
 
-	l = nod(OXXX, N, N);
-	tempname(l, n->type);
-	a = nod(OAS, l, n);
-	typecheck(&a, Etop);
-	walkexpr(&a, init);
-	*init = list(*init, a);
-	return l;
+	return copyexpr(n, n->type, init);
+}
+
+/*
+ * return n in a local variable of type t if it is not already.
+ */
+Node*
+localexpr(Node *n, Type *t, NodeList **init)
+{
+	if(n->op == ONAME &&
+		(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
+		convertop(n->type, t, nil) == OCONVNOP)
+		return n;
+	
+	return copyexpr(n, t, init);
 }
 
 void
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index dfe0f30..78cdb5b 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -124,9 +124,16 @@ typecheck(Node **np, int top)
 	n = *np;
 	if(n == N)
 		return N;
+	
+	lno = setlineno(n);
+
+	// Skip over parens.
+	while(n->op == OPAREN)
+		n = n->left;
 
 	// Resolve definition of name and value of iota lazily.
 	n = resolve(n);
+
 	*np = n;
 
 	// Skip typecheck if already done.
@@ -139,17 +146,18 @@ typecheck(Node **np, int top)
 		case OPACK:
 			break;
 		default:
+			lineno = lno;
 			return n;
 		}
 	}
 
 	if(n->typecheck == 2) {
 		yyerror("typechecking loop");
+		lineno = lno;
 		return n;
 	}
 	n->typecheck = 2;
 
-	lno = setlineno(n);
 	if(n->sym) {
 		if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
 			yyerror("use of builtin %S not in function call", n->sym);
@@ -239,6 +247,8 @@ reswitch:
 			t->bound = -1;	// slice
 		} else if(l->op == ODDD) {
 			t->bound = -100;	// to be filled in
+			if(!(top&Ecomplit))
+				yyerror("use of [...] array outside of array literal");
 		} else {
 			l = typecheck(&n->left, Erv);
 			switch(consttype(l)) {
@@ -1342,11 +1352,6 @@ ret:
 		case TNIL:
 		case TBLANK:
 			break;
-		case TARRAY:
-			if(t->bound == -100) {
-				yyerror("use of [...] array outside of array literal");
-				t->bound = 1;
-			}
 		default:
 			checkwidth(t);
 		}
@@ -1971,7 +1976,7 @@ typecheckcomplit(Node **np)
 	}
 
 	setlineno(n->right);
-	l = typecheck(&n->right /* sic */, Etype);
+	l = typecheck(&n->right /* sic */, Etype|Ecomplit);
 	if((t = l->type) == T)
 		goto error;
 	nerr = nerrors;
@@ -2039,7 +2044,7 @@ typecheckcomplit(Node **np)
 				l->right->right = typenod(pushtype);
 			typecheck(&l->right, Erv);
 			defaultlit(&l->right, t->type);
-			l->right = assignconv(l->right, t->type, "array index");
+			l->right = assignconv(l->right, t->type, "array element");
 		}
 		if(t->bound == -100)
 			t->bound = len;
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 4d06179..0383e5a 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -494,24 +494,13 @@ walkexpr(Node **np, NodeList **init)
 		if(n->left->op == OCLOSURE) {
 			walkcallclosure(n, init);
 			t = n->left->type;
-		} else
-			walkexpr(&n->left, init);
+		}
 
+		walkexpr(&n->left, init);
 		walkexprlist(n->list, init);
 
 		ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
 		n->list = reorder1(ll);
-		if(isselect(n)) {
-			// special prob with selectsend and selectrecv:
-			// if chan is nil, they don't know big the channel
-			// element is and therefore don't know how to find
-			// the output bool, so we clear it before the call.
-			Node *b;
-			b = nodbool(0);
-			typecheck(&b, Erv);
-			lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init);
-			n->list = concat(n->list, lr);
-		}
 		goto ret;
 
 	case OCALLMETH:
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
index 06a18be..f40d717 100644
--- a/src/cmd/godoc/Makefile
+++ b/src/cmd/godoc/Makefile
@@ -11,6 +11,7 @@ GOFILES=\
 	filesystem.go\
 	format.go\
 	godoc.go\
+	httpzip.go\
 	index.go\
 	main.go\
 	mapping.go\
@@ -18,5 +19,6 @@ GOFILES=\
 	snippet.go\
 	spec.go\
 	utils.go\
+	zip.go\
 
 include ../../Make.cmd
diff --git a/src/cmd/godoc/appconfig.go b/src/cmd/godoc/appconfig.go
new file mode 100644
index 0000000..9cbe7a4
--- /dev/null
+++ b/src/cmd/godoc/appconfig.go
@@ -0,0 +1,19 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains configuration information used by
+// godoc when running on app engine. Adjust as needed
+// (typically when the .zip file changes).
+
+package main
+
+const (
+	// zipFilename is the name of the .zip file
+	// containing the file system served by godoc.
+	zipFilename = "go.zip"
+
+	// zipGoroot is the path of the goroot directory
+	// in the .zip file.
+	zipGoroot = "/home/username/go"
+)
diff --git a/src/cmd/godoc/appinit.go b/src/cmd/godoc/appinit.go
new file mode 100644
index 0000000..9b89872
--- /dev/null
+++ b/src/cmd/godoc/appinit.go
@@ -0,0 +1,86 @@
+// 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.
+
+// To run godoc under app engine, substitute main.go with
+// this file (appinit.go), provide a .zip file containing
+// the file system to serve, and adjust the configuration
+// parameters in appconfig.go accordingly.
+//
+// The current app engine SDK may be based on an older Go
+// release version. To correct for version skew, copy newer
+// packages into the alt directory (e.g. alt/strings) and
+// adjust the imports in the godoc source files (e.g. from
+// `import "strings"` to `import "alt/strings"`). Both old
+// and new packages may be used simultaneously as long as
+// there is no package global state that needs to be shared.
+//
+// The directory structure should look as follows:
+//
+// godoc			// directory containing the app engine app
+//      alt			// alternative packages directory to
+//				//	correct for version skew
+//		strings		// never version of the strings package
+//		...		//
+//	app.yaml		// app engine control file
+//	go.zip			// zip file containing the file system to serve
+//	godoc			// contains godoc sources
+//		appinit.go	// this file instead of godoc/main.go
+//		appconfig.go	// godoc for app engine configuration
+//		...		//
+//
+// To run app the engine emulator locally:
+//
+//	dev_appserver.py -a 0 godoc
+//
+// godoc is the top-level "goroot" directory.
+// The godoc home page is served at: <hostname>:8080 and localhost:8080.
+
+package main
+
+import (
+	"alt/archive/zip"
+	"http"
+	"log"
+	"os"
+)
+
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
+	contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
+	w.WriteHeader(http.StatusNotFound)
+	servePage(w, "File "+relpath, "", "", contents)
+}
+
+func init() {
+	log.Println("initializing godoc ...")
+	*goroot = path.Join("/", zipGoroot) // fsHttp paths are relative to '/'
+
+	// read .zip file and set up file systems
+	const zipfile = zipFilename
+	rc, err := zip.OpenReader(zipfile)
+	if err != nil {
+		log.Fatalf("%s: %s\n", zipfile, err)
+	}
+	fs = NewZipFS(rc)
+	fsHttp = NewHttpZipFS(rc, *goroot)
+
+	// initialize http handlers
+	initHandlers()
+	readTemplates()
+	registerPublicHandlers(http.DefaultServeMux)
+
+	// initialize default directory tree with corresponding timestamp.
+	initFSTree()
+
+	// initialize directory trees for user-defined file systems (-path flag).
+	initDirTrees()
+
+	// create search index
+	// TODO(gri) Disabled for now as it takes too long. Find a solution for this.
+	/*
+		*indexEnabled = true
+		go indexer()
+	*/
+
+	log.Println("godoc initialization complete")
+}
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 50043e2..e2643e4 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -28,7 +28,6 @@ import (
 	"xml"
 )
 
-
 // Handler for /doc/codewalk/ and below.
 func codewalk(w http.ResponseWriter, r *http.Request) {
 	relpath := r.URL.Path[len("/doc/codewalk/"):]
@@ -71,7 +70,6 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
 	servePage(w, "Codewalk: "+cw.Title, "", "", b)
 }
 
-
 // A Codewalk represents a single codewalk read from an XML file.
 type Codewalk struct {
 	Title string `xml:"attr"`
@@ -79,7 +77,6 @@ type Codewalk struct {
 	Step  []*Codestep
 }
 
-
 // A Codestep is a single step in a codewalk.
 type Codestep struct {
 	// Filled in from XML
@@ -97,7 +94,6 @@ type Codestep struct {
 	Data   []byte
 }
 
-
 // String method for printing in template.
 // Formats file address nicely.
 func (st *Codestep) String() string {
@@ -111,7 +107,6 @@ func (st *Codestep) String() string {
 	return s
 }
 
-
 // loadCodewalk reads a codewalk from the named XML file.
 func loadCodewalk(filename string) (*Codewalk, os.Error) {
 	f, err := fs.Open(filename)
@@ -173,7 +168,6 @@ func loadCodewalk(filename string) (*Codewalk, os.Error) {
 	return cw, nil
 }
 
-
 // codewalkDir serves the codewalk directory listing.
 // It scans the directory for subdirectories or files named *.xml
 // and prepares a table.
@@ -207,7 +201,6 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
 	servePage(w, "Codewalks", "", "", b)
 }
 
-
 // codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
 // The filename f has already been retrieved and is passed as an argument.
 // Lo and hi are the numbers of the first and last line to highlight
@@ -256,7 +249,6 @@ func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
 	io.WriteString(w, "</pre>")
 }
 
-
 // addrToByte evaluates the given address starting at offset start in data.
 // It returns the lo and hi byte offset of the matched region within data.
 // See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
@@ -351,7 +343,6 @@ func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err os.Er
 	return lo, hi, nil
 }
 
-
 // addrNumber applies the given dir, n, and charOffset to the address lo, hi.
 // dir is '+' or '-', n is the count, and charOffset is true if the syntax
 // used was #n.  Applying +n (or +#n) means to advance n lines
@@ -437,7 +428,6 @@ func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int,
 	return 0, 0, os.NewError("address out of range")
 }
 
-
 // addrRegexp searches for pattern in the given direction starting at lo, hi.
 // The direction dir is '+' (search forward from hi) or '-' (search backward from lo).
 // Backward searches are unimplemented.
@@ -465,7 +455,6 @@ func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os
 	return m[0], m[1], nil
 }
 
-
 // lineToByte returns the byte index of the first byte of line n.
 // Line numbers begin at 1.
 func lineToByte(data []byte, n int) int {
@@ -483,7 +472,6 @@ func lineToByte(data []byte, n int) int {
 	return len(data)
 }
 
-
 // byteToLine returns the number of the line containing the byte at index i.
 func byteToLine(data []byte, i int) int {
 	l := 1
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
index e98e93a..aa590b3 100644
--- a/src/cmd/godoc/dirtrees.go
+++ b/src/cmd/godoc/dirtrees.go
@@ -17,7 +17,6 @@ import (
 	"unicode"
 )
 
-
 type Directory struct {
 	Depth int
 	Path  string // includes Name
@@ -26,7 +25,6 @@ type Directory struct {
 	Dirs  []*Directory // subdirectories
 }
 
-
 func isGoFile(fi FileInfo) bool {
 	name := fi.Name()
 	return fi.IsRegular() &&
@@ -34,20 +32,17 @@ func isGoFile(fi FileInfo) bool {
 		filepath.Ext(name) == ".go"
 }
 
-
 func isPkgFile(fi FileInfo) bool {
 	return isGoFile(fi) &&
 		!strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
 }
 
-
 func isPkgDir(fi FileInfo) bool {
 	name := fi.Name()
 	return fi.IsDirectory() && len(name) > 0 &&
 		name[0] != '_' && name[0] != '.' // ignore _files and .files
 }
 
-
 func firstSentence(s string) string {
 	i := -1 // index+1 of first terminator (punctuation ending a sentence)
 	j := -1 // index+1 of first terminator followed by white space
@@ -83,13 +78,11 @@ func firstSentence(s string) string {
 	return s[0:j]
 }
 
-
 type treeBuilder struct {
 	pathFilter func(string) bool
 	maxDepth   int
 }
 
-
 func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
 	if b.pathFilter != nil && !b.pathFilter(path) {
 		return nil
@@ -185,7 +178,6 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
 	return &Directory{depth, path, name, synopsis, dirs}
 }
 
-
 // newDirectory creates a new package directory tree with at most maxDepth
 // levels, anchored at root. The result tree is pruned such that it only
 // contains directories that contain package files or that contain
@@ -218,7 +210,6 @@ func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Dire
 	return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
 }
 
-
 func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
 	if dir != nil {
 		if len(dir.Dirs) == 0 {
@@ -233,7 +224,6 @@ func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
 	}
 }
 
-
 func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
 	if dir != nil {
 		if !skipRoot {
@@ -245,7 +235,6 @@ func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
 	}
 }
 
-
 func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
 	c := make(chan *Directory)
 	go func() {
@@ -255,7 +244,6 @@ func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
 	return c
 }
 
-
 func (dir *Directory) lookupLocal(name string) *Directory {
 	for _, d := range dir.Dirs {
 		if d.Name == name {
@@ -265,7 +253,6 @@ func (dir *Directory) lookupLocal(name string) *Directory {
 	return nil
 }
 
-
 // lookup looks for the *Directory for a given path, relative to dir.
 func (dir *Directory) lookup(path string) *Directory {
 	d := strings.Split(dir.Path, string(filepath.Separator))
@@ -284,7 +271,6 @@ func (dir *Directory) lookup(path string) *Directory {
 	return dir
 }
 
-
 // DirEntry describes a directory entry. The Depth and Height values
 // are useful for presenting an entry in an indented fashion.
 //
@@ -296,13 +282,11 @@ type DirEntry struct {
 	Synopsis string
 }
 
-
 type DirList struct {
 	MaxHeight int // directory tree height, > 0
 	List      []DirEntry
 }
 
-
 // listing creates a (linear) directory listing from a directory tree.
 // If skipRoot is set, the root directory itself is excluded from the list.
 //
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index 26d436d..dc98b0e 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -73,6 +73,8 @@ The flags are:
 		filter file containing permitted package directory paths
 	-filter_minutes=0
 		filter file update interval in minutes; update is disabled if <= 0
+	-zip=""
+		zip file providing the file system to serve; disabled if empty
 
 The -path flag accepts a list of colon-separated paths; unrooted paths are relative
 to the current working directory. Each path is considered as an additional root for
@@ -95,10 +97,9 @@ may be provided with the -filter flag; if it exists, only directories
 on those paths are considered. If -filter_minutes is set, the filter_file is
 updated regularly by walking the entire directory tree.
 
-When godoc runs as a web server, it creates a search index from all .go files
-under -goroot (excluding files starting with .). The index is created at startup
-and is automatically updated every time the -sync command terminates with exit
-status 0, indicating that files have changed.
+When godoc runs as a web server and -index is set, a search index is maintained.
+The index is created at startup and is automatically updated every time the
+-sync command terminates with exit status 0, indicating that files have changed.
 
 If the sync exit status is 1, godoc assumes that it succeeded without errors
 but that no files changed; the index is not updated in this case.
@@ -107,5 +108,23 @@ In all other cases, sync is assumed to have failed and godoc backs off running
 sync exponentially (up to 1 day). As soon as sync succeeds again (exit status 0
 or 1), the normal sync rhythm is re-established.
 
+The index contains both identifier and full text search information (searchable
+via regular expressions). The maximum number of full text search results shown
+can be set with the -maxresults flag; if set to 0, no full text results are
+shown, and only an identifier index but no full text search index is created.
+
+By default, godoc serves files from the file system of the underlying OS.
+Instead, a .zip file may be provided via the -zip flag, which contains
+the file system to serve. The file paths stored in the .zip file must use
+slash ('/') as path separator; and they must be unrooted. $GOROOT (or -goroot)
+must be set to the .zip file directory path containing the Go root directory.
+For instance, for a .zip file created by the command:
+
+	zip go.zip $HOME/go
+
+one may run godoc as follows:
+
+	godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
+
 */
 package documentation
diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
index bf68378..a68c085 100644
--- a/src/cmd/godoc/filesystem.go
+++ b/src/cmd/godoc/filesystem.go
@@ -2,26 +2,28 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file defines abstract file system access.
+// This file defines types for abstract file system access and
+// provides an implementation accessing the file system of the
+// underlying OS.
 
 package main
 
 import (
+	"fmt"
 	"io"
 	"io/ioutil"
 	"os"
 )
 
-
 // The FileInfo interface provides access to file information.
 type FileInfo interface {
 	Name() string
 	Size() int64
+	Mtime_ns() int64
 	IsRegular() bool
 	IsDirectory() bool
 }
 
-
 // The FileSystem interface specifies the methods godoc is using
 // to access the file system for which it serves documentation.
 type FileSystem interface {
@@ -32,24 +34,20 @@ type FileSystem interface {
 	ReadFile(path string) ([]byte, os.Error)
 }
 
-
 // ----------------------------------------------------------------------------
 // OS-specific FileSystem implementation
 
 var OS FileSystem = osFS{}
 
-
 // osFI is the OS-specific implementation of FileInfo.
 type osFI struct {
 	*os.FileInfo
 }
 
-
 func (fi osFI) Name() string {
 	return fi.FileInfo.Name
 }
 
-
 func (fi osFI) Size() int64 {
 	if fi.IsDirectory() {
 		return 0
@@ -57,29 +55,40 @@ func (fi osFI) Size() int64 {
 	return fi.FileInfo.Size
 }
 
+func (fi osFI) Mtime_ns() int64 {
+	return fi.FileInfo.Mtime_ns
+}
 
 // osFS is the OS-specific implementation of FileSystem
 type osFS struct{}
 
 func (osFS) Open(path string) (io.ReadCloser, os.Error) {
-	return os.Open(path)
+	f, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	fi, err := f.Stat()
+	if err != nil {
+		return nil, err
+	}
+	if fi.IsDirectory() {
+		return nil, fmt.Errorf("Open: %s is a directory", path)
+	}
+	return f, nil
 }
 
-
 func (osFS) Lstat(path string) (FileInfo, os.Error) {
 	fi, err := os.Lstat(path)
 	return osFI{fi}, err
 }
 
-
 func (osFS) Stat(path string) (FileInfo, os.Error) {
 	fi, err := os.Stat(path)
 	return osFI{fi}, err
 }
 
-
 func (osFS) ReadDir(path string) ([]FileInfo, os.Error) {
-	l0, err := ioutil.ReadDir(path)
+	l0, err := ioutil.ReadDir(path) // l0 is sorted
 	if err != nil {
 		return nil, err
 	}
@@ -90,7 +99,6 @@ func (osFS) ReadDir(path string) ([]FileInfo, os.Error) {
 	return l1, nil
 }
 
-
 func (osFS) ReadFile(path string) ([]byte, os.Error) {
 	return ioutil.ReadFile(path)
 }
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
index 7e64708..78dde41 100644
--- a/src/cmd/godoc/format.go
+++ b/src/cmd/godoc/format.go
@@ -20,7 +20,6 @@ import (
 	"template"
 )
 
-
 // ----------------------------------------------------------------------------
 // Implementation of FormatSelections
 
@@ -34,13 +33,11 @@ import (
 //
 type Selection func() []int
 
-
 // A LinkWriter writes some start or end "tag" to w for the text offset offs.
 // It is called by FormatSelections at the start or end of each link segment.
 //
 type LinkWriter func(w io.Writer, offs int, start bool)
 
-
 // A SegmentWriter formats a text according to selections and writes it to w.
 // The selections parameter is a bit set indicating which selections provided
 // to FormatSelections overlap with the text segment: If the n'th bit is set
@@ -49,7 +46,6 @@ type LinkWriter func(w io.Writer, offs int, start bool)
 //
 type SegmentWriter func(w io.Writer, text []byte, selections int)
 
-
 // FormatSelections takes a text and writes it to w using link and segment
 // writers lw and sw as follows: lw is invoked for consecutive segment starts
 // and ends as specified through the links selection, and sw is invoked for
@@ -138,7 +134,6 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection,
 	flush()
 }
 
-
 // A merger merges a slice of Selections and produces a sequence of
 // consecutive segment change events through repeated next() calls.
 //
@@ -147,7 +142,6 @@ type merger struct {
 	segments   [][]int // segments[i] is the next segment of selections[i]
 }
 
-
 const infinity int = 2e9
 
 func newMerger(selections []Selection) *merger {
@@ -163,7 +157,6 @@ func newMerger(selections []Selection) *merger {
 	return &merger{selections, segments}
 }
 
-
 // next returns the next segment change: index specifies the Selection
 // to which the segment belongs, offs is the segment start or end offset
 // as determined by the start value. If there are no more segment changes,
@@ -208,7 +201,6 @@ func (m *merger) next() (index, offs int, start bool) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Implementation of FormatText
 
@@ -232,7 +224,6 @@ func lineSelection(text []byte) Selection {
 	}
 }
 
-
 // commentSelection returns the sequence of consecutive comments
 // in the Go src text as a Selection.
 //
@@ -257,7 +248,6 @@ func commentSelection(src []byte) Selection {
 	}
 }
 
-
 // makeSelection is a helper function to make a Selection from a slice of pairs.
 func makeSelection(matches [][]int) Selection {
 	return func() (seg []int) {
@@ -269,7 +259,6 @@ func makeSelection(matches [][]int) Selection {
 	}
 }
 
-
 // regexpSelection computes the Selection for the regular expression expr in text.
 func regexpSelection(text []byte, expr string) Selection {
 	var matches [][]int
@@ -279,7 +268,6 @@ func regexpSelection(text []byte, expr string) Selection {
 	return makeSelection(matches)
 }
 
-
 var selRx = regexp.MustCompile(`^([0-9]+):([0-9]+)`)
 
 // rangeSelection computes the Selection for a text range described
@@ -298,7 +286,6 @@ func rangeSelection(str string) Selection {
 	return nil
 }
 
-
 // Span tags for all the possible selection combinations that may
 // be generated by FormatText. Selections are indicated by a bitset,
 // and the value of the bitset specifies the tag to be used.
@@ -320,7 +307,6 @@ var startTags = [][]byte{
 
 var endTag = []byte(`</span>`)
 
-
 func selectionTag(w io.Writer, text []byte, selections int) {
 	if selections < len(startTags) {
 		if tag := startTags[selections]; len(tag) > 0 {
@@ -333,7 +319,6 @@ func selectionTag(w io.Writer, text []byte, selections int) {
 	template.HTMLEscape(w, text)
 }
 
-
 // FormatText HTML-escapes text and writes it to w.
 // Consecutive text segments are wrapped in HTML spans (with tags as
 // defined by startTags and endTag) as follows:
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 20ebd31..03ac1b9 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -27,7 +27,6 @@ import (
 	"time"
 )
 
-
 // ----------------------------------------------------------------------------
 // Globals
 
@@ -35,7 +34,6 @@ type delayTime struct {
 	RWValue
 }
 
-
 func (dt *delayTime) backoff(max int) {
 	dt.mutex.Lock()
 	v := dt.value.(int) * 2
@@ -47,7 +45,6 @@ func (dt *delayTime) backoff(max int) {
 	dt.mutex.Unlock()
 }
 
-
 var (
 	verbose = flag.Bool("v", false, "verbose mode")
 
@@ -70,11 +67,12 @@ var (
 	maxResults   = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
 
 	// file system mapping
-	fs         FileSystem // the underlying file system
-	fsMap      Mapping    // user-defined mapping
-	fsTree     RWValue    // *Directory tree of packages, updated with each sync
-	pathFilter RWValue    // filter used when building fsMap directory trees
-	fsModified RWValue    // timestamp of last call to invalidateIndex
+	fs         FileSystem      // the underlying file system for godoc
+	fsHttp     http.FileSystem // the underlying file system for http
+	fsMap      Mapping         // user-defined mapping
+	fsTree     RWValue         // *Directory tree of packages, updated with each sync
+	pathFilter RWValue         // filter used when building fsMap directory trees
+	fsModified RWValue         // timestamp of last call to invalidateIndex
 
 	// http handlers
 	fileServer http.Handler // default file server
@@ -82,7 +80,6 @@ var (
 	pkgHandler httpHandler
 )
 
-
 func initHandlers() {
 	paths := filepath.SplitList(*pkgPath)
 	for _, t := range build.Path {
@@ -93,12 +90,11 @@ func initHandlers() {
 	}
 	fsMap.Init(paths)
 
-	fileServer = http.FileServer(http.Dir(*goroot))
+	fileServer = http.FileServer(fsHttp)
 	cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false}
 	pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true}
 }
 
-
 func registerPublicHandlers(mux *http.ServeMux) {
 	mux.Handle(cmdHandler.pattern, &cmdHandler)
 	mux.Handle(pkgHandler.pattern, &pkgHandler)
@@ -108,13 +104,11 @@ func registerPublicHandlers(mux *http.ServeMux) {
 	mux.HandleFunc("/", serveFile)
 }
 
-
 func initFSTree() {
 	fsTree.set(newDirectory(filepath.Join(*goroot, *testDir), nil, -1))
 	invalidateIndex()
 }
 
-
 // ----------------------------------------------------------------------------
 // Directory filters
 
@@ -125,7 +119,6 @@ func isParentOf(p, q string) bool {
 	return strings.HasPrefix(q, p) && (len(q) <= n || q[n] == '/')
 }
 
-
 func setPathFilter(list []string) {
 	if len(list) == 0 {
 		pathFilter.set(nil)
@@ -142,7 +135,6 @@ func setPathFilter(list []string) {
 	})
 }
 
-
 func getPathFilter() func(string) bool {
 	f, _ := pathFilter.get()
 	if f != nil {
@@ -151,7 +143,6 @@ func getPathFilter() func(string) bool {
 	return nil
 }
 
-
 // readDirList reads a file containing a newline-separated list
 // of directory paths and returns the list of paths.
 func readDirList(filename string) ([]string, os.Error) {
@@ -170,7 +161,7 @@ func readDirList(filename string) ([]string, os.Error) {
 		return e == nil && isPkgDir(d)
 	}
 	list := canonicalizePaths(strings.Split(string(contents), "\n"), filter)
-	// for each parent path, remove all it's children q
+	// for each parent path, remove all its children q
 	// (requirement for binary search to work when filtering)
 	i := 0
 	for _, q := range list {
@@ -182,7 +173,6 @@ func readDirList(filename string) ([]string, os.Error) {
 	return list[0:i], err
 }
 
-
 // updateMappedDirs computes the directory tree for
 // each user-defined file system mapping. If a filter
 // is provided, it is used to filter directories.
@@ -197,7 +187,6 @@ func updateMappedDirs(filter func(string) bool) {
 	}
 }
 
-
 func updateFilterFile() {
 	updateMappedDirs(nil) // no filter for accuracy
 
@@ -220,7 +209,6 @@ func updateFilterFile() {
 	}
 }
 
-
 func initDirTrees() {
 	// setup initial path filter
 	if *filter != "" {
@@ -255,7 +243,6 @@ func initDirTrees() {
 	}
 }
 
-
 // ----------------------------------------------------------------------------
 // Path mapping
 
@@ -271,7 +258,6 @@ func absolutePath(relpath, defaultRoot string) string {
 	return abspath
 }
 
-
 func relativeURL(abspath string) string {
 	relpath := fsMap.ToRelative(abspath)
 	if relpath == "" {
@@ -293,7 +279,6 @@ func relativeURL(abspath string) string {
 	return relpath
 }
 
-
 // ----------------------------------------------------------------------------
 // Tab conversion
 
@@ -311,7 +296,6 @@ type tconv struct {
 	indent int // valid if state == indenting
 }
 
-
 func (p *tconv) writeIndent() (err os.Error) {
 	i := p.indent
 	for i >= len(spaces) {
@@ -327,7 +311,6 @@ func (p *tconv) writeIndent() (err os.Error) {
 	return
 }
 
-
 func (p *tconv) Write(data []byte) (n int, err os.Error) {
 	if len(data) == 0 {
 		return
@@ -371,7 +354,6 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Templates
 
@@ -389,7 +371,6 @@ func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
 	(&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x)
 }
 
-
 // Write anything to w.
 func writeAny(w io.Writer, fset *token.FileSet, x interface{}) {
 	switch v := x.(type) {
@@ -404,7 +385,6 @@ func writeAny(w io.Writer, fset *token.FileSet, x interface{}) {
 	}
 }
 
-
 // Write anything html-escaped to w.
 func writeAnyHTML(w io.Writer, fset *token.FileSet, x interface{}) {
 	switch v := x.(type) {
@@ -423,7 +403,6 @@ func writeAnyHTML(w io.Writer, fset *token.FileSet, x interface{}) {
 	}
 }
 
-
 func fileset(x []interface{}) *token.FileSet {
 	if len(x) > 1 {
 		if fset, ok := x[1].(*token.FileSet); ok {
@@ -433,13 +412,11 @@ func fileset(x []interface{}) *token.FileSet {
 	return nil
 }
 
-
 // Template formatter for "html-esc" format.
 func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
 	writeAnyHTML(w, fileset(x), x[0])
 }
 
-
 // Template formatter for "html-comment" format.
 func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
 	var buf bytes.Buffer
@@ -449,13 +426,11 @@ func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
 	doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping
 }
 
-
 // Template formatter for "" (default) format.
 func textFmt(w io.Writer, format string, x ...interface{}) {
 	writeAny(w, fileset(x), x[0])
 }
 
-
 // Template formatter for "urlquery-esc" format.
 func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) {
 	var buf bytes.Buffer
@@ -463,7 +438,6 @@ func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) {
 	template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes()))))
 }
 
-
 // Template formatter for the various "url-xxx" formats excluding url-esc.
 func urlFmt(w io.Writer, format string, x ...interface{}) {
 	var path string
@@ -536,7 +510,6 @@ func urlFmt(w io.Writer, format string, x ...interface{}) {
 	}
 }
 
-
 // The strings in infoKinds must be properly html-escaped.
 var infoKinds = [nKinds]string{
 	PackageClause: "package clause",
@@ -549,13 +522,11 @@ var infoKinds = [nKinds]string{
 	Use:           "use",
 }
 
-
 // Template formatter for "infoKind" format.
 func infoKindFmt(w io.Writer, format string, x ...interface{}) {
 	fmt.Fprintf(w, infoKinds[x[0].(SpotKind)]) // infoKind entries are html-escaped
 }
 
-
 // Template formatter for "infoLine" format.
 func infoLineFmt(w io.Writer, format string, x ...interface{}) {
 	info := x[0].(SpotInfo)
@@ -575,7 +546,6 @@ func infoLineFmt(w io.Writer, format string, x ...interface{}) {
 	fmt.Fprintf(w, "%d", line)
 }
 
-
 // Template formatter for "infoSnippet" format.
 func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
 	info := x[0].(SpotInfo)
@@ -589,7 +559,6 @@ func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
 	w.Write(text)
 }
 
-
 // Template formatter for "padding" format.
 func paddingFmt(w io.Writer, format string, x ...interface{}) {
 	for i := x[0].(int); i > 0; i-- {
@@ -597,27 +566,33 @@ func paddingFmt(w io.Writer, format string, x ...interface{}) {
 	}
 }
 
-
-// Template formatter for "time" format.
-func timeFmt(w io.Writer, format string, x ...interface{}) {
-	template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x[0].(int64)/1e9).String()))
+// Template formatter for "localname" format.
+func localnameFmt(w io.Writer, format string, x ...interface{}) {
+	_, localname := filepath.Split(x[0].(string))
+	template.HTMLEscape(w, []byte(localname))
 }
 
-
-// Template formatter for "dir/" format.
-func dirslashFmt(w io.Writer, format string, x ...interface{}) {
-	if x[0].(FileInfo).IsDirectory() {
+// Template formatter for "fileInfoName" format.
+func fileInfoNameFmt(w io.Writer, format string, x ...interface{}) {
+	fi := x[0].(FileInfo)
+	template.HTMLEscape(w, []byte(fi.Name()))
+	if fi.IsDirectory() {
 		w.Write([]byte{'/'})
 	}
 }
 
-
-// Template formatter for "localname" format.
-func localnameFmt(w io.Writer, format string, x ...interface{}) {
-	_, localname := filepath.Split(x[0].(string))
-	template.HTMLEscape(w, []byte(localname))
+// Template formatter for "fileInfoSize" format.
+func fileInfoSizeFmt(w io.Writer, format string, x ...interface{}) {
+	fmt.Fprintf(w, "%d", x[0].(FileInfo).Size())
 }
 
+// Template formatter for "fileInfoTime" format.
+func fileInfoTimeFmt(w io.Writer, format string, x ...interface{}) {
+	if t := x[0].(FileInfo).Mtime_ns(); t != 0 {
+		template.HTMLEscape(w, []byte(time.SecondsToLocalTime(t/1e9).String()))
+	}
+	// don't print epoch if time is obviously not set
+}
 
 // Template formatter for "numlines" format.
 func numlinesFmt(w io.Writer, format string, x ...interface{}) {
@@ -625,7 +600,6 @@ func numlinesFmt(w io.Writer, format string, x ...interface{}) {
 	fmt.Fprintf(w, "%d", len(list))
 }
 
-
 var fmap = template.FormatterMap{
 	"":             textFmt,
 	"html-esc":     htmlEscFmt,
@@ -638,13 +612,13 @@ var fmap = template.FormatterMap{
 	"infoLine":     infoLineFmt,
 	"infoSnippet":  infoSnippetFmt,
 	"padding":      paddingFmt,
-	"time":         timeFmt,
-	"dir/":         dirslashFmt,
+	"fileInfoName": fileInfoNameFmt,
+	"fileInfoSize": fileInfoSizeFmt,
+	"fileInfoTime": fileInfoTimeFmt,
 	"localname":    localnameFmt,
 	"numlines":     numlinesFmt,
 }
 
-
 func readTemplate(name string) *template.Template {
 	path := filepath.Join(*goroot, "lib", "godoc", name)
 	if *templateDir != "" {
@@ -666,7 +640,6 @@ func readTemplate(name string) *template.Template {
 	return t
 }
 
-
 var (
 	codewalkHTML,
 	codewalkdirHTML,
@@ -692,7 +665,6 @@ func readTemplates() {
 	searchText = readTemplate("search.txt")
 }
 
-
 // ----------------------------------------------------------------------------
 // Generic HTML wrapper
 
@@ -722,13 +694,11 @@ func servePage(w http.ResponseWriter, title, subtitle, query string, content []b
 	}
 }
 
-
 func serveText(w http.ResponseWriter, text []byte) {
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 	w.Write(text)
 }
 
-
 // ----------------------------------------------------------------------------
 // Files
 
@@ -738,7 +708,6 @@ var (
 	firstCommentRx = regexp.MustCompile(`<!--([^\-]*)-->`)
 )
 
-
 func extractString(src []byte, rx *regexp.Regexp) (s string) {
 	m := rx.FindSubmatch(src)
 	if m != nil {
@@ -747,7 +716,6 @@ func extractString(src []byte, rx *regexp.Regexp) (s string) {
 	return
 }
 
-
 func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
 	// get HTML body contents
 	src, err := fs.ReadFile(abspath)
@@ -782,7 +750,6 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
 	servePage(w, title, subtitle, "", src)
 }
 
-
 func applyTemplate(t *template.Template, name string, data interface{}) []byte {
 	var buf bytes.Buffer
 	if err := t.Execute(&buf, data); err != nil {
@@ -791,7 +758,6 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
 	return buf.Bytes()
 }
 
-
 func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
 	if canonical := path.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
 		http.Redirect(w, r, canonical, http.StatusMovedPermanently)
@@ -816,7 +782,6 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
 	servePage(w, title+" "+relpath, "", "", buf.Bytes())
 }
 
-
 func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
 	if redirect(w, r) {
 		return
@@ -833,7 +798,6 @@ func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath str
 	servePage(w, "Directory "+relpath, "", "", contents)
 }
 
-
 func serveFile(w http.ResponseWriter, r *http.Request) {
 	relpath := r.URL.Path[1:] // serveFile URL paths start with '/'
 	abspath := absolutePath(relpath, *goroot)
@@ -893,7 +857,6 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
 	fileServer.ServeHTTP(w, r)
 }
 
-
 // ----------------------------------------------------------------------------
 // Packages
 
@@ -908,7 +871,6 @@ const (
 	genDoc                               // generate documentation
 )
 
-
 type PageInfo struct {
 	Dirname string          // directory containing the package
 	PList   []string        // list of package names found
@@ -921,19 +883,16 @@ type PageInfo struct {
 	Err     os.Error        // directory read error or nil
 }
 
-
 func (info *PageInfo) IsEmpty() bool {
 	return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
 }
 
-
 type httpHandler struct {
 	pattern string // url pattern; e.g. "/pkg/"
 	fsRoot  string // file system root to which the pattern is mapped
 	isPkg   bool   // true if this handler serves real package documentation (as opposed to command documentation)
 }
 
-
 // getPageInfo returns the PageInfo for a package directory abspath. If the
 // parameter genAST is set, an AST containing only the package exports is
 // computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
@@ -1072,7 +1031,6 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
 	return PageInfo{abspath, plist, fset, past, pdoc, dir.listing(true), timestamp, h.isPkg, nil}
 }
 
-
 func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	if redirect(w, r) {
 		return
@@ -1123,7 +1081,6 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	servePage(w, title, subtitle, "", contents)
 }
 
-
 // ----------------------------------------------------------------------------
 // Search
 
@@ -1143,7 +1100,6 @@ type SearchResult struct {
 	Complete bool        // true if all textual occurrences of Query are reported
 }
 
-
 func lookup(query string) (result SearchResult) {
 	result.Query = query
 
@@ -1195,7 +1151,6 @@ func lookup(query string) (result SearchResult) {
 	return
 }
 
-
 func search(w http.ResponseWriter, r *http.Request) {
 	query := strings.TrimSpace(r.FormValue("q"))
 	result := lookup(query)
@@ -1217,7 +1172,6 @@ func search(w http.ResponseWriter, r *http.Request) {
 	servePage(w, title, "", query, contents)
 }
 
-
 // ----------------------------------------------------------------------------
 // Indexer
 
@@ -1228,7 +1182,6 @@ func invalidateIndex() {
 	fsModified.set(nil)
 }
 
-
 // indexUpToDate() returns true if the search index is not older
 // than any of the file systems under godoc's observation.
 //
@@ -1238,7 +1191,6 @@ func indexUpToDate() bool {
 	return fsTime <= siTime
 }
 
-
 // feedDirnames feeds the directory names of all directories
 // under the file system given by root to channel c.
 //
@@ -1250,7 +1202,6 @@ func feedDirnames(root *RWValue, c chan<- string) {
 	}
 }
 
-
 // fsDirnames() returns a channel sending all directory names
 // of all the file systems under godoc's observation.
 //
@@ -1267,7 +1218,6 @@ func fsDirnames() <-chan string {
 	return c
 }
 
-
 func indexer() {
 	for {
 		if !indexUpToDate() {
diff --git a/src/cmd/godoc/httpzip.go b/src/cmd/godoc/httpzip.go
new file mode 100644
index 0000000..cb8322e
--- /dev/null
+++ b/src/cmd/godoc/httpzip.go
@@ -0,0 +1,181 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides an implementation of the http.FileSystem
+// interface based on the contents of a .zip file.
+//
+// Assumptions:
+//
+// - The file paths stored in the zip file must use a slash ('/') as path
+//   separator; and they must be relative (i.e., they must not start with
+//   a '/' - this is usually the case if the file was created w/o special
+//   options).
+// - The zip file system treats the file paths found in the zip internally
+//   like absolute paths w/o a leading '/'; i.e., the paths are considered
+//   relative to the root of the file system.
+// - All path arguments to file system methods are considered relative to
+//   the root specified with NewHttpZipFS (even if the paths start with a '/').
+
+// TODO(gri) Should define a commonly used FileSystem API that is the same
+//           for http and godoc. Then we only need one zip-file based file
+//           system implementation.
+
+package main
+
+import (
+	"archive/zip"
+	"fmt"
+	"http"
+	"io"
+	"os"
+	"path"
+	"sort"
+	"strings"
+)
+
+// We cannot import syscall on app engine.
+// TODO(gri) Once we have a truly abstract FileInfo implementation
+//           this won't be needed anymore.
+const (
+	S_IFDIR = 0x4000 // == syscall.S_IFDIR
+	S_IFREG = 0x8000 // == syscall.S_IFREG
+)
+
+// httpZipFile is the zip-file based implementation of http.File
+type httpZipFile struct {
+	path          string // absolute path within zip FS without leading '/'
+	info          os.FileInfo
+	io.ReadCloser // nil for directory
+	list          zipList
+}
+
+func (f *httpZipFile) Close() os.Error {
+	if f.info.IsRegular() {
+		return f.ReadCloser.Close()
+	}
+	f.list = nil
+	return nil
+}
+
+func (f *httpZipFile) Stat() (*os.FileInfo, os.Error) {
+	return &f.info, nil
+}
+
+func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) {
+	var list []os.FileInfo
+	dirname := f.path + "/"
+	prevname := ""
+	for i, e := range f.list {
+		if count == 0 {
+			f.list = f.list[i:]
+			break
+		}
+		if !strings.HasPrefix(e.Name, dirname) {
+			f.list = nil
+			break // not in the same directory anymore
+		}
+		name := e.Name[len(dirname):] // local name
+		var mode uint32
+		var size, mtime_ns int64
+		if i := strings.IndexRune(name, '/'); i >= 0 {
+			// We infer directories from files in subdirectories.
+			// If we have x/y, return a directory entry for x.
+			name = name[0:i] // keep local directory name only
+			mode = S_IFDIR
+			// no size or mtime_ns for directories
+		} else {
+			mode = S_IFREG
+			size = int64(e.UncompressedSize)
+			mtime_ns = e.Mtime_ns()
+		}
+		// If we have x/y and x/z, don't return two directory entries for x.
+		// TODO(gri): It should be possible to do this more efficiently
+		// by determining the (fs.list) range of local directory entries
+		// (via two binary searches).
+		if name != prevname {
+			list = append(list, os.FileInfo{
+				Name:     name,
+				Mode:     mode,
+				Size:     size,
+				Mtime_ns: mtime_ns,
+			})
+			prevname = name
+			count--
+		}
+	}
+
+	if count >= 0 && len(list) == 0 {
+		return nil, os.EOF
+	}
+
+	return list, nil
+}
+
+func (f *httpZipFile) Seek(offset int64, whence int) (int64, os.Error) {
+	return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name)
+}
+
+// httpZipFS is the zip-file based implementation of http.FileSystem
+type httpZipFS struct {
+	*zip.ReadCloser
+	list zipList
+	root string
+}
+
+func (fs *httpZipFS) Open(name string) (http.File, os.Error) {
+	// fs.root does not start with '/'.
+	path := path.Join(fs.root, name) // path is clean
+	index, exact := fs.list.lookup(path)
+	if index < 0 || !strings.HasPrefix(path, fs.root) {
+		// file not found or not under root
+		return nil, fmt.Errorf("file not found: %s", name)
+	}
+
+	if exact {
+		// exact match found - must be a file
+		f := fs.list[index]
+		rc, err := f.Open()
+		if err != nil {
+			return nil, err
+		}
+		return &httpZipFile{
+			path,
+			os.FileInfo{
+				Name:     name,
+				Mode:     S_IFREG,
+				Size:     int64(f.UncompressedSize),
+				Mtime_ns: f.Mtime_ns(),
+			},
+			rc,
+			nil,
+		}, nil
+	}
+
+	// not an exact match - must be a directory
+	return &httpZipFile{
+		path,
+		os.FileInfo{
+			Name: name,
+			Mode: S_IFDIR,
+			// no size or mtime_ns for directories
+		},
+		nil,
+		fs.list[index:],
+	}, nil
+}
+
+func (fs *httpZipFS) Close() os.Error {
+	fs.list = nil
+	return fs.ReadCloser.Close()
+}
+
+// NewHttpZipFS creates a new http.FileSystem based on the contents of
+// the zip file rc restricted to the directory tree specified by root;
+// root must be an absolute path.
+func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem {
+	list := make(zipList, len(rc.File))
+	copy(list, rc.File) // sort a copy of rc.File
+	sort.Sort(list)
+	return &httpZipFS{rc, list, zipPath(root)}
+}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index e0c89e7..9b4f315 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -52,7 +52,6 @@ import (
 	"strings"
 )
 
-
 // ----------------------------------------------------------------------------
 // RunList
 
@@ -69,13 +68,11 @@ type RunList struct {
 
 func (h *RunList) Less(i, j int) bool { return h.less(h.At(i), h.At(j)) }
 
-
 func (h *RunList) sort(less func(x, y interface{}) bool) {
 	h.less = less
 	sort.Sort(h)
 }
 
-
 // Compress entries which are the same according to a sort criteria
 // (specified by less) into "runs".
 func (h *RunList) reduce(less func(x, y interface{}) bool, newRun func(h *RunList, i, j int) interface{}) *RunList {
@@ -99,7 +96,6 @@ func (h *RunList) reduce(less func(x, y interface{}) bool, newRun func(h *RunLis
 	return &hh
 }
 
-
 // ----------------------------------------------------------------------------
 // SpotInfo
 
@@ -130,7 +126,6 @@ const (
 	nKinds
 )
 
-
 func init() {
 	// sanity check: if nKinds is too large, the SpotInfo
 	// accessor functions may need to be updated
@@ -139,7 +134,6 @@ func init() {
 	}
 }
 
-
 // makeSpotInfo makes a SpotInfo.
 func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
 	// encode lori: bits [4..32)
@@ -159,12 +153,10 @@ func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
 	return x
 }
 
-
 func (x SpotInfo) Kind() SpotKind { return SpotKind(x >> 1 & 7) }
 func (x SpotInfo) Lori() int      { return int(x >> 4) }
 func (x SpotInfo) IsIndex() bool  { return x&1 != 0 }
 
-
 // ----------------------------------------------------------------------------
 // KindRun
 
@@ -177,18 +169,15 @@ type KindRun struct {
 	Infos []SpotInfo
 }
 
-
 // KindRuns are sorted by line number or index. Since the isIndex bit
 // is always the same for all infos in one list we can compare lori's.
 func (f *KindRun) Len() int           { return len(f.Infos) }
 func (f *KindRun) Less(i, j int) bool { return f.Infos[i].Lori() < f.Infos[j].Lori() }
 func (f *KindRun) Swap(i, j int)      { f.Infos[i], f.Infos[j] = f.Infos[j], f.Infos[i] }
 
-
 // FileRun contents are sorted by Kind for the reduction into KindRuns.
 func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
 
-
 // newKindRun allocates a new KindRun from the SpotInfo run [i, j) in h.
 func newKindRun(h *RunList, i, j int) interface{} {
 	kind := h.At(i).(SpotInfo).Kind()
@@ -224,7 +213,6 @@ func newKindRun(h *RunList, i, j int) interface{} {
 	return run
 }
 
-
 // ----------------------------------------------------------------------------
 // FileRun
 
@@ -239,32 +227,27 @@ func (p *Pak) less(q *Pak) bool {
 	return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path
 }
 
-
 // A File describes a Go file.
 type File struct {
 	Path string // complete file name
 	Pak  Pak    // the package to which the file belongs
 }
 
-
 // A Spot describes a single occurrence of a word.
 type Spot struct {
 	File *File
 	Info SpotInfo
 }
 
-
 // A FileRun is a list of KindRuns belonging to the same file.
 type FileRun struct {
 	File   *File
 	Groups []*KindRun
 }
 
-
 // Spots are sorted by path for the reduction into FileRuns.
 func lessSpot(x, y interface{}) bool { return x.(Spot).File.Path < y.(Spot).File.Path }
 
-
 // newFileRun allocates a new FileRun from the Spot run [i, j) in h.
 func newFileRun(h0 *RunList, i, j int) interface{} {
 	file := h0.At(i).(Spot).File
@@ -287,7 +270,6 @@ func newFileRun(h0 *RunList, i, j int) interface{} {
 	return &FileRun{file, groups}
 }
 
-
 // ----------------------------------------------------------------------------
 // PakRun
 
@@ -302,13 +284,11 @@ func (p *PakRun) Len() int           { return len(p.Files) }
 func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Path < p.Files[j].File.Path }
 func (p *PakRun) Swap(i, j int)      { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
 
-
 // FileRuns are sorted by package for the reduction into PakRuns.
 func lessFileRun(x, y interface{}) bool {
 	return x.(*FileRun).File.Pak.less(&y.(*FileRun).File.Pak)
 }
 
-
 // newPakRun allocates a new PakRun from the *FileRun run [i, j) in h.
 func newPakRun(h *RunList, i, j int) interface{} {
 	pak := h.At(i).(*FileRun).File.Pak
@@ -323,18 +303,15 @@ func newPakRun(h *RunList, i, j int) interface{} {
 	return run
 }
 
-
 // ----------------------------------------------------------------------------
 // HitList
 
 // A HitList describes a list of PakRuns.
 type HitList []*PakRun
 
-
 // PakRuns are sorted by package.
 func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(&y.(*PakRun).Pak) }
 
-
 func reduce(h0 *RunList) HitList {
 	// reduce a list of Spots into a list of FileRuns
 	h1 := h0.reduce(lessSpot, newFileRun)
@@ -350,7 +327,6 @@ func reduce(h0 *RunList) HitList {
 	return h
 }
 
-
 func (h HitList) filter(pakname string) HitList {
 	// determine number of matching packages (most of the time just one)
 	n := 0
@@ -371,7 +347,6 @@ func (h HitList) filter(pakname string) HitList {
 	return hh
 }
 
-
 // ----------------------------------------------------------------------------
 // AltWords
 
@@ -380,7 +355,6 @@ type wordPair struct {
 	alt   string // alternative spelling
 }
 
-
 // An AltWords describes a list of alternative spellings for a
 // canonical (all lowercase) spelling of a word.
 type AltWords struct {
@@ -388,11 +362,9 @@ type AltWords struct {
 	Alts  []string // alternative spelling for the same word
 }
 
-
 // wordPairs are sorted by their canonical spelling.
 func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
 
-
 // newAltWords allocates a new AltWords from the *wordPair run [i, j) in h.
 func newAltWords(h *RunList, i, j int) interface{} {
 	canon := h.At(i).(*wordPair).canon
@@ -405,7 +377,6 @@ func newAltWords(h *RunList, i, j int) interface{} {
 	return &AltWords{canon, alts}
 }
 
-
 func (a *AltWords) filter(s string) *AltWords {
 	if len(a.Alts) == 1 && a.Alts[0] == s {
 		// there are no different alternatives
@@ -424,7 +395,6 @@ func (a *AltWords) filter(s string) *AltWords {
 	return &AltWords{a.Canon, alts[0:i]}
 }
 
-
 // ----------------------------------------------------------------------------
 // Indexer
 
@@ -432,13 +402,11 @@ func (a *AltWords) filter(s string) *AltWords {
 const includeMainPackages = true
 const includeTestFiles = true
 
-
 type IndexResult struct {
 	Decls  RunList // package-level declarations (with snippets)
 	Others RunList // all other occurrences
 }
 
-
 // Statistics provides statistics information for an index.
 type Statistics struct {
 	Bytes int // total size of indexed source files
@@ -448,7 +416,6 @@ type Statistics struct {
 	Spots int // number of identifier occurrences
 }
 
-
 // An Indexer maintains the data structures and provides the machinery
 // for indexing .go files under a file tree. It implements the path.Visitor
 // interface for walking file trees, and the ast.Visitor interface for
@@ -464,21 +431,18 @@ type Indexer struct {
 	stats    Statistics
 }
 
-
 func (x *Indexer) addSnippet(s *Snippet) int {
 	index := x.snippets.Len()
 	x.snippets.Push(s)
 	return index
 }
 
-
 func (x *Indexer) visitComment(c *ast.CommentGroup) {
 	if c != nil {
 		ast.Walk(x, c)
 	}
 }
 
-
 func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
 	if id != nil {
 		lists, found := x.words[id.Name]
@@ -502,7 +466,6 @@ func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
 	}
 }
 
-
 func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
 	switch n := spec.(type) {
 	case *ast.ImportSpec:
@@ -534,7 +497,6 @@ func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
 	}
 }
 
-
 func (x *Indexer) Visit(node ast.Node) ast.Visitor {
 	// TODO(gri): methods in interface types are categorized as VarDecl
 	switch n := node.(type) {
@@ -606,7 +568,6 @@ func (x *Indexer) Visit(node ast.Node) ast.Visitor {
 	return nil
 }
 
-
 func pkgName(filename string) string {
 	// use a new file set each time in order to not pollute the indexer's
 	// file set (which must stay in sync with the concatenated source code)
@@ -617,7 +578,6 @@ func pkgName(filename string) string {
 	return file.Name.Name
 }
 
-
 // addFile adds a file to the index if possible and returns the file set file
 // and the file's AST if it was successfully parsed as a Go file. If addFile
 // failed (that is, if the file was not added), it returns file == nil.
@@ -633,7 +593,7 @@ func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *
 	// this permits the direct mapping of suffix array lookup results to
 	// to corresponding Pos values.
 	//
-	// When a file is added to the file set, it's offset base increases by
+	// When a file is added to the file set, its offset base increases by
 	// the size of the file + 1; and the initial base offset is 1. Add an
 	// extra byte to the sources here.
 	x.sources.WriteByte(0)
@@ -679,7 +639,6 @@ func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *
 	return
 }
 
-
 // Design note: Using an explicit white list of permitted files for indexing
 // makes sure that the important files are included and massively reduces the
 // number of files to index. The advantage over a blacklist is that unexpected
@@ -712,7 +671,6 @@ var whitelisted = map[string]bool{
 	"README":       true,
 }
 
-
 // isWhitelisted returns true if a file is on the list
 // of "permitted" files for indexing. The filename must
 // be the directory-local name of the file.
@@ -725,7 +683,6 @@ func isWhitelisted(filename string) bool {
 	return whitelisted[key]
 }
 
-
 func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
 	if !f.IsRegular() {
 		return
@@ -768,7 +725,6 @@ func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
 	x.stats.Lines += file.LineCount()
 }
 
-
 // ----------------------------------------------------------------------------
 // Index
 
@@ -777,7 +733,6 @@ type LookupResult struct {
 	Others HitList // all other occurrences
 }
 
-
 type Index struct {
 	fset     *token.FileSet           // file set used during indexing; nil if no textindex
 	suffixes *suffixarray.Index       // suffixes for concatenated sources; nil if no textindex
@@ -787,10 +742,8 @@ type Index struct {
 	stats    Statistics
 }
 
-
 func canonical(w string) string { return strings.ToLower(w) }
 
-
 // NewIndex creates a new index for the .go files
 // in the directories given by dirnames.
 //
@@ -865,13 +818,11 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
 	return &Index{x.fset, suffixes, words, alts, snippets, x.stats}
 }
 
-
 // Stats() returns index statistics.
 func (x *Index) Stats() Statistics {
 	return x.stats
 }
 
-
 func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
 	match = x.words[w]
 	alt = x.alts[canonical(w)]
@@ -884,7 +835,6 @@ func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
 	return
 }
 
-
 func isIdentifier(s string) bool {
 	var S scanner.Scanner
 	fset := token.NewFileSet()
@@ -896,7 +846,6 @@ func isIdentifier(s string) bool {
 	return false
 }
 
-
 // For a given query, which is either a single identifier or a qualified
 // identifier, Lookup returns a LookupResult, and a list of alternative
 // spellings, if any. If the query syntax is wrong, an error is reported.
@@ -932,7 +881,6 @@ func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os
 	return
 }
 
-
 func (x *Index) Snippet(i int) *Snippet {
 	// handle illegal snippet indices gracefully
 	if 0 <= i && i < len(x.snippets) {
@@ -941,7 +889,6 @@ func (x *Index) Snippet(i int) *Snippet {
 	return nil
 }
 
-
 type positionList []struct {
 	filename string
 	line     int
@@ -951,7 +898,6 @@ func (list positionList) Len() int           { return len(list) }
 func (list positionList) Less(i, j int) bool { return list[i].filename < list[j].filename }
 func (list positionList) Swap(i, j int)      { list[i], list[j] = list[j], list[i] }
 
-
 // unique returns the list sorted and with duplicate entries removed
 func unique(list []int) []int {
 	sort.Ints(list)
@@ -967,14 +913,12 @@ func unique(list []int) []int {
 	return list[0:i]
 }
 
-
 // A FileLines value specifies a file and line numbers within that file.
 type FileLines struct {
 	Filename string
 	Lines    []int
 }
 
-
 // LookupRegexp returns the number of matches and the matches where a regular
 // expression r is found in the full text index. At most n matches are
 // returned (thus found <= n).
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 51fcf8d..943c81c 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -26,6 +26,7 @@
 package main
 
 import (
+	"archive/zip"
 	"bytes"
 	_ "expvar" // to serve /debug/vars
 	"flag"
@@ -37,6 +38,7 @@ import (
 	"io"
 	"log"
 	"os"
+	"path"
 	"path/filepath"
 	"regexp"
 	"runtime"
@@ -47,6 +49,10 @@ import (
 const defaultAddr = ":6060" // default webserver address
 
 var (
+	// file system to serve
+	// (with e.g.: zip -r go.zip $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i favicon.ico)
+	zipfile = flag.String("zip", "", "zip file providing the file system to serve; disabled if empty")
+
 	// periodic sync
 	syncCmd   = flag.String("sync", "", "sync command; disabled if empty")
 	syncMin   = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
@@ -64,14 +70,12 @@ var (
 	query = flag.Bool("q", false, "arguments are considered search queries")
 )
 
-
 func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
 	contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
 	w.WriteHeader(http.StatusNotFound)
 	servePage(w, "File "+relpath, "", "", contents)
 }
 
-
 func exec(rw http.ResponseWriter, args []string) (status int) {
 	r, w, err := os.Pipe()
 	if err != nil {
@@ -119,7 +123,6 @@ func exec(rw http.ResponseWriter, args []string) (status int) {
 	return
 }
 
-
 func dosync(w http.ResponseWriter, r *http.Request) {
 	args := []string{"/bin/sh", "-c", *syncCmd}
 	switch exec(w, args) {
@@ -141,7 +144,6 @@ func dosync(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-
 func usage() {
 	fmt.Fprintf(os.Stderr,
 		"usage: godoc package [name ...]\n"+
@@ -150,7 +152,6 @@ func usage() {
 	os.Exit(2)
 }
 
-
 func loggingHandler(h http.Handler) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 		log.Printf("%s\t%s", req.RemoteAddr, req.URL)
@@ -158,7 +159,6 @@ func loggingHandler(h http.Handler) http.Handler {
 	})
 }
 
-
 func remoteSearch(query string) (res *http.Response, err os.Error) {
 	search := "/search?f=text&q=" + http.URLEscape(query)
 
@@ -190,13 +190,11 @@ func remoteSearch(query string) (res *http.Response, err os.Error) {
 	return
 }
 
-
 // Does s look like a regular expression?
 func isRegexp(s string) bool {
 	return strings.IndexAny(s, ".(|)*+?^$[]") >= 0
 }
 
-
 // Make a regular expression of the form
 // names[0]|names[1]|...names[len(names)-1].
 // Returns nil if the regular expression is illegal.
@@ -218,18 +216,10 @@ func makeRx(names []string) (rx *regexp.Regexp) {
 	return
 }
 
-
 func main() {
 	flag.Usage = usage
 	flag.Parse()
 
-	// Determine file system to use.
-	// TODO(gri) Complete this - for now we only have one.
-	fs = OS
-
-	// Clean goroot: normalize path separator.
-	*goroot = filepath.Clean(*goroot)
-
 	// Check usage: either server and no args, or command line and args
 	if (*httpAddr != "") != (flag.NArg() == 0) {
 		usage()
@@ -239,6 +229,26 @@ func main() {
 		log.Fatalf("negative tabwidth %d", *tabwidth)
 	}
 
+	// Determine file system to use.
+	// TODO(gri) - fs and fsHttp should really be the same. Try to unify.
+	//           - fsHttp doesn't need to be set up in command-line mode,
+	//             same is true for the http handlers in initHandlers.
+	if *zipfile == "" {
+		// use file system of underlying OS
+		*goroot = filepath.Clean(*goroot) // normalize path separator
+		fs = OS
+		fsHttp = http.Dir(*goroot)
+	} else {
+		// use file system specified via .zip file (path separator must be '/')
+		rc, err := zip.OpenReader(*zipfile)
+		if err != nil {
+			log.Fatalf("%s: %s\n", *zipfile, err)
+		}
+		*goroot = path.Join("/", *goroot) // fsHttp paths are relative to '/'
+		fs = NewZipFS(rc)
+		fsHttp = NewHttpZipFS(rc, *goroot)
+	}
+
 	initHandlers()
 	readTemplates()
 
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
index 92614e8..51f23ab 100644
--- a/src/cmd/godoc/mapping.go
+++ b/src/cmd/godoc/mapping.go
@@ -15,7 +15,6 @@ import (
 	"strings"
 )
 
-
 // A Mapping object maps relative paths (e.g. from URLs)
 // to absolute paths (of the file system) and vice versa.
 //
@@ -52,13 +51,11 @@ type Mapping struct {
 	prefixes []string // lazily computed from list
 }
 
-
 type mapping struct {
 	prefix, path string
 	value        *RWValue
 }
 
-
 // Init initializes the Mapping from a list of paths.
 // Empty paths are ignored; relative paths are assumed to be relative to
 // the current working directory and converted to absolute paths.
@@ -93,11 +90,9 @@ func (m *Mapping) Init(paths []string) {
 	m.list = list
 }
 
-
 // IsEmpty returns true if there are no mappings specified.
 func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }
 
-
 // PrefixList returns a list of all prefixes, with duplicates removed.
 // For instance, for the mapping:
 //
@@ -137,7 +132,6 @@ func (m *Mapping) PrefixList() []string {
 	return m.prefixes
 }
 
-
 // Fprint prints the mapping.
 func (m *Mapping) Fprint(w io.Writer) {
 	for _, e := range m.list {
@@ -145,7 +139,6 @@ func (m *Mapping) Fprint(w io.Writer) {
 	}
 }
 
-
 func splitFirst(path string) (head, tail string) {
 	i := strings.Index(path, string(filepath.Separator))
 	if i > 0 {
@@ -155,7 +148,6 @@ func splitFirst(path string) (head, tail string) {
 	return "", path
 }
 
-
 // ToAbsolute maps a slash-separated relative path to an absolute filesystem
 // path using the Mapping specified by the receiver. If the path cannot
 // be mapped, the empty string is returned.
@@ -181,7 +173,6 @@ func (m *Mapping) ToAbsolute(spath string) string {
 	return "" // no match
 }
 
-
 // ToRelative maps an absolute filesystem path to a relative slash-separated
 // path using the Mapping specified by the receiver. If the path cannot
 // be mapped, the empty string is returned.
@@ -197,7 +188,6 @@ func (m *Mapping) ToRelative(fpath string) string {
 	return "" // no match
 }
 
-
 // Iterate calls f for each path and RWValue in the mapping (in uspecified order)
 // until f returns false.
 //
diff --git a/src/cmd/godoc/parser.go b/src/cmd/godoc/parser.go
index 423db22..da4b385 100644
--- a/src/cmd/godoc/parser.go
+++ b/src/cmd/godoc/parser.go
@@ -48,7 +48,6 @@ func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.P
 	return
 }
 
-
 func parseDir(fset *token.FileSet, path string, filter func(FileInfo) bool) (map[string]*ast.Package, os.Error) {
 	list, err := fs.ReadDir(path)
 	if err != nil {
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
index c5f4c1e..626b014 100755
--- a/src/cmd/godoc/snippet.go
+++ b/src/cmd/godoc/snippet.go
@@ -16,13 +16,11 @@ import (
 	"fmt"
 )
 
-
 type Snippet struct {
 	Line int
 	Text []byte
 }
 
-
 func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
 	// TODO instead of pretty-printing the node, should use the original source instead
 	var buf1 bytes.Buffer
@@ -35,7 +33,6 @@ func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
 	return &Snippet{fset.Position(id.Pos()).Line, buf2.Bytes()}
 }
 
-
 func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
 	for _, spec := range list {
 		switch s := spec.(type) {
@@ -58,7 +55,6 @@ func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
 	return nil
 }
 
-
 func genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
 	s := findSpec(d.Specs, id)
 	if s == nil {
@@ -71,7 +67,6 @@ func genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
 	return newSnippet(fset, dd, id)
 }
 
-
 func funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
 	if d.Name != id {
 		return nil //  declaration doesn't contain id - exit gracefully
@@ -83,7 +78,6 @@ func funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
 	return newSnippet(fset, dd, id)
 }
 
-
 // NewSnippet creates a text snippet from a declaration decl containing an
 // identifier id. Parts of the declaration not containing the identifier
 // may be removed for a more compact snippet.
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index 444e36e..3f69add 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -18,7 +18,6 @@ import (
 	"io"
 )
 
-
 type ebnfParser struct {
 	out     io.Writer   // parser output
 	src     []byte      // parser source
@@ -30,14 +29,12 @@ type ebnfParser struct {
 	lit     string      // token literal
 }
 
-
 func (p *ebnfParser) flush() {
 	offs := p.file.Offset(p.pos)
 	p.out.Write(p.src[p.prev:offs])
 	p.prev = offs
 }
 
-
 func (p *ebnfParser) next() {
 	if p.pos.IsValid() {
 		p.flush()
@@ -50,12 +47,10 @@ func (p *ebnfParser) next() {
 	}
 }
 
-
 func (p *ebnfParser) Error(pos token.Position, msg string) {
 	fmt.Fprintf(p.out, `<span class="alert">error: %s</span>`, msg)
 }
 
-
 func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
 	msg = "expected " + msg
 	if pos == p.pos {
@@ -69,7 +64,6 @@ func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
 	p.Error(p.file.Position(pos), msg)
 }
 
-
 func (p *ebnfParser) expect(tok token.Token) token.Pos {
 	pos := p.pos
 	if p.tok != tok {
@@ -79,7 +73,6 @@ func (p *ebnfParser) expect(tok token.Token) token.Pos {
 	return pos
 }
 
-
 func (p *ebnfParser) parseIdentifier(def bool) {
 	name := p.lit
 	p.expect(token.IDENT)
@@ -91,7 +84,6 @@ func (p *ebnfParser) parseIdentifier(def bool) {
 	p.prev += len(name) // skip identifier when calling flush
 }
 
-
 func (p *ebnfParser) parseTerm() bool {
 	switch p.tok {
 	case token.IDENT:
@@ -127,7 +119,6 @@ func (p *ebnfParser) parseTerm() bool {
 	return true
 }
 
-
 func (p *ebnfParser) parseSequence() {
 	if !p.parseTerm() {
 		p.errorExpected(p.pos, "term")
@@ -136,7 +127,6 @@ func (p *ebnfParser) parseSequence() {
 	}
 }
 
-
 func (p *ebnfParser) parseExpression() {
 	for {
 		p.parseSequence()
@@ -147,7 +137,6 @@ func (p *ebnfParser) parseExpression() {
 	}
 }
 
-
 func (p *ebnfParser) parseProduction() {
 	p.parseIdentifier(true)
 	p.expect(token.ASSIGN)
@@ -157,7 +146,6 @@ func (p *ebnfParser) parseProduction() {
 	p.expect(token.PERIOD)
 }
 
-
 func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
 	// initialize ebnfParser
 	p.out = out
@@ -173,14 +161,12 @@ func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
 	p.flush()
 }
 
-
 // Markers around EBNF sections
 var (
 	openTag  = []byte(`<pre class="ebnf">`)
 	closeTag = []byte(`</pre>`)
 )
 
-
 func linkify(out io.Writer, src []byte) {
 	fset := token.NewFileSet()
 	for len(src) > 0 {
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index e2637ab..11e46ae 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -18,7 +18,6 @@ import (
 	"utf8"
 )
 
-
 // An RWValue wraps a value and permits mutually exclusive
 // access to it and records the time the value was last set.
 //
@@ -28,7 +27,6 @@ type RWValue struct {
 	timestamp int64 // time of last set(), in seconds since epoch
 }
 
-
 func (v *RWValue) set(value interface{}) {
 	v.mutex.Lock()
 	v.value = value
@@ -36,14 +34,12 @@ func (v *RWValue) set(value interface{}) {
 	v.mutex.Unlock()
 }
 
-
 func (v *RWValue) get() (interface{}, int64) {
 	v.mutex.RLock()
 	defer v.mutex.RUnlock()
 	return v.value, v.timestamp
 }
 
-
 // TODO(gri) For now, using os.Getwd() is ok here since the functionality
 //           based on this code is not invoked for the appengine version,
 //           but this is fragile. Determine what the right thing to do is,
@@ -94,7 +90,6 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string {
 	return list[0:i]
 }
 
-
 // writeFileAtomically writes data to a temporary file and then
 // atomically renames that file to the file named by filename.
 //
@@ -115,7 +110,6 @@ func writeFileAtomically(filename string, data []byte) os.Error {
 	return os.Rename(f.Name(), filename)
 }
 
-
 // isText returns true if a significant prefix of s looks like correct UTF-8;
 // that is, if it is likely that s is human-readable text.
 //
@@ -129,7 +123,7 @@ func isText(s []byte) bool {
 			// last char may be incomplete - ignore
 			break
 		}
-		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
+		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' {
 			// decoding error or control character - not a text file
 			return false
 		}
@@ -137,7 +131,6 @@ func isText(s []byte) bool {
 	return true
 }
 
-
 // TODO(gri): Should have a mapping from extension to handler, eventually.
 
 // textExt[x] is true if the extension x indicates a text file, and false otherwise.
@@ -146,7 +139,6 @@ var textExt = map[string]bool{
 	".js":  false, // must be served raw
 }
 
-
 // isTextFile returns true if the file has a known extension indicating
 // a text file, or if a significant chunk of the specified file looks like
 // correct UTF-8; that is, if it is likely that the file contains human-
diff --git a/src/cmd/godoc/zip.go b/src/cmd/godoc/zip.go
new file mode 100644
index 0000000..27dc142
--- /dev/null
+++ b/src/cmd/godoc/zip.go
@@ -0,0 +1,207 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides an implementation of the FileSystem
+// interface based on the contents of a .zip file.
+//
+// Assumptions:
+//
+// - The file paths stored in the zip file must use a slash ('/') as path
+//   separator; and they must be relative (i.e., they must not start with
+//   a '/' - this is usually the case if the file was created w/o special
+//   options).
+// - The zip file system treats the file paths found in the zip internally
+//   like absolute paths w/o a leading '/'; i.e., the paths are considered
+//   relative to the root of the file system.
+// - All path arguments to file system methods must be absolute paths.
+
+package main
+
+import (
+	"archive/zip"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path"
+	"sort"
+	"strings"
+)
+
+// zipFI is the zip-file based implementation of FileInfo
+type zipFI struct {
+	name string    // directory-local name
+	file *zip.File // nil for a directory
+}
+
+func (fi zipFI) Name() string {
+	return fi.name
+}
+
+func (fi zipFI) Size() int64 {
+	if f := fi.file; f != nil {
+		return int64(f.UncompressedSize)
+	}
+	return 0 // directory
+}
+
+func (fi zipFI) Mtime_ns() int64 {
+	if f := fi.file; f != nil {
+		return f.Mtime_ns()
+	}
+	return 0 // directory has no modified time entry
+}
+
+func (fi zipFI) IsDirectory() bool {
+	return fi.file == nil
+}
+
+func (fi zipFI) IsRegular() bool {
+	return fi.file != nil
+}
+
+// zipFS is the zip-file based implementation of FileSystem
+type zipFS struct {
+	*zip.ReadCloser
+	list zipList
+}
+
+func (fs *zipFS) Close() os.Error {
+	fs.list = nil
+	return fs.ReadCloser.Close()
+}
+
+func zipPath(name string) string {
+	name = path.Clean(name)
+	if !path.IsAbs(name) {
+		panic(fmt.Sprintf("stat: not an absolute path: %s", name))
+	}
+	return name[1:] // strip leading '/'
+}
+
+func (fs *zipFS) stat(abspath string) (int, zipFI, os.Error) {
+	i, exact := fs.list.lookup(abspath)
+	if i < 0 {
+		// abspath has leading '/' stripped - print it explicitly
+		return -1, zipFI{}, fmt.Errorf("file not found: /%s", abspath)
+	}
+	_, name := path.Split(abspath)
+	var file *zip.File
+	if exact {
+		file = fs.list[i] // exact match found - must be a file
+	}
+	return i, zipFI{name, file}, nil
+}
+
+func (fs *zipFS) Open(abspath string) (io.ReadCloser, os.Error) {
+	_, fi, err := fs.stat(zipPath(abspath))
+	if err != nil {
+		return nil, err
+	}
+	if fi.IsDirectory() {
+		return nil, fmt.Errorf("Open: %s is a directory", abspath)
+	}
+	return fi.file.Open()
+}
+
+func (fs *zipFS) Lstat(abspath string) (FileInfo, os.Error) {
+	_, fi, err := fs.stat(zipPath(abspath))
+	return fi, err
+}
+
+func (fs *zipFS) Stat(abspath string) (FileInfo, os.Error) {
+	_, fi, err := fs.stat(zipPath(abspath))
+	return fi, err
+}
+
+func (fs *zipFS) ReadDir(abspath string) ([]FileInfo, os.Error) {
+	path := zipPath(abspath)
+	i, fi, err := fs.stat(path)
+	if err != nil {
+		return nil, err
+	}
+	if !fi.IsDirectory() {
+		return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
+	}
+
+	var list []FileInfo
+	dirname := path + "/"
+	prevname := ""
+	for _, e := range fs.list[i:] {
+		if !strings.HasPrefix(e.Name, dirname) {
+			break // not in the same directory anymore
+		}
+		name := e.Name[len(dirname):] // local name
+		file := e
+		if i := strings.IndexRune(name, '/'); i >= 0 {
+			// We infer directories from files in subdirectories.
+			// If we have x/y, return a directory entry for x.
+			name = name[0:i] // keep local directory name only
+			file = nil
+		}
+		// If we have x/y and x/z, don't return two directory entries for x.
+		// TODO(gri): It should be possible to do this more efficiently
+		// by determining the (fs.list) range of local directory entries
+		// (via two binary searches).
+		if name != prevname {
+			list = append(list, zipFI{name, file})
+			prevname = name
+		}
+	}
+
+	return list, nil
+}
+
+func (fs *zipFS) ReadFile(abspath string) ([]byte, os.Error) {
+	rc, err := fs.Open(abspath)
+	if err != nil {
+		return nil, err
+	}
+	return ioutil.ReadAll(rc)
+}
+
+func NewZipFS(rc *zip.ReadCloser) FileSystem {
+	list := make(zipList, len(rc.File))
+	copy(list, rc.File) // sort a copy of rc.File
+	sort.Sort(list)
+	return &zipFS{rc, list}
+}
+
+type zipList []*zip.File
+
+// zipList implements sort.Interface
+func (z zipList) Len() int           { return len(z) }
+func (z zipList) Less(i, j int) bool { return z[i].Name < z[j].Name }
+func (z zipList) Swap(i, j int)      { z[i], z[j] = z[j], z[i] }
+
+// lookup returns the smallest index of an entry with an exact match
+// for name, or an inexact match starting with name/. If there is no
+// such entry, the result is -1, false.
+func (z zipList) lookup(name string) (index int, exact bool) {
+	// look for exact match first (name comes before name/ in z)
+	i := sort.Search(len(z), func(i int) bool {
+		return name <= z[i].Name
+	})
+	if i < 0 {
+		return -1, false
+	}
+	if z[i].Name == name {
+		return i, true
+	}
+
+	// look for inexact match (must be in z[i:], if present)
+	z = z[i:]
+	name += "/"
+	j := sort.Search(len(z), func(i int) bool {
+		return name <= z[i].Name
+	})
+	if j < 0 {
+		return -1, false
+	}
+	if strings.HasPrefix(z[j].Name, name) {
+		return i + j, false
+	}
+
+	return -1, false
+}
diff --git a/src/cmd/gofix/oserrorstring.go b/src/cmd/gofix/oserrorstring.go
index 5e61ab9..db39ee9 100644
--- a/src/cmd/gofix/oserrorstring.go
+++ b/src/cmd/gofix/oserrorstring.go
@@ -62,7 +62,6 @@ func oserrorstring(f *ast.File) bool {
 	return fixed
 }
 
-
 // callExpr returns the call expression if x is a call to pkg.name with one argument;
 // otherwise it returns nil.
 func callExpr(x interface{}, pkg, name string) *ast.CallExpr {
diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/gofix/signal_test.go
index 2500e9c..4abba35 100644
--- a/src/cmd/gofix/signal_test.go
+++ b/src/cmd/gofix/signal_test.go
@@ -63,7 +63,6 @@ func f() {
 
 import "os"
 
-
 func f() {
 	var _ os.Error
 	_ = os.SIGHUP
@@ -86,7 +85,6 @@ func f() {
 
 import "os"
 
-
 func f() {
 	var _ os.Error
 	_ = os.SIGHUP
diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/gofix/sorthelpers.go
index 4d0bee6..4e89fa8 100644
--- a/src/cmd/gofix/sorthelpers.go
+++ b/src/cmd/gofix/sorthelpers.go
@@ -17,7 +17,6 @@ func init() {
 	})
 }
 
-
 func sorthelpers(f *ast.File) (fixed bool) {
 	if !imports(f, "sort") {
 		return
diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/gofix/sortslice.go
index b9c108b..7cfa169 100644
--- a/src/cmd/gofix/sortslice.go
+++ b/src/cmd/gofix/sortslice.go
@@ -20,7 +20,6 @@ http://codereview.appspot.com/4639041
 	})
 }
 
-
 func sortslice(f *ast.File) (fixed bool) {
 	if !imports(f, "sort") {
 		return
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.in b/src/cmd/gofix/testdata/reflect.asn1.go.in
index c531451..43128f6 100644
--- a/src/cmd/gofix/testdata/reflect.asn1.go.in
+++ b/src/cmd/gofix/testdata/reflect.asn1.go.in
@@ -198,7 +198,6 @@ func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
 // An Enumerated is represented as a plain int.
 type Enumerated int
 
-
 // FLAG
 
 // A Flag accepts any data and is set to true if present.
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.out b/src/cmd/gofix/testdata/reflect.asn1.go.out
index f5716f2..ba6224e 100644
--- a/src/cmd/gofix/testdata/reflect.asn1.go.out
+++ b/src/cmd/gofix/testdata/reflect.asn1.go.out
@@ -198,7 +198,6 @@ func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
 // An Enumerated is represented as a plain int.
 type Enumerated int
 
-
 // FLAG
 
 // A Flag accepts any data and is set to true if present.
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.in b/src/cmd/gofix/testdata/reflect.datafmt.go.in
index 46c4123..91f885f 100644
--- a/src/cmd/gofix/testdata/reflect.datafmt.go.in
+++ b/src/cmd/gofix/testdata/reflect.datafmt.go.in
@@ -211,7 +211,6 @@ import (
 	"runtime"
 )
 
-
 // ----------------------------------------------------------------------------
 // Format representation
 
@@ -228,13 +227,11 @@ import (
 //
 type Formatter func(state *State, value interface{}, ruleName string) bool
 
-
 // A FormatterMap is a set of custom formatters.
 // It maps a rule name to a formatter function.
 //
 type FormatterMap map[string]Formatter
 
-
 // A parsed format expression is built from the following nodes.
 //
 type (
@@ -269,13 +266,11 @@ type (
 	}
 )
 
-
 // A Format is the result of parsing a format specification.
 // The format may be applied repeatedly to format values.
 //
 type Format map[string]expr
 
-
 // ----------------------------------------------------------------------------
 // Formatting
 
@@ -293,7 +288,6 @@ type Environment interface {
 	Copy() Environment
 }
 
-
 // State represents the current formatting state.
 // It is provided as argument to custom formatters.
 //
@@ -309,7 +303,6 @@ type State struct {
 	separator expr           // possibly nil
 }
 
-
 func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	s := new(State)
 	s.fmt = fmt
@@ -330,17 +323,14 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	return s
 }
 
-
 // Env returns the environment passed to Format.Apply.
 func (s *State) Env() interface{} { return s.env }
 
-
 // LinePos returns the position of the current line beginning
 // in the state's output buffer. Line numbers start at 1.
 //
 func (s *State) LinePos() token.Position { return s.linePos }
 
-
 // Pos returns the position of the next byte to be written to the
 // output buffer. Line numbers start at 1.
 //
@@ -349,7 +339,6 @@ func (s *State) Pos() token.Position {
 	return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
 }
 
-
 // Write writes data to the output buffer, inserting the indentation
 // string after each newline or form feed character. It cannot return an error.
 //
@@ -371,7 +360,6 @@ func (s *State) Write(data []byte) (int, os.Error) {
 	return n + n3, nil
 }
 
-
 type checkpoint struct {
 	env       Environment
 	hasOutput bool
@@ -379,7 +367,6 @@ type checkpoint struct {
 	linePos   token.Position
 }
 
-
 func (s *State) save() checkpoint {
 	saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
 	if s.env != nil {
@@ -388,19 +375,16 @@ func (s *State) save() checkpoint {
 	return saved
 }
 
-
 func (s *State) restore(m checkpoint) {
 	s.env = m.env
 	s.output.Truncate(m.outputLen)
 }
 
-
 func (s *State) error(msg string) {
 	s.errors <- os.NewError(msg)
 	runtime.Goexit()
 }
 
-
 // TODO At the moment, unnamed types are simply mapped to the default
 //      names below. For instance, all unnamed arrays are mapped to
 //      'array' which is not really sufficient. Eventually one may want
@@ -440,7 +424,6 @@ func (s *State) getFormat(name string) expr {
 	return nil
 }
 
-
 // eval applies a format expression fexpr to a value. If the expression
 // evaluates internally to a non-nil []byte, that slice is appended to
 // the state's output buffer and eval returns true. Otherwise, eval
@@ -653,7 +636,6 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
 	return false
 }
 
-
 // Eval formats each argument according to the format
 // f and returns the resulting []byte and os.Error. If
 // an error occurred, the []byte contains the partially
@@ -688,7 +670,6 @@ func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
 	return s.output.Bytes(), err
 }
 
-
 // ----------------------------------------------------------------------------
 // Convenience functions
 
@@ -705,7 +686,6 @@ func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int,
 	return w.Write(data)
 }
 
-
 // Print formats each argument according to the format f
 // and writes to standard output. The result is the total
 // number of bytes written and an os.Error, if any.
@@ -714,7 +694,6 @@ func (f Format) Print(args ...interface{}) (int, os.Error) {
 	return f.Fprint(os.Stdout, nil, args...)
 }
 
-
 // Sprint formats each argument according to the format f
 // and returns the resulting string. If an error occurs
 // during formatting, the result string contains the
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.out b/src/cmd/gofix/testdata/reflect.datafmt.go.out
index bd7f5fd..fd44758 100644
--- a/src/cmd/gofix/testdata/reflect.datafmt.go.out
+++ b/src/cmd/gofix/testdata/reflect.datafmt.go.out
@@ -211,7 +211,6 @@ import (
 	"runtime"
 )
 
-
 // ----------------------------------------------------------------------------
 // Format representation
 
@@ -228,13 +227,11 @@ import (
 //
 type Formatter func(state *State, value interface{}, ruleName string) bool
 
-
 // A FormatterMap is a set of custom formatters.
 // It maps a rule name to a formatter function.
 //
 type FormatterMap map[string]Formatter
 
-
 // A parsed format expression is built from the following nodes.
 //
 type (
@@ -269,13 +266,11 @@ type (
 	}
 )
 
-
 // A Format is the result of parsing a format specification.
 // The format may be applied repeatedly to format values.
 //
 type Format map[string]expr
 
-
 // ----------------------------------------------------------------------------
 // Formatting
 
@@ -293,7 +288,6 @@ type Environment interface {
 	Copy() Environment
 }
 
-
 // State represents the current formatting state.
 // It is provided as argument to custom formatters.
 //
@@ -309,7 +303,6 @@ type State struct {
 	separator expr           // possibly nil
 }
 
-
 func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	s := new(State)
 	s.fmt = fmt
@@ -330,17 +323,14 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	return s
 }
 
-
 // Env returns the environment passed to Format.Apply.
 func (s *State) Env() interface{} { return s.env }
 
-
 // LinePos returns the position of the current line beginning
 // in the state's output buffer. Line numbers start at 1.
 //
 func (s *State) LinePos() token.Position { return s.linePos }
 
-
 // Pos returns the position of the next byte to be written to the
 // output buffer. Line numbers start at 1.
 //
@@ -349,7 +339,6 @@ func (s *State) Pos() token.Position {
 	return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
 }
 
-
 // Write writes data to the output buffer, inserting the indentation
 // string after each newline or form feed character. It cannot return an error.
 //
@@ -371,7 +360,6 @@ func (s *State) Write(data []byte) (int, os.Error) {
 	return n + n3, nil
 }
 
-
 type checkpoint struct {
 	env       Environment
 	hasOutput bool
@@ -379,7 +367,6 @@ type checkpoint struct {
 	linePos   token.Position
 }
 
-
 func (s *State) save() checkpoint {
 	saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
 	if s.env != nil {
@@ -388,19 +375,16 @@ func (s *State) save() checkpoint {
 	return saved
 }
 
-
 func (s *State) restore(m checkpoint) {
 	s.env = m.env
 	s.output.Truncate(m.outputLen)
 }
 
-
 func (s *State) error(msg string) {
 	s.errors <- os.NewError(msg)
 	runtime.Goexit()
 }
 
-
 // TODO At the moment, unnamed types are simply mapped to the default
 //      names below. For instance, all unnamed arrays are mapped to
 //      'array' which is not really sufficient. Eventually one may want
@@ -440,7 +424,6 @@ func (s *State) getFormat(name string) expr {
 	return nil
 }
 
-
 // eval applies a format expression fexpr to a value. If the expression
 // evaluates internally to a non-nil []byte, that slice is appended to
 // the state's output buffer and eval returns true. Otherwise, eval
@@ -653,7 +636,6 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
 	return false
 }
 
-
 // Eval formats each argument according to the format
 // f and returns the resulting []byte and os.Error. If
 // an error occurred, the []byte contains the partially
@@ -688,7 +670,6 @@ func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
 	return s.output.Bytes(), err
 }
 
-
 // ----------------------------------------------------------------------------
 // Convenience functions
 
@@ -705,7 +686,6 @@ func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int,
 	return w.Write(data)
 }
 
-
 // Print formats each argument according to the format f
 // and writes to standard output. The result is the total
 // number of bytes written and an os.Error, if any.
@@ -714,7 +694,6 @@ func (f Format) Print(args ...interface{}) (int, os.Error) {
 	return f.Fprint(os.Stdout, nil, args...)
 }
 
-
 // Sprint formats each argument according to the format f
 // and returns the resulting string. If an error occurs
 // during formatting, the result string contains the
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.in b/src/cmd/gofix/testdata/reflect.decode.go.in
index 501230c..f831abe 100644
--- a/src/cmd/gofix/testdata/reflect.decode.go.in
+++ b/src/cmd/gofix/testdata/reflect.decode.go.in
@@ -71,7 +71,6 @@ type Unmarshaler interface {
 	UnmarshalJSON([]byte) os.Error
 }
 
-
 // An UnmarshalTypeError describes a JSON value that was
 // not appropriate for a value of a specific Go type.
 type UnmarshalTypeError struct {
@@ -732,7 +731,6 @@ func (d *decodeState) objectInterface() map[string]interface{} {
 	return m
 }
 
-
 // literalInterface is like literal but returns an interface value.
 func (d *decodeState) literalInterface() interface{} {
 	// All bytes inside literal return scanContinue op code.
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.out b/src/cmd/gofix/testdata/reflect.decode.go.out
index feeb7b8..fb7910e 100644
--- a/src/cmd/gofix/testdata/reflect.decode.go.out
+++ b/src/cmd/gofix/testdata/reflect.decode.go.out
@@ -71,7 +71,6 @@ type Unmarshaler interface {
 	UnmarshalJSON([]byte) os.Error
 }
 
-
 // An UnmarshalTypeError describes a JSON value that was
 // not appropriate for a value of a specific Go type.
 type UnmarshalTypeError struct {
@@ -735,7 +734,6 @@ func (d *decodeState) objectInterface() map[string]interface{} {
 	return m
 }
 
-
 // literalInterface is like literal but returns an interface value.
 func (d *decodeState) literalInterface() interface{} {
 	// All bytes inside literal return scanContinue op code.
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.in b/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
index 5209c1a..3d9c312 100644
--- a/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
+++ b/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
@@ -117,7 +117,6 @@ type dnsRR interface {
 	Header() *dnsRR_Header
 }
 
-
 // Specific DNS RR formats for each query type.
 
 type dnsRR_CNAME struct {
@@ -645,7 +644,6 @@ type dnsMsg struct {
 	extra    []dnsRR
 }
 
-
 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
 	var dh dnsHeader
 
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out b/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
index 12e4c34..c777fe2 100644
--- a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
+++ b/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
@@ -117,7 +117,6 @@ type dnsRR interface {
 	Header() *dnsRR_Header
 }
 
-
 // Specific DNS RR formats for each query type.
 
 type dnsRR_CNAME struct {
@@ -645,7 +644,6 @@ type dnsMsg struct {
 	extra    []dnsRR
 }
 
-
 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
 	var dh dnsHeader
 
diff --git a/src/cmd/gofix/testdata/reflect.print.go.in b/src/cmd/gofix/testdata/reflect.print.go.in
index 194bcdb..cba1df2 100644
--- a/src/cmd/gofix/testdata/reflect.print.go.in
+++ b/src/cmd/gofix/testdata/reflect.print.go.in
@@ -252,7 +252,6 @@ func Sprintln(a ...interface{}) string {
 	return s
 }
 
-
 // Get the i'th arg of the struct value.
 // If the arg itself is an interface, return a value for
 // the thing inside the interface, not the interface itself.
diff --git a/src/cmd/gofix/testdata/reflect.print.go.out b/src/cmd/gofix/testdata/reflect.print.go.out
index 10379bd..b475a2a 100644
--- a/src/cmd/gofix/testdata/reflect.print.go.out
+++ b/src/cmd/gofix/testdata/reflect.print.go.out
@@ -252,7 +252,6 @@ func Sprintln(a ...interface{}) string {
 	return s
 }
 
-
 // Get the i'th arg of the struct value.
 // If the arg itself is an interface, return a value for
 // the thing inside the interface, not the interface itself.
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.in b/src/cmd/gofix/testdata/reflect.scan.go.in
index 36271a8..83650e6 100644
--- a/src/cmd/gofix/testdata/reflect.scan.go.in
+++ b/src/cmd/gofix/testdata/reflect.scan.go.in
@@ -324,7 +324,6 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
 	return
 }
 
-
 var ssFree = newCache(func() interface{} { return new(ss) })
 
 // Allocate a new ss struct or grab a cached one.
@@ -398,7 +397,6 @@ func (s *ss) skipSpace(stopAtNewline bool) {
 	}
 }
 
-
 // token returns the next space-delimited string from the input.  It
 // skips white space.  For Scanln, it stops at newlines.  For Scan,
 // newlines are treated as spaces.
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.out b/src/cmd/gofix/testdata/reflect.scan.go.out
index 2b07115..956c13b 100644
--- a/src/cmd/gofix/testdata/reflect.scan.go.out
+++ b/src/cmd/gofix/testdata/reflect.scan.go.out
@@ -324,7 +324,6 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
 	return
 }
 
-
 var ssFree = newCache(func() interface{} { return new(ss) })
 
 // Allocate a new ss struct or grab a cached one.
@@ -398,7 +397,6 @@ func (s *ss) skipSpace(stopAtNewline bool) {
 	}
 }
 
-
 // token returns the next space-delimited string from the input.  It
 // skips white space.  For Scanln, it stops at newlines.  For Scan,
 // newlines are treated as spaces.
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 1373b26..fca42b7 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -14,11 +14,12 @@ Usage:
 	gofmt [flags] [path ...]
 
 The flags are:
-
 	-d
 		Do not print reformatted sources to standard output.
 		If a file's formatting is different than gofmt's, print diffs
 		to standard output.
+	-e
+		Print all (including spurious) errors.
 	-l
 		Do not print reformatted sources to standard output.
 		If a file's formatting is different from gofmt's, print its name
@@ -31,6 +32,8 @@ The flags are:
 		Do not print reformatted sources to standard output.
 		If a file's formatting is different from gofmt's, overwrite it
 		with gofmt's version.
+
+Formatting control flags:
 	-comments=true
 		Print comments; if false, all comments are elided from the output.
 	-spaces
@@ -40,6 +43,7 @@ The flags are:
 	-tabwidth=8
 		Tab width in spaces.
 
+
 The rewrite rule specified with the -r flag must be a string of the form:
 
 	pattern -> replacement
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index ea1c1b0..975ae6a 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -22,7 +22,6 @@ import (
 	"strings"
 )
 
-
 var (
 	// main operation modes
 	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
@@ -30,6 +29,7 @@ var (
 	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
 	simplifyAST = flag.Bool("s", false, "simplify code")
 	doDiff      = flag.Bool("d", false, "display diffs instead of rewriting files")
+	allErrors   = flag.Bool("e", false, "print all (including spurious) errors")
 
 	// layout control
 	comments  = flag.Bool("comments", true, "print comments")
@@ -41,7 +41,6 @@ var (
 	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
 )
 
-
 var (
 	fset        = token.NewFileSet()
 	exitCode    = 0
@@ -50,28 +49,27 @@ var (
 	printerMode uint
 )
 
-
 func report(err os.Error) {
 	scanner.PrintError(os.Stderr, err)
 	exitCode = 2
 }
 
-
 func usage() {
 	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
 	flag.PrintDefaults()
 	os.Exit(2)
 }
 
-
 func initParserMode() {
 	parserMode = uint(0)
 	if *comments {
 		parserMode |= parser.ParseComments
 	}
+	if *allErrors {
+		parserMode |= parser.SpuriousErrors
+	}
 }
 
-
 func initPrinterMode() {
 	printerMode = uint(0)
 	if *tabIndent {
@@ -82,13 +80,11 @@ func initPrinterMode() {
 	}
 }
 
-
 func isGoFile(f *os.FileInfo) bool {
 	// ignore non-Go files
 	return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
 }
 
-
 // If in == nil, the source is the contents of the file with the given filename.
 func processFile(filename string, in io.Reader, out io.Writer) os.Error {
 	if in == nil {
@@ -153,14 +149,12 @@ func processFile(filename string, in io.Reader, out io.Writer) os.Error {
 	return err
 }
 
-
 type fileVisitor chan os.Error
 
 func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
 	return true
 }
 
-
 func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
 	if isGoFile(f) {
 		v <- nil // synchronize error handler
@@ -170,7 +164,6 @@ func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
 	}
 }
 
-
 func walkDir(path string) {
 	v := make(fileVisitor)
 	go func() {
@@ -184,7 +177,6 @@ func walkDir(path string) {
 	}
 }
 
-
 func main() {
 	// call gofmtMain in a separate function
 	// so that it can use defer and have them
@@ -193,7 +185,6 @@ func main() {
 	os.Exit(exitCode)
 }
 
-
 func gofmtMain() {
 	flag.Usage = usage
 	flag.Parse()
@@ -241,7 +232,6 @@ func gofmtMain() {
 	}
 }
 
-
 func diff(b1, b2 []byte) (data []byte, err os.Error) {
 	f1, err := ioutil.TempFile("", "gofmt")
 	if err != nil {
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index 7070055..2e35ce9 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -12,7 +12,6 @@ import (
 	"testing"
 )
 
-
 func runTest(t *testing.T, dirname, in, out, flags string) {
 	in = filepath.Join(dirname, in)
 	out = filepath.Join(dirname, out)
@@ -62,7 +61,6 @@ func runTest(t *testing.T, dirname, in, out, flags string) {
 	}
 }
 
-
 // TODO(gri) Add more test cases!
 var tests = []struct {
 	dirname, in, out, flags string
@@ -74,7 +72,6 @@ var tests = []struct {
 	{"testdata", "rewrite2.input", "rewrite2.golden", "-r=int->bool"},
 }
 
-
 func TestRewrite(t *testing.T) {
 	for _, test := range tests {
 		runTest(t, test.dirname, test.in, test.out, test.flags)
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index f7f1fe8..3d74dea 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -16,7 +16,6 @@ import (
 	"utf8"
 )
 
-
 func initRewrite() {
 	if *rewriteRule == "" {
 		rewrite = nil // disable any previous rewrite
@@ -32,7 +31,6 @@ func initRewrite() {
 	rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
 }
 
-
 // parseExpr parses s as an expression.
 // It might make sense to expand this to allow statement patterns,
 // but there are problems with preserving formatting and also
@@ -46,7 +44,6 @@ func parseExpr(s string, what string) ast.Expr {
 	return x
 }
 
-
 // Keep this function for debugging.
 /*
 func dump(msg string, val reflect.Value) {
@@ -56,7 +53,6 @@ func dump(msg string, val reflect.Value) {
 }
 */
 
-
 // rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
 func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
 	m := make(map[string]reflect.Value)
@@ -80,7 +76,6 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
 	return apply(f, reflect.ValueOf(p)).Interface().(*ast.File)
 }
 
-
 // setValue is a wrapper for x.SetValue(y); it protects
 // the caller from panics if x cannot be changed to y.
 func setValue(x, y reflect.Value) {
@@ -100,7 +95,6 @@ func setValue(x, y reflect.Value) {
 	x.Set(y)
 }
 
-
 // Values/types for special cases.
 var (
 	objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
@@ -112,7 +106,6 @@ var (
 	scopePtrType  = reflect.TypeOf((*ast.Scope)(nil))
 )
 
-
 // apply replaces each AST field x in val with f(x), returning val.
 // To avoid extra conversions, f operates on the reflect.Value form.
 func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
@@ -150,13 +143,11 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value
 	return val
 }
 
-
 func isWildcard(s string) bool {
 	rune, size := utf8.DecodeRuneInString(s)
 	return size == len(s) && unicode.IsLower(rune)
 }
 
-
 // match returns true if pattern matches val,
 // recording wildcard submatches in m.
 // If m == nil, match checks whether pattern == val.
@@ -238,7 +229,6 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
 	return p.Interface() == v.Interface()
 }
 
-
 // subst returns a copy of pattern with values from m substituted in place
 // of wildcards and pos used as the position of tokens from the pattern.
 // if m == nil, subst returns a copy of pattern and doesn't change the line
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
index 40a9f8f..d9afc0e 100644
--- a/src/cmd/gofmt/simplify.go
+++ b/src/cmd/gofmt/simplify.go
@@ -9,7 +9,6 @@ import (
 	"reflect"
 )
 
-
 type simplifier struct{}
 
 func (s *simplifier) Visit(node ast.Node) ast.Visitor {
@@ -60,7 +59,6 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
 	return s
 }
 
-
 func simplify(node ast.Node) {
 	var s simplifier
 	ast.Walk(&s, node)
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index a5df7b3..8260cb4 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -17,7 +17,6 @@ Flags and default settings:
 	-clean=false      clean the package directory before installing
 	-dashboard=true   tally public packages on godashboard.appspot.com
 	-install=true     build and install the package and its dependencies
-	-log=true         log installed packages to $GOROOT/goinstall.log for use by -a
 	-nuke=false       remove the target object and clean before installing
 	-u=false          update already-downloaded packages
 	-v=false          verbose operation
@@ -69,7 +68,10 @@ Goinstall recognizes packages from a few common code hosting sites:
 		import "github.com/user/project"
 		import "github.com/user/project/sub/directory"
 
-	Google Code Project Hosting (Mercurial, Subversion)
+	Google Code Project Hosting (Git, Mercurial, Subversion)
+
+		import "project.googlecode.com/git"
+		import "project.googlecode.com/git/sub/directory"
 
 		import "project.googlecode.com/hg"
 		import "project.googlecode.com/hg/sub/directory"
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index da892a6..3e9927c 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -97,6 +97,7 @@ var git = vcs{
 	protocols:         []string{"git", "https", "http"},
 	suffix:            ".git",
 	defaultHosts: []host{
+		{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/git)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
 		{regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"},
 	},
 }
@@ -148,9 +149,9 @@ type vcsMatch struct {
 	prefix, repo string
 }
 
-// findHostedRepo checks whether pkg is located at one of
+// findPublicRepo checks whether pkg is located at one of
 // the supported code hosting sites and, if so, returns a match.
-func findHostedRepo(pkg string) (*vcsMatch, os.Error) {
+func findPublicRepo(pkg string) (*vcsMatch, os.Error) {
 	for _, v := range vcsList {
 		for _, host := range v.defaultHosts {
 			if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
@@ -214,17 +215,17 @@ func isRemote(pkg string) bool {
 }
 
 // download checks out or updates pkg from the remote server.
-func download(pkg, srcDir string) (dashReport bool, err os.Error) {
+func download(pkg, srcDir string) (public bool, err os.Error) {
 	if strings.Contains(pkg, "..") {
 		err = os.NewError("invalid path (contains ..)")
 		return
 	}
-	m, err := findHostedRepo(pkg)
+	m, err := findPublicRepo(pkg)
 	if err != nil {
 		return
 	}
 	if m != nil {
-		dashReport = true // only report public code hosting sites
+		public = true
 	} else {
 		m, err = findAnyRepo(pkg)
 		if err != nil {
@@ -235,13 +236,7 @@ func download(pkg, srcDir string) (dashReport bool, err os.Error) {
 		err = os.NewError("cannot download: " + pkg)
 		return
 	}
-	installed, err := m.checkoutRepo(srcDir, m.prefix, m.repo)
-	if err != nil {
-		return
-	}
-	if !installed {
-		dashReport = false
-	}
+	err = m.checkoutRepo(srcDir, m.prefix, m.repo)
 	return
 }
 
@@ -266,41 +261,36 @@ func (v *vcs) updateRepo(dst string) os.Error {
 // exists and -u was specified on the command line)
 // the repository at tag/branch "release".  If there is no
 // such tag or branch, it falls back to the repository tip.
-func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) (installed bool, err os.Error) {
+func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) os.Error {
 	dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
 	dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
 	if err == nil && !dir.IsDirectory() {
-		err = os.NewError("not a directory: " + dst)
-		return
+		return os.NewError("not a directory: " + dst)
 	}
 	if err != nil {
 		parent, _ := filepath.Split(dst)
 		if err = os.MkdirAll(parent, 0777); err != nil {
-			return
+			return err
 		}
 		if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
-			return
-		}
-		if err = vcs.updateRepo(dst); err != nil {
-			return
+			return err
 		}
-		installed = true
-	} else if *update {
+		return vcs.updateRepo(dst)
+	}
+	if *update {
 		// Retrieve new revisions from the remote branch, if the VCS
 		// supports this operation independently (e.g. svn doesn't)
 		if vcs.pull != "" {
 			if vcs.pullForceFlag != "" {
 				if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
-					return
+					return err
 				}
 			} else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil {
-				return
+				return err
 			}
 		}
 		// Update to release or latest revision
-		if err = vcs.updateRepo(dst); err != nil {
-			return
-		}
+		return vcs.updateRepo(dst)
 	}
-	return
+	return nil
 }
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index 5cdf0f1..86e490e 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -14,6 +14,7 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strings"
 )
@@ -25,18 +26,19 @@ func usage() {
 	os.Exit(2)
 }
 
+const logfile = "goinstall.log"
+
 var (
 	fset          = token.NewFileSet()
 	argv0         = os.Args[0]
 	errors        = false
 	parents       = make(map[string]string)
 	visit         = make(map[string]status)
-	logfile       = filepath.Join(runtime.GOROOT(), "goinstall.log")
-	installedPkgs = make(map[string]bool)
+	installedPkgs = make(map[string]map[string]bool)
+	schemeRe      = regexp.MustCompile(`^[a-z]+://`)
 
 	allpkg            = flag.Bool("a", false, "install all previously installed packages")
 	reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
-	logPkgs           = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
 	update            = flag.Bool("u", false, "update already-downloaded packages")
 	doInstall         = flag.Bool("install", true, "build and install")
 	clean             = flag.Bool("clean", false, "clean the package directory before installing")
@@ -76,36 +78,35 @@ func main() {
 		fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0)
 		os.Exit(1)
 	}
+	readPackageList()
 
 	// special case - "unsafe" is already installed
 	visit["unsafe"] = done
 
 	args := flag.Args()
-	if *allpkg || *logPkgs {
-		readPackageList()
-	}
 	if *allpkg {
 		if len(args) != 0 {
 			usage() // -a and package list both provided
 		}
 		// install all packages that were ever installed
-		if len(installedPkgs) == 0 {
-			fmt.Fprintf(os.Stderr, "%s: no installed packages\n", argv0)
-			os.Exit(1)
+		n := 0
+		for _, pkgs := range installedPkgs {
+			for pkg := range pkgs {
+				args = append(args, pkg)
+				n++
+			}
 		}
-		args = make([]string, len(installedPkgs), len(installedPkgs))
-		i := 0
-		for pkg := range installedPkgs {
-			args[i] = pkg
-			i++
+		if n == 0 {
+			logf("no installed packages\n")
+			os.Exit(1)
 		}
 	}
 	if len(args) == 0 {
 		usage()
 	}
 	for _, path := range args {
-		if strings.HasPrefix(path, "http://") {
-			errorf("'http://' used in remote path, try '%s'\n", path[7:])
+		if s := schemeRe.FindString(path); s != "" {
+			errorf("%q used in import path, try %q\n", s, path[len(s):])
 			continue
 		}
 
@@ -127,27 +128,40 @@ func printDeps(pkg string) {
 	fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
 }
 
-// readPackageList reads the list of installed packages from goinstall.log
+// readPackageList reads the list of installed packages from the
+// goinstall.log files in GOROOT and the GOPATHs and initalizes
+// the installedPkgs variable.
 func readPackageList() {
-	pkglistdata, _ := ioutil.ReadFile(logfile)
-	pkglist := strings.Fields(string(pkglistdata))
-	for _, pkg := range pkglist {
-		installedPkgs[pkg] = true
+	for _, t := range build.Path {
+		installedPkgs[t.Path] = make(map[string]bool)
+		name := filepath.Join(t.Path, logfile)
+		pkglistdata, err := ioutil.ReadFile(name)
+		if err != nil {
+			printf("%s\n", err)
+			continue
+		}
+		pkglist := strings.Fields(string(pkglistdata))
+		for _, pkg := range pkglist {
+			installedPkgs[t.Path][pkg] = true
+		}
 	}
 }
 
-// logPackage logs the named package as installed in goinstall.log, if the package is not found in there
-func logPackage(pkg string) {
-	if installedPkgs[pkg] {
-		return
+// logPackage logs the named package as installed in the goinstall.log file
+// in the given tree if the package is not already in that file.
+func logPackage(pkg string, tree *build.Tree) (logged bool) {
+	if installedPkgs[tree.Path][pkg] {
+		return false
 	}
-	fout, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+	name := filepath.Join(tree.Path, logfile)
+	fout, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
 	if err != nil {
-		fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err)
-		return
+		logf("%s\n", err)
+		return false
 	}
 	fmt.Fprintf(fout, "%s\n", pkg)
 	fout.Close()
+	return true
 }
 
 // install installs the package named by path, which is needed by parent.
@@ -181,11 +195,10 @@ func install(pkg, parent string) {
 		return
 	}
 	// Download remote packages if not found or forced with -u flag.
-	remote := isRemote(pkg)
-	dashReport := false
+	remote, public := isRemote(pkg), false
 	if remote && (err == build.ErrNotFound || (err == nil && *update)) {
 		printf("%s: download\n", pkg)
-		dashReport, err = download(pkg, tree.SrcDir())
+		public, err = download(pkg, tree.SrcDir())
 	}
 	if err != nil {
 		errorf("%s: %v\n", pkg, err)
@@ -244,17 +257,19 @@ func install(pkg, parent string) {
 			}
 		}
 	}
-	if dashReport {
-		maybeReportToDashboard(pkg)
-	}
+
 	if remote {
-		// mark package as installed in $GOROOT/goinstall.log
-		logPackage(pkg)
+		// mark package as installed in goinstall.log
+		logged := logPackage(pkg, tree)
+
+		// report installation to the dashboard if this is the first
+		// install from a public repository.
+		if logged && public {
+			maybeReportToDashboard(pkg)
+		}
 	}
-	return
 }
 
-
 // Is this a standard package path?  strings container/vector etc.
 // Assume that if the first element has a dot, it's a domain name
 // and is not the standard package path.
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index 0fd9b02..25f79d6 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -8,11 +8,11 @@ package main
 
 import (
 	"bytes"
+	"exp/template"
 	"go/build"
 	"os"
 	"path/filepath"
 	"strings"
-	"template"
 )
 
 // domake builds the package in dir.
@@ -138,43 +138,38 @@ type makedata struct {
 	Imports   []string // gc/ld import paths
 }
 
-var makefileTemplate = template.MustParse(`
+var makefileTemplate = template.Must(template.New("Makefile").Parse(`
 include $(GOROOT)/src/Make.inc
 
-TARG={Targ}
-TARGDIR={TargDir}
+TARG={{.Targ}}
+TARGDIR={{.TargDir}}
 
-{.section GoFiles}
+{{with .GoFiles}}
 GOFILES=\
-{.repeated section @}
-	{@}\
-{.end}
+{{range .}}	{{.}}\
+{{end}}
 
-{.end}
-{.section OFiles}
+{{end}}
+{{with .OFiles}}
 OFILES=\
-{.repeated section @}
-	{@}\
-{.end}
+{{range .}}	{{.}}\
+{{end}}
 
-{.end}
-{.section CgoFiles}
+{{end}}
+{{with .CgoFiles}}
 CGOFILES=\
-{.repeated section @}
-	{@}\
-{.end}
+{{range .}}	{{.}}\
+{{end}}
 
-{.end}
-{.section CgoOFiles}
+{{end}}
+{{with .CgoOFiles}}
 CGO_OFILES=\
-{.repeated section @}
-	{@}\
-{.end}
+{{range .}}	{{.}}\
+{{end}}
 
-{.end}
-GCIMPORTS={.repeated section Imports}-I "{@}" {.end}
-LDIMPORTS={.repeated section Imports}-L "{@}" {.end}
+{{end}}
+GCIMPORTS={{range .Imports}}-I "{{.}}" {{end}}
+LDIMPORTS={{range .Imports}}-L "{{.}}" {{end}}
 
-include $(GOROOT)/src/Make.{Type}
-`,
-	nil)
+include $(GOROOT)/src/Make.{{.Type}}
+`))
diff --git a/src/cmd/gotry/gotry b/src/cmd/gotry/gotry
index 52c5d2d..3cc7a98 100755
--- a/src/cmd/gotry/gotry
+++ b/src/cmd/gotry/gotry
@@ -111,7 +111,8 @@ function getFunctions() {
 functions=$(getFunctions)
 
 # Write file to compile
-rm -f /tmp/$USER.try.go
+file="/tmp/$USER.try"
+rm -f "file.go"
 (
 cat <<'!'
 package main
@@ -159,9 +160,9 @@ var _ os.Error
 func toSlice(a ...interface{}) []interface{} { return a }
 !
 
-)>/tmp/$USER.try.go
+)>"$file.go"
 
-$GC -o /tmp/$USER.try.$O /tmp/$USER.try.go &&
-$GL -o /tmp/$USER.try /tmp/$USER.try.$O &&
-/tmp/$USER.try "_$@"
-rm -f /tmp/$USER.try /tmp/$USER.try.go /tmp/$USER.try.$O
+$GC -o "$file.$O" "$file.go" &&
+$GL -o "$file" "$file.$O" &&
+"$file" "_$@"
+rm -f "$file" "$file.go" "$file.$O"
diff --git a/src/cmd/gotype/doc.go b/src/cmd/gotype/doc.go
index ec4eb7c..1aa0faa 100644
--- a/src/cmd/gotype/doc.go
+++ b/src/cmd/gotype/doc.go
@@ -24,18 +24,20 @@ Usage:
 	gotype [flags] [path ...]
 
 The flags are:
+	-e
+		Print all (including spurious) errors.
 	-p pkgName
-		process only those files in package pkgName.
+		Process only those files in package pkgName.
 	-r
-		recursively process subdirectories.
+		Recursively process subdirectories.
 	-v
-		verbose mode.
+		Verbose mode.
 
 Debugging flags:
-	-trace
-		print parse trace (disables concurrent parsing).
 	-ast
-		print AST (disables concurrent parsing).
+		Print AST (disables concurrent parsing).
+	-trace
+		Print parse trace (disables concurrent parsing).
 
 
 Examples
diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go
index 501ead4..e5e9417 100644
--- a/src/cmd/gotype/gotype.go
+++ b/src/cmd/gotype/gotype.go
@@ -18,35 +18,31 @@ import (
 	"strings"
 )
 
-
 var (
 	// main operation modes
 	pkgName   = flag.String("p", "", "process only those files in package pkgName")
 	recursive = flag.Bool("r", false, "recursively process subdirectories")
 	verbose   = flag.Bool("v", false, "verbose mode")
+	allErrors = flag.Bool("e", false, "print all (including spurious) errors")
 
 	// debugging support
 	printTrace = flag.Bool("trace", false, "print parse trace")
 	printAST   = flag.Bool("ast", false, "print AST")
 )
 
-
 var exitCode = 0
 
-
 func usage() {
 	fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
 	flag.PrintDefaults()
 	os.Exit(2)
 }
 
-
 func report(err os.Error) {
 	scanner.PrintError(os.Stderr, err)
 	exitCode = 2
 }
 
-
 // parse returns the AST for the Go source src.
 // The filename is for error reporting only.
 // The result is nil if there were errors or if
@@ -73,6 +69,9 @@ func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
 
 	// parse entire file
 	mode := parser.DeclarationErrors
+	if *allErrors {
+		mode |= parser.SpuriousErrors
+	}
 	if *printTrace {
 		mode |= parser.Trace
 	}
@@ -88,7 +87,6 @@ func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
 	return file
 }
 
-
 func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
 	files = make(map[string]*ast.File)
 	src, err := ioutil.ReadAll(os.Stdin)
@@ -103,7 +101,6 @@ func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
 	return
 }
 
-
 func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
 	files = make(map[string]*ast.File)
 	for _, filename := range filenames {
@@ -123,13 +120,11 @@ func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.
 	return
 }
 
-
 func isGoFilename(filename string) bool {
 	// ignore non-Go files
 	return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
 }
 
-
 func processDirectory(dirname string) {
 	f, err := os.Open(dirname)
 	if err != nil {
@@ -148,7 +143,6 @@ func processDirectory(dirname string) {
 	processFiles(filenames, false)
 }
 
-
 func processFiles(filenames []string, allFiles bool) {
 	i := 0
 	for _, filename := range filenames {
@@ -170,7 +164,6 @@ func processFiles(filenames []string, allFiles bool) {
 	processPackage(fset, parseFiles(fset, filenames[0:i]))
 }
 
-
 func processPackage(fset *token.FileSet, files map[string]*ast.File) {
 	// make a package (resolve all identifiers)
 	pkg, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe)
@@ -184,7 +177,6 @@ func processPackage(fset *token.FileSet, files map[string]*ast.File) {
 	}
 }
 
-
 func main() {
 	flag.Usage = usage
 	flag.Parse()
diff --git a/src/cmd/gotype/gotype_test.go b/src/cmd/gotype/gotype_test.go
index 9c8f8f2..ad0bc89 100644
--- a/src/cmd/gotype/gotype_test.go
+++ b/src/cmd/gotype/gotype_test.go
@@ -10,7 +10,6 @@ import (
 	"testing"
 )
 
-
 func runTest(t *testing.T, path, pkg string) {
 	exitCode = 0
 	*pkgName = pkg
@@ -27,7 +26,6 @@ func runTest(t *testing.T, path, pkg string) {
 	}
 }
 
-
 var tests = []struct {
 	path string
 	pkg  string
@@ -44,7 +42,6 @@ var tests = []struct {
 	{filepath.Join(runtime.GOROOT(), "src/pkg/go/types"), "types"},
 }
 
-
 func Test(t *testing.T) {
 	for _, test := range tests {
 		runTest(t, test.path, test.pkg)
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
index 5b24d2f..98d3d5c 100644
--- a/src/cmd/govet/govet.go
+++ b/src/cmd/govet/govet.go
@@ -348,7 +348,6 @@ FlagLoop:
 	return
 }
 
-
 // checkPrint checks a call to an unformatted print routine such as Println.
 // The skip argument records how many arguments to ignore; that is,
 // call.Args[skip] is the first argument to be printed.
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
index 543f8b1..4815401 100644
--- a/src/cmd/goyacc/goyacc.go
+++ b/src/cmd/goyacc/goyacc.go
@@ -410,7 +410,7 @@ outer:
 					if t < NTBASE {
 						j = TYPE(toklev[t])
 						if j != 0 && j != ty {
-							errorf("type redeclaration of token ",
+							errorf("type redeclaration of token %s",
 								tokset[t].name)
 						} else {
 							toklev[t] = SETTYPE(toklev[t], ty)
@@ -1448,15 +1448,15 @@ func cpres() {
 
 func dumppres() {
 	for i := 0; i <= nnonter; i++ {
-		print("nonterm %d\n", i)
+		fmt.Printf("nonterm %d\n", i)
 		curres := pres[i]
 		for j := 0; j < len(curres); j++ {
-			print("\tproduction %d:", j)
+			fmt.Printf("\tproduction %d:", j)
 			prd := curres[j]
 			for k := 0; k < len(prd); k++ {
-				print(" %d", prd[k])
+				fmt.Printf(" %d", prd[k])
 			}
-			print("\n")
+			fmt.Print("\n")
 		}
 	}
 }
@@ -1550,7 +1550,7 @@ again:
 func dumpempty() {
 	for i := 0; i <= nnonter; i++ {
 		if pempty[i] == EMPTY {
-			print("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
+			fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
 		}
 	}
 }
@@ -2768,8 +2768,8 @@ func others() {
 		j = tokset[i].value
 		if j >= 0 && j < 256 {
 			if temp1[j] != 0 {
-				print("yacc bug -- cant have 2 different Ts with same value\n")
-				print("	%s and %s\n", tokset[i].name, tokset[temp1[j]].name)
+				fmt.Print("yacc bug -- cant have 2 different Ts with same value\n")
+				fmt.Printf("	%s and %s\n", tokset[i].name, tokset[temp1[j]].name)
 				nerrors++
 			}
 			temp1[j] = i
@@ -2792,8 +2792,8 @@ func others() {
 		j = tokset[i].value - PRIVATE
 		if j >= 0 && j < 256 {
 			if temp1[j] != 0 {
-				print("yacc bug -- cant have 2 different Ts with same value\n")
-				print("	%s and %s\n", tokset[i].name, tokset[temp1[j]].name)
+				fmt.Print("yacc bug -- cant have 2 different Ts with same value\n")
+				fmt.Printf("	%s and %s\n", tokset[i].name, tokset[temp1[j]].name)
 				nerrors++
 			}
 			temp1[j] = i
diff --git a/src/cmd/goyacc/units.y b/src/cmd/goyacc/units.y
index 06ce116..d9ef663 100644
--- a/src/cmd/goyacc/units.y
+++ b/src/cmd/goyacc/units.y
@@ -69,10 +69,10 @@ var vflag bool
 
 %union
 {
-	node	Node;
-	vvar	*Var;
-	numb	int;
-	vval	float64;
+	node	Node
+	vvar	*Var
+	numb	int
+	vval	float64
 }
 
 %type	<node>	prog expr expr0 expr1 expr2 expr3 expr4
@@ -84,42 +84,41 @@ var vflag bool
 prog:
 	':' VAR expr
 	{
-		var f int;
+		var f int
 
-		f = int($2.node.dim[0]);
-		$2.node = $3;
-		$2.node.dim[0] = 1;
+		f = int($2.node.dim[0])
+		$2.node = $3
+		$2.node.dim[0] = 1
 		if f != 0 {
-			Errorf("redefinition of %v", $2.name);
-		} else
-		if vflag {
-			fmt.Printf("%v\t%v\n", $2.name, &$2.node);
+			Errorf("redefinition of %v", $2.name)
+		} else if vflag {
+			fmt.Printf("%v\t%v\n", $2.name, &$2.node)
 		}
 	}
 |	':' VAR '#'
 	{
-		var f, i int;
+		var f, i int
 
 		for i=1; i<Ndim; i++ {
 			if fund[i] == nil {
-				break;
+				break
 			}
 		}
 		if i >= Ndim {
-			Errorf("too many dimensions");
-			i = Ndim-1;
+			Error("too many dimensions")
+			i = Ndim-1
 		}
-		fund[i] = $2;
+		fund[i] = $2
 
-		f = int($2.node.dim[0]);
-		$2.node = one;
-		$2.node.dim[0] = 1;
-		$2.node.dim[i] = 1;
+		f = int($2.node.dim[0])
+		$2.node = one
+		$2.node.dim[0] = 1
+		$2.node.dim[i] = 1
 		if f != 0 {
-			Errorf("redefinition of %v", $2.name);
+			Errorf("redefinition of %v", $2.name)
 		} else
 		if vflag {
-			fmt.Printf("%v\t#\n", $2.name);
+			fmt.Printf("%v\t#\n", $2.name)
 		}
 	}
 |	':'
@@ -127,65 +126,65 @@ prog:
 	}
 |	'?' expr
 	{
-		retnode1 = $2;
+		retnode1 = $2
 	}
 |	'?'
 	{
-		retnode1 = one;
+		retnode1 = one
 	}
 
 expr:
 	expr4
 |	expr '+' expr4
 	{
-		add(&$$, &$1, &$3);
+		add(&$$, &$1, &$3)
 	}
 |	expr '-' expr4
 	{
-		sub(&$$, &$1, &$3);
+		sub(&$$, &$1, &$3)
 	}
 
 expr4:
 	expr3
 |	expr4 '*' expr3
 	{
-		mul(&$$, &$1, &$3);
+		mul(&$$, &$1, &$3)
 	}
 |	expr4 '/' expr3
 	{
-		div(&$$, &$1, &$3);
+		div(&$$, &$1, &$3)
 	}
 
 expr3:
 	expr2
 |	expr3 expr2
 	{
-		mul(&$$, &$1, &$2);
+		mul(&$$, &$1, &$2)
 	}
 
 expr2:
 	expr1
 |	expr2 SUP
 	{
-		xpn(&$$, &$1, $2);
+		xpn(&$$, &$1, $2)
 	}
 |	expr2 '^' expr1
 	{
-		var i int;
+		var i int
 
 		for i=1; i<Ndim; i++ {
 			if $3.dim[i] != 0 {
-				Errorf("exponent has units");
-				$$ = $1;
-				break;
+				Error("exponent has units")
+				$$ = $1
+				break
 			}
 		}
 		if i >= Ndim {
-			i = int($3.vval);
+			i = int($3.vval)
 			if float64(i) != $3.vval {
-				Errorf("exponent not integral");
+				Error("exponent not integral")
 			}
-			xpn(&$$, &$1, i);
+			xpn(&$$, &$1, i)
 		}
 	}
 
@@ -193,26 +192,27 @@ expr1:
 	expr0
 |	expr1 '|' expr0
 	{
-		div(&$$, &$1, &$3);
+		div(&$$, &$1, &$3)
 	}
 
 expr0:
 	VAR
 	{
 		if $1.node.dim[0] == 0 {
-			Errorf("undefined %v", $1.name);
-			$$ = one;
-		} else
-			$$ = $1.node;
+			Errorf("undefined %v", $1.name)
+			$$ = one
+		} else {
+			$$ = $1.node
+		}
 	}
 |	VAL
 	{
-		$$ = one;
-		$$.vval = $1;
+		$$ = one
+		$$.vval = $1
 	}
 |	'(' expr ')'
 	{
-		$$ = $2;
+		$$ = $2
 	}
 %%
 
@@ -403,6 +403,10 @@ func Errorf(s string, v ...interface{}) {
 	}
 }
 
+func Error(s string) {
+	Errorf("%s", s)
+}
+
 func add(c, a, b *Node) {
 	var i int
 	var d int8
@@ -411,7 +415,7 @@ func add(c, a, b *Node) {
 		d = a.dim[i]
 		c.dim[i] = d
 		if d != b.dim[i] {
-			Errorf("add must be like units")
+			Error("add must be like units")
 		}
 	}
 	c.vval = fadd(a.vval, b.vval)
@@ -425,7 +429,7 @@ func sub(c, a, b *Node) {
 		d = a.dim[i]
 		c.dim[i] = d
 		if d != b.dim[i] {
-			Errorf("sub must be like units")
+			Error("sub must be like units")
 		}
 	}
 	c.vval = fadd(a.vval, -b.vval)
@@ -633,29 +637,29 @@ type Prefix struct {
 }
 
 var prefix = []Prefix{ // prefix table
-	Prefix{1e-24, "yocto"},
-	Prefix{1e-21, "zepto"},
-	Prefix{1e-18, "atto"},
-	Prefix{1e-15, "femto"},
-	Prefix{1e-12, "pico"},
-	Prefix{1e-9, "nano"},
-	Prefix{1e-6, "micro"},
-	Prefix{1e-6, "μ"},
-	Prefix{1e-3, "milli"},
-	Prefix{1e-2, "centi"},
-	Prefix{1e-1, "deci"},
-	Prefix{1e1, "deka"},
-	Prefix{1e2, "hecta"},
-	Prefix{1e2, "hecto"},
-	Prefix{1e3, "kilo"},
-	Prefix{1e6, "mega"},
-	Prefix{1e6, "meg"},
-	Prefix{1e9, "giga"},
-	Prefix{1e12, "tera"},
-	Prefix{1e15, "peta"},
-	Prefix{1e18, "exa"},
-	Prefix{1e21, "zetta"},
-	Prefix{1e24, "yotta"},
+	{1e-24, "yocto"},
+	{1e-21, "zepto"},
+	{1e-18, "atto"},
+	{1e-15, "femto"},
+	{1e-12, "pico"},
+	{1e-9, "nano"},
+	{1e-6, "micro"},
+	{1e-6, "μ"},
+	{1e-3, "milli"},
+	{1e-2, "centi"},
+	{1e-1, "deci"},
+	{1e1, "deka"},
+	{1e2, "hecta"},
+	{1e2, "hecto"},
+	{1e3, "kilo"},
+	{1e6, "mega"},
+	{1e6, "meg"},
+	{1e9, "giga"},
+	{1e12, "tera"},
+	{1e15, "peta"},
+	{1e18, "exa"},
+	{1e21, "zetta"},
+	{1e24, "yotta"},
 }
 
 func pname() float64 {
@@ -711,11 +715,11 @@ func fmul(a, b float64) float64 {
 	}
 
 	if l > Maxe {
-		Errorf("overflow in multiply")
+		Error("overflow in multiply")
 		return 1
 	}
 	if l < -Maxe {
-		Errorf("underflow in multiply")
+		Error("underflow in multiply")
 		return 0
 	}
 	return a * b
@@ -746,11 +750,11 @@ func fdiv(a, b float64) float64 {
 	}
 
 	if l < -Maxe {
-		Errorf("overflow in divide")
+		Error("overflow in divide")
 		return 1
 	}
 	if l > Maxe {
-		Errorf("underflow in divide")
+		Error("underflow in divide")
 		return 0
 	}
 	return a / b
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index 4f7aec2..9e338ab 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -182,7 +182,6 @@ func main() {
 	}
 }
 
-
 // make parent directory for name, if necessary
 func makeParent(name string) {
 	parent, _ := filepath.Split(name)
@@ -240,7 +239,6 @@ func chk(err os.Error) {
 	}
 }
 
-
 // Undo log
 type undo func() os.Error
 
@@ -258,7 +256,6 @@ func runUndo() {
 	}
 }
 
-
 // hgRoot returns the root directory of the repository.
 func hgRoot() (string, os.Error) {
 	out, err := run([]string{"hg", "root"}, nil)
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index f1132fc..974c087 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -36,6 +36,7 @@
 #include	"../ld/pe.h"
 
 void	dynreloc(void);
+static vlong addaddrplus4(Sym *s, Sym *t, int32 add);
 
 /*
  * divide-and-conquer list-link
@@ -255,11 +256,19 @@ dynrelocsym(Sym *s)
 				r->add = targ->plt;
 				
 				// jmp *addr
-				adduint8(rel, 0xff);
-				adduint8(rel, 0x25);
-				addaddr(rel, targ);
-				adduint8(rel, 0x90);
-				adduint8(rel, 0x90);
+				if(thechar == '8') {
+					adduint8(rel, 0xff);
+					adduint8(rel, 0x25);
+					addaddr(rel, targ);
+					adduint8(rel, 0x90);
+					adduint8(rel, 0x90);
+				} else {
+					adduint8(rel, 0xff);
+					adduint8(rel, 0x24);
+					adduint8(rel, 0x25);
+					addaddrplus4(rel, targ, 0);
+					adduint8(rel, 0x90);
+				}
 			} else if(r->sym->plt >= 0) {
 				r->sym = rel;
 				r->add = targ->plt;
@@ -451,7 +460,7 @@ codeblk(int32 addr, int32 size)
 	uchar *q;
 
 	if(debug['a'])
-		Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
+		Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
 
 	blk(textp, addr, size);
 
@@ -503,7 +512,7 @@ codeblk(int32 addr, int32 size)
 				epc = p->link->pc;
 			else
 				epc = sym->value + sym->size;
-			Bprint(&bso, "%.6ux\t", p->pc);
+			Bprint(&bso, "%.6llux\t", (uvlong)p->pc);
 			q = sym->p + p->pc - sym->value;
 			n = epc - p->pc;
 			Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p);
@@ -527,7 +536,7 @@ datblk(int32 addr, int32 size)
 	uchar *p, *ep;
 
 	if(debug['a'])
-		Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
+		Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
 
 	blk(datap, addr, size);
 
@@ -679,6 +688,27 @@ addaddrplus(Sym *s, Sym *t, int32 add)
 }
 
 vlong
+addaddrplus4(Sym *s, Sym *t, int32 add)
+{
+	vlong i;
+	Reloc *r;
+
+	if(s->type == 0)
+		s->type = SDATA;
+	s->reachable = 1;
+	i = s->size;
+	s->size += 4;
+	symgrow(s, s->size);
+	r = addrel(s);
+	r->sym = t;
+	r->off = i;
+	r->siz = 4;
+	r->type = D_ADDR;
+	r->add = add;
+	return i;
+}
+
+vlong
 addpcrelplus(Sym *s, Sym *t, int32 add)
 {
 	vlong i;
@@ -791,9 +821,8 @@ dodata(void)
 	s = datap;
 	for(; s != nil && s->type < SSYMTAB; s = s->next) {
 		s->type = SRODATA;
-		t = rnd(s->size, PtrSize);
 		s->value = datsize;
-		datsize += t;
+		datsize += rnd(s->size, PtrSize);
 	}
 	sect->len = datsize - sect->vaddr;
 
@@ -806,21 +835,43 @@ dodata(void)
 		datsize += s->size;
 	}
 	sect->len = datsize - sect->vaddr;
+	datsize = rnd(datsize, PtrSize);
 
 	/* gopclntab */
 	sect = addsection(&segtext, ".gopclntab", 04);
 	sect->vaddr = datsize;
-	for(; s != nil && s->type < SDATA; s = s->next) {
+	for(; s != nil && s->type < SELFROSECT; s = s->next) {
 		s->type = SRODATA;
 		s->value = datsize;
 		datsize += s->size;
 	}
 	sect->len = datsize - sect->vaddr;
+	datsize = rnd(datsize, PtrSize);
 
-	/* data */
+	/* read-only ELF sections */
+	for(; s != nil && s->type < SELFSECT; s = s->next) {
+		sect = addsection(&segtext, s->name, 04);
+		sect->vaddr = datsize;
+		s->type = SRODATA;
+		s->value = datsize;
+		datsize += rnd(s->size, PtrSize);
+		sect->len = datsize - sect->vaddr;
+	}
+
+	/* writable ELF sections */
 	datsize = 0;
+	for(; s != nil && s->type < SDATA; s = s->next) {
+		sect = addsection(&segdata, s->name, 06);
+		sect->vaddr = datsize;
+		s->type = SDATA;
+		s->value = datsize;
+		datsize += rnd(s->size, PtrSize);
+		sect->len = datsize - sect->vaddr;
+	}
+
+	/* data */
 	sect = addsection(&segdata, ".data", 06);
-	sect->vaddr = 0;
+	sect->vaddr = datsize;
 	for(; s != nil && s->type < SBSS; s = s->next) {
 		s->type = SDATA;
 		t = s->size;
@@ -920,38 +971,43 @@ address(void)
 	segtext.fileoff = HEADR;
 	for(s=segtext.sect; s != nil; s=s->next) {
 		s->vaddr = va;
-		va += s->len;
-		segtext.len = va - INITTEXT;
-		va = rnd(va, INITRND);
+		va += rnd(s->len, PtrSize);
 	}
+	segtext.len = va - INITTEXT;
 	segtext.filelen = segtext.len;
 
+	va = rnd(va, INITRND);
+
 	segdata.rwx = 06;
 	segdata.vaddr = va;
 	segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
+	segdata.filelen = 0;
 	if(HEADTYPE == Hwindows)
 		segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
 	if(HEADTYPE == Hplan9x32)
 		segdata.fileoff = segtext.fileoff + segtext.filelen;
+	data = nil;
 	for(s=segdata.sect; s != nil; s=s->next) {
 		s->vaddr = va;
 		va += s->len;
+		segdata.filelen += s->len;
 		segdata.len = va - segdata.vaddr;
+		if(strcmp(s->name, ".data") == 0)
+			data = s;
 	}
-	segdata.filelen = segdata.sect->len;	// assume .data is first
-	
+	segdata.filelen -= data->next->len; // deduct .bss
+
 	text = segtext.sect;
 	rodata = text->next;
 	symtab = rodata->next;
 	pclntab = symtab->next;
-	data = segdata.sect;
 
 	for(sym = datap; sym != nil; sym = sym->next) {
 		cursym = sym;
 		if(sym->type < SDATA)
 			sym->value += rodata->vaddr;
 		else
-			sym->value += data->vaddr;
+			sym->value += segdata.sect->vaddr;
 		for(sub = sym->sub; sub != nil; sub = sub->sub)
 			sub->value += sym->value;
 	}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 1c10dc7..d8ca27a 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -1209,7 +1209,7 @@ copychildren(DWDie *dst, DWDie *src)
 }
 
 // Search children (assumed to have DW_TAG_member) for the one named
-// field and set it's DW_AT_type to dwtype
+// field and set its DW_AT_type to dwtype
 static void
 substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
 {
@@ -1422,7 +1422,6 @@ synthesizechantypes(DWDie *die)
 		copychildren(dwh, hchan);
 		substitutetype(dwh, "recvq", dww);
 		substitutetype(dwh, "sendq", dww);
-		substitutetype(dwh, "free", defptrto(dws));
 		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
 			getattr(hchan, DW_AT_byte_size)->value, nil);
 
@@ -1698,7 +1697,7 @@ inithist(Auto *a)
 			// We could just fixup the current
 			// linehist->line, but there doesn't appear to
 			// be a guarantee that every 'Z' is preceded
-			// by it's own 'z', so do the safe thing and
+			// by its own 'z', so do the safe thing and
 			// update the stack and push a new Linehist
 			// entry
 			includestack[includetop].line =	 a->aoffset;
@@ -1816,15 +1815,13 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
 		cput(0);  // start extended opcode
 		uleb128put(1);
 		cput(DW_LNE_end_sequence);
-		cflush();
 
 		here = cpos();
-		seek(cout, unitstart, 0);
+		cseek(unitstart);
 		LPUT(here - unitstart - sizeof(int32));	 // unit_length
 		WPUT(3);  // dwarf version
 		LPUT(header_length); // header length starting here
-		cflush();
-		seek(cout, here, 0);
+		cseek(here);
 	}
 }
 
@@ -2105,17 +2102,14 @@ writeframes(void)
 		pad = rnd(fdesize, PtrSize) - fdesize;
 		strnput("", pad);
 		fdesize += pad;
-		cflush();
 
 		// Emit the FDE header for real, Section 6.4.1.
-		seek(cout, fdeo, 0);
+		cseek(fdeo);
 		LPUT(fdesize);
 		LPUT(0);
 		addrput(p->pc);
 		addrput(s->size);
-
-		cflush();
-		seek(cout, fdeo + 4 + fdesize, 0);
+		cseek(fdeo + 4 + fdesize);
 	}
 
 	cflush();
@@ -2151,14 +2145,12 @@ writeinfo(void)
 
 		putdie(compunit);
 
-		cflush();
 		here = cpos();
-		seek(cout, unitstart, 0);
+		cseek(unitstart);
 		LPUT(here - unitstart - 4);	// exclude the length field.
-		cflush();
-		seek(cout, here, 0);
+		cseek(here);
 	}
-
+	cflush();
 }
 
 /*
@@ -2213,12 +2205,10 @@ writepub(int (*ispub)(DWDie*))
 		}
 		LPUT(0);
 
-		cflush();
 		here = cpos();
-		seek(cout, sectionstart, 0);
+		cseek(sectionstart);
 		LPUT(here - sectionstart - 4);	// exclude the length field.
-		cflush();
-		seek(cout, here, 0);
+		cseek(here);
 
 	}
 
@@ -2358,7 +2348,7 @@ dwarfemitdebugsections(void)
 	if (fwdcount > 0) {
 		if (debug['v'])
 			Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
-		seek(cout, infoo, 0);
+		cseek(infoo);
 		writeinfo();
 		if (fwdcount > 0) {
 			diag("dwarf: unresolved references after first dwarf info pass");
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index fc917b2..f9f9ef6 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -308,13 +308,13 @@ int
 elfwriteinterp(void)
 {
 	int n;
-	
+
 	if(interp == nil)
 		return 0;
 
 	n = strlen(interp)+1;
-	seek(cout, ELFRESERVE-n, 0);
-	ewrite(cout, interp, n);
+	cseek(ELFRESERVE-n);
+	cwrite(interp, n);
 	return n;
 }
 
@@ -322,7 +322,7 @@ void
 elfinterp(ElfShdr *sh, uint64 startva, char *p)
 {
 	int n;
-	
+
 	interp = p;
 	n = strlen(interp)+1;
 	sh->addr = startva + ELFRESERVE - n;
@@ -393,7 +393,7 @@ elfdynhash(void)
 
 	nsym = nelfsym;
 	s = lookup(".hash", 0);
-	s->type = SELFDATA;
+	s->type = SELFROSECT;
 	s->reachable = 1;
 
 	i = nsym;
@@ -539,6 +539,12 @@ elfshbits(Section *sect)
 	return nil;
 
 found:
+	for(i=0; i<hdr.shnum; i++) {
+		sh = shdr[i];
+		if(sh->name == off)
+			return sh;
+	}
+
 	sh = newElfShdr(off);
 	if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
 		sh->type = SHT_PROGBITS;
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 05d1cc1..cc0262f 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -32,6 +32,7 @@ enum {
 };
 static Import *ihash[NIHASH];
 static int nimport;
+static void imported(char *pkg, char *import);
 
 static int
 hashstr(char *name)
@@ -308,12 +309,23 @@ loop:
 		p += 6;
 	else if(strncmp(p, "import ", 7) == 0) {
 		p += 7;
+		while(p < ep && *p != ' ')
+			p++;
+		p++;
+		name = p;
 		while(p < ep && *p != '\n')
 			p++;
+		if(p >= ep) {
+			fprint(2, "%s: %s: confused in import line\n", argv0, file);
+			nerrors++;
+			return -1;
+		}
+		*p++ = '\0';
+		imported(pkg, name);
 		goto loop;
 	}
 	else {
-		fprint(2, "%s: confused in pkg data near <<%.40s>>\n", argv0, prefix);
+		fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix);
 		nerrors++;
 		return -1;
 	}
@@ -708,3 +720,147 @@ addexport(void)
 	for(i=0; i<ndynexp; i++)
 		adddynsym(dynexp[i]);
 }
+
+/* %Z from gc, for quoting import paths */
+int
+Zconv(Fmt *fp)
+{
+	Rune r;
+	char *s, *se;
+	int n;
+
+	s = va_arg(fp->args, char*);
+	if(s == nil)
+		return fmtstrcpy(fp, "<nil>");
+
+	se = s + strlen(s);
+	while(s < se) {
+		n = chartorune(&r, s);
+		s += n;
+		switch(r) {
+		case Runeerror:
+			if(n == 1) {
+				fmtprint(fp, "\\x%02x", (uchar)*(s-1));
+				break;
+			}
+			// fall through
+		default:
+			if(r < ' ') {
+				fmtprint(fp, "\\x%02x", r);
+				break;
+			}
+			fmtrune(fp, r);
+			break;
+		case '\t':
+			fmtstrcpy(fp, "\\t");
+			break;
+		case '\n':
+			fmtstrcpy(fp, "\\n");
+			break;
+		case '\"':
+		case '\\':
+			fmtrune(fp, '\\');
+			fmtrune(fp, r);
+			break;
+		}
+	}
+	return 0;
+}
+
+
+typedef struct Pkg Pkg;
+struct Pkg
+{
+	uchar mark;
+	uchar checked;
+	Pkg *next;
+	char *path;
+	Pkg **impby;
+	int nimpby;
+	int mimpby;
+	Pkg *all;
+};
+
+static Pkg *phash[1024];
+static Pkg *pkgall;
+
+static Pkg*
+getpkg(char *path)
+{
+	Pkg *p;
+	int h;
+	
+	h = hashstr(path) % nelem(phash);
+	for(p=phash[h]; p; p=p->next)
+		if(strcmp(p->path, path) == 0)
+			return p;
+	p = mal(sizeof *p);
+	p->path = strdup(path);
+	p->next = phash[h];
+	phash[h] = p;
+	p->all = pkgall;
+	pkgall = p;
+	return p;
+}
+
+static void
+imported(char *pkg, char *import)
+{
+	Pkg *p, *i;
+	
+	// everyone imports runtime, even runtime.
+	if(strcmp(import, "\"runtime\"") == 0)
+		return;
+
+	pkg = smprint("\"%Z\"", pkg);  // turn pkg path into quoted form, freed below
+	p = getpkg(pkg);
+	i = getpkg(import);
+	if(i->nimpby >= i->mimpby) {
+		i->mimpby *= 2;
+		if(i->mimpby == 0)
+			i->mimpby = 16;
+		i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]);
+	}
+	i->impby[i->nimpby++] = p;
+	free(pkg);
+}
+
+static Pkg*
+cycle(Pkg *p)
+{
+	int i;
+	Pkg *bad;
+
+	if(p->checked)
+		return 0;
+
+	if(p->mark) {
+		nerrors++;
+		print("import cycle:\n");
+		print("\t%s\n", p->path);
+		return p;
+	}
+	p->mark = 1;
+	for(i=0; i<p->nimpby; i++) {
+		if((bad = cycle(p->impby[i])) != nil) {
+			p->mark = 0;
+			p->checked = 1;
+			print("\timports %s\n", p->path);
+			if(bad == p)
+				return nil;
+			return bad;
+		}
+	}
+	p->checked = 1;
+	p->mark = 0;
+	return 0;
+}
+
+void
+importcycles(void)
+{
+	Pkg *p;
+	
+	for(p=pkgall; p; p=p->all)
+		cycle(p);
+}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 8334e98..9246878 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -398,13 +398,13 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
 		goto bad;
 
 	if(e->e16(hdr->type) != ElfTypeRelocatable) {
-		diag("%s: elf but not elf relocatable object");
+		diag("%s: elf but not elf relocatable object", pn);
 		return;
 	}
 
 	switch(thechar) {
 	default:
-		diag("%s: elf %s unimplemented", thestring);
+		diag("%s: elf %s unimplemented", pn, thestring);
 		return;
 	case '5':
 		if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index abbc3b3..3888487 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -480,7 +480,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
 	
 	switch(thechar) {
 	default:
-		diag("%s: mach-o %s unimplemented", thestring);
+		diag("%s: mach-o %s unimplemented", pn, thestring);
 		return;
 	case '6':
 		if(e != &le || m->cputype != MachoCpuAmd64) {
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 98c866f..6805570 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -73,6 +73,24 @@
 #define IMAGE_REL_I386_SECREL7	0x000D
 #define IMAGE_REL_I386_REL32	0x0014
 
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001 // R_X86_64_64
+#define IMAGE_REL_AMD64_ADDR32 0x0002 // R_X86_64_PC32
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004 
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
 typedef struct PeSym PeSym;
 typedef struct PeSect PeSect;
 typedef struct PeObj PeObj;
@@ -204,6 +222,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
 				s->type = SRODATA;
 				break;
 			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
+				s->type = SBSS;
+				break;
 			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
 				s->type = SDATA;
 				break;
@@ -261,6 +281,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
 				default:
 					diag("%s: unknown relocation type %d;", pn, type);
 				case IMAGE_REL_I386_REL32:
+				case IMAGE_REL_AMD64_REL32:
 					rp->type = D_PCREL;
 					rp->add = 0;
 					break;
@@ -270,6 +291,16 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
 					// load addend from image
 					rp->add = le32(rsect->base+rp->off);
 					break;
+				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
+					rp->type = D_PCREL;
+					rp->add += 4;
+					break;
+				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
+					rp->siz = 8;
+					rp->type = D_ADDR;
+					// load addend from image
+					rp->add = le64(rsect->base+rp->off);
+					break;
 			}
 		}
 		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
@@ -280,8 +311,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
 	}
 	
 	// enter sub-symbols into symbol table.
-	// frist 2 entry is file name.
-	for(i=2; i<obj->npesym; i++) {
+	for(i=0; i<obj->npesym; i++) {
 		if(obj->pesym[i].name == 0)
 			continue;
 		if(obj->pesym[i].name[0] == '.') //skip section
@@ -298,13 +328,17 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
 		if(sym->sectnum == 0) {// extern
 			if(s->type == SDYNIMPORT)
 				s->plt = -2; // flag for dynimport in PE object files.
+			if (s->type == SXREF && sym->value > 0) {// global data
+				s->type = SDATA; 
+				s->size = sym->value;
+			}
 			continue;
 		} else if (sym->sectnum > 0) {
 			sect = &obj->sect[sym->sectnum-1];
 			if(sect->sym == 0)
 				diag("%s: %s sym == 0!", pn, s->name);
 		} else {
-			diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum);
+			diag("%s: %s sectnum < 0!", pn, s->name);
 		}
 
 		if(sect == nil) 
@@ -349,6 +383,8 @@ map(PeObj *obj, PeSect *sect)
 		return 0;
 
 	sect->base = mal(sect->sh.SizeOfRawData);
+	if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file
+		return 0;
 	werrstr("short read");
 	if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || 
 			Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 77a62f5..5d1e6d6 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -41,7 +41,7 @@ char	symname[]	= SYMDEF;
 char	pkgname[]	= "__.PKGDEF";
 char*	libdir[16];
 int	nlibdir = 0;
-int	cout = -1;
+static int	cout = -1;
 
 char*	goroot;
 char*	goarch;
@@ -62,6 +62,7 @@ libinit(void)
 {
 	fmtinstall('i', iconv);
 	fmtinstall('Y', Yconv);
+	fmtinstall('Z', Zconv);
 	mywhatsys();	// get goroot, goarch, goos
 	if(strcmp(goarch, thestring) != 0)
 		print("goarch is not known: %s\n", goarch);
@@ -281,6 +282,8 @@ loadlib(void)
 	// binaries, so leave it enabled on OS X (Mach-O) binaries.
 	if(!havedynamic && HEADTYPE != Hdarwin)
 		debug['d'] = 1;
+	
+	importcycles();
 }
 
 /*
@@ -938,15 +941,6 @@ addsection(Segment *seg, char *name, int rwx)
 }
 
 void
-ewrite(int fd, void *buf, int n)
-{
-	if(write(fd, buf, n) < 0) {
-		diag("write error: %r");
-		errorexit();
-	}
-}
-
-void
 pclntab(void)
 {
 	vlong oldpc;
@@ -1359,3 +1353,65 @@ Yconv(Fmt *fp)
 
 	return 0;
 }
+
+vlong coutpos;
+
+void
+cflush(void)
+{
+	int n;
+
+	if(cbpmax < cbp)
+		cbpmax = cbp;
+	n = cbpmax - buf.cbuf;
+	if(n) {
+		if(write(cout, buf.cbuf, n) != n) {
+			diag("write error: %r");
+			errorexit();
+		}
+		coutpos += n;
+	}
+	cbp = buf.cbuf;
+	cbc = sizeof(buf.cbuf);
+	cbpmax = cbp;
+}
+
+vlong
+cpos(void)
+{
+	return coutpos + cbp - buf.cbuf;
+}
+
+void
+cseek(vlong p)
+{
+	vlong start;
+	int delta;
+
+	if(cbpmax < cbp)
+		cbpmax = cbp;
+	start = coutpos;
+	if(start <= p && p <= start+(cbpmax - buf.cbuf)) {
+//print("cseek %lld in [%lld,%lld] (%lld)\n", p, start, start+sizeof(buf.cbuf), cpos());
+		delta = p - (start + cbp - buf.cbuf);
+		cbp += delta;
+		cbc -= delta;
+//print("now at %lld\n", cpos());
+		return;
+	}
+
+	cflush();
+	seek(cout, p, 0);
+	coutpos = p;
+}
+
+void
+cwrite(void *buf, int n)
+{
+	cflush();
+	if(write(cout, buf, n) != n) {
+		diag("write error: %r");
+		errorexit();
+	}
+	coutpos += n;
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 3479871..d13eea3 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -34,7 +34,6 @@ enum
 	
 	/* order here is order in output file */
 	STEXT,
-	SELFDATA,
 	SMACHOPLT,
 	STYPE,
 	SSTRING,
@@ -42,6 +41,8 @@ enum
 	SRODATA,
 	SSYMTAB,
 	SPCLNTAB,
+	SELFROSECT,
+	SELFSECT,
 	SDATA,
 	SMACHO,	/* Mach-O __nl_symbol_ptr */
 	SMACHOGOT,
@@ -102,7 +103,6 @@ struct Section
 extern	char	symname[];
 extern	char	*libdir[];
 extern	int	nlibdir;
-extern	int	cout;
 
 EXTERN	char*	INITENTRY;
 EXTERN	char*	thestring;
@@ -169,7 +169,6 @@ void	mark(Sym *s);
 void	mkfwd(void);
 char*	expandpkg(char*, char*);
 void	deadcode(void);
-void	ewrite(int, void*, int);
 Reloc*	addrel(Sym*);
 void	codeblk(int32, int32);
 void	datblk(int32, int32);
@@ -264,6 +263,7 @@ enum {
 	Hlinux,		// Linux ELF
 	Hfreebsd,	// FreeBSD ELF
 	Hwindows,	// MS Windows PE
+	Hopenbsd,	// OpenBSD ELF
 };
 
 typedef struct Header Header;
@@ -278,4 +278,31 @@ extern	Header	headers[];
 int	headtype(char*);
 
 int	Yconv(Fmt*);
+
+#pragma	varargck	type	"O"	int
 #pragma	varargck	type	"Y"	Sym*
+
+// buffered output
+
+EXTERN	Biobuf	bso;
+
+EXTERN struct
+{
+	char	cbuf[MAXIO];	/* output buffer */
+} buf;
+
+EXTERN	int	cbc;
+EXTERN	char*	cbp;
+EXTERN	char*	cbpmax;
+
+#define	cput(c)\
+	{ *cbp++ = c;\
+	if(--cbc <= 0)\
+		cflush(); }
+
+void	cflush(void);
+vlong	cpos(void);
+void	cseek(vlong);
+void	cwrite(void*, int);
+void	importcycles(void);
+int	Zconv(Fmt*);
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 0b12ac1..70133d6 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -506,12 +506,12 @@ domacholink(void)
 
 	if(size > 0) {
 		linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
-		seek(cout, linkoff, 0);
+		cseek(linkoff);
 
-		ewrite(cout, s1->p, s1->size);
-		ewrite(cout, s2->p, s2->size);
-		ewrite(cout, s3->p, s3->size);
-		ewrite(cout, s4->p, s4->size);
+		cwrite(s1->p, s1->size);
+		cwrite(s2->p, s2->size);
+		cwrite(s3->p, s3->size);
+		cwrite(s4->p, s4->size);
 	}
 
 	return rnd(size, INITRND);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 9ac0a50..6608a97 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -76,7 +76,7 @@ static Sym *dexport[1024];
 static int nexport;
 
 static IMAGE_SECTION_HEADER*
-addpesection(char *name, int sectsize, int filesize, Segment *s)
+addpesection(char *name, int sectsize, int filesize)
 {
 	IMAGE_SECTION_HEADER *h;
 
@@ -94,19 +94,31 @@ addpesection(char *name, int sectsize, int filesize, Segment *s)
 		h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
 		nextfileoff += h->SizeOfRawData;
 	}
-	if(s) {
-		if(s->vaddr-PEBASE != h->VirtualAddress) {
-			diag("%s.VirtualAddress = %#llux, want %#llux", name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
-			errorexit();
-		}
-		if(s->fileoff != h->PointerToRawData) {
-			diag("%s.PointerToRawData = %#llux, want %#llux", name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
-			errorexit();
-		}
-	}
 	return h;
 }
 
+static void
+chksectoff(IMAGE_SECTION_HEADER *h, vlong off)
+{
+	if(off != h->PointerToRawData) {
+		diag("%s.PointerToRawData = %#llux, want %#llux", h->Name, (vlong)h->PointerToRawData, off);
+		errorexit();
+	}
+}
+
+static void
+chksectseg(IMAGE_SECTION_HEADER *h, Segment *s)
+{
+	if(s->vaddr-PEBASE != h->VirtualAddress) {
+		diag("%s.VirtualAddress = %#llux, want %#llux", h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
+		errorexit();
+	}
+	if(s->fileoff != h->PointerToRawData) {
+		diag("%s.PointerToRawData = %#llux, want %#llux", h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
+		errorexit();
+	}
+}
+
 void
 peinit(void)
 {
@@ -135,20 +147,19 @@ peinit(void)
 static void
 pewrite(void)
 {
-	seek(cout, 0, 0);
-	ewrite(cout, dosstub, sizeof dosstub);
+	cseek(0);
+	cwrite(dosstub, sizeof dosstub);
 	strnput("PE", 4);
-	cflush();
 	// TODO: This code should not assume that the
 	// memory representation is little-endian or
 	// that the structs are packed identically to
 	// their file representation.
-	ewrite(cout, &fh, sizeof fh);
+	cwrite(&fh, sizeof fh);
 	if(pe64)
-		ewrite(cout, &oh64, sizeof oh64);
+		cwrite(&oh64, sizeof oh64);
 	else
-		ewrite(cout, &oh, sizeof oh);
-	ewrite(cout, sh, nsect * sizeof sh[0]);
+		cwrite(&oh, sizeof oh);
+	cwrite(sh, nsect * sizeof sh[0]);
 }
 
 static void
@@ -213,39 +224,41 @@ initdynimport(void)
 }
 
 static void
-addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
+addimports(IMAGE_SECTION_HEADER *datsect)
 {
 	IMAGE_SECTION_HEADER *isect;
 	uvlong n, oftbase, ftbase;
+	vlong startoff, endoff;
 	Imp *m;
 	Dll *d;
 	Sym* dynamic;
 	
+	startoff = cpos();
 	dynamic = lookup(".windynamic", 0);
 
 	// skip import descriptor table (will write it later)
 	n = 0;
 	for(d = dr; d != nil; d = d->next)
 		n++;
-	seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0);
+	cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1));
 
 	// write dll names
 	for(d = dr; d != nil; d = d->next) {
-		d->nameoff = cpos() - fileoff;
+		d->nameoff = cpos() - startoff;
 		strput(d->name);
 	}
 
 	// write function names
 	for(d = dr; d != nil; d = d->next) {
 		for(m = d->ms; m != nil; m = m->next) {
-			m->off = nextsectoff + cpos() - fileoff;
+			m->off = nextsectoff + cpos() - startoff;
 			wputl(0); // hint
 			strput(m->s->dynimpname);
 		}
 	}
 	
 	// write OriginalFirstThunks
-	oftbase = cpos() - fileoff;
+	oftbase = cpos() - startoff;
 	n = cpos();
 	for(d = dr; d != nil; d = d->next) {
 		d->thunkoff = cpos() - n;
@@ -255,25 +268,25 @@ addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
 	}
 
 	// add pe section and pad it at the end
-	n = cpos() - fileoff;
-	isect = addpesection(".idata", n, n, 0);
+	n = cpos() - startoff;
+	isect = addpesection(".idata", n, n);
 	isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
 		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+	chksectoff(isect, startoff);
 	strnput("", isect->SizeOfRawData - n);
-	cflush();
+	endoff = cpos();
 
 	// write FirstThunks (allocated in .data section)
 	ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
-	seek(cout, datsect->PointerToRawData + ftbase, 0);
+	cseek(datsect->PointerToRawData + ftbase);
 	for(d = dr; d != nil; d = d->next) {
 		for(m = d->ms; m != nil; m = m->next)
 			put(m->off);
 		put(0);
 	}
-	cflush();
 	
 	// finally write import descriptor table
-	seek(cout, fileoff, 0);
+	cseek(startoff);
 	for(d = dr; d != nil; d = d->next) {
 		lputl(isect->VirtualAddress + oftbase + d->thunkoff);
 		lputl(0);
@@ -286,7 +299,6 @@ addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
 	lputl(0);
 	lputl(0);
 	lputl(0);
-	cflush();
 	
 	// update data directory
 	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
@@ -294,7 +306,7 @@ addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
 	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
 	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
 
-	seek(cout, 0, 2);
+	cseek(endoff);
 }
 
 static int
@@ -329,7 +341,7 @@ initdynexport(void)
 }
 
 void
-addexports(vlong fileoff)
+addexports(void)
 {
 	IMAGE_SECTION_HEADER *sect;
 	IMAGE_EXPORT_DIRECTORY e;
@@ -342,13 +354,13 @@ addexports(vlong fileoff)
 	if (nexport == 0)
 		return;
 		
-	sect = addpesection(".edata", size, size, 0);
+	sect = addpesection(".edata", size, size);
 	sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
+	chksectoff(sect, cpos());
 	va = sect->VirtualAddress;
 	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
 	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
 
-	seek(cout, fileoff, 0);
 	va_name = va + sizeof e + nexport*4;
 	va_addr = va + sizeof e;
 	va_na = va + sizeof e + nexport*8;
@@ -383,9 +395,6 @@ addexports(vlong fileoff)
 	for(i=0; i<nexport; i++)
 		strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
 	strnput("", sect->SizeOfRawData - size);
-	cflush();
-
-	seek(cout, 0, 2);
 }
 
 void
@@ -396,7 +405,7 @@ dope(void)
 	/* relocation table */
 	rel = lookup(".rel", 0);
 	rel->reachable = 1;
-	rel->type = SELFDATA;
+	rel->type = SELFROSECT;
 
 	initdynimport();
 	initdynexport();
@@ -428,7 +437,7 @@ newPEDWARFSection(char *name, vlong size)
 	nextsymoff += strlen(name);
 	symnames[nextsymoff] = 0;
 	nextsymoff ++;
-	h = addpesection(s, size, size, 0);
+	h = addpesection(s, size, size);
 	h->Characteristics = IMAGE_SCN_MEM_READ|
 		IMAGE_SCN_MEM_DISCARDABLE;
 
@@ -445,9 +454,10 @@ addsymtable(void)
 		return;
 	
 	size  = nextsymoff + 4;
-	h = addpesection(".symtab", size, size, 0);
+	h = addpesection(".symtab", size, size);
 	h->Characteristics = IMAGE_SCN_MEM_READ|
 		IMAGE_SCN_MEM_DISCARDABLE;
+	chksectoff(h, cpos());
 	fh.PointerToSymbolTable = cpos();
 	fh.NumberOfSymbols = 0;
 	// put symbol string table
@@ -455,7 +465,6 @@ addsymtable(void)
 	for (i=0; i<nextsymoff; i++)
 		cput(symnames[i]);
 	strnput("", h->SizeOfRawData - size);
-	cflush();
 }
 
 void
@@ -478,9 +487,10 @@ addpersrc(void)
 	if(rsrcsym == nil)
 		return;
 	
-	h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0);
+	h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size);
 	h->Characteristics = IMAGE_SCN_MEM_READ|
 		IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
+	chksectoff(h, cpos());
 	// relocation
 	for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
 		p = rsrcsym->p + r->off;
@@ -491,9 +501,8 @@ addpersrc(void)
 		p[2] = val>>16;
 		p[3] = val>>24;
 	}
-	ewrite(cout, rsrcsym->p, rsrcsym->size);
+	cwrite(rsrcsym->p, rsrcsym->size);
 	strnput("", h->SizeOfRawData - rsrcsym->size);
-	cflush();
 
 	// update data directory
 	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
@@ -517,24 +526,24 @@ asmbpe(void)
 		break;
 	}
 
-	t = addpesection(".text", segtext.len, segtext.len, &segtext);
+	t = addpesection(".text", segtext.len, segtext.len);
 	t->Characteristics = IMAGE_SCN_CNT_CODE|
 		IMAGE_SCN_CNT_INITIALIZED_DATA|
 		IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
+	chksectseg(t, &segtext);
 
-	d = addpesection(".data", segdata.len, segdata.filelen, &segdata);
+	d = addpesection(".data", segdata.len, segdata.filelen);
 	d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
 		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+	chksectseg(d, &segdata);
 
 	if(!debug['s'])
 		dwarfaddpeheaders();
 
-	addimports(nextfileoff, d);
-	
-	addexports(nextfileoff);
-	
+	cseek(nextfileoff);
+	addimports(d);
+	addexports();
 	addsymtable();
-	
 	addpersrc();
 	
 	fh.NumberOfSections = nsect;
diff --git a/src/env.bash b/src/env.bash
index f83012a..de446bf 100644
--- a/src/env.bash
+++ b/src/env.bash
@@ -88,6 +88,11 @@ if bison --version 2>&1 | grep 'bison++' >/dev/null 2>&1; then
 	exit 1
 fi
 
+# Issue 2020: some users configure bash to default to
+#	set -o noclobber
+# which makes >x fail if x already exists.  Restore sanity.
+set +o noclobber
+
 # Tried to use . <($MAKE ...) here, but it cannot set environment
 # variables in the version of bash that ships with OS X.  Amazing.
 eval $($MAKE --no-print-directory -f Make.inc go-env | egrep 'GOARCH|GOOS|GOHOSTARCH|GOHOSTOS|GO_ENV')
diff --git a/src/lib9/fmt/dofmt.c b/src/lib9/fmt/dofmt.c
index 51f0f07..cc6ab92 100644
--- a/src/lib9/fmt/dofmt.c
+++ b/src/lib9/fmt/dofmt.c
@@ -369,7 +369,7 @@ __ifmt(Fmt *f)
 	}
 #endif
 	if(f->r == 'p'){
-		u = (ulong)va_arg(f->args, void*);
+		u = (uintptr)va_arg(f->args, void*);
 		f->r = 'x';
 		fl |= FmtUnsigned;
 	}else if(fl & FmtVLong){
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
index c3dd2b5..3c8cafb 100644
--- a/src/lib9/getwd.c
+++ b/src/lib9/getwd.c
@@ -3,6 +3,7 @@ Plan 9 from User Space src/lib9/getwd.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
 
 Copyright 2001-2007 Russ Cox.  All Rights Reserved.
+Portions Copyright 2011 The Go Authors.  All Rights Reserved.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +24,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */
 #include <u.h>
+#include <errno.h>
+#include <sys/stat.h>
 #include <libc.h>
 
 #undef getwd
@@ -30,5 +33,23 @@ THE SOFTWARE.
 char*
 p9getwd(char *s, int ns)
 {
+	char *pwd;
+	struct stat st1, st2;
+
+	// Clumsy but widespread kludge:
+	// if $PWD is set and matches ".", use it.
+	// Matches glibc's get_current_dir_name and Go's os.Getwd.
+	pwd = getenv("PWD");  // note: getenv, not p9getenv, so no free
+	if(pwd != nil && pwd[0] &&
+			stat(pwd, &st1) >= 0 && stat(".", &st2) >= 0 &&
+			st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
+		if(strlen(pwd) >= ns) {
+			errno = ERANGE;
+			return nil;
+		}
+		strcpy(s, pwd);
+		return s;
+	}
+
 	return getcwd(s, ns);
 }
diff --git a/src/libmach/5.c b/src/libmach/5.c
index 67bd88d..9882c1a 100644
--- a/src/libmach/5.c
+++ b/src/libmach/5.c
@@ -35,7 +35,7 @@
 #include "ureg_arm.h"
 #include <mach.h>
 
-#define	REGOFF(x)	(ulong) (&((struct Ureg *) 0)->x)
+#define	REGOFF(x)	(uintptr) (&((struct Ureg *) 0)->x)
 
 #define SP		REGOFF(r13)
 #define PC		REGOFF(pc)
diff --git a/src/libmach/openbsd.c b/src/libmach/openbsd.c
new file mode 100644
index 0000000..d919383
--- /dev/null
+++ b/src/libmach/openbsd.c
@@ -0,0 +1,46 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+	sysfatal("ctlproc unimplemented in OpenBSD");
+	return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+	sysfatal("proctextfile unimplemented in OpenBSD");
+	return nil;
+}
+
+char*
+procstatus(int pid)
+{
+	sysfatal("procstatus unimplemented in OpenBSD");
+	return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+	sysfatal("attachproc unimplemented in OpenBSD");
+	return nil;
+}
+
+void
+detachproc(Map *m)
+{
+	sysfatal("detachproc unimplemented in OpenBSD");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+	sysfatal("procthreadpids unimplemented in OpenBSD");
+	return -1;
+}
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index 7338399..7542ae7 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -68,7 +68,6 @@ DIRS=\
 	debug/elf\
 	debug/gosym\
 	debug/pe\
-	debug/proc\
 	ebnf\
 	encoding/ascii85\
 	encoding/base32\
@@ -79,7 +78,6 @@ DIRS=\
 	encoding/pem\
 	exec\
 	exp/datafmt\
-	exp/eval\
 	exp/gui\
 	exp/gui/x11\
 	exp/regexp/syntax\
@@ -188,7 +186,6 @@ endif
 ifeq ($(GOOS),plan9)
 NOPLAN9BUILD=\
 	crypto/tls\
-	debug/proc\
 	exp/gui/x11\
 	expvar\
 	http\
@@ -219,7 +216,6 @@ NOTEST+=\
 	crypto\
 	crypto/openpgp/error\
 	crypto/x509/pkix\
-	debug/proc\
 	exp/gui\
 	exp/gui/x11\
 	go/ast\
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
index 32fc8f9..f473c90 100644
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/archive/tar/reader_test.go
@@ -178,7 +178,6 @@ func TestPartialRead(t *testing.T) {
 	}
 }
 
-
 func TestIncrementalRead(t *testing.T) {
 	test := gnuTarTest
 	f, err := os.Open(test.file)
diff --git a/src/pkg/archive/zip/Makefile b/src/pkg/archive/zip/Makefile
index 32a5431..9071690 100644
--- a/src/pkg/archive/zip/Makefile
+++ b/src/pkg/archive/zip/Makefile
@@ -8,5 +8,6 @@ TARG=archive/zip
 GOFILES=\
 	reader.go\
 	struct.go\
+	writer.go\
 
 include ../../../Make.pkg
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index 17464c5..f92f929 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -2,18 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-/*
-Package zip provides support for reading ZIP archives.
-
-See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
-
-This package does not support ZIP64 or disk spanning.
-*/
 package zip
 
 import (
 	"bufio"
-	"bytes"
 	"compress/flate"
 	"hash"
 	"hash/crc32"
@@ -24,9 +16,9 @@ import (
 )
 
 var (
-	FormatError       = os.NewError("not a valid zip file")
-	UnsupportedMethod = os.NewError("unsupported compression algorithm")
-	ChecksumError     = os.NewError("checksum error")
+	FormatError       = os.NewError("zip: not a valid zip file")
+	UnsupportedMethod = os.NewError("zip: unsupported compression algorithm")
+	ChecksumError     = os.NewError("zip: checksum error")
 )
 
 type Reader struct {
@@ -44,15 +36,14 @@ type File struct {
 	FileHeader
 	zipr         io.ReaderAt
 	zipsize      int64
-	headerOffset uint32
-	bodyOffset   int64
+	headerOffset int64
 }
 
 func (f *File) hasDataDescriptor() bool {
 	return f.Flags&0x8 != 0
 }
 
-// OpenReader will open the Zip file specified by name and return a ReaderCloser.
+// OpenReader will open the Zip file specified by name and return a ReadCloser.
 func OpenReader(name string) (*ReadCloser, os.Error) {
 	f, err := os.Open(name)
 	if err != nil {
@@ -87,18 +78,33 @@ func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
 		return err
 	}
 	z.r = r
-	z.File = make([]*File, end.directoryRecords)
+	z.File = make([]*File, 0, end.directoryRecords)
 	z.Comment = end.comment
 	rs := io.NewSectionReader(r, 0, size)
 	if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
 		return err
 	}
 	buf := bufio.NewReader(rs)
-	for i := range z.File {
-		z.File[i] = &File{zipr: r, zipsize: size}
-		if err := readDirectoryHeader(z.File[i], buf); err != nil {
+
+	// The count of files inside a zip is truncated to fit in a uint16.
+	// Gloss over this by reading headers until we encounter
+	// a bad one, and then only report a FormatError or UnexpectedEOF if
+	// the file count modulo 65536 is incorrect.
+	for {
+		f := &File{zipr: r, zipsize: size}
+		err = readDirectoryHeader(f, buf)
+		if err == FormatError || err == io.ErrUnexpectedEOF {
+			break
+		}
+		if err != nil {
 			return err
 		}
+		z.File = append(z.File, f)
+	}
+	if uint16(len(z.File)) != end.directoryRecords {
+		// Return the readDirectoryHeader error if we read
+		// the wrong number of directory entries.
+		return err
 	}
 	return nil
 }
@@ -109,31 +115,22 @@ func (rc *ReadCloser) Close() os.Error {
 }
 
 // Open returns a ReadCloser that provides access to the File's contents.
+// It is safe to Open and Read from files concurrently.
 func (f *File) Open() (rc io.ReadCloser, err os.Error) {
-	off := int64(f.headerOffset)
-	if f.bodyOffset == 0 {
-		r := io.NewSectionReader(f.zipr, off, f.zipsize-off)
-		if err = readFileHeader(f, r); err != nil {
-			return
-		}
-		if f.bodyOffset, err = r.Seek(0, os.SEEK_CUR); err != nil {
-			return
-		}
+	bodyOffset, err := f.findBodyOffset()
+	if err != nil {
+		return
 	}
 	size := int64(f.CompressedSize)
-	if f.hasDataDescriptor() {
-		if size == 0 {
-			// permit SectionReader to see the rest of the file
-			size = f.zipsize - (off + f.bodyOffset)
-		} else {
-			size += dataDescriptorLen
-		}
+	if size == 0 && f.hasDataDescriptor() {
+		// permit SectionReader to see the rest of the file
+		size = f.zipsize - (f.headerOffset + bodyOffset)
 	}
-	r := io.NewSectionReader(f.zipr, off+f.bodyOffset, size)
+	r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
 	switch f.Method {
-	case 0: // store (no compression)
+	case Store: // (no compression)
 		rc = ioutil.NopCloser(r)
-	case 8: // DEFLATE
+	case Deflate:
 		rc = flate.NewReader(r)
 	default:
 		err = UnsupportedMethod
@@ -170,90 +167,102 @@ func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
 
 func (r *checksumReader) Close() os.Error { return r.rc.Close() }
 
-func readFileHeader(f *File, r io.Reader) (err os.Error) {
-	defer func() {
-		if rerr, ok := recover().(os.Error); ok {
-			err = rerr
-		}
-	}()
-	var (
-		signature      uint32
-		filenameLength uint16
-		extraLength    uint16
-	)
-	read(r, &signature)
-	if signature != fileHeaderSignature {
+func readFileHeader(f *File, r io.Reader) os.Error {
+	var b [fileHeaderLen]byte
+	if _, err := io.ReadFull(r, b[:]); err != nil {
+		return err
+	}
+	c := binary.LittleEndian
+	if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
 		return FormatError
 	}
-	read(r, &f.ReaderVersion)
-	read(r, &f.Flags)
-	read(r, &f.Method)
-	read(r, &f.ModifiedTime)
-	read(r, &f.ModifiedDate)
-	read(r, &f.CRC32)
-	read(r, &f.CompressedSize)
-	read(r, &f.UncompressedSize)
-	read(r, &filenameLength)
-	read(r, &extraLength)
-	f.Name = string(readByteSlice(r, filenameLength))
-	f.Extra = readByteSlice(r, extraLength)
-	return
+	f.ReaderVersion = c.Uint16(b[4:6])
+	f.Flags = c.Uint16(b[6:8])
+	f.Method = c.Uint16(b[8:10])
+	f.ModifiedTime = c.Uint16(b[10:12])
+	f.ModifiedDate = c.Uint16(b[12:14])
+	f.CRC32 = c.Uint32(b[14:18])
+	f.CompressedSize = c.Uint32(b[18:22])
+	f.UncompressedSize = c.Uint32(b[22:26])
+	filenameLen := int(c.Uint16(b[26:28]))
+	extraLen := int(c.Uint16(b[28:30]))
+	d := make([]byte, filenameLen+extraLen)
+	if _, err := io.ReadFull(r, d); err != nil {
+		return err
+	}
+	f.Name = string(d[:filenameLen])
+	f.Extra = d[filenameLen:]
+	return nil
 }
 
-func readDirectoryHeader(f *File, r io.Reader) (err os.Error) {
-	defer func() {
-		if rerr, ok := recover().(os.Error); ok {
-			err = rerr
-		}
-	}()
-	var (
-		signature          uint32
-		filenameLength     uint16
-		extraLength        uint16
-		commentLength      uint16
-		startDiskNumber    uint16 // unused
-		internalAttributes uint16 // unused
-		externalAttributes uint32 // unused
-	)
-	read(r, &signature)
-	if signature != directoryHeaderSignature {
+// findBodyOffset does the minimum work to verify the file has a header
+// and returns the file body offset.
+func (f *File) findBodyOffset() (int64, os.Error) {
+	r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset)
+	var b [fileHeaderLen]byte
+	if _, err := io.ReadFull(r, b[:]); err != nil {
+		return 0, err
+	}
+	c := binary.LittleEndian
+	if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
+		return 0, FormatError
+	}
+	filenameLen := int(c.Uint16(b[26:28]))
+	extraLen := int(c.Uint16(b[28:30]))
+	return int64(fileHeaderLen + filenameLen + extraLen), nil
+}
+
+// readDirectoryHeader attempts to read a directory header from r.
+// It returns io.ErrUnexpectedEOF if it cannot read a complete header,
+// and FormatError if it doesn't find a valid header signature.
+func readDirectoryHeader(f *File, r io.Reader) os.Error {
+	var b [directoryHeaderLen]byte
+	if _, err := io.ReadFull(r, b[:]); err != nil {
+		return err
+	}
+	c := binary.LittleEndian
+	if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature {
 		return FormatError
 	}
-	read(r, &f.CreatorVersion)
-	read(r, &f.ReaderVersion)
-	read(r, &f.Flags)
-	read(r, &f.Method)
-	read(r, &f.ModifiedTime)
-	read(r, &f.ModifiedDate)
-	read(r, &f.CRC32)
-	read(r, &f.CompressedSize)
-	read(r, &f.UncompressedSize)
-	read(r, &filenameLength)
-	read(r, &extraLength)
-	read(r, &commentLength)
-	read(r, &startDiskNumber)
-	read(r, &internalAttributes)
-	read(r, &externalAttributes)
-	read(r, &f.headerOffset)
-	f.Name = string(readByteSlice(r, filenameLength))
-	f.Extra = readByteSlice(r, extraLength)
-	f.Comment = string(readByteSlice(r, commentLength))
-	return
+	f.CreatorVersion = c.Uint16(b[4:6])
+	f.ReaderVersion = c.Uint16(b[6:8])
+	f.Flags = c.Uint16(b[8:10])
+	f.Method = c.Uint16(b[10:12])
+	f.ModifiedTime = c.Uint16(b[12:14])
+	f.ModifiedDate = c.Uint16(b[14:16])
+	f.CRC32 = c.Uint32(b[16:20])
+	f.CompressedSize = c.Uint32(b[20:24])
+	f.UncompressedSize = c.Uint32(b[24:28])
+	filenameLen := int(c.Uint16(b[28:30]))
+	extraLen := int(c.Uint16(b[30:32]))
+	commentLen := int(c.Uint16(b[32:34]))
+	// startDiskNumber := c.Uint16(b[34:36])    // Unused
+	// internalAttributes := c.Uint16(b[36:38]) // Unused
+	// externalAttributes := c.Uint32(b[38:42]) // Unused
+	f.headerOffset = int64(c.Uint32(b[42:46]))
+	d := make([]byte, filenameLen+extraLen+commentLen)
+	if _, err := io.ReadFull(r, d); err != nil {
+		return err
+	}
+	f.Name = string(d[:filenameLen])
+	f.Extra = d[filenameLen : filenameLen+extraLen]
+	f.Comment = string(d[filenameLen+extraLen:])
+	return nil
 }
 
-func readDataDescriptor(r io.Reader, f *File) (err os.Error) {
-	defer func() {
-		if rerr, ok := recover().(os.Error); ok {
-			err = rerr
-		}
-	}()
-	read(r, &f.CRC32)
-	read(r, &f.CompressedSize)
-	read(r, &f.UncompressedSize)
-	return
+func readDataDescriptor(r io.Reader, f *File) os.Error {
+	var b [dataDescriptorLen]byte
+	if _, err := io.ReadFull(r, b[:]); err != nil {
+		return err
+	}
+	c := binary.LittleEndian
+	f.CRC32 = c.Uint32(b[:4])
+	f.CompressedSize = c.Uint32(b[4:8])
+	f.UncompressedSize = c.Uint32(b[8:12])
+	return nil
 }
 
-func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
+func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err os.Error) {
 	// look for directoryEndSignature in the last 1k, then in the last 65k
 	var b []byte
 	for i, bLen := range []int64{1024, 65 * 1024} {
@@ -274,53 +283,29 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error)
 	}
 
 	// read header into struct
-	defer func() {
-		if rerr, ok := recover().(os.Error); ok {
-			err = rerr
-			d = nil
-		}
-	}()
-	br := bytes.NewBuffer(b[4:]) // skip over signature
-	d = new(directoryEnd)
-	read(br, &d.diskNbr)
-	read(br, &d.dirDiskNbr)
-	read(br, &d.dirRecordsThisDisk)
-	read(br, &d.directoryRecords)
-	read(br, &d.directorySize)
-	read(br, &d.directoryOffset)
-	read(br, &d.commentLen)
-	d.comment = string(readByteSlice(br, d.commentLen))
+	c := binary.LittleEndian
+	d := new(directoryEnd)
+	d.diskNbr = c.Uint16(b[4:6])
+	d.dirDiskNbr = c.Uint16(b[6:8])
+	d.dirRecordsThisDisk = c.Uint16(b[8:10])
+	d.directoryRecords = c.Uint16(b[10:12])
+	d.directorySize = c.Uint32(b[12:16])
+	d.directoryOffset = c.Uint32(b[16:20])
+	d.commentLen = c.Uint16(b[20:22])
+	d.comment = string(b[22 : 22+int(d.commentLen)])
 	return d, nil
 }
 
 func findSignatureInBlock(b []byte) int {
-	const minSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 // fixed part of header
-	for i := len(b) - minSize; i >= 0; i-- {
+	for i := len(b) - directoryEndLen; i >= 0; i-- {
 		// defined from directoryEndSignature in struct.go
 		if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
 			// n is length of comment
-			n := int(b[i+minSize-2]) | int(b[i+minSize-1])<<8
-			if n+minSize+i == len(b) {
+			n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
+			if n+directoryEndLen+i == len(b) {
 				return i
 			}
 		}
 	}
 	return -1
 }
-
-func read(r io.Reader, data interface{}) {
-	if err := binary.Read(r, binary.LittleEndian, data); err != nil {
-		panic(err)
-	}
-}
-
-func readByteSlice(r io.Reader, l uint16) []byte {
-	b := make([]byte, l)
-	if l == 0 {
-		return b
-	}
-	if _, err := io.ReadFull(r, b); err != nil {
-		panic(err)
-	}
-	return b
-}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index c72cd9a..fd5fed2 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -11,6 +11,7 @@ import (
 	"io/ioutil"
 	"os"
 	"testing"
+	"time"
 )
 
 type ZipTest struct {
@@ -24,8 +25,19 @@ type ZipTestFile struct {
 	Name    string
 	Content []byte // if blank, will attempt to compare against File
 	File    string // name of file to compare to (relative to testdata/)
+	Mtime   string // modified time in format "mm-dd-yy hh:mm:ss"
 }
 
+// Caution: The Mtime values found for the test files should correspond to
+//          the values listed with unzip -l <zipfile>. However, the values
+//          listed by unzip appear to be off by some hours. When creating
+//          fresh test files and testing them, this issue is not present.
+//          The test files were created in Sydney, so there might be a time
+//          zone issue. The time zone information does have to be encoded
+//          somewhere, because otherwise unzip -l could not provide a different
+//          time from what the archive/zip package provides, but there appears
+//          to be no documentation about this.
+
 var tests = []ZipTest{
 	{
 		Name:    "test.zip",
@@ -34,10 +46,12 @@ var tests = []ZipTest{
 			{
 				Name:    "test.txt",
 				Content: []byte("This is a test text file.\n"),
+				Mtime:   "09-05-10 12:12:02",
 			},
 			{
-				Name: "gophercolor16x16.png",
-				File: "gophercolor16x16.png",
+				Name:  "gophercolor16x16.png",
+				File:  "gophercolor16x16.png",
+				Mtime: "09-05-10 15:52:58",
 			},
 		},
 	},
@@ -45,8 +59,9 @@ var tests = []ZipTest{
 		Name: "r.zip",
 		File: []ZipTestFile{
 			{
-				Name: "r/r.zip",
-				File: "r.zip",
+				Name:  "r/r.zip",
+				File:  "r.zip",
+				Mtime: "03-04-10 00:24:16",
 			},
 		},
 	},
@@ -58,6 +73,7 @@ var tests = []ZipTest{
 			{
 				Name:    "filename",
 				Content: []byte("This is a test textfile.\n"),
+				Mtime:   "02-02-11 13:06:20",
 			},
 		},
 	},
@@ -136,18 +152,36 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
 	if f.Name != ft.Name {
 		t.Errorf("name=%q, want %q", f.Name, ft.Name)
 	}
+
+	mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want {
+		t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
+	}
+
+	size0 := f.UncompressedSize
+
 	var b bytes.Buffer
 	r, err := f.Open()
 	if err != nil {
 		t.Error(err)
 		return
 	}
+
+	if size1 := f.UncompressedSize; size0 != size1 {
+		t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
+	}
+
 	_, err = io.Copy(&b, r)
 	if err != nil {
 		t.Error(err)
 		return
 	}
 	r.Close()
+
 	var c []byte
 	if len(ft.Content) != 0 {
 		c = ft.Content
@@ -155,10 +189,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
 		t.Error(err)
 		return
 	}
+
 	if b.Len() != len(c) {
 		t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
 		return
 	}
+
 	for i, b := range b.Bytes() {
 		if b != c[i] {
 			t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index bfe0aae..1d6e70f 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -1,9 +1,32 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package zip provides support for reading and writing ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
 package zip
 
+import "os"
+import "time"
+
+// Compression methods.
+const (
+	Store   uint16 = 0
+	Deflate uint16 = 8
+)
+
 const (
 	fileHeaderSignature      = 0x04034b50
 	directoryHeaderSignature = 0x02014b50
 	directoryEndSignature    = 0x06054b50
+	fileHeaderLen            = 30 // + filename + extra
+	directoryHeaderLen       = 46 // + filename + extra + comment
+	directoryEndLen          = 22 // + comment
 	dataDescriptorLen        = 12
 )
 
@@ -13,8 +36,8 @@ type FileHeader struct {
 	ReaderVersion    uint16
 	Flags            uint16
 	Method           uint16
-	ModifiedTime     uint16
-	ModifiedDate     uint16
+	ModifiedTime     uint16 // MS-DOS time
+	ModifiedDate     uint16 // MS-DOS date
 	CRC32            uint32
 	CompressedSize   uint32
 	UncompressedSize uint32
@@ -32,3 +55,37 @@ type directoryEnd struct {
 	commentLen         uint16
 	comment            string
 }
+
+func recoverError(err *os.Error) {
+	if e := recover(); e != nil {
+		if osErr, ok := e.(os.Error); ok {
+			*err = osErr
+			return
+		}
+		panic(e)
+	}
+}
+
+// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
+// The resolution is 2s.
+// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
+func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
+	return time.Time{
+		// date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
+		Year:  int64(dosDate>>9 + 1980),
+		Month: int(dosDate >> 5 & 0xf),
+		Day:   int(dosDate & 0x1f),
+
+		// time bits 0-4: second/2; 5-10: minute; 11-15: hour
+		Hour:   int(dosTime >> 11),
+		Minute: int(dosTime >> 5 & 0x3f),
+		Second: int(dosTime & 0x1f * 2),
+	}
+}
+
+// Mtime_ns returns the modified time in ns since epoch.
+// The resolution is 2s.
+func (h *FileHeader) Mtime_ns() int64 {
+	t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
+	return t.Seconds() * 1e9
+}
diff --git a/src/pkg/archive/zip/writer.go b/src/pkg/archive/zip/writer.go
new file mode 100644
index 0000000..2065b06
--- /dev/null
+++ b/src/pkg/archive/zip/writer.go
@@ -0,0 +1,244 @@
+// 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 zip
+
+import (
+	"bufio"
+	"compress/flate"
+	"encoding/binary"
+	"hash"
+	"hash/crc32"
+	"io"
+	"os"
+)
+
+// TODO(adg): support zip file comments
+// TODO(adg): support specifying deflate level
+
+// Writer implements a zip file writer.
+type Writer struct {
+	*countWriter
+	dir    []*header
+	last   *fileWriter
+	closed bool
+}
+
+type header struct {
+	*FileHeader
+	offset uint32
+}
+
+// NewWriter returns a new Writer writing a zip file to w.
+func NewWriter(w io.Writer) *Writer {
+	return &Writer{countWriter: &countWriter{w: bufio.NewWriter(w)}}
+}
+
+// Close finishes writing the zip file by writing the central directory.
+// It does not (and can not) close the underlying writer.
+func (w *Writer) Close() (err os.Error) {
+	if w.last != nil && !w.last.closed {
+		if err = w.last.close(); err != nil {
+			return
+		}
+		w.last = nil
+	}
+	if w.closed {
+		return os.NewError("zip: writer closed twice")
+	}
+	w.closed = true
+
+	defer recoverError(&err)
+
+	// write central directory
+	start := w.count
+	for _, h := range w.dir {
+		write(w, uint32(directoryHeaderSignature))
+		write(w, h.CreatorVersion)
+		write(w, h.ReaderVersion)
+		write(w, h.Flags)
+		write(w, h.Method)
+		write(w, h.ModifiedTime)
+		write(w, h.ModifiedDate)
+		write(w, h.CRC32)
+		write(w, h.CompressedSize)
+		write(w, h.UncompressedSize)
+		write(w, uint16(len(h.Name)))
+		write(w, uint16(len(h.Extra)))
+		write(w, uint16(len(h.Comment)))
+		write(w, uint16(0)) // disk number start
+		write(w, uint16(0)) // internal file attributes
+		write(w, uint32(0)) // external file attributes
+		write(w, h.offset)
+		writeBytes(w, []byte(h.Name))
+		writeBytes(w, h.Extra)
+		writeBytes(w, []byte(h.Comment))
+	}
+	end := w.count
+
+	// write end record
+	write(w, uint32(directoryEndSignature))
+	write(w, uint16(0))          // disk number
+	write(w, uint16(0))          // disk number where directory starts
+	write(w, uint16(len(w.dir))) // number of entries this disk
+	write(w, uint16(len(w.dir))) // number of entries total
+	write(w, uint32(end-start))  // size of directory
+	write(w, uint32(start))      // start of directory
+	write(w, uint16(0))          // size of comment
+
+	return w.w.(*bufio.Writer).Flush()
+}
+
+// Create adds a file to the zip file using the provided name.
+// It returns a Writer to which the file contents should be written.
+// The file's contents must be written to the io.Writer before the next
+// call to Create, CreateHeader, or Close.
+func (w *Writer) Create(name string) (io.Writer, os.Error) {
+	header := &FileHeader{
+		Name:   name,
+		Method: Deflate,
+	}
+	return w.CreateHeader(header)
+}
+
+// CreateHeader adds a file to the zip file using the provided FileHeader
+// for the file metadata. 
+// It returns a Writer to which the file contents should be written.
+// The file's contents must be written to the io.Writer before the next
+// call to Create, CreateHeader, or Close.
+func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) {
+	if w.last != nil && !w.last.closed {
+		if err := w.last.close(); err != nil {
+			return nil, err
+		}
+	}
+
+	fh.Flags |= 0x8 // we will write a data descriptor
+	fh.CreatorVersion = 0x14
+	fh.ReaderVersion = 0x14
+
+	fw := &fileWriter{
+		zipw:      w,
+		compCount: &countWriter{w: w},
+		crc32:     crc32.NewIEEE(),
+	}
+	switch fh.Method {
+	case Store:
+		fw.comp = nopCloser{fw.compCount}
+	case Deflate:
+		fw.comp = flate.NewWriter(fw.compCount, 5)
+	default:
+		return nil, UnsupportedMethod
+	}
+	fw.rawCount = &countWriter{w: fw.comp}
+
+	h := &header{
+		FileHeader: fh,
+		offset:     uint32(w.count),
+	}
+	w.dir = append(w.dir, h)
+	fw.header = h
+
+	if err := writeHeader(w, fh); err != nil {
+		return nil, err
+	}
+
+	w.last = fw
+	return fw, nil
+}
+
+func writeHeader(w io.Writer, h *FileHeader) (err os.Error) {
+	defer recoverError(&err)
+	write(w, uint32(fileHeaderSignature))
+	write(w, h.ReaderVersion)
+	write(w, h.Flags)
+	write(w, h.Method)
+	write(w, h.ModifiedTime)
+	write(w, h.ModifiedDate)
+	write(w, h.CRC32)
+	write(w, h.CompressedSize)
+	write(w, h.UncompressedSize)
+	write(w, uint16(len(h.Name)))
+	write(w, uint16(len(h.Extra)))
+	writeBytes(w, []byte(h.Name))
+	writeBytes(w, h.Extra)
+	return nil
+}
+
+type fileWriter struct {
+	*header
+	zipw      io.Writer
+	rawCount  *countWriter
+	comp      io.WriteCloser
+	compCount *countWriter
+	crc32     hash.Hash32
+	closed    bool
+}
+
+func (w *fileWriter) Write(p []byte) (int, os.Error) {
+	if w.closed {
+		return 0, os.NewError("zip: write to closed file")
+	}
+	w.crc32.Write(p)
+	return w.rawCount.Write(p)
+}
+
+func (w *fileWriter) close() (err os.Error) {
+	if w.closed {
+		return os.NewError("zip: file closed twice")
+	}
+	w.closed = true
+	if err = w.comp.Close(); err != nil {
+		return
+	}
+
+	// update FileHeader
+	fh := w.header.FileHeader
+	fh.CRC32 = w.crc32.Sum32()
+	fh.CompressedSize = uint32(w.compCount.count)
+	fh.UncompressedSize = uint32(w.rawCount.count)
+
+	// write data descriptor
+	defer recoverError(&err)
+	write(w.zipw, fh.CRC32)
+	write(w.zipw, fh.CompressedSize)
+	write(w.zipw, fh.UncompressedSize)
+
+	return nil
+}
+
+type countWriter struct {
+	w     io.Writer
+	count int64
+}
+
+func (w *countWriter) Write(p []byte) (int, os.Error) {
+	n, err := w.w.Write(p)
+	w.count += int64(n)
+	return n, err
+}
+
+type nopCloser struct {
+	io.Writer
+}
+
+func (w nopCloser) Close() os.Error {
+	return nil
+}
+
+func write(w io.Writer, data interface{}) {
+	if err := binary.Write(w, binary.LittleEndian, data); err != nil {
+		panic(err)
+	}
+}
+
+func writeBytes(w io.Writer, b []byte) {
+	n, err := w.Write(b)
+	if err != nil {
+		panic(err)
+	}
+	if n != len(b) {
+		panic(io.ErrShortWrite)
+	}
+}
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
new file mode 100644
index 0000000..eb2a80c
--- /dev/null
+++ b/src/pkg/archive/zip/writer_test.go
@@ -0,0 +1,73 @@
+// 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 zip
+
+import (
+	"bytes"
+	"io/ioutil"
+	"rand"
+	"testing"
+)
+
+// TODO(adg): a more sophisticated test suite
+
+const testString = "Rabbits, guinea pigs, gophers, marsupial rats, and quolls."
+
+func TestWriter(t *testing.T) {
+	largeData := make([]byte, 1<<17)
+	for i := range largeData {
+		largeData[i] = byte(rand.Int())
+	}
+
+	// write a zip file
+	buf := new(bytes.Buffer)
+	w := NewWriter(buf)
+	testCreate(t, w, "foo", []byte(testString), Store)
+	testCreate(t, w, "bar", largeData, Deflate)
+	if err := w.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// read it back
+	r, err := NewReader(sliceReaderAt(buf.Bytes()), int64(buf.Len()))
+	if err != nil {
+		t.Fatal(err)
+	}
+	testReadFile(t, r.File[0], []byte(testString))
+	testReadFile(t, r.File[1], largeData)
+}
+
+func testCreate(t *testing.T, w *Writer, name string, data []byte, method uint16) {
+	header := &FileHeader{
+		Name:   name,
+		Method: method,
+	}
+	f, err := w.CreateHeader(header)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.Write(data)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func testReadFile(t *testing.T, f *File, data []byte) {
+	rc, err := f.Open()
+	if err != nil {
+		t.Fatal("opening:", err)
+	}
+	b, err := ioutil.ReadAll(rc)
+	if err != nil {
+		t.Fatal("reading:", err)
+	}
+	err = rc.Close()
+	if err != nil {
+		t.Fatal("closing:", err)
+	}
+	if !bytes.Equal(b, data) {
+		t.Errorf("File contents %q, want %q", b, data)
+	}
+}
diff --git a/src/pkg/archive/zip/zip_test.go b/src/pkg/archive/zip/zip_test.go
new file mode 100644
index 0000000..0f71fdf
--- /dev/null
+++ b/src/pkg/archive/zip/zip_test.go
@@ -0,0 +1,57 @@
+// 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.
+
+// Tests that involve both reading and writing.
+
+package zip
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"testing"
+)
+
+type stringReaderAt string
+
+func (s stringReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
+	if off >= int64(len(s)) {
+		return 0, os.EOF
+	}
+	n = copy(p, s[off:])
+	return
+}
+
+func TestOver65kFiles(t *testing.T) {
+	if testing.Short() {
+		t.Logf("slow test; skipping")
+		return
+	}
+	buf := new(bytes.Buffer)
+	w := NewWriter(buf)
+	const nFiles = (1 << 16) + 42
+	for i := 0; i < nFiles; i++ {
+		_, err := w.Create(fmt.Sprintf("%d.dat", i))
+		if err != nil {
+			t.Fatalf("creating file %d: %v", i, err)
+		}
+	}
+	if err := w.Close(); err != nil {
+		t.Fatalf("Writer.Close: %v", err)
+	}
+	rat := stringReaderAt(buf.String())
+	zr, err := NewReader(rat, int64(len(rat)))
+	if err != nil {
+		t.Fatalf("NewReader: %v", err)
+	}
+	if got := len(zr.File); got != nFiles {
+		t.Fatalf("File contains %d files, want %d", got, nFiles)
+	}
+	for i := 0; i < nFiles; i++ {
+		want := fmt.Sprintf("%d.dat", i)
+		if zr.File[i].Name != want {
+			t.Fatalf("File(%d) = %q, want %q", i, zr.File[i].Name, want)
+		}
+	}
+}
diff --git a/src/pkg/asn1/asn1.go b/src/pkg/asn1/asn1.go
index 6557729..2dcdcfe 100644
--- a/src/pkg/asn1/asn1.go
+++ b/src/pkg/asn1/asn1.go
@@ -220,7 +220,6 @@ func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
 // An Enumerated is represented as a plain int.
 type Enumerated int
 
-
 // FLAG
 
 // A Flag accepts any data and is set to true if present.
diff --git a/src/pkg/big/arith.go b/src/pkg/big/arith.go
index b9aeea9..0a02a4e 100644
--- a/src/pkg/big/arith.go
+++ b/src/pkg/big/arith.go
@@ -27,7 +27,6 @@ const (
 	_M2 = _B2 - 1  // half digit mask
 )
 
-
 // ----------------------------------------------------------------------------
 // Elementary operations on words
 //
@@ -43,7 +42,6 @@ func addWW_g(x, y, c Word) (z1, z0 Word) {
 	return
 }
 
-
 // z1<<_W + z0 = x-y-c, with c == 0 or 1
 func subWW_g(x, y, c Word) (z1, z0 Word) {
 	yc := y + c
@@ -54,7 +52,6 @@ func subWW_g(x, y, c Word) (z1, z0 Word) {
 	return
 }
 
-
 // z1<<_W + z0 = x*y
 // Adapted from Warren, Hacker's Delight, p. 132.
 func mulWW_g(x, y Word) (z1, z0 Word) {
@@ -72,7 +69,6 @@ func mulWW_g(x, y Word) (z1, z0 Word) {
 	return
 }
 
-
 // z1<<_W + z0 = x*y + c
 func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
 	z1, zz0 := mulWW(x, y)
@@ -82,7 +78,6 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
 	return
 }
 
-
 // Length of x in bits.
 func bitLen(x Word) (n int) {
 	for ; x >= 0x100; x >>= 8 {
@@ -94,7 +89,6 @@ func bitLen(x Word) (n int) {
 	return
 }
 
-
 // log2 computes the integer binary logarithm of x.
 // The result is the integer n for which 2^n <= x < 2^(n+1).
 // If x == 0, the result is -1.
@@ -102,13 +96,11 @@ func log2(x Word) int {
 	return bitLen(x) - 1
 }
 
-
 // Number of leading zeros in x.
 func leadingZeros(x Word) uint {
 	return uint(_W - bitLen(x))
 }
 
-
 // q = (u1<<_W + u0 - r)/y
 // Adapted from Warren, Hacker's Delight, p. 152.
 func divWW_g(u1, u0, v Word) (q, r Word) {
@@ -153,7 +145,6 @@ again2:
 	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
 }
 
-
 func addVV_g(z, x, y []Word) (c Word) {
 	for i := range z {
 		c, z[i] = addWW_g(x[i], y[i], c)
@@ -161,7 +152,6 @@ func addVV_g(z, x, y []Word) (c Word) {
 	return
 }
 
-
 func subVV_g(z, x, y []Word) (c Word) {
 	for i := range z {
 		c, z[i] = subWW_g(x[i], y[i], c)
@@ -169,7 +159,6 @@ func subVV_g(z, x, y []Word) (c Word) {
 	return
 }
 
-
 func addVW_g(z, x []Word, y Word) (c Word) {
 	c = y
 	for i := range z {
@@ -178,7 +167,6 @@ func addVW_g(z, x []Word, y Word) (c Word) {
 	return
 }
 
-
 func subVW_g(z, x []Word, y Word) (c Word) {
 	c = y
 	for i := range z {
@@ -187,7 +175,6 @@ func subVW_g(z, x []Word, y Word) (c Word) {
 	return
 }
 
-
 func shlVU_g(z, x []Word, s uint) (c Word) {
 	if n := len(z); n > 0 {
 		ŝ := _W - s
@@ -203,7 +190,6 @@ func shlVU_g(z, x []Word, s uint) (c Word) {
 	return
 }
 
-
 func shrVU_g(z, x []Word, s uint) (c Word) {
 	if n := len(z); n > 0 {
 		ŝ := _W - s
@@ -219,7 +205,6 @@ func shrVU_g(z, x []Word, s uint) (c Word) {
 	return
 }
 
-
 func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
 	c = r
 	for i := range z {
@@ -228,7 +213,6 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
 	return
 }
 
-
 func addMulVVW_g(z, x []Word, y Word) (c Word) {
 	for i := range z {
 		z1, z0 := mulAddWWW_g(x[i], y, z[i])
@@ -238,7 +222,6 @@ func addMulVVW_g(z, x []Word, y Word) (c Word) {
 	return
 }
 
-
 func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
 	r = xn
 	for i := len(z) - 1; i >= 0; i-- {
diff --git a/src/pkg/big/arith_test.go b/src/pkg/big/arith_test.go
index f3e2d47..b6c56c3 100644
--- a/src/pkg/big/arith_test.go
+++ b/src/pkg/big/arith_test.go
@@ -6,7 +6,6 @@ package big
 
 import "testing"
 
-
 type funWW func(x, y, c Word) (z1, z0 Word)
 type argWW struct {
 	x, y, c, z1, z0 Word
@@ -26,7 +25,6 @@ var sumWW = []argWW{
 	{_M, _M, 1, 1, _M},
 }
 
-
 func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
 	z1, z0 := f(a.x, a.y, a.c)
 	if z1 != a.z1 || z0 != a.z0 {
@@ -34,7 +32,6 @@ func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
 	}
 }
 
-
 func TestFunWW(t *testing.T) {
 	for _, a := range sumWW {
 		arg := a
@@ -51,7 +48,6 @@ func TestFunWW(t *testing.T) {
 	}
 }
 
-
 type funVV func(z, x, y []Word) (c Word)
 type argVV struct {
 	z, x, y nat
@@ -70,7 +66,6 @@ var sumVV = []argVV{
 	{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
 }
 
-
 func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
 	z := make(nat, len(a.z))
 	c := f(z, a.x, a.y)
@@ -85,7 +80,6 @@ func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
 	}
 }
 
-
 func TestFunVV(t *testing.T) {
 	for _, a := range sumVV {
 		arg := a
@@ -106,7 +100,6 @@ func TestFunVV(t *testing.T) {
 	}
 }
 
-
 type funVW func(z, x []Word, y Word) (c Word)
 type argVW struct {
 	z, x nat
@@ -169,7 +162,6 @@ var rshVW = []argVW{
 	{nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
 }
 
-
 func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
 	z := make(nat, len(a.z))
 	c := f(z, a.x, a.y)
@@ -184,14 +176,12 @@ func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
 	}
 }
 
-
 func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
 	return func(z, x []Word, s Word) (c Word) {
 		return f(z, x, uint(s))
 	}
 }
 
-
 func TestFunVW(t *testing.T) {
 	for _, a := range sumVW {
 		arg := a
@@ -220,7 +210,6 @@ func TestFunVW(t *testing.T) {
 	}
 }
 
-
 type funVWW func(z, x []Word, y, r Word) (c Word)
 type argVWW struct {
 	z, x nat
@@ -254,7 +243,6 @@ var prodVWW = []argVWW{
 	{nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
 }
 
-
 func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
 	z := make(nat, len(a.z))
 	c := f(z, a.x, a.y, a.r)
@@ -269,7 +257,6 @@ func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
 	}
 }
 
-
 // TODO(gri) mulAddVWW and divWVW are symmetric operations but
 //           their signature is not symmetric. Try to unify.
 
@@ -296,7 +283,6 @@ func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
 	}
 }
 
-
 func TestFunVWW(t *testing.T) {
 	for _, a := range prodVWW {
 		arg := a
@@ -311,7 +297,6 @@ func TestFunVWW(t *testing.T) {
 	}
 }
 
-
 var mulWWTests = []struct {
 	x, y Word
 	q, r Word
@@ -320,7 +305,6 @@ var mulWWTests = []struct {
 	// 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
 }
 
-
 func TestMulWW(t *testing.T) {
 	for i, test := range mulWWTests {
 		q, r := mulWW_g(test.x, test.y)
@@ -330,7 +314,6 @@ func TestMulWW(t *testing.T) {
 	}
 }
 
-
 var mulAddWWWTests = []struct {
 	x, y, c Word
 	q, r    Word
@@ -342,7 +325,6 @@ var mulAddWWWTests = []struct {
 	{_M, _M, _M, _M, 0},
 }
 
-
 func TestMulAddWWW(t *testing.T) {
 	for i, test := range mulAddWWWTests {
 		q, r := mulAddWWW_g(test.x, test.y, test.c)
diff --git a/src/pkg/big/calibrate_test.go b/src/pkg/big/calibrate_test.go
index c6cd2e6..1cd93b1 100644
--- a/src/pkg/big/calibrate_test.go
+++ b/src/pkg/big/calibrate_test.go
@@ -19,10 +19,8 @@ import (
 	"time"
 )
 
-
 var calibrate = flag.Bool("calibrate", false, "run calibration test")
 
-
 // measure returns the time to run f
 func measure(f func()) int64 {
 	const N = 100
@@ -34,7 +32,6 @@ func measure(f func()) int64 {
 	return (stop - start) / N
 }
 
-
 func computeThresholds() {
 	fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
 	fmt.Printf("(run repeatedly for good results)\n")
@@ -84,7 +81,6 @@ func computeThresholds() {
 	}
 }
 
-
 func TestCalibrate(t *testing.T) {
 	if *calibrate {
 		computeThresholds()
diff --git a/src/pkg/big/hilbert_test.go b/src/pkg/big/hilbert_test.go
index 66a2121..1a84341 100644
--- a/src/pkg/big/hilbert_test.go
+++ b/src/pkg/big/hilbert_test.go
@@ -13,13 +13,11 @@ import (
 	"testing"
 )
 
-
 type matrix struct {
 	n, m int
 	a    []*Rat
 }
 
-
 func (a *matrix) at(i, j int) *Rat {
 	if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
 		panic("index out of range")
@@ -27,7 +25,6 @@ func (a *matrix) at(i, j int) *Rat {
 	return a.a[i*a.m+j]
 }
 
-
 func (a *matrix) set(i, j int, x *Rat) {
 	if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
 		panic("index out of range")
@@ -35,7 +32,6 @@ func (a *matrix) set(i, j int, x *Rat) {
 	a.a[i*a.m+j] = x
 }
 
-
 func newMatrix(n, m int) *matrix {
 	if !(0 <= n && 0 <= m) {
 		panic("illegal matrix")
@@ -47,7 +43,6 @@ func newMatrix(n, m int) *matrix {
 	return a
 }
 
-
 func newUnit(n int) *matrix {
 	a := newMatrix(n, n)
 	for i := 0; i < n; i++ {
@@ -62,7 +57,6 @@ func newUnit(n int) *matrix {
 	return a
 }
 
-
 func newHilbert(n int) *matrix {
 	a := newMatrix(n, n)
 	for i := 0; i < n; i++ {
@@ -73,7 +67,6 @@ func newHilbert(n int) *matrix {
 	return a
 }
 
-
 func newInverseHilbert(n int) *matrix {
 	a := newMatrix(n, n)
 	for i := 0; i < n; i++ {
@@ -98,7 +91,6 @@ func newInverseHilbert(n int) *matrix {
 	return a
 }
 
-
 func (a *matrix) mul(b *matrix) *matrix {
 	if a.m != b.n {
 		panic("illegal matrix multiply")
@@ -116,7 +108,6 @@ func (a *matrix) mul(b *matrix) *matrix {
 	return c
 }
 
-
 func (a *matrix) eql(b *matrix) bool {
 	if a.n != b.n || a.m != b.m {
 		return false
@@ -131,7 +122,6 @@ func (a *matrix) eql(b *matrix) bool {
 	return true
 }
 
-
 func (a *matrix) String() string {
 	s := ""
 	for i := 0; i < a.n; i++ {
@@ -143,7 +133,6 @@ func (a *matrix) String() string {
 	return s
 }
 
-
 func doHilbert(t *testing.T, n int) {
 	a := newHilbert(n)
 	b := newInverseHilbert(n)
@@ -160,12 +149,10 @@ func doHilbert(t *testing.T, n int) {
 	}
 }
 
-
 func TestHilbert(t *testing.T) {
 	doHilbert(t, 10)
 }
 
-
 func BenchmarkHilbert(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		doHilbert(nil, 10)
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
index 0948919..701b697 100755
--- a/src/pkg/big/int.go
+++ b/src/pkg/big/int.go
@@ -21,10 +21,8 @@ type Int struct {
 	abs nat  // absolute value of the integer
 }
 
-
 var intOne = &Int{false, natOne}
 
-
 // Sign returns:
 //
 //	-1 if x <  0
@@ -41,7 +39,6 @@ func (x *Int) Sign() int {
 	return 1
 }
 
-
 // SetInt64 sets z to x and returns z.
 func (z *Int) SetInt64(x int64) *Int {
 	neg := false
@@ -54,13 +51,11 @@ func (z *Int) SetInt64(x int64) *Int {
 	return z
 }
 
-
 // NewInt allocates and returns a new Int set to x.
 func NewInt(x int64) *Int {
 	return new(Int).SetInt64(x)
 }
 
-
 // Set sets z to x and returns z.
 func (z *Int) Set(x *Int) *Int {
 	z.abs = z.abs.set(x.abs)
@@ -68,7 +63,6 @@ func (z *Int) Set(x *Int) *Int {
 	return z
 }
 
-
 // Abs sets z to |x| (the absolute value of x) and returns z.
 func (z *Int) Abs(x *Int) *Int {
 	z.abs = z.abs.set(x.abs)
@@ -76,7 +70,6 @@ func (z *Int) Abs(x *Int) *Int {
 	return z
 }
 
-
 // Neg sets z to -x and returns z.
 func (z *Int) Neg(x *Int) *Int {
 	z.abs = z.abs.set(x.abs)
@@ -84,7 +77,6 @@ func (z *Int) Neg(x *Int) *Int {
 	return z
 }
 
-
 // Add sets z to the sum x+y and returns z.
 func (z *Int) Add(x, y *Int) *Int {
 	neg := x.neg
@@ -106,7 +98,6 @@ func (z *Int) Add(x, y *Int) *Int {
 	return z
 }
 
-
 // Sub sets z to the difference x-y and returns z.
 func (z *Int) Sub(x, y *Int) *Int {
 	neg := x.neg
@@ -128,7 +119,6 @@ func (z *Int) Sub(x, y *Int) *Int {
 	return z
 }
 
-
 // Mul sets z to the product x*y and returns z.
 func (z *Int) Mul(x, y *Int) *Int {
 	// x * y == x * y
@@ -140,7 +130,6 @@ func (z *Int) Mul(x, y *Int) *Int {
 	return z
 }
 
-
 // MulRange sets z to the product of all integers
 // in the range [a, b] inclusively and returns z.
 // If a > b (empty range), the result is 1.
@@ -164,7 +153,6 @@ func (z *Int) MulRange(a, b int64) *Int {
 	return z
 }
 
-
 // Binomial sets z to the binomial coefficient of (n, k) and returns z.
 func (z *Int) Binomial(n, k int64) *Int {
 	var a, b Int
@@ -173,7 +161,6 @@ func (z *Int) Binomial(n, k int64) *Int {
 	return z.Quo(&a, &b)
 }
 
-
 // Quo sets z to the quotient x/y for y != 0 and returns z.
 // If y == 0, a division-by-zero run-time panic occurs.
 // See QuoRem for more details.
@@ -183,7 +170,6 @@ func (z *Int) Quo(x, y *Int) *Int {
 	return z
 }
 
-
 // Rem sets z to the remainder x%y for y != 0 and returns z.
 // If y == 0, a division-by-zero run-time panic occurs.
 // See QuoRem for more details.
@@ -193,7 +179,6 @@ func (z *Int) Rem(x, y *Int) *Int {
 	return z
 }
 
-
 // QuoRem sets z to the quotient x/y and r to the remainder x%y
 // and returns the pair (z, r) for y != 0.
 // If y == 0, a division-by-zero run-time panic occurs.
@@ -211,7 +196,6 @@ func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
 	return z, r
 }
 
-
 // Div sets z to the quotient x/y for y != 0 and returns z.
 // If y == 0, a division-by-zero run-time panic occurs.
 // See DivMod for more details.
@@ -229,7 +213,6 @@ func (z *Int) Div(x, y *Int) *Int {
 	return z
 }
 
-
 // Mod sets z to the modulus x%y for y != 0 and returns z.
 // If y == 0, a division-by-zero run-time panic occurs.
 // See DivMod for more details.
@@ -250,7 +233,6 @@ func (z *Int) Mod(x, y *Int) *Int {
 	return z
 }
 
-
 // DivMod sets z to the quotient x div y and m to the modulus x mod y
 // and returns the pair (z, m) for y != 0.
 // If y == 0, a division-by-zero run-time panic occurs.
@@ -283,7 +265,6 @@ func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
 	return z, m
 }
 
-
 // Cmp compares x and y and returns:
 //
 //   -1 if x <  y
@@ -309,7 +290,6 @@ func (x *Int) Cmp(y *Int) (r int) {
 	return
 }
 
-
 func (x *Int) String() string {
 	switch {
 	case x == nil:
@@ -320,7 +300,6 @@ func (x *Int) String() string {
 	return x.abs.decimalString()
 }
 
-
 func charset(ch int) string {
 	switch ch {
 	case 'b':
@@ -337,10 +316,26 @@ func charset(ch int) string {
 	return "" // unknown format
 }
 
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+	if len(text) > 0 {
+		b := []byte(text)
+		for ; count > 0; count-- {
+			s.Write(b)
+		}
+	}
+}
 
 // Format is a support routine for fmt.Formatter. It accepts
 // the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
 // (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
 //
 func (x *Int) Format(s fmt.State, ch int) {
 	cs := charset(ch)
@@ -356,75 +351,74 @@ func (x *Int) Format(s fmt.State, ch int) {
 		return
 	}
 
-	// determine format
-	format := "%s"
+	// determine sign character
+	sign := ""
+	switch {
+	case x.neg:
+		sign = "-"
+	case s.Flag('+'): // supersedes ' ' when both specified
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	// determine prefix characters for indicating output base
+	prefix := ""
 	if s.Flag('#') {
 		switch ch {
-		case 'o':
-			format = "0%s"
-		case 'x':
-			format = "0x%s"
+		case 'o': // octal
+			prefix = "0"
+		case 'x': // hexadecimal
+			prefix = "0x"
 		case 'X':
-			format = "0X%s"
-		}
-	}
-	t := fmt.Sprintf(format, x.abs.string(cs))
-
-	// insert spaces in hexadecimal formats if needed
-	if len(t) > 0 && s.Flag(' ') && (ch == 'x' || ch == 'X') {
-		spaces := (len(t)+1)/2 - 1
-		spaced := make([]byte, len(t)+spaces)
-		var i, j int
-		spaced[i] = t[j]
-		i++
-		j++
-		if len(t)&1 == 0 {
-			spaced[i] = t[j]
-			i++
-			j++
+			prefix = "0X"
 		}
-		for j < len(t) {
-			spaced[i] = ' '
-			i++
-			spaced[i] = t[j]
-			i++
-			j++
-			spaced[i] = t[j]
-			i++
-			j++
-		}
-		t = string(spaced)
 	}
 
-	// determine sign prefix
-	prefix := ""
-	switch {
-	case x.neg:
-		prefix = "-"
-	case s.Flag('+'):
-		prefix = "+"
-	case s.Flag(' ') && ch != 'x' && ch != 'X':
-		prefix = " "
+	// determine digits with base set by len(cs) and digit characters from cs
+	digits := x.abs.string(cs)
+
+	// number of characters for the three classes of number padding
+	var left int   // space characters to left of digits for right justification ("%8d")
+	var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+	var right int  // space characters to right of digits for left justification ("%-8d")
+
+	// determine number padding from precision: the least number of digits to output
+	precision, precisionSet := s.Precision()
+	if precisionSet {
+		switch {
+		case len(digits) < precision:
+			zeroes = precision - len(digits) // count of zero padding 
+		case digits == "0" && precision == 0:
+			return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+		}
 	}
 
-	// fill to minimum width and prepend sign prefix
-	if width, ok := s.Width(); ok && len(t)+len(prefix) < width {
-		if s.Flag('0') {
-			t = fmt.Sprintf("%s%0*d%s", prefix, width-len(t)-len(prefix), 0, t)
-		} else {
-			if s.Flag('-') {
-				width = -width
-			}
-			t = fmt.Sprintf("%*s", width, prefix+t)
+	// determine field pad from width: the least number of characters to output
+	length := len(sign) + len(prefix) + zeroes + len(digits)
+	if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+		switch d := width - length; {
+		case s.Flag('-'):
+			// pad on the right with spaces; supersedes '0' when both specified
+			right = d
+		case s.Flag('0') && !precisionSet:
+			// pad with zeroes unless precision also specified
+			zeroes = d
+		default:
+			// pad on the left with spaces
+			left = d
 		}
-	} else if prefix != "" {
-		t = prefix + t
 	}
 
-	fmt.Fprint(s, t)
+	// print number as [left pad][sign][prefix][zero pad][digits][right pad]
+	writeMultiple(s, " ", left)
+	writeMultiple(s, sign, 1)
+	writeMultiple(s, prefix, 1)
+	writeMultiple(s, "0", zeroes)
+	writeMultiple(s, digits, 1)
+	writeMultiple(s, " ", right)
 }
 
-
 // scan sets z to the integer value corresponding to the longest possible prefix
 // read from r representing a signed integer number in a given conversion base.
 // It returns z, the actual conversion base used, and an error, if any. In the
@@ -461,7 +455,6 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
 	return z, base, nil
 }
 
-
 // Scan is a support routine for fmt.Scanner; it sets z to the value of
 // the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
 // 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
@@ -486,7 +479,6 @@ func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
 	return err
 }
 
-
 // Int64 returns the int64 representation of x.
 // If x cannot be represented in an int64, the result is undefined.
 func (x *Int) Int64() int64 {
@@ -503,7 +495,6 @@ func (x *Int) Int64() int64 {
 	return v
 }
 
-
 // SetString sets z to the value of s, interpreted in the given base,
 // and returns z and a boolean indicating success. If SetString fails,
 // the value of z is undefined.
@@ -523,7 +514,6 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
 	return z, err == os.EOF // err == os.EOF => scan consumed all of s
 }
 
-
 // SetBytes interprets buf as the bytes of a big-endian unsigned
 // integer, sets z to that value, and returns z.
 func (z *Int) SetBytes(buf []byte) *Int {
@@ -532,21 +522,18 @@ func (z *Int) SetBytes(buf []byte) *Int {
 	return z
 }
 
-
 // Bytes returns the absolute value of z as a big-endian byte slice.
 func (z *Int) Bytes() []byte {
 	buf := make([]byte, len(z.abs)*_S)
 	return buf[z.abs.bytes(buf):]
 }
 
-
 // BitLen returns the length of the absolute value of z in bits.
 // The bit length of 0 is 0.
 func (z *Int) BitLen() int {
 	return z.abs.bitLen()
 }
 
-
 // Exp sets z = x**y mod m. If m is nil, z = x**y.
 // See Knuth, volume 2, section 4.6.3.
 func (z *Int) Exp(x, y, m *Int) *Int {
@@ -567,7 +554,6 @@ func (z *Int) Exp(x, y, m *Int) *Int {
 	return z
 }
 
-
 // GcdInt sets d to the greatest common divisor of a and b, which must be
 // positive numbers.
 // If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
@@ -626,7 +612,6 @@ func GcdInt(d, x, y, a, b *Int) {
 	*d = *A
 }
 
-
 // ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
 // If it returns true, z is prime with probability 1 - 1/4^n.
 // If it returns false, z is not prime.
@@ -634,7 +619,6 @@ func ProbablyPrime(z *Int, n int) bool {
 	return !z.neg && z.abs.probablyPrime(n)
 }
 
-
 // Rand sets z to a pseudo-random number in [0, n) and returns z.
 func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
 	z.neg = false
@@ -646,7 +630,6 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
 	return z
 }
 
-
 // ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
 // p is a prime) and returns z.
 func (z *Int) ModInverse(g, p *Int) *Int {
@@ -660,7 +643,6 @@ func (z *Int) ModInverse(g, p *Int) *Int {
 	return z
 }
 
-
 // Lsh sets z = x << n and returns z.
 func (z *Int) Lsh(x *Int, n uint) *Int {
 	z.abs = z.abs.shl(x.abs, n)
@@ -668,7 +650,6 @@ func (z *Int) Lsh(x *Int, n uint) *Int {
 	return z
 }
 
-
 // Rsh sets z = x >> n and returns z.
 func (z *Int) Rsh(x *Int, n uint) *Int {
 	if x.neg {
@@ -685,7 +666,6 @@ func (z *Int) Rsh(x *Int, n uint) *Int {
 	return z
 }
 
-
 // Bit returns the value of the i'th bit of z. That is, it
 // returns (z>>i)&1. The bit index i must be >= 0.
 func (z *Int) Bit(i int) uint {
@@ -700,7 +680,6 @@ func (z *Int) Bit(i int) uint {
 	return z.abs.bit(uint(i))
 }
 
-
 // SetBit sets the i'th bit of z to bit and returns z.
 // That is, if bit is 1 SetBit sets z = x | (1 << i);
 // if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
@@ -721,7 +700,6 @@ func (z *Int) SetBit(x *Int, i int, b uint) *Int {
 	return z
 }
 
-
 // And sets z = x & y and returns z.
 func (z *Int) And(x, y *Int) *Int {
 	if x.neg == y.neg {
@@ -752,7 +730,6 @@ func (z *Int) And(x, y *Int) *Int {
 	return z
 }
 
-
 // AndNot sets z = x &^ y and returns z.
 func (z *Int) AndNot(x, y *Int) *Int {
 	if x.neg == y.neg {
@@ -786,7 +763,6 @@ func (z *Int) AndNot(x, y *Int) *Int {
 	return z
 }
 
-
 // Or sets z = x | y and returns z.
 func (z *Int) Or(x, y *Int) *Int {
 	if x.neg == y.neg {
@@ -817,7 +793,6 @@ func (z *Int) Or(x, y *Int) *Int {
 	return z
 }
 
-
 // Xor sets z = x ^ y and returns z.
 func (z *Int) Xor(x, y *Int) *Int {
 	if x.neg == y.neg {
@@ -848,7 +823,6 @@ func (z *Int) Xor(x, y *Int) *Int {
 	return z
 }
 
-
 // Not sets z = ^x and returns z.
 func (z *Int) Not(x *Int) *Int {
 	if x.neg {
@@ -864,7 +838,6 @@ func (z *Int) Not(x *Int) *Int {
 	return z
 }
 
-
 // Gob codec version. Permits backward-compatible changes to the encoding.
 const intGobVersion byte = 1
 
@@ -880,7 +853,6 @@ func (z *Int) GobEncode() ([]byte, os.Error) {
 	return buf[i:], nil
 }
 
-
 // GobDecode implements the gob.GobDecoder interface.
 func (z *Int) GobDecode(buf []byte) os.Error {
 	if len(buf) == 0 {
diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go
index 7f33c95..03446d6 100755
--- a/src/pkg/big/int_test.go
+++ b/src/pkg/big/int_test.go
@@ -13,7 +13,6 @@ import (
 	"testing/quick"
 )
 
-
 func isNormalized(x *Int) bool {
 	if len(x.abs) == 0 {
 		return !x.neg
@@ -22,13 +21,11 @@ func isNormalized(x *Int) bool {
 	return x.abs[len(x.abs)-1] != 0
 }
 
-
 type funZZ func(z, x, y *Int) *Int
 type argZZ struct {
 	z, x, y *Int
 }
 
-
 var sumZZ = []argZZ{
 	{NewInt(0), NewInt(0), NewInt(0)},
 	{NewInt(1), NewInt(1), NewInt(0)},
@@ -38,7 +35,6 @@ var sumZZ = []argZZ{
 	{NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
 }
 
-
 var prodZZ = []argZZ{
 	{NewInt(0), NewInt(0), NewInt(0)},
 	{NewInt(0), NewInt(1), NewInt(0)},
@@ -47,7 +43,6 @@ var prodZZ = []argZZ{
 	// TODO(gri) add larger products
 }
 
-
 func TestSignZ(t *testing.T) {
 	var zero Int
 	for _, a := range sumZZ {
@@ -59,7 +54,6 @@ func TestSignZ(t *testing.T) {
 	}
 }
 
-
 func TestSetZ(t *testing.T) {
 	for _, a := range sumZZ {
 		var z Int
@@ -73,7 +67,6 @@ func TestSetZ(t *testing.T) {
 	}
 }
 
-
 func TestAbsZ(t *testing.T) {
 	var zero Int
 	for _, a := range sumZZ {
@@ -90,7 +83,6 @@ func TestAbsZ(t *testing.T) {
 	}
 }
 
-
 func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
 	var z Int
 	f(&z, a.x, a.y)
@@ -102,7 +94,6 @@ func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
 	}
 }
 
-
 func TestSumZZ(t *testing.T) {
 	AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
 	SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
@@ -121,7 +112,6 @@ func TestSumZZ(t *testing.T) {
 	}
 }
 
-
 func TestProdZZ(t *testing.T) {
 	MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
 	for _, a := range prodZZ {
@@ -133,7 +123,6 @@ func TestProdZZ(t *testing.T) {
 	}
 }
 
-
 // mulBytes returns x*y via grade school multiplication. Both inputs
 // and the result are assumed to be in big-endian representation (to
 // match the semantics of Int.Bytes and Int.SetBytes).
@@ -166,7 +155,6 @@ func mulBytes(x, y []byte) []byte {
 	return z[i:]
 }
 
-
 func checkMul(a, b []byte) bool {
 	var x, y, z1 Int
 	x.SetBytes(a)
@@ -179,14 +167,12 @@ func checkMul(a, b []byte) bool {
 	return z1.Cmp(&z2) == 0
 }
 
-
 func TestMul(t *testing.T) {
 	if err := quick.Check(checkMul, nil); err != nil {
 		t.Error(err)
 	}
 }
 
-
 var mulRangesZ = []struct {
 	a, b int64
 	prod string
@@ -212,7 +198,6 @@ var mulRangesZ = []struct {
 	},
 }
 
-
 func TestMulRangeZ(t *testing.T) {
 	var tmp Int
 	// test entirely positive ranges
@@ -231,7 +216,6 @@ func TestMulRangeZ(t *testing.T) {
 	}
 }
 
-
 var stringTests = []struct {
 	in   string
 	out  string
@@ -280,7 +264,6 @@ var stringTests = []struct {
 	{"1001010111", "1001010111", 2, 0x257, true},
 }
 
-
 func format(base int) string {
 	switch base {
 	case 2:
@@ -293,7 +276,6 @@ func format(base int) string {
 	return "%d"
 }
 
-
 func TestGetString(t *testing.T) {
 	z := new(Int)
 	for i, test := range stringTests {
@@ -316,7 +298,6 @@ func TestGetString(t *testing.T) {
 	}
 }
 
-
 func TestSetString(t *testing.T) {
 	tmp := new(Int)
 	for i, test := range stringTests {
@@ -347,7 +328,6 @@ func TestSetString(t *testing.T) {
 	}
 }
 
-
 var formatTests = []struct {
 	input  string
 	format string
@@ -386,12 +366,10 @@ var formatTests = []struct {
 	{"1234", "%-5d", "1234 "},
 	{"1234", "%x", "4d2"},
 	{"1234", "%X", "4D2"},
-	{"1234", "% x", "4 d2"},
 	{"-1234", "%3x", "-4d2"},
 	{"-1234", "%4x", "-4d2"},
 	{"-1234", "%5x", " -4d2"},
 	{"-1234", "%-5x", "-4d2 "},
-	{"-1234", "% x", "-4 d2"},
 	{"1234", "%03d", "1234"},
 	{"1234", "%04d", "1234"},
 	{"1234", "%05d", "01234"},
@@ -400,14 +378,105 @@ var formatTests = []struct {
 	{"1234", "%+06d", "+01234"},
 	{"1234", "% 06d", " 01234"},
 	{"1234", "%-6d", "1234  "},
-	{"1234", "%-06d", "001234"},
-	{"-1234", "%-06d", "-01234"},
-	{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", // 10**100
-		"% x",
-		"12 49 ad 25 94 c3 7c eb 0b 27 84 c4 ce 0b f3 8a ce 40 8e 21 1a 7c aa b2 43 08 a8 2e 8f 10 00 00 00 00 00 00 00 00 00 00 00 00"},
+	{"1234", "%-06d", "1234  "},
+	{"-1234", "%-06d", "-1234 "},
+
+	{"1234", "%.3d", "1234"},
+	{"1234", "%.4d", "1234"},
+	{"1234", "%.5d", "01234"},
+	{"1234", "%.6d", "001234"},
+	{"-1234", "%.3d", "-1234"},
+	{"-1234", "%.4d", "-1234"},
+	{"-1234", "%.5d", "-01234"},
+	{"-1234", "%.6d", "-001234"},
+
+	{"1234", "%8.3d", "    1234"},
+	{"1234", "%8.4d", "    1234"},
+	{"1234", "%8.5d", "   01234"},
+	{"1234", "%8.6d", "  001234"},
+	{"-1234", "%8.3d", "   -1234"},
+	{"-1234", "%8.4d", "   -1234"},
+	{"-1234", "%8.5d", "  -01234"},
+	{"-1234", "%8.6d", " -001234"},
+
+	{"1234", "%+8.3d", "   +1234"},
+	{"1234", "%+8.4d", "   +1234"},
+	{"1234", "%+8.5d", "  +01234"},
+	{"1234", "%+8.6d", " +001234"},
+	{"-1234", "%+8.3d", "   -1234"},
+	{"-1234", "%+8.4d", "   -1234"},
+	{"-1234", "%+8.5d", "  -01234"},
+	{"-1234", "%+8.6d", " -001234"},
+
+	{"1234", "% 8.3d", "    1234"},
+	{"1234", "% 8.4d", "    1234"},
+	{"1234", "% 8.5d", "   01234"},
+	{"1234", "% 8.6d", "  001234"},
+	{"-1234", "% 8.3d", "   -1234"},
+	{"-1234", "% 8.4d", "   -1234"},
+	{"-1234", "% 8.5d", "  -01234"},
+	{"-1234", "% 8.6d", " -001234"},
+
+	{"1234", "%.3x", "4d2"},
+	{"1234", "%.4x", "04d2"},
+	{"1234", "%.5x", "004d2"},
+	{"1234", "%.6x", "0004d2"},
+	{"-1234", "%.3x", "-4d2"},
+	{"-1234", "%.4x", "-04d2"},
+	{"-1234", "%.5x", "-004d2"},
+	{"-1234", "%.6x", "-0004d2"},
+
+	{"1234", "%8.3x", "     4d2"},
+	{"1234", "%8.4x", "    04d2"},
+	{"1234", "%8.5x", "   004d2"},
+	{"1234", "%8.6x", "  0004d2"},
+	{"-1234", "%8.3x", "    -4d2"},
+	{"-1234", "%8.4x", "   -04d2"},
+	{"-1234", "%8.5x", "  -004d2"},
+	{"-1234", "%8.6x", " -0004d2"},
+
+	{"1234", "%+8.3x", "    +4d2"},
+	{"1234", "%+8.4x", "   +04d2"},
+	{"1234", "%+8.5x", "  +004d2"},
+	{"1234", "%+8.6x", " +0004d2"},
+	{"-1234", "%+8.3x", "    -4d2"},
+	{"-1234", "%+8.4x", "   -04d2"},
+	{"-1234", "%+8.5x", "  -004d2"},
+	{"-1234", "%+8.6x", " -0004d2"},
+
+	{"1234", "% 8.3x", "     4d2"},
+	{"1234", "% 8.4x", "    04d2"},
+	{"1234", "% 8.5x", "   004d2"},
+	{"1234", "% 8.6x", "  0004d2"},
+	{"1234", "% 8.7x", " 00004d2"},
+	{"1234", "% 8.8x", " 000004d2"},
+	{"-1234", "% 8.3x", "    -4d2"},
+	{"-1234", "% 8.4x", "   -04d2"},
+	{"-1234", "% 8.5x", "  -004d2"},
+	{"-1234", "% 8.6x", " -0004d2"},
+	{"-1234", "% 8.7x", "-00004d2"},
+	{"-1234", "% 8.8x", "-000004d2"},
+
+	{"1234", "%-8.3d", "1234    "},
+	{"1234", "%-8.4d", "1234    "},
+	{"1234", "%-8.5d", "01234   "},
+	{"1234", "%-8.6d", "001234  "},
+	{"1234", "%-8.7d", "0001234 "},
+	{"1234", "%-8.8d", "00001234"},
+	{"-1234", "%-8.3d", "-1234   "},
+	{"-1234", "%-8.4d", "-1234   "},
+	{"-1234", "%-8.5d", "-01234  "},
+	{"-1234", "%-8.6d", "-001234 "},
+	{"-1234", "%-8.7d", "-0001234"},
+	{"-1234", "%-8.8d", "-00001234"},
+
+	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+	{"0", "%.d", ""},
+	{"0", "%.0d", ""},
+	{"0", "%3.d", ""},
 }
 
-
 func TestFormat(t *testing.T) {
 	for i, test := range formatTests {
 		var x *Int
@@ -420,12 +489,11 @@ func TestFormat(t *testing.T) {
 		}
 		output := fmt.Sprintf(test.format, x)
 		if output != test.output {
-			t.Errorf("#%d got %q; want %q", i, output, test.output)
+			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
 		}
 	}
 }
 
-
 var scanTests = []struct {
 	input     string
 	format    string
@@ -449,7 +517,6 @@ var scanTests = []struct {
 	{"0XABC 12", "%v", "2748", 3},
 }
 
-
 func TestScan(t *testing.T) {
 	var buf bytes.Buffer
 	for i, test := range scanTests {
@@ -468,7 +535,6 @@ func TestScan(t *testing.T) {
 	}
 }
 
-
 // Examples from the Go Language Spec, section "Arithmetic operators"
 var divisionSignsTests = []struct {
 	x, y int64
@@ -483,7 +549,6 @@ var divisionSignsTests = []struct {
 	{8, 4, 2, 0, 2, 0},
 }
 
-
 func TestDivisionSigns(t *testing.T) {
 	for i, test := range divisionSignsTests {
 		x := NewInt(test.x)
@@ -541,7 +606,6 @@ func TestDivisionSigns(t *testing.T) {
 	}
 }
 
-
 func checkSetBytes(b []byte) bool {
 	hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
 	hex2 := hex.EncodeToString(b)
@@ -557,27 +621,23 @@ func checkSetBytes(b []byte) bool {
 	return hex1 == hex2
 }
 
-
 func TestSetBytes(t *testing.T) {
 	if err := quick.Check(checkSetBytes, nil); err != nil {
 		t.Error(err)
 	}
 }
 
-
 func checkBytes(b []byte) bool {
 	b2 := new(Int).SetBytes(b).Bytes()
 	return bytes.Compare(b, b2) == 0
 }
 
-
 func TestBytes(t *testing.T) {
 	if err := quick.Check(checkSetBytes, nil); err != nil {
 		t.Error(err)
 	}
 }
 
-
 func checkQuo(x, y []byte) bool {
 	u := new(Int).SetBytes(x)
 	v := new(Int).SetBytes(y)
@@ -600,7 +660,6 @@ func checkQuo(x, y []byte) bool {
 	return uprime.Cmp(u) == 0
 }
 
-
 var quoTests = []struct {
 	x, y string
 	q, r string
@@ -619,7 +678,6 @@ var quoTests = []struct {
 	},
 }
 
-
 func TestQuo(t *testing.T) {
 	if err := quick.Check(checkQuo, nil); err != nil {
 		t.Error(err)
@@ -640,7 +698,6 @@ func TestQuo(t *testing.T) {
 	}
 }
 
-
 func TestQuoStepD6(t *testing.T) {
 	// See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
 	// a code path which only triggers 1 in 10^{-19} cases.
@@ -660,7 +717,6 @@ func TestQuoStepD6(t *testing.T) {
 	}
 }
 
-
 var bitLenTests = []struct {
 	in  string
 	out int
@@ -679,7 +735,6 @@ var bitLenTests = []struct {
 	{"-0x4000000000000000000000", 87},
 }
 
-
 func TestBitLen(t *testing.T) {
 	for i, test := range bitLenTests {
 		x, ok := new(Int).SetString(test.in, 0)
@@ -694,7 +749,6 @@ func TestBitLen(t *testing.T) {
 	}
 }
 
-
 var expTests = []struct {
 	x, y, m string
 	out     string
@@ -719,7 +773,6 @@ var expTests = []struct {
 	},
 }
 
-
 func TestExp(t *testing.T) {
 	for i, test := range expTests {
 		x, ok1 := new(Int).SetString(test.x, 0)
@@ -750,7 +803,6 @@ func TestExp(t *testing.T) {
 	}
 }
 
-
 func checkGcd(aBytes, bBytes []byte) bool {
 	a := new(Int).SetBytes(aBytes)
 	b := new(Int).SetBytes(bBytes)
@@ -767,7 +819,6 @@ func checkGcd(aBytes, bBytes []byte) bool {
 	return x.Cmp(d) == 0
 }
 
-
 var gcdTests = []struct {
 	a, b    int64
 	d, x, y int64
@@ -775,7 +826,6 @@ var gcdTests = []struct {
 	{120, 23, 1, -9, 47},
 }
 
-
 func TestGcd(t *testing.T) {
 	for i, test := range gcdTests {
 		a := NewInt(test.a)
@@ -801,7 +851,6 @@ func TestGcd(t *testing.T) {
 	quick.Check(checkGcd, nil)
 }
 
-
 var primes = []string{
 	"2",
 	"3",
@@ -827,7 +876,6 @@ var primes = []string{
 	"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
 }
 
-
 var composites = []string{
 	"21284175091214687912771199898307297748211672914763848041968395774954376176754",
 	"6084766654921918907427900243509372380954290099172559290432744450051395395951",
@@ -835,7 +883,6 @@ var composites = []string{
 	"82793403787388584738507275144194252681",
 }
 
-
 func TestProbablyPrime(t *testing.T) {
 	nreps := 20
 	if testing.Short() {
@@ -859,14 +906,12 @@ func TestProbablyPrime(t *testing.T) {
 	}
 }
 
-
 type intShiftTest struct {
 	in    string
 	shift uint
 	out   string
 }
 
-
 var rshTests = []intShiftTest{
 	{"0", 0, "0"},
 	{"-0", 0, "0"},
@@ -894,7 +939,6 @@ var rshTests = []intShiftTest{
 	{"340282366920938463463374607431768211456", 128, "1"},
 }
 
-
 func TestRsh(t *testing.T) {
 	for i, test := range rshTests {
 		in, _ := new(Int).SetString(test.in, 10)
@@ -910,7 +954,6 @@ func TestRsh(t *testing.T) {
 	}
 }
 
-
 func TestRshSelf(t *testing.T) {
 	for i, test := range rshTests {
 		z, _ := new(Int).SetString(test.in, 10)
@@ -926,7 +969,6 @@ func TestRshSelf(t *testing.T) {
 	}
 }
 
-
 var lshTests = []intShiftTest{
 	{"0", 0, "0"},
 	{"0", 1, "0"},
@@ -949,7 +991,6 @@ var lshTests = []intShiftTest{
 	{"1", 128, "340282366920938463463374607431768211456"},
 }
 
-
 func TestLsh(t *testing.T) {
 	for i, test := range lshTests {
 		in, _ := new(Int).SetString(test.in, 10)
@@ -965,7 +1006,6 @@ func TestLsh(t *testing.T) {
 	}
 }
 
-
 func TestLshSelf(t *testing.T) {
 	for i, test := range lshTests {
 		z, _ := new(Int).SetString(test.in, 10)
@@ -981,7 +1021,6 @@ func TestLshSelf(t *testing.T) {
 	}
 }
 
-
 func TestLshRsh(t *testing.T) {
 	for i, test := range rshTests {
 		in, _ := new(Int).SetString(test.in, 10)
@@ -1009,7 +1048,6 @@ func TestLshRsh(t *testing.T) {
 	}
 }
 
-
 var int64Tests = []int64{
 	0,
 	1,
@@ -1023,7 +1061,6 @@ var int64Tests = []int64{
 	-9223372036854775808,
 }
 
-
 func TestInt64(t *testing.T) {
 	for i, testVal := range int64Tests {
 		in := NewInt(testVal)
@@ -1035,7 +1072,6 @@ func TestInt64(t *testing.T) {
 	}
 }
 
-
 var bitwiseTests = []struct {
 	x, y                 string
 	and, or, xor, andNot string
@@ -1079,7 +1115,6 @@ var bitwiseTests = []struct {
 	},
 }
 
-
 type bitFun func(z, x, y *Int) *Int
 
 func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
@@ -1092,7 +1127,6 @@ func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
 	}
 }
 
-
 func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
 	self := new(Int)
 	self.Set(x)
@@ -1105,7 +1139,6 @@ func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
 	}
 }
 
-
 func altBit(x *Int, i int) uint {
 	z := new(Int).Rsh(x, uint(i))
 	z = z.And(z, NewInt(1))
@@ -1115,7 +1148,6 @@ func altBit(x *Int, i int) uint {
 	return 0
 }
 
-
 func altSetBit(z *Int, x *Int, i int, b uint) *Int {
 	one := NewInt(1)
 	m := one.Lsh(one, uint(i))
@@ -1128,7 +1160,6 @@ func altSetBit(z *Int, x *Int, i int, b uint) *Int {
 	panic("set bit is not 0 or 1")
 }
 
-
 func testBitset(t *testing.T, x *Int) {
 	n := x.BitLen()
 	z := new(Int).Set(x)
@@ -1166,7 +1197,6 @@ func testBitset(t *testing.T, x *Int) {
 	}
 }
 
-
 var bitsetTests = []struct {
 	x string
 	i int
@@ -1186,7 +1216,6 @@ var bitsetTests = []struct {
 	{"-0x2000000000000000000000000001", 110, 1},
 }
 
-
 func TestBitSet(t *testing.T) {
 	for _, test := range bitwiseTests {
 		x := new(Int)
@@ -1207,7 +1236,6 @@ func TestBitSet(t *testing.T) {
 	}
 }
 
-
 func BenchmarkBitset(b *testing.B) {
 	z := new(Int)
 	z.SetBit(z, 512, 1)
@@ -1218,7 +1246,6 @@ func BenchmarkBitset(b *testing.B) {
 	}
 }
 
-
 func BenchmarkBitsetNeg(b *testing.B) {
 	z := NewInt(-1)
 	z.SetBit(z, 512, 0)
@@ -1229,7 +1256,6 @@ func BenchmarkBitsetNeg(b *testing.B) {
 	}
 }
 
-
 func BenchmarkBitsetOrig(b *testing.B) {
 	z := new(Int)
 	altSetBit(z, z, 512, 1)
@@ -1240,7 +1266,6 @@ func BenchmarkBitsetOrig(b *testing.B) {
 	}
 }
 
-
 func BenchmarkBitsetNegOrig(b *testing.B) {
 	z := NewInt(-1)
 	altSetBit(z, z, 512, 0)
@@ -1251,7 +1276,6 @@ func BenchmarkBitsetNegOrig(b *testing.B) {
 	}
 }
 
-
 func TestBitwise(t *testing.T) {
 	x := new(Int)
 	y := new(Int)
@@ -1270,7 +1294,6 @@ func TestBitwise(t *testing.T) {
 	}
 }
 
-
 var notTests = []struct {
 	in  string
 	out string
@@ -1286,7 +1309,6 @@ var notTests = []struct {
 	},
 }
 
-
 func TestNot(t *testing.T) {
 	in := new(Int)
 	out := new(Int)
@@ -1305,7 +1327,6 @@ func TestNot(t *testing.T) {
 	}
 }
 
-
 var modInverseTests = []struct {
 	element string
 	prime   string
@@ -1315,7 +1336,6 @@ var modInverseTests = []struct {
 	{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
 }
 
-
 func TestModInverse(t *testing.T) {
 	var element, prime Int
 	one := NewInt(1)
@@ -1331,7 +1351,6 @@ func TestModInverse(t *testing.T) {
 	}
 }
 
-
 // used by TestIntGobEncoding and TestRatGobEncoding
 var gobEncodingTests = []string{
 	"0",
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
index 6755832..be3aff2 100755
--- a/src/pkg/big/nat.go
+++ b/src/pkg/big/nat.go
@@ -24,7 +24,6 @@ import (
 	"rand"
 )
 
-
 // An unsigned integer x of the form
 //
 //   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
@@ -45,14 +44,12 @@ var (
 	natTen = nat{10}
 )
 
-
 func (z nat) clear() {
 	for i := range z {
 		z[i] = 0
 	}
 }
 
-
 func (z nat) norm() nat {
 	i := len(z)
 	for i > 0 && z[i-1] == 0 {
@@ -61,7 +58,6 @@ func (z nat) norm() nat {
 	return z[0:i]
 }
 
-
 func (z nat) make(n int) nat {
 	if n <= cap(z) {
 		return z[0:n] // reuse z
@@ -72,7 +68,6 @@ func (z nat) make(n int) nat {
 	return make(nat, n, n+e)
 }
 
-
 func (z nat) setWord(x Word) nat {
 	if x == 0 {
 		return z.make(0)
@@ -82,7 +77,6 @@ func (z nat) setWord(x Word) nat {
 	return z
 }
 
-
 func (z nat) setUint64(x uint64) nat {
 	// single-digit values
 	if w := Word(x); uint64(w) == x {
@@ -105,14 +99,12 @@ func (z nat) setUint64(x uint64) nat {
 	return z
 }
 
-
 func (z nat) set(x nat) nat {
 	z = z.make(len(x))
 	copy(z, x)
 	return z
 }
 
-
 func (z nat) add(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -139,7 +131,6 @@ func (z nat) add(x, y nat) nat {
 	return z.norm()
 }
 
-
 func (z nat) sub(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -168,7 +159,6 @@ func (z nat) sub(x, y nat) nat {
 	return z.norm()
 }
 
-
 func (x nat) cmp(y nat) (r int) {
 	m := len(x)
 	n := len(y)
@@ -196,7 +186,6 @@ func (x nat) cmp(y nat) (r int) {
 	return
 }
 
-
 func (z nat) mulAddWW(x nat, y, r Word) nat {
 	m := len(x)
 	if m == 0 || y == 0 {
@@ -210,7 +199,6 @@ func (z nat) mulAddWW(x nat, y, r Word) nat {
 	return z.norm()
 }
 
-
 // basicMul multiplies x and y and leaves the result in z.
 // The (non-normalized) result is placed in z[0 : len(x) + len(y)].
 func basicMul(z, x, y nat) {
@@ -222,7 +210,6 @@ func basicMul(z, x, y nat) {
 	}
 }
 
-
 // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
 // Factored out for readability - do not use outside karatsuba.
 func karatsubaAdd(z, x nat, n int) {
@@ -231,7 +218,6 @@ func karatsubaAdd(z, x nat, n int) {
 	}
 }
 
-
 // Like karatsubaAdd, but does subtract.
 func karatsubaSub(z, x nat, n int) {
 	if c := subVV(z[0:n], z, x); c != 0 {
@@ -239,7 +225,6 @@ func karatsubaSub(z, x nat, n int) {
 	}
 }
 
-
 // Operands that are shorter than karatsubaThreshold are multiplied using
 // "grade school" multiplication; for longer operands the Karatsuba algorithm
 // is used.
@@ -344,13 +329,11 @@ func karatsuba(z, x, y nat) {
 	}
 }
 
-
 // alias returns true if x and y share the same base array.
 func alias(x, y nat) bool {
 	return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
 }
 
-
 // addAt implements z += x*(1<<(_W*i)); z must be long enough.
 // (we don't use nat.add because we need z to stay the same
 // slice, and we don't need to normalize z after each addition)
@@ -365,7 +348,6 @@ func addAt(z, x nat, i int) {
 	}
 }
 
-
 func max(x, y int) int {
 	if x > y {
 		return x
@@ -373,7 +355,6 @@ func max(x, y int) int {
 	return y
 }
 
-
 // karatsubaLen computes an approximation to the maximum k <= n such that
 // k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
 // result is the largest number that can be divided repeatedly by 2 before
@@ -387,7 +368,6 @@ func karatsubaLen(n int) int {
 	return n << i
 }
 
-
 func (z nat) mul(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -455,7 +435,6 @@ func (z nat) mul(x, y nat) nat {
 	return z.norm()
 }
 
-
 // mulRange computes the product of all the unsigned integers in the
 // range [a, b] inclusively. If a > b (empty range), the result is 1.
 func (z nat) mulRange(a, b uint64) nat {
@@ -474,7 +453,6 @@ func (z nat) mulRange(a, b uint64) nat {
 	return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
 }
 
-
 // q = (x-r)/y, with 0 <= r < y
 func (z nat) divW(x nat, y Word) (q nat, r Word) {
 	m := len(x)
@@ -495,7 +473,6 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) {
 	return
 }
 
-
 func (z nat) div(z2, u, v nat) (q, r nat) {
 	if len(v) == 0 {
 		panic("division by zero")
@@ -523,7 +500,6 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
 	return
 }
 
-
 // q = (uIn-r)/v, with 0 <= r < y
 // Uses z as storage for q, and u as storage for r if possible.
 // See Knuth, Volume 2, section 4.3.1, Algorithm D.
@@ -602,7 +578,6 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 	return q, r
 }
 
-
 // Length of x in bits. x must be normalized.
 func (x nat) bitLen() int {
 	if i := len(x) - 1; i >= 0 {
@@ -611,7 +586,6 @@ func (x nat) bitLen() int {
 	return 0
 }
 
-
 // MaxBase is the largest number base accepted for string conversions.
 const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
 
@@ -629,7 +603,6 @@ func hexValue(ch int) Word {
 	return Word(d)
 }
 
-
 // scan sets z to the natural number corresponding to the longest possible prefix
 // read from r representing an unsigned integer in a given conversion base.
 // It returns z, the actual conversion base used, and an error, if any. In the
@@ -727,21 +700,18 @@ func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
 	return z.norm(), int(b), nil
 }
 
-
 // Character sets for string conversion.
 const (
 	lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
 	uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 )
 
-
 // decimalString returns a decimal representation of x.
 // It calls x.string with the charset "0123456789".
 func (x nat) decimalString() string {
 	return x.string(lowercaseDigits[0:10])
 }
 
-
 // string converts x to a string using digits from a charset; a digit with
 // value d is represented by charset[d]. The conversion base is determined
 // by len(charset), which must be >= 2.
@@ -863,7 +833,6 @@ func (x nat) string(charset string) string {
 	return string(s[i:])
 }
 
-
 const deBruijn32 = 0x077CB531
 
 var deBruijn32Lookup = []byte{
@@ -880,7 +849,6 @@ var deBruijn64Lookup = []byte{
 	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
 }
 
-
 // trailingZeroBits returns the number of consecutive zero bits on the right
 // side of the given Word.
 // See Knuth, volume 4, section 7.3.1
@@ -905,7 +873,6 @@ func trailingZeroBits(x Word) int {
 	return 0
 }
 
-
 // z = x << s
 func (z nat) shl(x nat, s uint) nat {
 	m := len(x)
@@ -922,7 +889,6 @@ func (z nat) shl(x nat, s uint) nat {
 	return z.norm()
 }
 
-
 // z = x >> s
 func (z nat) shr(x nat, s uint) nat {
 	m := len(x)
@@ -938,7 +904,6 @@ func (z nat) shr(x nat, s uint) nat {
 	return z.norm()
 }
 
-
 func (z nat) setBit(x nat, i uint, b uint) nat {
 	j := int(i / _W)
 	m := Word(1) << (i % _W)
@@ -966,7 +931,6 @@ func (z nat) setBit(x nat, i uint, b uint) nat {
 	panic("set bit is not 0 or 1")
 }
 
-
 func (z nat) bit(i uint) uint {
 	j := int(i / _W)
 	if j >= len(z) {
@@ -975,7 +939,6 @@ func (z nat) bit(i uint) uint {
 	return uint(z[j] >> (i % _W) & 1)
 }
 
-
 func (z nat) and(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -992,7 +955,6 @@ func (z nat) and(x, y nat) nat {
 	return z.norm()
 }
 
-
 func (z nat) andNot(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -1010,7 +972,6 @@ func (z nat) andNot(x, y nat) nat {
 	return z.norm()
 }
 
-
 func (z nat) or(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -1030,7 +991,6 @@ func (z nat) or(x, y nat) nat {
 	return z.norm()
 }
 
-
 func (z nat) xor(x, y nat) nat {
 	m := len(x)
 	n := len(y)
@@ -1050,13 +1010,11 @@ func (z nat) xor(x, y nat) nat {
 	return z.norm()
 }
 
-
 // greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
 func greaterThan(x1, x2, y1, y2 Word) bool {
 	return x1 > y1 || x1 == y1 && x2 > y2
 }
 
-
 // modW returns x % d.
 func (x nat) modW(d Word) (r Word) {
 	// TODO(agl): we don't actually need to store the q value.
@@ -1065,7 +1023,6 @@ func (x nat) modW(d Word) (r Word) {
 	return divWVW(q, 0, x, d)
 }
 
-
 // powersOfTwoDecompose finds q and k with x = q * 1<<k and q is odd, or q and k are 0.
 func (x nat) powersOfTwoDecompose() (q nat, k int) {
 	if len(x) == 0 {
@@ -1089,7 +1046,6 @@ func (x nat) powersOfTwoDecompose() (q nat, k int) {
 	return
 }
 
-
 // random creates a random integer in [0..limit), using the space in z if
 // possible. n is the bit length of limit.
 func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
@@ -1120,7 +1076,6 @@ func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
 	return z.norm()
 }
 
-
 // If m != nil, expNN calculates x**y mod m. Otherwise it calculates x**y. It
 // reuses the storage of z if possible.
 func (z nat) expNN(x, y, m nat) nat {
@@ -1189,7 +1144,6 @@ func (z nat) expNN(x, y, m nat) nat {
 	return z
 }
 
-
 // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
 // If it returns true, n is prime with probability 1 - 1/4^reps.
 // If it returns false, n is not prime.
@@ -1272,7 +1226,6 @@ NextRandom:
 	return true
 }
 
-
 // bytes writes the value of z into buf using big-endian encoding.
 // len(buf) must be >= len(z)*_S. The value of z is encoded in the
 // slice buf[i:]. The number i of unused bytes at the beginning of
@@ -1294,7 +1247,6 @@ func (z nat) bytes(buf []byte) (i int) {
 	return
 }
 
-
 // setBytes interprets buf as the bytes of a big-endian unsigned
 // integer, sets z to that value, and returns z.
 func (z nat) setBytes(buf []byte) nat {
diff --git a/src/pkg/big/nat_test.go b/src/pkg/big/nat_test.go
index fd93592..71d0860 100755
--- a/src/pkg/big/nat_test.go
+++ b/src/pkg/big/nat_test.go
@@ -31,7 +31,6 @@ var cmpTests = []struct {
 	{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
 }
 
-
 func TestCmp(t *testing.T) {
 	for i, a := range cmpTests {
 		r := a.x.cmp(a.y)
@@ -41,13 +40,11 @@ func TestCmp(t *testing.T) {
 	}
 }
 
-
 type funNN func(z, x, y nat) nat
 type argNN struct {
 	z, x, y nat
 }
 
-
 var sumNN = []argNN{
 	{},
 	{nat{1}, nil, nat{1}},
@@ -57,7 +54,6 @@ var sumNN = []argNN{
 	{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
 }
 
-
 var prodNN = []argNN{
 	{},
 	{nil, nil, nil},
@@ -69,7 +65,6 @@ var prodNN = []argNN{
 	{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
 }
 
-
 func TestSet(t *testing.T) {
 	for _, a := range sumNN {
 		z := nat(nil).set(a.z)
@@ -79,7 +74,6 @@ func TestSet(t *testing.T) {
 	}
 }
 
-
 func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
 	z := f(nil, a.x, a.y)
 	if z.cmp(a.z) != 0 {
@@ -87,7 +81,6 @@ func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
 	}
 }
 
-
 func TestFunNN(t *testing.T) {
 	for _, a := range sumNN {
 		arg := a
@@ -112,7 +105,6 @@ func TestFunNN(t *testing.T) {
 	}
 }
 
-
 var mulRangesN = []struct {
 	a, b uint64
 	prod string
@@ -135,7 +127,6 @@ var mulRangesN = []struct {
 	},
 }
 
-
 func TestMulRangeN(t *testing.T) {
 	for i, r := range mulRangesN {
 		prod := nat(nil).mulRange(r.a, r.b).decimalString()
@@ -145,7 +136,6 @@ func TestMulRangeN(t *testing.T) {
 	}
 }
 
-
 var mulArg, mulTmp nat
 
 func init() {
@@ -156,7 +146,6 @@ func init() {
 	}
 }
 
-
 func benchmarkMulLoad() {
 	for j := 1; j <= 10; j++ {
 		x := mulArg[0 : j*100]
@@ -164,14 +153,12 @@ func benchmarkMulLoad() {
 	}
 }
 
-
 func BenchmarkMul(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		benchmarkMulLoad()
 	}
 }
 
-
 func toString(x nat, charset string) string {
 	base := len(charset)
 
@@ -201,7 +188,6 @@ func toString(x nat, charset string) string {
 	return string(s[i:])
 }
 
-
 var strTests = []struct {
 	x nat    // nat value to be converted
 	c string // conversion charset
@@ -219,7 +205,6 @@ var strTests = []struct {
 	{nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
 }
 
-
 func TestString(t *testing.T) {
 	for _, a := range strTests {
 		s := a.x.string(a.c)
@@ -240,7 +225,6 @@ func TestString(t *testing.T) {
 	}
 }
 
-
 var natScanTests = []struct {
 	s    string // string to be scanned
 	base int    // input base
@@ -284,7 +268,6 @@ var natScanTests = []struct {
 	{"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0},
 }
 
-
 func TestScanBase(t *testing.T) {
 	for _, a := range natScanTests {
 		r := strings.NewReader(a.s)
@@ -315,7 +298,6 @@ func TestScanBase(t *testing.T) {
 	}
 }
 
-
 var pi = "3" +
 	"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
 	"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
@@ -369,7 +351,6 @@ var pi = "3" +
 	"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
 	"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
 
-
 // Test case for BenchmarkScanPi.
 func TestScanPi(t *testing.T) {
 	var x nat
@@ -382,7 +363,6 @@ func TestScanPi(t *testing.T) {
 	}
 }
 
-
 func BenchmarkScanPi(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var x nat
@@ -390,7 +370,6 @@ func BenchmarkScanPi(b *testing.B) {
 	}
 }
 
-
 const (
 	// 314**271
 	// base  2: 2249 digits
@@ -417,67 +396,54 @@ const (
 	longExponent = 27182
 )
 
-
 func BenchmarkScanShort2(b *testing.B) {
 	ScanHelper(b, 2, shortBase, shortExponent)
 }
 
-
 func BenchmarkScanShort8(b *testing.B) {
 	ScanHelper(b, 8, shortBase, shortExponent)
 }
 
-
 func BenchmarkScanSort10(b *testing.B) {
 	ScanHelper(b, 10, shortBase, shortExponent)
 }
 
-
 func BenchmarkScanShort16(b *testing.B) {
 	ScanHelper(b, 16, shortBase, shortExponent)
 }
 
-
 func BenchmarkScanMedium2(b *testing.B) {
 	ScanHelper(b, 2, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkScanMedium8(b *testing.B) {
 	ScanHelper(b, 8, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkScanMedium10(b *testing.B) {
 	ScanHelper(b, 10, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkScanMedium16(b *testing.B) {
 	ScanHelper(b, 16, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkScanLong2(b *testing.B) {
 	ScanHelper(b, 2, longBase, longExponent)
 }
 
-
 func BenchmarkScanLong8(b *testing.B) {
 	ScanHelper(b, 8, longBase, longExponent)
 }
 
-
 func BenchmarkScanLong10(b *testing.B) {
 	ScanHelper(b, 10, longBase, longExponent)
 }
 
-
 func BenchmarkScanLong16(b *testing.B) {
 	ScanHelper(b, 16, longBase, longExponent)
 }
 
-
 func ScanHelper(b *testing.B, base int, xv, yv Word) {
 	b.StopTimer()
 	var x, y, z nat
@@ -497,67 +463,54 @@ func ScanHelper(b *testing.B, base int, xv, yv Word) {
 	}
 }
 
-
 func BenchmarkStringShort2(b *testing.B) {
 	StringHelper(b, 2, shortBase, shortExponent)
 }
 
-
 func BenchmarkStringShort8(b *testing.B) {
 	StringHelper(b, 8, shortBase, shortExponent)
 }
 
-
 func BenchmarkStringShort10(b *testing.B) {
 	StringHelper(b, 10, shortBase, shortExponent)
 }
 
-
 func BenchmarkStringShort16(b *testing.B) {
 	StringHelper(b, 16, shortBase, shortExponent)
 }
 
-
 func BenchmarkStringMedium2(b *testing.B) {
 	StringHelper(b, 2, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkStringMedium8(b *testing.B) {
 	StringHelper(b, 8, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkStringMedium10(b *testing.B) {
 	StringHelper(b, 10, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkStringMedium16(b *testing.B) {
 	StringHelper(b, 16, mediumBase, mediumExponent)
 }
 
-
 func BenchmarkStringLong2(b *testing.B) {
 	StringHelper(b, 2, longBase, longExponent)
 }
 
-
 func BenchmarkStringLong8(b *testing.B) {
 	StringHelper(b, 8, longBase, longExponent)
 }
 
-
 func BenchmarkStringLong10(b *testing.B) {
 	StringHelper(b, 10, longBase, longExponent)
 }
 
-
 func BenchmarkStringLong16(b *testing.B) {
 	StringHelper(b, 16, longBase, longExponent)
 }
 
-
 func StringHelper(b *testing.B, base int, xv, yv Word) {
 	b.StopTimer()
 	var x, y, z nat
@@ -571,7 +524,6 @@ func StringHelper(b *testing.B, base int, xv, yv Word) {
 	}
 }
 
-
 func TestLeadingZeros(t *testing.T) {
 	var x Word = _B >> 1
 	for i := 0; i <= _W; i++ {
@@ -582,14 +534,12 @@ func TestLeadingZeros(t *testing.T) {
 	}
 }
 
-
 type shiftTest struct {
 	in    nat
 	shift uint
 	out   nat
 }
 
-
 var leftShiftTests = []shiftTest{
 	{nil, 0, nil},
 	{nil, 1, nil},
@@ -599,7 +549,6 @@ var leftShiftTests = []shiftTest{
 	{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
 }
 
-
 func TestShiftLeft(t *testing.T) {
 	for i, test := range leftShiftTests {
 		var z nat
@@ -613,7 +562,6 @@ func TestShiftLeft(t *testing.T) {
 	}
 }
 
-
 var rightShiftTests = []shiftTest{
 	{nil, 0, nil},
 	{nil, 1, nil},
@@ -624,7 +572,6 @@ var rightShiftTests = []shiftTest{
 	{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
 }
 
-
 func TestShiftRight(t *testing.T) {
 	for i, test := range rightShiftTests {
 		var z nat
@@ -638,24 +585,20 @@ func TestShiftRight(t *testing.T) {
 	}
 }
 
-
 type modWTest struct {
 	in       string
 	dividend string
 	out      string
 }
 
-
 var modWTests32 = []modWTest{
 	{"23492635982634928349238759823742", "252341", "220170"},
 }
 
-
 var modWTests64 = []modWTest{
 	{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
 }
 
-
 func runModWTests(t *testing.T, tests []modWTest) {
 	for i, test := range tests {
 		in, _ := new(Int).SetString(test.in, 10)
@@ -669,7 +612,6 @@ func runModWTests(t *testing.T, tests []modWTest) {
 	}
 }
 
-
 func TestModW(t *testing.T) {
 	if _W >= 32 {
 		runModWTests(t, modWTests32)
@@ -679,7 +621,6 @@ func TestModW(t *testing.T) {
 	}
 }
 
-
 func TestTrailingZeroBits(t *testing.T) {
 	var x Word
 	x--
@@ -708,7 +649,6 @@ var expNNTests = []struct {
 	},
 }
 
-
 func TestExpNN(t *testing.T) {
 	for i, test := range expNNTests {
 		x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
diff --git a/src/pkg/big/rat.go b/src/pkg/big/rat.go
index b61cbb9..327b9bd 100644
--- a/src/pkg/big/rat.go
+++ b/src/pkg/big/rat.go
@@ -20,13 +20,11 @@ type Rat struct {
 	b nat
 }
 
-
 // NewRat creates a new Rat with numerator a and denominator b.
 func NewRat(a, b int64) *Rat {
 	return new(Rat).SetFrac64(a, b)
 }
 
-
 // SetFrac sets z to a/b and returns z.
 func (z *Rat) SetFrac(a, b *Int) *Rat {
 	z.a.Set(a)
@@ -35,7 +33,6 @@ func (z *Rat) SetFrac(a, b *Int) *Rat {
 	return z.norm()
 }
 
-
 // SetFrac64 sets z to a/b and returns z.
 func (z *Rat) SetFrac64(a, b int64) *Rat {
 	z.a.SetInt64(a)
@@ -47,7 +44,6 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
 	return z.norm()
 }
 
-
 // SetInt sets z to x (by making a copy of x) and returns z.
 func (z *Rat) SetInt(x *Int) *Rat {
 	z.a.Set(x)
@@ -55,7 +51,6 @@ func (z *Rat) SetInt(x *Int) *Rat {
 	return z
 }
 
-
 // SetInt64 sets z to x and returns z.
 func (z *Rat) SetInt64(x int64) *Rat {
 	z.a.SetInt64(x)
@@ -63,7 +58,6 @@ func (z *Rat) SetInt64(x int64) *Rat {
 	return z
 }
 
-
 // Sign returns:
 //
 //	-1 if x <  0
@@ -74,13 +68,11 @@ func (x *Rat) Sign() int {
 	return x.a.Sign()
 }
 
-
 // IsInt returns true if the denominator of x is 1.
 func (x *Rat) IsInt() bool {
 	return len(x.b) == 1 && x.b[0] == 1
 }
 
-
 // Num returns the numerator of z; it may be <= 0.
 // The result is a reference to z's numerator; it
 // may change if a new value is assigned to z.
@@ -88,7 +80,6 @@ func (z *Rat) Num() *Int {
 	return &z.a
 }
 
-
 // Denom returns the denominator of z; it is always > 0.
 // The result is a reference to z's denominator; it
 // may change if a new value is assigned to z.
@@ -96,7 +87,6 @@ func (z *Rat) Denom() *Int {
 	return &Int{false, z.b}
 }
 
-
 func gcd(x, y nat) nat {
 	// Euclidean algorithm.
 	var a, b nat
@@ -111,7 +101,6 @@ func gcd(x, y nat) nat {
 	return a
 }
 
-
 func (z *Rat) norm() *Rat {
 	f := gcd(z.a.abs, z.b)
 	if len(z.a.abs) == 0 {
@@ -127,7 +116,6 @@ func (z *Rat) norm() *Rat {
 	return z
 }
 
-
 func mulNat(x *Int, y nat) *Int {
 	var z Int
 	z.abs = z.abs.mul(x.abs, y)
@@ -135,7 +123,6 @@ func mulNat(x *Int, y nat) *Int {
 	return &z
 }
 
-
 // Cmp compares x and y and returns:
 //
 //   -1 if x <  y
@@ -146,7 +133,6 @@ func (x *Rat) Cmp(y *Rat) (r int) {
 	return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b))
 }
 
-
 // Abs sets z to |x| (the absolute value of x) and returns z.
 func (z *Rat) Abs(x *Rat) *Rat {
 	z.a.Abs(&x.a)
@@ -154,7 +140,6 @@ func (z *Rat) Abs(x *Rat) *Rat {
 	return z
 }
 
-
 // Add sets z to the sum x+y and returns z.
 func (z *Rat) Add(x, y *Rat) *Rat {
 	a1 := mulNat(&x.a, y.b)
@@ -164,7 +149,6 @@ func (z *Rat) Add(x, y *Rat) *Rat {
 	return z.norm()
 }
 
-
 // Sub sets z to the difference x-y and returns z.
 func (z *Rat) Sub(x, y *Rat) *Rat {
 	a1 := mulNat(&x.a, y.b)
@@ -174,7 +158,6 @@ func (z *Rat) Sub(x, y *Rat) *Rat {
 	return z.norm()
 }
 
-
 // Mul sets z to the product x*y and returns z.
 func (z *Rat) Mul(x, y *Rat) *Rat {
 	z.a.Mul(&x.a, &y.a)
@@ -182,7 +165,6 @@ func (z *Rat) Mul(x, y *Rat) *Rat {
 	return z.norm()
 }
 
-
 // Quo sets z to the quotient x/y and returns z.
 // If y == 0, a division-by-zero run-time panic occurs.
 func (z *Rat) Quo(x, y *Rat) *Rat {
@@ -197,7 +179,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
 	return z.norm()
 }
 
-
 // Neg sets z to -x (by making a copy of x if necessary) and returns z.
 func (z *Rat) Neg(x *Rat) *Rat {
 	z.a.Neg(&x.a)
@@ -205,7 +186,6 @@ func (z *Rat) Neg(x *Rat) *Rat {
 	return z
 }
 
-
 // Set sets z to x (by making a copy of x if necessary) and returns z.
 func (z *Rat) Set(x *Rat) *Rat {
 	z.a.Set(&x.a)
@@ -213,12 +193,10 @@ func (z *Rat) Set(x *Rat) *Rat {
 	return z
 }
 
-
 func ratTok(ch int) bool {
 	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
 }
 
-
 // Scan is a support routine for fmt.Scanner. It accepts the formats
 // 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
 func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error {
@@ -235,7 +213,6 @@ func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error {
 	return nil
 }
 
-
 // SetString sets z to the value of s and returns z and a boolean indicating
 // success. s can be given as a fraction "a/b" or as a floating-point number
 // optionally followed by an exponent. If the operation failed, the value of z
@@ -294,13 +271,11 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
 	return z, true
 }
 
-
 // String returns a string representation of z in the form "a/b" (even if b == 1).
 func (z *Rat) String() string {
 	return z.a.String() + "/" + z.b.decimalString()
 }
 
-
 // RatString returns a string representation of z in the form "a/b" if b != 1,
 // and in the form "a" if b == 1.
 func (z *Rat) RatString() string {
@@ -310,7 +285,6 @@ func (z *Rat) RatString() string {
 	return z.String()
 }
 
-
 // FloatString returns a string representation of z in decimal form with prec
 // digits of precision after the decimal point and the last digit rounded.
 func (z *Rat) FloatString(prec int) string {
@@ -356,7 +330,6 @@ func (z *Rat) FloatString(prec int) string {
 	return s
 }
 
-
 // Gob codec version. Permits backward-compatible changes to the encoding.
 const ratGobVersion byte = 1
 
@@ -380,7 +353,6 @@ func (z *Rat) GobEncode() ([]byte, os.Error) {
 	return buf[j:], nil
 }
 
-
 // GobDecode implements the gob.GobDecoder interface.
 func (z *Rat) GobDecode(buf []byte) os.Error {
 	if len(buf) == 0 {
diff --git a/src/pkg/big/rat_test.go b/src/pkg/big/rat_test.go
index e64505e..dbc5bb6 100644
--- a/src/pkg/big/rat_test.go
+++ b/src/pkg/big/rat_test.go
@@ -11,7 +11,6 @@ import (
 	"testing"
 )
 
-
 var setStringTests = []struct {
 	in, out string
 	ok      bool
@@ -57,7 +56,6 @@ func TestRatSetString(t *testing.T) {
 	}
 }
 
-
 func TestRatScan(t *testing.T) {
 	var buf bytes.Buffer
 	for i, test := range setStringTests {
@@ -80,7 +78,6 @@ func TestRatScan(t *testing.T) {
 	}
 }
 
-
 var floatStringTests = []struct {
 	in   string
 	prec int
@@ -113,7 +110,6 @@ func TestFloatString(t *testing.T) {
 	}
 }
 
-
 func TestRatSign(t *testing.T) {
 	zero := NewRat(0, 1)
 	for _, a := range setStringTests {
@@ -127,7 +123,6 @@ func TestRatSign(t *testing.T) {
 	}
 }
 
-
 var ratCmpTests = []struct {
 	rat1, rat2 string
 	out        int
@@ -155,7 +150,6 @@ func TestRatCmp(t *testing.T) {
 	}
 }
 
-
 func TestIsInt(t *testing.T) {
 	one := NewInt(1)
 	for _, a := range setStringTests {
@@ -169,7 +163,6 @@ func TestIsInt(t *testing.T) {
 	}
 }
 
-
 func TestRatAbs(t *testing.T) {
 	zero := NewRat(0, 1)
 	for _, a := range setStringTests {
@@ -187,7 +180,6 @@ func TestRatAbs(t *testing.T) {
 	}
 }
 
-
 type ratBinFun func(z, x, y *Rat) *Rat
 type ratBinArg struct {
 	x, y, z string
@@ -204,7 +196,6 @@ func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
 	}
 }
 
-
 var ratBinTests = []struct {
 	x, y      string
 	sum, prod string
@@ -261,7 +252,6 @@ func TestRatBin(t *testing.T) {
 	}
 }
 
-
 func TestIssue820(t *testing.T) {
 	x := NewRat(3, 1)
 	y := NewRat(2, 1)
@@ -287,7 +277,6 @@ func TestIssue820(t *testing.T) {
 	}
 }
 
-
 var setFrac64Tests = []struct {
 	a, b int64
 	out  string
@@ -310,7 +299,6 @@ func TestRatSetFrac64Rat(t *testing.T) {
 	}
 }
 
-
 func TestRatGobEncoding(t *testing.T) {
 	var medium bytes.Buffer
 	enc := gob.NewEncoder(&medium)
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index cb2667b..727ebfd 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -15,7 +15,6 @@ import (
 	"utf8"
 )
 
-
 const (
 	defaultBufSize = 4096
 )
@@ -42,7 +41,6 @@ func (b BufSizeError) String() string {
 	return "bufio: bad buffer size " + strconv.Itoa(int(b))
 }
 
-
 // Buffered input.
 
 // Reader implements buffering for an io.Reader object.
@@ -375,7 +373,6 @@ func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
 	return string(bytes), e
 }
 
-
 // buffered output
 
 // Writer implements buffering for an io.Writer object.
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 5709213..82c73d3 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -76,7 +76,6 @@ func TestReaderSimple(t *testing.T) {
 	}
 }
 
-
 type readMaker struct {
 	name string
 	fn   func(io.Reader) io.Reader
diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go
index 14f9501..06d2a65 100644
--- a/src/pkg/bytes/buffer_test.go
+++ b/src/pkg/bytes/buffer_test.go
@@ -12,7 +12,6 @@ import (
 	"utf8"
 )
 
-
 const N = 10000  // make this bigger for a larger (and slower) test
 var data string  // test data for write tests
 var bytes []byte // test data; same as data but as a slice.
@@ -47,7 +46,6 @@ func check(t *testing.T, testname string, buf *Buffer, s string) {
 	}
 }
 
-
 // Fill buf through n writes of string fus.
 // The initial contents of buf corresponds to the string s;
 // the result is the final contents of buf returned as a string.
@@ -67,7 +65,6 @@ func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus
 	return s
 }
 
-
 // Fill buf through n writes of byte slice fub.
 // The initial contents of buf corresponds to the string s;
 // the result is the final contents of buf returned as a string.
@@ -87,19 +84,16 @@ func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub
 	return s
 }
 
-
 func TestNewBuffer(t *testing.T) {
 	buf := NewBuffer(bytes)
 	check(t, "NewBuffer", buf, data)
 }
 
-
 func TestNewBufferString(t *testing.T) {
 	buf := NewBufferString(data)
 	check(t, "NewBufferString", buf, data)
 }
 
-
 // Empty buf through repeated reads into fub.
 // The initial contents of buf corresponds to the string s.
 func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
@@ -120,7 +114,6 @@ func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
 	check(t, testname+" (empty 4)", buf, "")
 }
 
-
 func TestBasicOperations(t *testing.T) {
 	var buf Buffer
 
@@ -175,7 +168,6 @@ func TestBasicOperations(t *testing.T) {
 	}
 }
 
-
 func TestLargeStringWrites(t *testing.T) {
 	var buf Buffer
 	limit := 30
@@ -189,7 +181,6 @@ func TestLargeStringWrites(t *testing.T) {
 	check(t, "TestLargeStringWrites (3)", &buf, "")
 }
 
-
 func TestLargeByteWrites(t *testing.T) {
 	var buf Buffer
 	limit := 30
@@ -203,7 +194,6 @@ func TestLargeByteWrites(t *testing.T) {
 	check(t, "TestLargeByteWrites (3)", &buf, "")
 }
 
-
 func TestLargeStringReads(t *testing.T) {
 	var buf Buffer
 	for i := 3; i < 30; i += 3 {
@@ -213,7 +203,6 @@ func TestLargeStringReads(t *testing.T) {
 	check(t, "TestLargeStringReads (3)", &buf, "")
 }
 
-
 func TestLargeByteReads(t *testing.T) {
 	var buf Buffer
 	for i := 3; i < 30; i += 3 {
@@ -223,7 +212,6 @@ func TestLargeByteReads(t *testing.T) {
 	check(t, "TestLargeByteReads (3)", &buf, "")
 }
 
-
 func TestMixedReadsAndWrites(t *testing.T) {
 	var buf Buffer
 	s := ""
@@ -243,7 +231,6 @@ func TestMixedReadsAndWrites(t *testing.T) {
 	empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
 }
 
-
 func TestNil(t *testing.T) {
 	var b *Buffer
 	if b.String() != "<nil>" {
@@ -251,7 +238,6 @@ func TestNil(t *testing.T) {
 	}
 }
 
-
 func TestReadFrom(t *testing.T) {
 	var buf Buffer
 	for i := 3; i < 30; i += 3 {
@@ -262,7 +248,6 @@ func TestReadFrom(t *testing.T) {
 	}
 }
 
-
 func TestWriteTo(t *testing.T) {
 	var buf Buffer
 	for i := 3; i < 30; i += 3 {
@@ -273,7 +258,6 @@ func TestWriteTo(t *testing.T) {
 	}
 }
 
-
 func TestRuneIO(t *testing.T) {
 	const NRune = 1000
 	// Built a test array while we write the data
@@ -323,7 +307,6 @@ func TestRuneIO(t *testing.T) {
 	}
 }
 
-
 func TestNext(t *testing.T) {
 	b := []byte{0, 1, 2, 3, 4}
 	tmp := make([]byte, 5)
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 3cec60f..5119fce 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -398,7 +398,6 @@ func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
 	return Map(func(r int) int { return _case.ToTitle(r) }, s)
 }
 
-
 // isSeparator reports whether the rune could mark a word boundary.
 // TODO: update when package unicode captures more of the properties.
 func isSeparator(rune int) bool {
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index 7539353..9444358 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -329,7 +329,6 @@ func TestExplode(t *testing.T) {
 	}
 }
 
-
 type SplitTest struct {
 	s   string
 	sep string
@@ -662,7 +661,6 @@ func TestRunes(t *testing.T) {
 	}
 }
 
-
 type TrimTest struct {
 	f               func([]byte, string) []byte
 	in, cutset, out string
diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go
index 2ac811c..9308236 100644
--- a/src/pkg/compress/flate/deflate_test.go
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -225,7 +225,6 @@ func testSync(t *testing.T, level int, input []byte, name string) {
 	}
 }
 
-
 func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error {
 	buffer := bytes.NewBuffer(nil)
 	w := NewWriter(buffer, level)
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
index 5b68827..2dfe5b4 100644
--- a/src/pkg/container/heap/heap.go
+++ b/src/pkg/container/heap/heap.go
@@ -21,7 +21,6 @@ type Interface interface {
 	Pop() interface{}
 }
 
-
 // A heap must be initialized before any of the heap operations
 // can be used. Init is idempotent with respect to the heap invariants
 // and may be called whenever the heap invariants may have been invalidated.
@@ -35,7 +34,6 @@ func Init(h Interface) {
 	}
 }
 
-
 // Push pushes the element x onto the heap. The complexity is
 // O(log(n)) where n = h.Len().
 //
@@ -44,7 +42,6 @@ func Push(h Interface, x interface{}) {
 	up(h, h.Len()-1)
 }
 
-
 // Pop removes the minimum element (according to Less) from the heap
 // and returns it. The complexity is O(log(n)) where n = h.Len().
 // Same as Remove(h, 0).
@@ -56,7 +53,6 @@ func Pop(h Interface) interface{} {
 	return h.Pop()
 }
 
-
 // Remove removes the element at index i from the heap.
 // The complexity is O(log(n)) where n = h.Len().
 //
@@ -70,7 +66,6 @@ func Remove(h Interface, i int) interface{} {
 	return h.Pop()
 }
 
-
 func up(h Interface, j int) {
 	for {
 		i := (j - 1) / 2 // parent
@@ -82,7 +77,6 @@ func up(h Interface, j int) {
 	}
 }
 
-
 func down(h Interface, i, n int) {
 	for {
 		j1 := 2*i + 1
diff --git a/src/pkg/container/heap/heap_test.go b/src/pkg/container/heap/heap_test.go
index 5eb5437..c5c1f76 100644
--- a/src/pkg/container/heap/heap_test.go
+++ b/src/pkg/container/heap/heap_test.go
@@ -10,17 +10,14 @@ import (
 	. "container/heap"
 )
 
-
 type myHeap struct {
 	// A vector.Vector implements sort.Interface except for Less,
 	// and it implements Push and Pop as required for heap.Interface.
 	vector.Vector
 }
 
-
 func (h *myHeap) Less(i, j int) bool { return h.At(i).(int) < h.At(j).(int) }
 
-
 func (h *myHeap) verify(t *testing.T, i int) {
 	n := h.Len()
 	j1 := 2*i + 1
@@ -41,7 +38,6 @@ func (h *myHeap) verify(t *testing.T, i int) {
 	}
 }
 
-
 func TestInit0(t *testing.T) {
 	h := new(myHeap)
 	for i := 20; i > 0; i-- {
@@ -59,7 +55,6 @@ func TestInit0(t *testing.T) {
 	}
 }
 
-
 func TestInit1(t *testing.T) {
 	h := new(myHeap)
 	for i := 20; i > 0; i-- {
@@ -77,7 +72,6 @@ func TestInit1(t *testing.T) {
 	}
 }
 
-
 func Test(t *testing.T) {
 	h := new(myHeap)
 	h.verify(t, 0)
@@ -105,7 +99,6 @@ func Test(t *testing.T) {
 	}
 }
 
-
 func TestRemove0(t *testing.T) {
 	h := new(myHeap)
 	for i := 0; i < 10; i++ {
@@ -123,7 +116,6 @@ func TestRemove0(t *testing.T) {
 	}
 }
 
-
 func TestRemove1(t *testing.T) {
 	h := new(myHeap)
 	for i := 0; i < 10; i++ {
@@ -140,7 +132,6 @@ func TestRemove1(t *testing.T) {
 	}
 }
 
-
 func TestRemove2(t *testing.T) {
 	N := 10
 
diff --git a/src/pkg/container/ring/ring.go b/src/pkg/container/ring/ring.go
index cc870ce..1d96918 100644
--- a/src/pkg/container/ring/ring.go
+++ b/src/pkg/container/ring/ring.go
@@ -16,14 +16,12 @@ type Ring struct {
 	Value      interface{} // for use by client; untouched by this library
 }
 
-
 func (r *Ring) init() *Ring {
 	r.next = r
 	r.prev = r
 	return r
 }
 
-
 // Next returns the next ring element. r must not be empty.
 func (r *Ring) Next() *Ring {
 	if r.next == nil {
@@ -32,7 +30,6 @@ func (r *Ring) Next() *Ring {
 	return r.next
 }
 
-
 // Prev returns the previous ring element. r must not be empty.
 func (r *Ring) Prev() *Ring {
 	if r.next == nil {
@@ -41,7 +38,6 @@ func (r *Ring) Prev() *Ring {
 	return r.prev
 }
 
-
 // Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
 // in the ring and returns that ring element. r must not be empty.
 //
@@ -62,7 +58,6 @@ func (r *Ring) Move(n int) *Ring {
 	return r
 }
 
-
 // New creates a ring of n elements.
 func New(n int) *Ring {
 	if n <= 0 {
@@ -79,7 +74,6 @@ func New(n int) *Ring {
 	return r
 }
 
-
 // Link connects ring r with with ring s such that r.Next()
 // becomes s and returns the original value for r.Next().
 // r must not be empty.
@@ -110,7 +104,6 @@ func (r *Ring) Link(s *Ring) *Ring {
 	return n
 }
 
-
 // Unlink removes n % r.Len() elements from the ring r, starting
 // at r.Next(). If n % r.Len() == 0, r remains unchanged.
 // The result is the removed subring. r must not be empty.
@@ -122,7 +115,6 @@ func (r *Ring) Unlink(n int) *Ring {
 	return r.Link(r.Move(n + 1))
 }
 
-
 // Len computes the number of elements in ring r.
 // It executes in time proportional to the number of elements.
 //
@@ -137,7 +129,6 @@ func (r *Ring) Len() int {
 	return n
 }
 
-
 // Do calls function f on each element of the ring, in forward order.
 // The behavior of Do is undefined if f changes *r.
 func (r *Ring) Do(f func(interface{})) {
diff --git a/src/pkg/container/ring/ring_test.go b/src/pkg/container/ring/ring_test.go
index 778c083..099d92b 100644
--- a/src/pkg/container/ring/ring_test.go
+++ b/src/pkg/container/ring/ring_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 )
 
-
 // For debugging - keep around.
 func dump(r *Ring) {
 	if r == nil {
@@ -24,7 +23,6 @@ func dump(r *Ring) {
 	fmt.Println()
 }
 
-
 func verify(t *testing.T, r *Ring, N int, sum int) {
 	// Len
 	n := r.Len()
@@ -96,7 +94,6 @@ func verify(t *testing.T, r *Ring, N int, sum int) {
 	}
 }
 
-
 func TestCornerCases(t *testing.T) {
 	var (
 		r0 *Ring
@@ -118,7 +115,6 @@ func TestCornerCases(t *testing.T) {
 	verify(t, &r1, 1, 0)
 }
 
-
 func makeN(n int) *Ring {
 	r := New(n)
 	for i := 1; i <= n; i++ {
@@ -130,7 +126,6 @@ func makeN(n int) *Ring {
 
 func sumN(n int) int { return (n*n + n) / 2 }
 
-
 func TestNew(t *testing.T) {
 	for i := 0; i < 10; i++ {
 		r := New(i)
@@ -142,7 +137,6 @@ func TestNew(t *testing.T) {
 	}
 }
 
-
 func TestLink1(t *testing.T) {
 	r1a := makeN(1)
 	var r1b Ring
@@ -163,7 +157,6 @@ func TestLink1(t *testing.T) {
 	verify(t, r2b, 1, 0)
 }
 
-
 func TestLink2(t *testing.T) {
 	var r0 *Ring
 	r1a := &Ring{Value: 42}
@@ -183,7 +176,6 @@ func TestLink2(t *testing.T) {
 	verify(t, r10, 12, sumN(10)+42+77)
 }
 
-
 func TestLink3(t *testing.T) {
 	var r Ring
 	n := 1
@@ -193,7 +185,6 @@ func TestLink3(t *testing.T) {
 	}
 }
 
-
 func TestUnlink(t *testing.T) {
 	r10 := makeN(10)
 	s10 := r10.Move(6)
@@ -215,7 +206,6 @@ func TestUnlink(t *testing.T) {
 	verify(t, r10, 9, sum10-2)
 }
 
-
 func TestLinkUnlink(t *testing.T) {
 	for i := 1; i < 4; i++ {
 		ri := New(i)
diff --git a/src/pkg/container/vector/defs.go b/src/pkg/container/vector/defs.go
index bfb5481..6d6b2ac 100644
--- a/src/pkg/container/vector/defs.go
+++ b/src/pkg/container/vector/defs.go
@@ -6,29 +6,24 @@
 // Vectors grow and shrink dynamically as necessary.
 package vector
 
-
 // Vector is a container for numbered sequences of elements of type interface{}.
 // A vector's length and capacity adjusts automatically as necessary.
 // The zero value for Vector is an empty vector ready to use.
 type Vector []interface{}
 
-
 // IntVector is a container for numbered sequences of elements of type int.
 // A vector's length and capacity adjusts automatically as necessary.
 // The zero value for IntVector is an empty vector ready to use.
 type IntVector []int
 
-
 // StringVector is a container for numbered sequences of elements of type string.
 // A vector's length and capacity adjusts automatically as necessary.
 // The zero value for StringVector is an empty vector ready to use.
 type StringVector []string
 
-
 // Initial underlying array size
 const initialSize = 8
 
-
 // Partial sort.Interface support
 
 // LessInterface provides partial support of the sort.Interface.
@@ -36,16 +31,13 @@ type LessInterface interface {
 	Less(y interface{}) bool
 }
 
-
 // Less returns a boolean denoting whether the i'th element is less than the j'th element.
 func (p *Vector) Less(i, j int) bool { return (*p)[i].(LessInterface).Less((*p)[j]) }
 
-
 // sort.Interface support
 
 // Less returns a boolean denoting whether the i'th element is less than the j'th element.
 func (p *IntVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
 
-
 // Less returns a boolean denoting whether the i'th element is less than the j'th element.
 func (p *StringVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
diff --git a/src/pkg/container/vector/intvector.go b/src/pkg/container/vector/intvector.go
index 5ad9e29..aa88cfe 100644
--- a/src/pkg/container/vector/intvector.go
+++ b/src/pkg/container/vector/intvector.go
@@ -7,7 +7,6 @@
 
 package vector
 
-
 func (p *IntVector) realloc(length, capacity int) (b []int) {
 	if capacity < initialSize {
 		capacity = initialSize
@@ -21,7 +20,6 @@ func (p *IntVector) realloc(length, capacity int) (b []int) {
 	return
 }
 
-
 // Insert n elements at position i.
 func (p *IntVector) Expand(i, n int) {
 	a := *p
@@ -51,11 +49,9 @@ func (p *IntVector) Expand(i, n int) {
 	*p = a
 }
 
-
 // Insert n elements at the end of a vector.
 func (p *IntVector) Extend(n int) { p.Expand(len(*p), n) }
 
-
 // Resize changes the length and capacity of a vector.
 // If the new length is shorter than the current length, Resize discards
 // trailing elements. If the new length is longer than the current length,
@@ -80,30 +76,24 @@ func (p *IntVector) Resize(length, capacity int) *IntVector {
 	return p
 }
 
-
 // Len returns the number of elements in the vector.
 // Same as len(*p).
 func (p *IntVector) Len() int { return len(*p) }
 
-
 // Cap returns the capacity of the vector; that is, the
 // maximum length the vector can grow without resizing.
 // Same as cap(*p).
 func (p *IntVector) Cap() int { return cap(*p) }
 
-
 // At returns the i'th element of the vector.
 func (p *IntVector) At(i int) int { return (*p)[i] }
 
-
 // Set sets the i'th element of the vector to value x.
 func (p *IntVector) Set(i int, x int) { (*p)[i] = x }
 
-
 // Last returns the element in the vector of highest index.
 func (p *IntVector) Last() int { return (*p)[len(*p)-1] }
 
-
 // Copy makes a copy of the vector and returns it.
 func (p *IntVector) Copy() IntVector {
 	arr := make(IntVector, len(*p))
@@ -111,7 +101,6 @@ func (p *IntVector) Copy() IntVector {
 	return arr
 }
 
-
 // Insert inserts into the vector an element of value x before
 // the current element at index i.
 func (p *IntVector) Insert(i int, x int) {
@@ -119,7 +108,6 @@ func (p *IntVector) Insert(i int, x int) {
 	(*p)[i] = x
 }
 
-
 // Delete deletes the i'th element of the vector.  The gap is closed so the old
 // element at index i+1 has index i afterwards.
 func (p *IntVector) Delete(i int) {
@@ -132,7 +120,6 @@ func (p *IntVector) Delete(i int) {
 	*p = a[0 : n-1]
 }
 
-
 // InsertVector inserts into the vector the contents of the vector
 // x such that the 0th element of x appears at index i after insertion.
 func (p *IntVector) InsertVector(i int, x *IntVector) {
@@ -142,7 +129,6 @@ func (p *IntVector) InsertVector(i int, x *IntVector) {
 	copy((*p)[i:i+len(b)], b)
 }
 
-
 // Cut deletes elements i through j-1, inclusive.
 func (p *IntVector) Cut(i, j int) {
 	a := *p
@@ -158,7 +144,6 @@ func (p *IntVector) Cut(i, j int) {
 	*p = a[0:m]
 }
 
-
 // Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
 // The elements are copied. The original vector is unchanged.
 func (p *IntVector) Slice(i, j int) *IntVector {
@@ -168,13 +153,11 @@ func (p *IntVector) Slice(i, j int) *IntVector {
 	return &s
 }
 
-
 // Convenience wrappers
 
 // Push appends x to the end of the vector.
 func (p *IntVector) Push(x int) { p.Insert(len(*p), x) }
 
-
 // Pop deletes the last element of the vector.
 func (p *IntVector) Pop() int {
 	a := *p
@@ -187,18 +170,15 @@ func (p *IntVector) Pop() int {
 	return x
 }
 
-
 // AppendVector appends the entire vector x to the end of this vector.
 func (p *IntVector) AppendVector(x *IntVector) { p.InsertVector(len(*p), x) }
 
-
 // Swap exchanges the elements at indexes i and j.
 func (p *IntVector) Swap(i, j int) {
 	a := *p
 	a[i], a[j] = a[j], a[i]
 }
 
-
 // Do calls function f for each element of the vector, in order.
 // The behavior of Do is undefined if f changes *p.
 func (p *IntVector) Do(f func(elem int)) {
diff --git a/src/pkg/container/vector/intvector_test.go b/src/pkg/container/vector/intvector_test.go
index 1e38a19..b825af9 100644
--- a/src/pkg/container/vector/intvector_test.go
+++ b/src/pkg/container/vector/intvector_test.go
@@ -9,7 +9,6 @@ package vector
 
 import "testing"
 
-
 func TestIntZeroLen(t *testing.T) {
 	a := new(IntVector)
 	if a.Len() != 0 {
@@ -27,7 +26,6 @@ func TestIntZeroLen(t *testing.T) {
 	}
 }
 
-
 func TestIntResize(t *testing.T) {
 	var a IntVector
 	checkSize(t, &a, 0, 0)
@@ -40,7 +38,6 @@ func TestIntResize(t *testing.T) {
 	checkSize(t, a.Resize(11, 100), 11, 100)
 }
 
-
 func TestIntResize2(t *testing.T) {
 	var a IntVector
 	checkSize(t, &a, 0, 0)
@@ -62,7 +59,6 @@ func TestIntResize2(t *testing.T) {
 	}
 }
 
-
 func checkIntZero(t *testing.T, a *IntVector, i int) {
 	for j := 0; j < i; j++ {
 		if a.At(j) == intzero {
@@ -82,7 +78,6 @@ func checkIntZero(t *testing.T, a *IntVector, i int) {
 	}
 }
 
-
 func TestIntTrailingElements(t *testing.T) {
 	var a IntVector
 	for i := 0; i < 10; i++ {
@@ -95,7 +90,6 @@ func TestIntTrailingElements(t *testing.T) {
 	checkIntZero(t, &a, 5)
 }
 
-
 func TestIntAccess(t *testing.T) {
 	const n = 100
 	var a IntVector
@@ -120,7 +114,6 @@ func TestIntAccess(t *testing.T) {
 	}
 }
 
-
 func TestIntInsertDeleteClear(t *testing.T) {
 	const n = 100
 	var a IntVector
@@ -207,7 +200,6 @@ func TestIntInsertDeleteClear(t *testing.T) {
 	}
 }
 
-
 func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
 	for k := i; k < j; k++ {
 		if elem2IntValue(x.At(k)) != int2IntValue(elt) {
@@ -223,7 +215,6 @@ func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
 	}
 }
 
-
 func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
 	n := a + b + c
 	if x.Len() != n {
@@ -237,7 +228,6 @@ func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
 	verify_sliceInt(t, x, 0, a+b, n)
 }
 
-
 func make_vectorInt(elt, len int) *IntVector {
 	x := new(IntVector).Resize(len, 0)
 	for i := 0; i < len; i++ {
@@ -246,7 +236,6 @@ func make_vectorInt(elt, len int) *IntVector {
 	return x
 }
 
-
 func TestIntInsertVector(t *testing.T) {
 	// 1
 	a := make_vectorInt(0, 0)
@@ -270,7 +259,6 @@ func TestIntInsertVector(t *testing.T) {
 	verify_patternInt(t, a, 8, 1000, 2)
 }
 
-
 func TestIntDo(t *testing.T) {
 	const n = 25
 	const salt = 17
@@ -325,7 +313,6 @@ func TestIntDo(t *testing.T) {
 
 }
 
-
 func TestIntVectorCopy(t *testing.T) {
 	// verify Copy() returns a copy, not simply a slice of the original vector
 	const Len = 10
diff --git a/src/pkg/container/vector/nogen_test.go b/src/pkg/container/vector/nogen_test.go
index 790d374..7b6a259 100644
--- a/src/pkg/container/vector/nogen_test.go
+++ b/src/pkg/container/vector/nogen_test.go
@@ -4,7 +4,6 @@
 
 package vector
 
-
 import (
 	"fmt"
 	"sort"
@@ -17,28 +16,23 @@ var (
 	strzero string
 )
 
-
 func int2Value(x int) int       { return x }
 func int2IntValue(x int) int    { return x }
 func int2StrValue(x int) string { return string(x) }
 
-
 func elem2Value(x interface{}) int  { return x.(int) }
 func elem2IntValue(x int) int       { return x }
 func elem2StrValue(x string) string { return x }
 
-
 func intf2Value(x interface{}) int       { return x.(int) }
 func intf2IntValue(x interface{}) int    { return x.(int) }
 func intf2StrValue(x interface{}) string { return x.(string) }
 
-
 type VectorInterface interface {
 	Len() int
 	Cap() int
 }
 
-
 func checkSize(t *testing.T, v VectorInterface, len, cap int) {
 	if v.Len() != len {
 		t.Errorf("%T expected len = %d; found %d", v, len, v.Len())
@@ -48,10 +42,8 @@ func checkSize(t *testing.T, v VectorInterface, len, cap int) {
 	}
 }
 
-
 func val(i int) int { return i*991 - 1234 }
 
-
 func TestSorting(t *testing.T) {
 	const n = 100
 
@@ -72,5 +64,4 @@ func TestSorting(t *testing.T) {
 	}
 }
 
-
 func tname(x interface{}) string { return fmt.Sprintf("%T: ", x) }
diff --git a/src/pkg/container/vector/numbers_test.go b/src/pkg/container/vector/numbers_test.go
index b83b0bf..abe01a8 100644
--- a/src/pkg/container/vector/numbers_test.go
+++ b/src/pkg/container/vector/numbers_test.go
@@ -11,10 +11,8 @@ import (
 	"testing"
 )
 
-
 const memTestN = 1000000
 
-
 func s(n uint64) string {
 	str := fmt.Sprintf("%d", n)
 	lens := len(str)
@@ -31,7 +29,6 @@ func s(n uint64) string {
 	return strings.Join(a, " ")
 }
 
-
 func TestVectorNums(t *testing.T) {
 	if testing.Short() {
 		return
@@ -52,7 +49,6 @@ func TestVectorNums(t *testing.T) {
 	t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
 }
 
-
 func TestIntVectorNums(t *testing.T) {
 	if testing.Short() {
 		return
@@ -73,7 +69,6 @@ func TestIntVectorNums(t *testing.T) {
 	t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
 }
 
-
 func TestStringVectorNums(t *testing.T) {
 	if testing.Short() {
 		return
@@ -94,7 +89,6 @@ func TestStringVectorNums(t *testing.T) {
 	t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
 }
 
-
 func BenchmarkVectorNums(b *testing.B) {
 	c := int(0)
 	var v Vector
@@ -106,7 +100,6 @@ func BenchmarkVectorNums(b *testing.B) {
 	}
 }
 
-
 func BenchmarkIntVectorNums(b *testing.B) {
 	c := int(0)
 	var v IntVector
@@ -118,7 +111,6 @@ func BenchmarkIntVectorNums(b *testing.B) {
 	}
 }
 
-
 func BenchmarkStringVectorNums(b *testing.B) {
 	c := ""
 	var v StringVector
diff --git a/src/pkg/container/vector/stringvector.go b/src/pkg/container/vector/stringvector.go
index 852685f..dc81f06 100644
--- a/src/pkg/container/vector/stringvector.go
+++ b/src/pkg/container/vector/stringvector.go
@@ -7,7 +7,6 @@
 
 package vector
 
-
 func (p *StringVector) realloc(length, capacity int) (b []string) {
 	if capacity < initialSize {
 		capacity = initialSize
@@ -21,7 +20,6 @@ func (p *StringVector) realloc(length, capacity int) (b []string) {
 	return
 }
 
-
 // Insert n elements at position i.
 func (p *StringVector) Expand(i, n int) {
 	a := *p
@@ -51,11 +49,9 @@ func (p *StringVector) Expand(i, n int) {
 	*p = a
 }
 
-
 // Insert n elements at the end of a vector.
 func (p *StringVector) Extend(n int) { p.Expand(len(*p), n) }
 
-
 // Resize changes the length and capacity of a vector.
 // If the new length is shorter than the current length, Resize discards
 // trailing elements. If the new length is longer than the current length,
@@ -80,30 +76,24 @@ func (p *StringVector) Resize(length, capacity int) *StringVector {
 	return p
 }
 
-
 // Len returns the number of elements in the vector.
 // Same as len(*p).
 func (p *StringVector) Len() int { return len(*p) }
 
-
 // Cap returns the capacity of the vector; that is, the
 // maximum length the vector can grow without resizing.
 // Same as cap(*p).
 func (p *StringVector) Cap() int { return cap(*p) }
 
-
 // At returns the i'th element of the vector.
 func (p *StringVector) At(i int) string { return (*p)[i] }
 
-
 // Set sets the i'th element of the vector to value x.
 func (p *StringVector) Set(i int, x string) { (*p)[i] = x }
 
-
 // Last returns the element in the vector of highest index.
 func (p *StringVector) Last() string { return (*p)[len(*p)-1] }
 
-
 // Copy makes a copy of the vector and returns it.
 func (p *StringVector) Copy() StringVector {
 	arr := make(StringVector, len(*p))
@@ -111,7 +101,6 @@ func (p *StringVector) Copy() StringVector {
 	return arr
 }
 
-
 // Insert inserts into the vector an element of value x before
 // the current element at index i.
 func (p *StringVector) Insert(i int, x string) {
@@ -119,7 +108,6 @@ func (p *StringVector) Insert(i int, x string) {
 	(*p)[i] = x
 }
 
-
 // Delete deletes the i'th element of the vector.  The gap is closed so the old
 // element at index i+1 has index i afterwards.
 func (p *StringVector) Delete(i int) {
@@ -132,7 +120,6 @@ func (p *StringVector) Delete(i int) {
 	*p = a[0 : n-1]
 }
 
-
 // InsertVector inserts into the vector the contents of the vector
 // x such that the 0th element of x appears at index i after insertion.
 func (p *StringVector) InsertVector(i int, x *StringVector) {
@@ -142,7 +129,6 @@ func (p *StringVector) InsertVector(i int, x *StringVector) {
 	copy((*p)[i:i+len(b)], b)
 }
 
-
 // Cut deletes elements i through j-1, inclusive.
 func (p *StringVector) Cut(i, j int) {
 	a := *p
@@ -158,7 +144,6 @@ func (p *StringVector) Cut(i, j int) {
 	*p = a[0:m]
 }
 
-
 // Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
 // The elements are copied. The original vector is unchanged.
 func (p *StringVector) Slice(i, j int) *StringVector {
@@ -168,13 +153,11 @@ func (p *StringVector) Slice(i, j int) *StringVector {
 	return &s
 }
 
-
 // Convenience wrappers
 
 // Push appends x to the end of the vector.
 func (p *StringVector) Push(x string) { p.Insert(len(*p), x) }
 
-
 // Pop deletes the last element of the vector.
 func (p *StringVector) Pop() string {
 	a := *p
@@ -187,18 +170,15 @@ func (p *StringVector) Pop() string {
 	return x
 }
 
-
 // AppendVector appends the entire vector x to the end of this vector.
 func (p *StringVector) AppendVector(x *StringVector) { p.InsertVector(len(*p), x) }
 
-
 // Swap exchanges the elements at indexes i and j.
 func (p *StringVector) Swap(i, j int) {
 	a := *p
 	a[i], a[j] = a[j], a[i]
 }
 
-
 // Do calls function f for each element of the vector, in order.
 // The behavior of Do is undefined if f changes *p.
 func (p *StringVector) Do(f func(elem string)) {
diff --git a/src/pkg/container/vector/stringvector_test.go b/src/pkg/container/vector/stringvector_test.go
index 776ae26..c75676f 100644
--- a/src/pkg/container/vector/stringvector_test.go
+++ b/src/pkg/container/vector/stringvector_test.go
@@ -9,7 +9,6 @@ package vector
 
 import "testing"
 
-
 func TestStrZeroLen(t *testing.T) {
 	a := new(StringVector)
 	if a.Len() != 0 {
@@ -27,7 +26,6 @@ func TestStrZeroLen(t *testing.T) {
 	}
 }
 
-
 func TestStrResize(t *testing.T) {
 	var a StringVector
 	checkSize(t, &a, 0, 0)
@@ -40,7 +38,6 @@ func TestStrResize(t *testing.T) {
 	checkSize(t, a.Resize(11, 100), 11, 100)
 }
 
-
 func TestStrResize2(t *testing.T) {
 	var a StringVector
 	checkSize(t, &a, 0, 0)
@@ -62,7 +59,6 @@ func TestStrResize2(t *testing.T) {
 	}
 }
 
-
 func checkStrZero(t *testing.T, a *StringVector, i int) {
 	for j := 0; j < i; j++ {
 		if a.At(j) == strzero {
@@ -82,7 +78,6 @@ func checkStrZero(t *testing.T, a *StringVector, i int) {
 	}
 }
 
-
 func TestStrTrailingElements(t *testing.T) {
 	var a StringVector
 	for i := 0; i < 10; i++ {
@@ -95,7 +90,6 @@ func TestStrTrailingElements(t *testing.T) {
 	checkStrZero(t, &a, 5)
 }
 
-
 func TestStrAccess(t *testing.T) {
 	const n = 100
 	var a StringVector
@@ -120,7 +114,6 @@ func TestStrAccess(t *testing.T) {
 	}
 }
 
-
 func TestStrInsertDeleteClear(t *testing.T) {
 	const n = 100
 	var a StringVector
@@ -207,7 +200,6 @@ func TestStrInsertDeleteClear(t *testing.T) {
 	}
 }
 
-
 func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
 	for k := i; k < j; k++ {
 		if elem2StrValue(x.At(k)) != int2StrValue(elt) {
@@ -223,7 +215,6 @@ func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
 	}
 }
 
-
 func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
 	n := a + b + c
 	if x.Len() != n {
@@ -237,7 +228,6 @@ func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
 	verify_sliceStr(t, x, 0, a+b, n)
 }
 
-
 func make_vectorStr(elt, len int) *StringVector {
 	x := new(StringVector).Resize(len, 0)
 	for i := 0; i < len; i++ {
@@ -246,7 +236,6 @@ func make_vectorStr(elt, len int) *StringVector {
 	return x
 }
 
-
 func TestStrInsertVector(t *testing.T) {
 	// 1
 	a := make_vectorStr(0, 0)
@@ -270,7 +259,6 @@ func TestStrInsertVector(t *testing.T) {
 	verify_patternStr(t, a, 8, 1000, 2)
 }
 
-
 func TestStrDo(t *testing.T) {
 	const n = 25
 	const salt = 17
@@ -325,7 +313,6 @@ func TestStrDo(t *testing.T) {
 
 }
 
-
 func TestStrVectorCopy(t *testing.T) {
 	// verify Copy() returns a copy, not simply a slice of the original vector
 	const Len = 10
diff --git a/src/pkg/container/vector/vector.go b/src/pkg/container/vector/vector.go
index f43e4d2..8470ec0 100644
--- a/src/pkg/container/vector/vector.go
+++ b/src/pkg/container/vector/vector.go
@@ -7,7 +7,6 @@
 
 package vector
 
-
 func (p *Vector) realloc(length, capacity int) (b []interface{}) {
 	if capacity < initialSize {
 		capacity = initialSize
@@ -21,7 +20,6 @@ func (p *Vector) realloc(length, capacity int) (b []interface{}) {
 	return
 }
 
-
 // Insert n elements at position i.
 func (p *Vector) Expand(i, n int) {
 	a := *p
@@ -51,11 +49,9 @@ func (p *Vector) Expand(i, n int) {
 	*p = a
 }
 
-
 // Insert n elements at the end of a vector.
 func (p *Vector) Extend(n int) { p.Expand(len(*p), n) }
 
-
 // Resize changes the length and capacity of a vector.
 // If the new length is shorter than the current length, Resize discards
 // trailing elements. If the new length is longer than the current length,
@@ -80,30 +76,24 @@ func (p *Vector) Resize(length, capacity int) *Vector {
 	return p
 }
 
-
 // Len returns the number of elements in the vector.
 // Same as len(*p).
 func (p *Vector) Len() int { return len(*p) }
 
-
 // Cap returns the capacity of the vector; that is, the
 // maximum length the vector can grow without resizing.
 // Same as cap(*p).
 func (p *Vector) Cap() int { return cap(*p) }
 
-
 // At returns the i'th element of the vector.
 func (p *Vector) At(i int) interface{} { return (*p)[i] }
 
-
 // Set sets the i'th element of the vector to value x.
 func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x }
 
-
 // Last returns the element in the vector of highest index.
 func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] }
 
-
 // Copy makes a copy of the vector and returns it.
 func (p *Vector) Copy() Vector {
 	arr := make(Vector, len(*p))
@@ -111,7 +101,6 @@ func (p *Vector) Copy() Vector {
 	return arr
 }
 
-
 // Insert inserts into the vector an element of value x before
 // the current element at index i.
 func (p *Vector) Insert(i int, x interface{}) {
@@ -119,7 +108,6 @@ func (p *Vector) Insert(i int, x interface{}) {
 	(*p)[i] = x
 }
 
-
 // Delete deletes the i'th element of the vector.  The gap is closed so the old
 // element at index i+1 has index i afterwards.
 func (p *Vector) Delete(i int) {
@@ -132,7 +120,6 @@ func (p *Vector) Delete(i int) {
 	*p = a[0 : n-1]
 }
 
-
 // InsertVector inserts into the vector the contents of the vector
 // x such that the 0th element of x appears at index i after insertion.
 func (p *Vector) InsertVector(i int, x *Vector) {
@@ -142,7 +129,6 @@ func (p *Vector) InsertVector(i int, x *Vector) {
 	copy((*p)[i:i+len(b)], b)
 }
 
-
 // Cut deletes elements i through j-1, inclusive.
 func (p *Vector) Cut(i, j int) {
 	a := *p
@@ -158,7 +144,6 @@ func (p *Vector) Cut(i, j int) {
 	*p = a[0:m]
 }
 
-
 // Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
 // The elements are copied. The original vector is unchanged.
 func (p *Vector) Slice(i, j int) *Vector {
@@ -168,13 +153,11 @@ func (p *Vector) Slice(i, j int) *Vector {
 	return &s
 }
 
-
 // Convenience wrappers
 
 // Push appends x to the end of the vector.
 func (p *Vector) Push(x interface{}) { p.Insert(len(*p), x) }
 
-
 // Pop deletes the last element of the vector.
 func (p *Vector) Pop() interface{} {
 	a := *p
@@ -187,18 +170,15 @@ func (p *Vector) Pop() interface{} {
 	return x
 }
 
-
 // AppendVector appends the entire vector x to the end of this vector.
 func (p *Vector) AppendVector(x *Vector) { p.InsertVector(len(*p), x) }
 
-
 // Swap exchanges the elements at indexes i and j.
 func (p *Vector) Swap(i, j int) {
 	a := *p
 	a[i], a[j] = a[j], a[i]
 }
 
-
 // Do calls function f for each element of the vector, in order.
 // The behavior of Do is undefined if f changes *p.
 func (p *Vector) Do(f func(elem interface{})) {
diff --git a/src/pkg/container/vector/vector_test.go b/src/pkg/container/vector/vector_test.go
index a9c4ceb..a7f47b8 100644
--- a/src/pkg/container/vector/vector_test.go
+++ b/src/pkg/container/vector/vector_test.go
@@ -9,7 +9,6 @@ package vector
 
 import "testing"
 
-
 func TestZeroLen(t *testing.T) {
 	a := new(Vector)
 	if a.Len() != 0 {
@@ -27,7 +26,6 @@ func TestZeroLen(t *testing.T) {
 	}
 }
 
-
 func TestResize(t *testing.T) {
 	var a Vector
 	checkSize(t, &a, 0, 0)
@@ -40,7 +38,6 @@ func TestResize(t *testing.T) {
 	checkSize(t, a.Resize(11, 100), 11, 100)
 }
 
-
 func TestResize2(t *testing.T) {
 	var a Vector
 	checkSize(t, &a, 0, 0)
@@ -62,7 +59,6 @@ func TestResize2(t *testing.T) {
 	}
 }
 
-
 func checkZero(t *testing.T, a *Vector, i int) {
 	for j := 0; j < i; j++ {
 		if a.At(j) == zero {
@@ -82,7 +78,6 @@ func checkZero(t *testing.T, a *Vector, i int) {
 	}
 }
 
-
 func TestTrailingElements(t *testing.T) {
 	var a Vector
 	for i := 0; i < 10; i++ {
@@ -95,7 +90,6 @@ func TestTrailingElements(t *testing.T) {
 	checkZero(t, &a, 5)
 }
 
-
 func TestAccess(t *testing.T) {
 	const n = 100
 	var a Vector
@@ -120,7 +114,6 @@ func TestAccess(t *testing.T) {
 	}
 }
 
-
 func TestInsertDeleteClear(t *testing.T) {
 	const n = 100
 	var a Vector
@@ -207,7 +200,6 @@ func TestInsertDeleteClear(t *testing.T) {
 	}
 }
 
-
 func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
 	for k := i; k < j; k++ {
 		if elem2Value(x.At(k)) != int2Value(elt) {
@@ -223,7 +215,6 @@ func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
 	}
 }
 
-
 func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
 	n := a + b + c
 	if x.Len() != n {
@@ -237,7 +228,6 @@ func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
 	verify_slice(t, x, 0, a+b, n)
 }
 
-
 func make_vector(elt, len int) *Vector {
 	x := new(Vector).Resize(len, 0)
 	for i := 0; i < len; i++ {
@@ -246,7 +236,6 @@ func make_vector(elt, len int) *Vector {
 	return x
 }
 
-
 func TestInsertVector(t *testing.T) {
 	// 1
 	a := make_vector(0, 0)
@@ -270,7 +259,6 @@ func TestInsertVector(t *testing.T) {
 	verify_pattern(t, a, 8, 1000, 2)
 }
 
-
 func TestDo(t *testing.T) {
 	const n = 25
 	const salt = 17
@@ -325,7 +313,6 @@ func TestDo(t *testing.T) {
 
 }
 
-
 func TestVectorCopy(t *testing.T) {
 	// verify Copy() returns a copy, not simply a slice of the original vector
 	const Len = 10
diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go
index e725bde..7ea7a1e 100644
--- a/src/pkg/crypto/ocsp/ocsp.go
+++ b/src/pkg/crypto/ocsp/ocsp.go
@@ -33,7 +33,6 @@ const (
 	ocspUnauthorized  = 5
 )
 
-
 type certID struct {
 	HashAlgorithm pkix.AlgorithmIdentifier
 	NameHash      []byte
diff --git a/src/pkg/crypto/openpgp/canonical_text_test.go b/src/pkg/crypto/openpgp/canonical_text_test.go
index 69ecf91..ccf2910 100644
--- a/src/pkg/crypto/openpgp/canonical_text_test.go
+++ b/src/pkg/crypto/openpgp/canonical_text_test.go
@@ -30,7 +30,6 @@ func (r recordingHash) Size() int {
 	panic("shouldn't be called")
 }
 
-
 func testCanonicalText(t *testing.T, input, expected string) {
 	r := recordingHash{bytes.NewBuffer(nil)}
 	c := NewCanonicalTextHash(r)
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
index b0a1490..b402245 100644
--- a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
@@ -21,7 +21,6 @@ func bigFromBase10(s string) *big.Int {
 	return b
 }
 
-
 var encryptedKeyPub = rsa.PublicKey{
 	E: 65537,
 	N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
diff --git a/src/pkg/crypto/openpgp/s2k/s2k_test.go b/src/pkg/crypto/openpgp/s2k/s2k_test.go
index 27d2e9a..ec4012c 100644
--- a/src/pkg/crypto/openpgp/s2k/s2k_test.go
+++ b/src/pkg/crypto/openpgp/s2k/s2k_test.go
@@ -37,7 +37,6 @@ func TestSalted(t *testing.T) {
 	}
 }
 
-
 var iteratedTests = []struct {
 	in, out string
 }{
@@ -63,7 +62,6 @@ func TestIterated(t *testing.T) {
 	}
 }
 
-
 var parseTests = []struct {
 	spec, in, out string
 }{
@@ -97,7 +95,6 @@ func TestParse(t *testing.T) {
 	}
 }
 
-
 func TestSerialize(t *testing.T) {
 	buf := bytes.NewBuffer(nil)
 	key := make([]byte, 16)
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index 5a1e754..b77646e 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -106,7 +106,6 @@ func TestClose(t *testing.T) {
 	}
 }
 
-
 func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
 	c, s := net.Pipe()
 	srv := Server(s, config)
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index 48472fb..a40d18f 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -78,7 +78,6 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
 	return preMasterSecret, ckx, nil
 }
 
-
 // md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
 // concatenation of an MD5 and SHA1 hash.
 func md5SHA1Hash(slices ...[]byte) []byte {
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index cad863d..4c0fecc 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -62,7 +62,6 @@ func (h HostnameError) String() string {
 	return "certificate is valid for " + valid + ", not " + h.Host
 }
 
-
 // UnknownAuthorityError results when the certificate issuer is unknown
 type UnknownAuthorityError struct {
 	cert *Certificate
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 348727a..0add9e3 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -9,7 +9,6 @@ import (
 	"asn1"
 	"big"
 	"bytes"
-	"container/vector"
 	"crypto"
 	"crypto/dsa"
 	"crypto/rsa"
@@ -794,7 +793,7 @@ func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
 // ParseCertificates parses one or more certificates from the given ASN.1 DER
 // data. The certificates must be concatenated with no intermediate padding.
 func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
-	v := new(vector.Vector)
+	var v []interface{}
 
 	for len(asn1Data) > 0 {
 		cert := new(certificate)
@@ -803,12 +802,12 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
 		if err != nil {
 			return nil, err
 		}
-		v.Push(cert)
+		v = append(v, cert)
 	}
 
-	ret := make([]*Certificate, v.Len())
-	for i := 0; i < v.Len(); i++ {
-		cert, err := parseCertificate(v.At(i).(*certificate))
+	ret := make([]*Certificate, len(v))
+	for i := 0; i < len(v); i++ {
+		cert, err := parseCertificate(v[i].(*certificate))
 		if err != nil {
 			return nil, err
 		}
diff --git a/src/pkg/csv/reader.go b/src/pkg/csv/reader.go
index 1f4b61c..ea2c266 100644
--- a/src/pkg/csv/reader.go
+++ b/src/pkg/csv/reader.go
@@ -87,7 +87,7 @@ var (
 // Comma is the field delimiter.  It defaults to ','.
 //
 // Comment, if not 0, is the comment character. Lines beginning with the
-// Comment character is ignored.
+// Comment character are ignored.
 //
 // If FieldsPerRecord is positive, Read requires each record to
 // have the given number of fields.  If FieldsPerRecord is 0, Read sets it to
@@ -97,7 +97,7 @@ var (
 // If LazyQuotes is true, a quote may appear in an unquoted field and a
 // non-doubled quote may appear in a quoted field.
 //
-// If TrailingComma is true, the last field may be a unquoted empty field.
+// If TrailingComma is true, the last field may be an unquoted empty field.
 //
 // If TrimLeadingSpace is true, leading white space in a field is ignored.
 type Reader struct {
@@ -171,7 +171,7 @@ func (r *Reader) ReadAll() (records [][]string, err os.Error) {
 }
 
 // readRune reads one rune from r, folding \r\n to \n and keeping track
-// of our far into the line we have read.  r.column will point to the start
+// of how far into the line we have read.  r.column will point to the start
 // of this rune, not the end of this rune.
 func (r *Reader) readRune() (int, os.Error) {
 	rune, _, err := r.r.ReadRune()
@@ -222,7 +222,7 @@ func (r *Reader) parseRecord() (fields []string, err os.Error) {
 
 	// Peek at the first rune.  If it is an error we are done.
 	// If we are support comments and it is the comment character
-	// the skip to the end of line.
+	// then skip to the end of line.
 
 	rune, _, err := r.r.ReadRune()
 	if err != nil {
@@ -249,7 +249,6 @@ func (r *Reader) parseRecord() (fields []string, err os.Error) {
 	panic("unreachable")
 }
 
-
 // parseField parses the next field in the record.  The read field is
 // located in r.field.  Delim is the first character not part of the field
 // (r.Comma or '\n').
@@ -281,7 +280,7 @@ func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
 		// will check below
 
 	case '\n':
-		// We are a trailing empty field or a blank linke
+		// We are a trailing empty field or a blank line
 		if r.column == 0 {
 			return false, rune, nil
 		}
@@ -352,7 +351,7 @@ func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
 	if !r.TrailingComma {
 		// We don't allow trailing commas.  See if we
 		// are at the end of the line (being mindful
-		// of triming spaces
+		// of trimming spaces).
 		c := r.column
 		rune, err = r.readRune()
 		if r.TrimLeadingSpace {
diff --git a/src/pkg/csv/writer.go b/src/pkg/csv/writer.go
index 01386da..ccf703f 100644
--- a/src/pkg/csv/writer.go
+++ b/src/pkg/csv/writer.go
@@ -22,7 +22,6 @@ import (
 // Comma is the field delimiter.
 //
 // If UseCRLF is true, the Writer ends each record with \r\n instead of \n.
-// just \n is written.
 type Writer struct {
 	Comma   int  // Field delimiter (set to to ',' by NewWriter)
 	UseCRLF bool // True to use \r\n as the line terminator
diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go
index e01f735..b9470a4 100644
--- a/src/pkg/debug/dwarf/type_test.go
+++ b/src/pkg/debug/dwarf/type_test.go
@@ -58,7 +58,6 @@ func machoData(t *testing.T, name string) *Data {
 	return d
 }
 
-
 func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
 
 func TestTypedefsMachO(t *testing.T) {
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
index 5d45b24..c71b230 100644
--- a/src/pkg/debug/elf/elf.go
+++ b/src/pkg/debug/elf/elf.go
@@ -1289,7 +1289,6 @@ func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings,
 // Magic number for the elf trampoline, chosen wisely to be an immediate value.
 const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
 
-
 // ELF32 File header.
 type Header32 struct {
 	Ident     [EI_NIDENT]byte /* File identification. */
@@ -1455,7 +1454,6 @@ func R_SYM64(info uint64) uint32    { return uint32(info >> 32) }
 func R_TYPE64(info uint64) uint32   { return uint32(info) }
 func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) }
 
-
 // ELF64 symbol table entries.
 type Sym64 struct {
 	Name  uint32 /* String table index of name. */
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index 346fe2a..a0ddb1f 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -93,6 +93,7 @@ func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<
 type ProgHeader struct {
 	Type   ProgType
 	Flags  ProgFlag
+	Off    uint64
 	Vaddr  uint64
 	Paddr  uint64
 	Filesz uint64
@@ -224,6 +225,8 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
 	f.ABIVersion = ident[EI_ABIVERSION]
 
 	// Read ELF file header
+	var phoff int64
+	var phentsize, phnum int
 	var shoff int64
 	var shentsize, shnum, shstrndx int
 	shstrndx = -1
@@ -239,6 +242,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
 		if v := Version(hdr.Version); v != f.Version {
 			return nil, &FormatError{0, "mismatched ELF version", v}
 		}
+		phoff = int64(hdr.Phoff)
+		phentsize = int(hdr.Phentsize)
+		phnum = int(hdr.Phnum)
 		shoff = int64(hdr.Shoff)
 		shentsize = int(hdr.Shentsize)
 		shnum = int(hdr.Shnum)
@@ -254,6 +260,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
 		if v := Version(hdr.Version); v != f.Version {
 			return nil, &FormatError{0, "mismatched ELF version", v}
 		}
+		phoff = int64(hdr.Phoff)
+		phentsize = int(hdr.Phentsize)
+		phnum = int(hdr.Phnum)
 		shoff = int64(hdr.Shoff)
 		shentsize = int(hdr.Shentsize)
 		shnum = int(hdr.Shnum)
@@ -264,7 +273,47 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
 	}
 
 	// Read program headers
-	// TODO
+	f.Progs = make([]*Prog, phnum)
+	for i := 0; i < phnum; i++ {
+		off := phoff + int64(i)*int64(phentsize)
+		sr.Seek(off, os.SEEK_SET)
+		p := new(Prog)
+		switch f.Class {
+		case ELFCLASS32:
+			ph := new(Prog32)
+			if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
+				return nil, err
+			}
+			p.ProgHeader = ProgHeader{
+				Type:   ProgType(ph.Type),
+				Flags:  ProgFlag(ph.Flags),
+				Off:    uint64(ph.Off),
+				Vaddr:  uint64(ph.Vaddr),
+				Paddr:  uint64(ph.Paddr),
+				Filesz: uint64(ph.Filesz),
+				Memsz:  uint64(ph.Memsz),
+				Align:  uint64(ph.Align),
+			}
+		case ELFCLASS64:
+			ph := new(Prog64)
+			if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
+				return nil, err
+			}
+			p.ProgHeader = ProgHeader{
+				Type:   ProgType(ph.Type),
+				Flags:  ProgFlag(ph.Flags),
+				Off:    uint64(ph.Off),
+				Vaddr:  uint64(ph.Vaddr),
+				Paddr:  uint64(ph.Paddr),
+				Filesz: uint64(ph.Filesz),
+				Memsz:  uint64(ph.Memsz),
+				Align:  uint64(ph.Align),
+			}
+		}
+		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
+		p.ReaderAt = p.sr
+		f.Progs[i] = p
+	}
 
 	// Read section headers
 	f.Sections = make([]*Section, shnum)
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 37f6279..451d3d5 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -7,7 +7,10 @@ package elf
 import (
 	"debug/dwarf"
 	"encoding/binary"
+	"net"
+	"os"
 	"reflect"
+	"runtime"
 	"testing"
 )
 
@@ -15,6 +18,7 @@ type fileTest struct {
 	file     string
 	hdr      FileHeader
 	sections []SectionHeader
+	progs    []ProgHeader
 }
 
 var fileTests = []fileTest{
@@ -53,6 +57,13 @@ var fileTests = []fileTest{
 			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
 			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
 		},
+		[]ProgHeader{
+			{PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
+			{PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
+			{PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
+			{PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
+			{PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
+		},
 	},
 	{
 		"testdata/gcc-amd64-linux-exec",
@@ -96,6 +107,16 @@ var fileTests = []fileTest{
 			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
 			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
 		},
+		[]ProgHeader{
+			{PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
+			{PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
+			{PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
+			{PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
+			{PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
+			{PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
+			{PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
+			{PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
+		},
 	},
 }
 
@@ -121,11 +142,25 @@ func TestOpen(t *testing.T) {
 				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
 			}
 		}
+		for i, p := range f.Progs {
+			if i >= len(tt.progs) {
+				break
+			}
+			ph := &tt.progs[i]
+			if !reflect.DeepEqual(&p.ProgHeader, ph) {
+				t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
+			}
+		}
 		tn := len(tt.sections)
 		fn := len(f.Sections)
 		if tn != fn {
 			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
 		}
+		tn = len(tt.progs)
+		fn = len(f.Progs)
+		if tn != fn {
+			t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
+		}
 	}
 }
 
@@ -178,3 +213,29 @@ func TestDWARFRelocations(t *testing.T) {
 		}
 	}
 }
+
+func TestNoSectionOverlaps(t *testing.T) {
+	// Ensure 6l outputs sections without overlaps.
+	if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
+		return // not ELF
+	}
+	_ = net.ResolveIPAddr // force dynamic linkage
+	f, err := Open(os.Args[0])
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	for i, si := range f.Sections {
+		sih := si.SectionHeader
+		for j, sj := range f.Sections {
+			sjh := sj.SectionHeader
+			if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
+				continue
+			}
+			if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
+				t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
+					sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
+			}
+		}
+	}
+}
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index 04991f7..d86d916 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -35,7 +35,6 @@ type SectionHeader struct {
 	Characteristics      uint32
 }
 
-
 type Section struct {
 	SectionHeader
 
@@ -69,7 +68,6 @@ func (s *Section) Data() ([]byte, os.Error) {
 // Open returns a new ReadSeeker reading the PE section.
 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
 
-
 type FormatError struct {
 	off int64
 	msg string
@@ -245,6 +243,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
 // satisfied by other libraries at dynamic load time.
 // It does not return weak symbols.
 func (f *File) ImportedSymbols() ([]string, os.Error) {
+	pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
 	ds := f.Section(".idata")
 	if ds == nil {
 		// not dynamic, so no libraries
@@ -274,17 +273,31 @@ func (f *File) ImportedSymbols() ([]string, os.Error) {
 		// seek to OriginalFirstThunk
 		d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
 		for len(d) > 0 {
-			va := binary.LittleEndian.Uint32(d[0:4])
-			d = d[4:]
-			if va == 0 {
-				break
-			}
-			if va&0x80000000 > 0 { // is Ordinal
-				// TODO add dynimport ordinal support.
-				//ord := va&0x0000FFFF
-			} else {
-				fn, _ := getString(names, int(va-ds.VirtualAddress+2))
-				all = append(all, fn+":"+dt.dll)
+			if pe64 { // 64bit
+				va := binary.LittleEndian.Uint64(d[0:8])
+				d = d[8:]
+				if va == 0 {
+					break
+				}
+				if va&0x8000000000000000 > 0 { // is Ordinal
+					// TODO add dynimport ordinal support.
+				} else {
+					fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
+					all = append(all, fn+":"+dt.dll)
+				}
+			} else { // 32bit
+				va := binary.LittleEndian.Uint32(d[0:4])
+				d = d[4:]
+				if va == 0 {
+					break
+				}
+				if va&0x80000000 > 0 { // is Ordinal
+					// TODO add dynimport ordinal support.
+					//ord := va&0x0000FFFF
+				} else {
+					fn, _ := getString(names, int(va-ds.VirtualAddress+2))
+					all = append(all, fn+":"+dt.dll)
+				}
 			}
 		}
 	}
diff --git a/src/pkg/debug/proc/Makefile b/src/pkg/debug/proc/Makefile
deleted file mode 100644
index c6d8798..0000000
--- a/src/pkg/debug/proc/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=debug/proc
-GOFILES=\
-	proc.go\
-	proc_$(GOOS).go\
-	regs_$(GOOS)_$(GOARCH).go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/debug/proc/proc.go b/src/pkg/debug/proc/proc.go
deleted file mode 100644
index d89649c..0000000
--- a/src/pkg/debug/proc/proc.go
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package proc provides a platform-independent interface for
-// tracing and controlling running processes.  It supports
-// multi-threaded processes and provides typical low-level debugging
-// controls such as breakpoints, single stepping, and manipulating
-// memory and registers.
-package proc
-
-// TODO(rsc): Have to import everything that proc_linux.go
-// and proc_darwin.go do, because deps.bash only looks at
-// this file.
-import (
-	_ "container/vector"
-	_ "fmt"
-	_ "io"
-	"os"
-	_ "runtime"
-	"strconv"
-	_ "strings"
-	_ "sync"
-	_ "syscall"
-)
-
-type Word uint64
-
-// A Cause explains why a thread is stopped.
-type Cause interface {
-	String() string
-}
-
-// Regs is a set of named machine registers, including a program
-// counter, link register, and stack pointer.
-//
-// TODO(austin) There's quite a proliferation of methods here.  We
-// could make a Reg interface with Get and Set and make this just PC,
-// Link, SP, Names, and Reg.  We could also put Index in Reg and that
-// makes it easy to get the index of things like the PC (currently
-// there's just no way to know that).  This would also let us include
-// other per-register information like how to print it.
-type Regs interface {
-	// PC returns the value of the program counter.
-	PC() Word
-
-	// SetPC sets the program counter to val.
-	SetPC(val Word) os.Error
-
-	// Link returns the link register, if any.
-	Link() Word
-
-	// SetLink sets the link register to val.
-	SetLink(val Word) os.Error
-
-	// SP returns the value of the stack pointer.
-	SP() Word
-
-	// SetSP sets the stack pointer register to val.
-	SetSP(val Word) os.Error
-
-	// Names returns the names of all of the registers.
-	Names() []string
-
-	// Get returns the value of a register, where i corresponds to
-	// the index of the register's name in the array returned by
-	// Names.
-	Get(i int) Word
-
-	// Set sets the value of a register.
-	Set(i int, val Word) os.Error
-}
-
-// Thread is a thread in the process being traced.
-type Thread interface {
-	// Step steps this thread by a single instruction.  The thread
-	// must be stopped.  If the thread is currently stopped on a
-	// breakpoint, this will step over the breakpoint.
-	//
-	// XXX What if it's stopped because of a signal?
-	Step() os.Error
-
-	// Stopped returns the reason that this thread is stopped.  It
-	// is an error is the thread not stopped.
-	Stopped() (Cause, os.Error)
-
-	// Regs retrieves the current register values from this
-	// thread.  The thread must be stopped.
-	Regs() (Regs, os.Error)
-
-	// Peek reads len(out) bytes from the address addr in this
-	// thread into out.  The thread must be stopped.  It returns
-	// the number of bytes successfully read.  If an error occurs,
-	// such as attempting to read unmapped memory, this count
-	// could be short and an error will be returned.  If this does
-	// encounter unmapped memory, it will read up to the byte
-	// preceding the unmapped area.
-	Peek(addr Word, out []byte) (int, os.Error)
-
-	// Poke writes b to the address addr in this thread.  The
-	// thread must be stopped.  It returns the number of bytes
-	// successfully written.  If an error occurs, such as
-	// attempting to write to unmapped memory, this count could be
-	// short and an error will be returned.  If this does
-	// encounter unmapped memory, it will write up to the byte
-	// preceding the unmapped area.
-	Poke(addr Word, b []byte) (int, os.Error)
-}
-
-// Process is a process being traced.  It consists of a set of
-// threads.  A process can be running, stopped, or terminated.  The
-// process's state extends to all of its threads.
-type Process interface {
-	// Threads returns an array of all threads in this process.
-	Threads() []Thread
-
-	// AddBreakpoint creates a new breakpoint at program counter
-	// pc.  Breakpoints can only be created when the process is
-	// stopped.  It is an error if a breakpoint already exists at
-	// pc.
-	AddBreakpoint(pc Word) os.Error
-
-	// RemoveBreakpoint removes the breakpoint at the program
-	// counter pc.  It is an error if no breakpoint exists at pc.
-	RemoveBreakpoint(pc Word) os.Error
-
-	// Stop stops all running threads in this process before
-	// returning.
-	Stop() os.Error
-
-	// Continue resumes execution of all threads in this process.
-	// Any thread that is stopped on a breakpoint will be stepped
-	// over that breakpoint.  Any thread that is stopped because
-	// of a signal (other than SIGSTOP or SIGTRAP) will receive
-	// the pending signal.
-	Continue() os.Error
-
-	// WaitStop waits until all threads in process p are stopped
-	// as a result of some thread hitting a breakpoint, receiving
-	// a signal, creating a new thread, or exiting.
-	WaitStop() os.Error
-
-	// Detach detaches from this process.  All stopped threads
-	// will be resumed.
-	Detach() os.Error
-}
-
-// Stopped is a stop cause used for threads that are stopped either by
-// user request (e.g., from the Stop method or after single stepping),
-// or that are stopped because some other thread caused the program to
-// stop.
-type Stopped struct{}
-
-func (c Stopped) String() string { return "stopped" }
-
-// Breakpoint is a stop cause resulting from a thread reaching a set
-// breakpoint.
-type Breakpoint Word
-
-// PC returns the program counter that the program is stopped at.
-func (c Breakpoint) PC() Word { return Word(c) }
-
-func (c Breakpoint) String() string {
-	return "breakpoint at 0x" + strconv.Uitob64(uint64(c.PC()), 16)
-}
-
-// Signal is a stop cause resulting from a thread receiving a signal.
-// When the process is continued, the signal will be delivered.
-type Signal string
-
-// Signal returns the signal being delivered to the thread.
-func (c Signal) Name() string { return string(c) }
-
-func (c Signal) String() string { return c.Name() }
-
-// ThreadCreate is a stop cause returned from an existing thread when
-// it creates a new thread.  The new thread exists in a primordial
-// form at this point and will begin executing in earnest when the
-// process is continued.
-type ThreadCreate struct {
-	thread Thread
-}
-
-func (c *ThreadCreate) NewThread() Thread { return c.thread }
-
-func (c *ThreadCreate) String() string { return "thread create" }
-
-// ThreadExit is a stop cause resulting from a thread exiting.  When
-// this cause first arises, the thread will still be in the list of
-// process threads and its registers and memory will still be
-// accessible.
-type ThreadExit struct {
-	exitStatus int
-	signal     string
-}
-
-// Exited returns true if the thread exited normally.
-func (c *ThreadExit) Exited() bool { return c.exitStatus != -1 }
-
-// ExitStatus returns the exit status of the thread if it exited
-// normally or -1 otherwise.
-func (c *ThreadExit) ExitStatus() int { return c.exitStatus }
-
-// Signaled returns true if the thread was terminated by a signal.
-func (c *ThreadExit) Signaled() bool { return c.exitStatus == -1 }
-
-// StopSignal returns the signal that terminated the thread, or "" if
-// it was not terminated by a signal.
-func (c *ThreadExit) StopSignal() string { return c.signal }
-
-func (c *ThreadExit) String() string {
-	res := "thread exited "
-	switch {
-	case c.Exited():
-		res += "with status " + strconv.Itoa(c.ExitStatus())
-	case c.Signaled():
-		res += "from signal " + c.StopSignal()
-	default:
-		res += "from unknown cause"
-	}
-	return res
-}
diff --git a/src/pkg/debug/proc/proc_darwin.go b/src/pkg/debug/proc/proc_darwin.go
deleted file mode 100644
index 49f0a53..0000000
--- a/src/pkg/debug/proc/proc_darwin.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-import "os"
-
-// Process tracing is not supported on OS X yet.
-
-func Attach(pid int) (Process, os.Error) {
-	return nil, os.NewError("debug/proc not implemented on OS X")
-}
-
-func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
-	return Attach(0)
-}
diff --git a/src/pkg/debug/proc/proc_freebsd.go b/src/pkg/debug/proc/proc_freebsd.go
deleted file mode 100644
index 4df07c3..0000000
--- a/src/pkg/debug/proc/proc_freebsd.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-import "os"
-
-// Process tracing is not supported on FreeBSD yet.
-
-func Attach(pid int) (Process, os.Error) {
-	return nil, os.NewError("debug/proc not implemented on FreeBSD")
-}
-
-func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
-	return Attach(0)
-}
diff --git a/src/pkg/debug/proc/proc_linux.go b/src/pkg/debug/proc/proc_linux.go
deleted file mode 100644
index 7ec7971..0000000
--- a/src/pkg/debug/proc/proc_linux.go
+++ /dev/null
@@ -1,1324 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-// TODO(rsc): Imports here after to be in proc.go too in order
-// for deps.bash to get the right answer.
-import (
-	"container/vector"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"runtime"
-	"strconv"
-	"strings"
-	"sync"
-	"syscall"
-)
-
-// This is an implementation of the process tracing interface using
-// Linux's ptrace(2) interface.  The implementation is multi-threaded.
-// Each attached process has an associated monitor thread, and each
-// running attached thread has an associated "wait" thread.  The wait
-// thread calls wait4 on the thread's TID and reports any wait events
-// or errors via "debug events".  The monitor thread consumes these
-// wait events and updates the internally maintained state of each
-// thread.  All ptrace calls must run in the monitor thread, so the
-// monitor executes closures received on the debugReq channel.
-//
-// As ptrace's documentation is somewhat light, this is heavily based
-// on information gleaned from the implementation of ptrace found at
-//   http://lxr.linux.no/linux+v2.6.30/kernel/ptrace.c
-//   http://lxr.linux.no/linux+v2.6.30/arch/x86/kernel/ptrace.c#L854
-// as well as experimentation and examination of gdb's behavior.
-
-const (
-	trace    = false
-	traceIP  = false
-	traceMem = false
-)
-
-/*
- * Thread state
- */
-
-// Each thread can be in one of the following set of states.
-// Each state satisfies
-//  isRunning() || isStopped() || isZombie() || isTerminal().
-//
-// Running threads can be sent signals and must be waited on, but they
-// cannot be inspected using ptrace.
-//
-// Stopped threads can be inspected and continued, but cannot be
-// meaningfully waited on.  They can be sent signals, but the signals
-// will be queued until they are running again.
-//
-// Zombie threads cannot be inspected, continued, or sent signals (and
-// therefore they cannot be stopped), but they must be waited on.
-//
-// Terminal threads no longer exist in the OS and thus you can't do
-// anything with them.
-type threadState string
-
-const (
-	running             threadState = "Running"
-	singleStepping      threadState = "SingleStepping" // Transient
-	stopping            threadState = "Stopping"       // Transient
-	stopped             threadState = "Stopped"
-	stoppedBreakpoint   threadState = "StoppedBreakpoint"
-	stoppedSignal       threadState = "StoppedSignal"
-	stoppedThreadCreate threadState = "StoppedThreadCreate"
-	stoppedExiting      threadState = "StoppedExiting"
-	exiting             threadState = "Exiting" // Transient (except main thread)
-	exited              threadState = "Exited"
-	detached            threadState = "Detached"
-)
-
-func (ts threadState) isRunning() bool {
-	return ts == running || ts == singleStepping || ts == stopping
-}
-
-func (ts threadState) isStopped() bool {
-	return ts == stopped || ts == stoppedBreakpoint || ts == stoppedSignal || ts == stoppedThreadCreate || ts == stoppedExiting
-}
-
-func (ts threadState) isZombie() bool { return ts == exiting }
-
-func (ts threadState) isTerminal() bool { return ts == exited || ts == detached }
-
-func (ts threadState) String() string { return string(ts) }
-
-/*
- * Basic types
- */
-
-// A breakpoint stores information about a single breakpoint,
-// including its program counter, the overwritten text if the
-// breakpoint is installed.
-type breakpoint struct {
-	pc      uintptr
-	olddata []byte
-}
-
-func (bp *breakpoint) String() string {
-	if bp == nil {
-		return "<nil>"
-	}
-	return fmt.Sprintf("%#x", bp.pc)
-}
-
-// bpinst386 is the breakpoint instruction used on 386 and amd64.
-var bpinst386 = []byte{0xcc}
-
-// A debugEvent represents a reason a thread stopped or a wait error.
-type debugEvent struct {
-	*os.Waitmsg
-	t   *thread
-	err os.Error
-}
-
-// A debugReq is a request to execute a closure in the monitor thread.
-type debugReq struct {
-	f   func() os.Error
-	res chan os.Error
-}
-
-// A transitionHandler specifies a function to be called when a thread
-// changes state and a function to be called when an error occurs in
-// the monitor.  Both run in the monitor thread.  Before the monitor
-// invokes a handler, it removes the handler from the handler queue.
-// The handler should re-add itself if needed.
-type transitionHandler struct {
-	handle func(*thread, threadState, threadState)
-	onErr  func(os.Error)
-}
-
-// A process is a Linux process, which consists of a set of threads.
-// Each running process has one monitor thread, which processes
-// messages from the debugEvents, debugReqs, and stopReq channels and
-// calls transition handlers.
-//
-// To send a message to the monitor thread, first receive from the
-// ready channel.  If the ready channel returns true, the monitor is
-// still running and will accept a message.  If the ready channel
-// returns false, the monitor is not running (the ready channel has
-// been closed), and the reason it is not running will be stored in err.
-type process struct {
-	pid                int
-	threads            map[int]*thread
-	breakpoints        map[uintptr]*breakpoint
-	ready              chan bool
-	debugEvents        chan *debugEvent
-	debugReqs          chan *debugReq
-	stopReq            chan os.Error
-	transitionHandlers vector.Vector
-	err                os.Error
-}
-
-// A thread represents a Linux thread in another process that is being
-// debugged.  Each running thread has an associated goroutine that
-// waits for thread updates and sends them to the process monitor.
-type thread struct {
-	tid  int
-	proc *process
-	// Whether to ignore the next SIGSTOP received by wait.
-	ignoreNextSigstop bool
-
-	// Thread state.  Only modified via setState.
-	state threadState
-	// If state == StoppedBreakpoint
-	breakpoint *breakpoint
-	// If state == StoppedSignal or state == Exited
-	signal int
-	// If state == StoppedThreadCreate
-	newThread *thread
-	// If state == Exited
-	exitStatus int
-}
-
-/*
- * Errors
- */
-
-type badState struct {
-	thread  *thread
-	message string
-	state   threadState
-}
-
-func (e *badState) String() string {
-	return fmt.Sprintf("Thread %d %s from state %v", e.thread.tid, e.message, e.state)
-}
-
-type breakpointExistsError Word
-
-func (e breakpointExistsError) String() string {
-	return fmt.Sprintf("breakpoint already exists at PC %#x", e)
-}
-
-type noBreakpointError Word
-
-func (e noBreakpointError) String() string { return fmt.Sprintf("no breakpoint at PC %#x", e) }
-
-type newThreadError struct {
-	*os.Waitmsg
-	wantPid int
-	wantSig int
-}
-
-func (e *newThreadError) String() string {
-	return fmt.Sprintf("newThread wait wanted pid %v and signal %v, got %v and %v", e.Pid, e.StopSignal(), e.wantPid, e.wantSig)
-}
-
-type ProcessExited struct{}
-
-func (p ProcessExited) String() string { return "process exited" }
-
-/*
- * Ptrace wrappers
- */
-
-func (t *thread) ptracePeekText(addr uintptr, out []byte) (int, os.Error) {
-	c, err := syscall.PtracePeekText(t.tid, addr, out)
-	if traceMem {
-		fmt.Printf("peek(%#x) => %v, %v\n", addr, out, err)
-	}
-	return c, os.NewSyscallError("ptrace(PEEKTEXT)", err)
-}
-
-func (t *thread) ptracePokeText(addr uintptr, out []byte) (int, os.Error) {
-	c, err := syscall.PtracePokeText(t.tid, addr, out)
-	if traceMem {
-		fmt.Printf("poke(%#x, %v) => %v\n", addr, out, err)
-	}
-	return c, os.NewSyscallError("ptrace(POKETEXT)", err)
-}
-
-func (t *thread) ptraceGetRegs(regs *syscall.PtraceRegs) os.Error {
-	err := syscall.PtraceGetRegs(t.tid, regs)
-	return os.NewSyscallError("ptrace(GETREGS)", err)
-}
-
-func (t *thread) ptraceSetRegs(regs *syscall.PtraceRegs) os.Error {
-	err := syscall.PtraceSetRegs(t.tid, regs)
-	return os.NewSyscallError("ptrace(SETREGS)", err)
-}
-
-func (t *thread) ptraceSetOptions(options int) os.Error {
-	err := syscall.PtraceSetOptions(t.tid, options)
-	return os.NewSyscallError("ptrace(SETOPTIONS)", err)
-}
-
-func (t *thread) ptraceGetEventMsg() (uint, os.Error) {
-	msg, err := syscall.PtraceGetEventMsg(t.tid)
-	return msg, os.NewSyscallError("ptrace(GETEVENTMSG)", err)
-}
-
-func (t *thread) ptraceCont() os.Error {
-	err := syscall.PtraceCont(t.tid, 0)
-	return os.NewSyscallError("ptrace(CONT)", err)
-}
-
-func (t *thread) ptraceContWithSignal(sig int) os.Error {
-	err := syscall.PtraceCont(t.tid, sig)
-	return os.NewSyscallError("ptrace(CONT)", err)
-}
-
-func (t *thread) ptraceStep() os.Error {
-	err := syscall.PtraceSingleStep(t.tid)
-	return os.NewSyscallError("ptrace(SINGLESTEP)", err)
-}
-
-func (t *thread) ptraceDetach() os.Error {
-	err := syscall.PtraceDetach(t.tid)
-	return os.NewSyscallError("ptrace(DETACH)", err)
-}
-
-/*
- * Logging utilities
- */
-
-var logLock sync.Mutex
-
-func (t *thread) logTrace(format string, args ...interface{}) {
-	if !trace {
-		return
-	}
-	logLock.Lock()
-	defer logLock.Unlock()
-	fmt.Fprintf(os.Stderr, "Thread %d", t.tid)
-	if traceIP {
-		var regs syscall.PtraceRegs
-		err := t.ptraceGetRegs(&regs)
-		if err == nil {
-			fmt.Fprintf(os.Stderr, "@%x", regs.PC())
-		}
-	}
-	fmt.Fprint(os.Stderr, ": ")
-	fmt.Fprintf(os.Stderr, format, args...)
-	fmt.Fprint(os.Stderr, "\n")
-}
-
-func (t *thread) warn(format string, args ...interface{}) {
-	logLock.Lock()
-	defer logLock.Unlock()
-	fmt.Fprintf(os.Stderr, "Thread %d: WARNING ", t.tid)
-	fmt.Fprintf(os.Stderr, format, args...)
-	fmt.Fprint(os.Stderr, "\n")
-}
-
-func (p *process) logTrace(format string, args ...interface{}) {
-	if !trace {
-		return
-	}
-	logLock.Lock()
-	defer logLock.Unlock()
-	fmt.Fprintf(os.Stderr, "Process %d: ", p.pid)
-	fmt.Fprintf(os.Stderr, format, args...)
-	fmt.Fprint(os.Stderr, "\n")
-}
-
-/*
- * State utilities
- */
-
-// someStoppedThread returns a stopped thread from the process.
-// Returns nil if no threads are stopped.
-//
-// Must be called from the monitor thread.
-func (p *process) someStoppedThread() *thread {
-	for _, t := range p.threads {
-		if t.state.isStopped() {
-			return t
-		}
-	}
-	return nil
-}
-
-// someRunningThread returns a running thread from the process.
-// Returns nil if no threads are running.
-//
-// Must be called from the monitor thread.
-func (p *process) someRunningThread() *thread {
-	for _, t := range p.threads {
-		if t.state.isRunning() {
-			return t
-		}
-	}
-	return nil
-}
-
-/*
- * Breakpoint utilities
- */
-
-// installBreakpoints adds breakpoints to the attached process.
-//
-// Must be called from the monitor thread.
-func (p *process) installBreakpoints() os.Error {
-	n := 0
-	main := p.someStoppedThread()
-	for _, b := range p.breakpoints {
-		if b.olddata != nil {
-			continue
-		}
-
-		b.olddata = make([]byte, len(bpinst386))
-		_, err := main.ptracePeekText(uintptr(b.pc), b.olddata)
-		if err != nil {
-			b.olddata = nil
-			return err
-		}
-
-		_, err = main.ptracePokeText(uintptr(b.pc), bpinst386)
-		if err != nil {
-			b.olddata = nil
-			return err
-		}
-		n++
-	}
-	if n > 0 {
-		p.logTrace("installed %d/%d breakpoints", n, len(p.breakpoints))
-	}
-
-	return nil
-}
-
-// uninstallBreakpoints removes the installed breakpoints from p.
-//
-// Must be called from the monitor thread.
-func (p *process) uninstallBreakpoints() os.Error {
-	if len(p.threads) == 0 {
-		return nil
-	}
-	n := 0
-	main := p.someStoppedThread()
-	for _, b := range p.breakpoints {
-		if b.olddata == nil {
-			continue
-		}
-
-		_, err := main.ptracePokeText(uintptr(b.pc), b.olddata)
-		if err != nil {
-			return err
-		}
-		b.olddata = nil
-		n++
-	}
-	if n > 0 {
-		p.logTrace("uninstalled %d/%d breakpoints", n, len(p.breakpoints))
-	}
-
-	return nil
-}
-
-/*
- * Debug event handling
- */
-
-// wait waits for a wait event from this thread and sends it on the
-// debug events channel for this thread's process.  This should be
-// started in its own goroutine when the attached thread enters a
-// running state.  The goroutine will exit as soon as it sends a debug
-// event.
-func (t *thread) wait() {
-	for {
-		var ev debugEvent
-		ev.t = t
-		t.logTrace("beginning wait")
-		ev.Waitmsg, ev.err = os.Wait(t.tid, syscall.WALL)
-		if ev.err == nil && ev.Pid != t.tid {
-			panic(fmt.Sprint("Wait returned pid ", ev.Pid, " wanted ", t.tid))
-		}
-		if ev.StopSignal() == syscall.SIGSTOP && t.ignoreNextSigstop {
-			// Spurious SIGSTOP.  See Thread.Stop().
-			t.ignoreNextSigstop = false
-			err := t.ptraceCont()
-			if err == nil {
-				continue
-			}
-			// If we failed to continue, just let
-			// the stop go through so we can
-			// update the thread's state.
-		}
-		if !<-t.proc.ready {
-			// The monitor exited
-			break
-		}
-		t.proc.debugEvents <- &ev
-		break
-	}
-}
-
-// setState sets this thread's state, starts a wait thread if
-// necessary, and invokes state transition handlers.
-//
-// Must be called from the monitor thread.
-func (t *thread) setState(newState threadState) {
-	oldState := t.state
-	t.state = newState
-	t.logTrace("state %v -> %v", oldState, newState)
-
-	if !oldState.isRunning() && (newState.isRunning() || newState.isZombie()) {
-		// Start waiting on this thread
-		go t.wait()
-	}
-
-	// Invoke state change handlers
-	handlers := t.proc.transitionHandlers
-	if handlers.Len() == 0 {
-		return
-	}
-
-	t.proc.transitionHandlers = nil
-	for _, h := range handlers {
-		h := h.(*transitionHandler)
-		h.handle(t, oldState, newState)
-	}
-}
-
-// sendSigstop sends a SIGSTOP to this thread.
-func (t *thread) sendSigstop() os.Error {
-	t.logTrace("sending SIGSTOP")
-	err := syscall.Tgkill(t.proc.pid, t.tid, syscall.SIGSTOP)
-	return os.NewSyscallError("tgkill", err)
-}
-
-// stopAsync sends SIGSTOP to all threads in state 'running'.
-//
-// Must be called from the monitor thread.
-func (p *process) stopAsync() os.Error {
-	for _, t := range p.threads {
-		if t.state == running {
-			err := t.sendSigstop()
-			if err != nil {
-				return err
-			}
-			t.setState(stopping)
-		}
-	}
-	return nil
-}
-
-// doTrap handles SIGTRAP debug events with a cause of 0.  These can
-// be caused either by an installed breakpoint, a breakpoint in the
-// program text, or by single stepping.
-//
-// TODO(austin) I think we also get this on an execve syscall.
-func (ev *debugEvent) doTrap() (threadState, os.Error) {
-	t := ev.t
-
-	if t.state == singleStepping {
-		return stopped, nil
-	}
-
-	// Hit a breakpoint.  Linux leaves the program counter after
-	// the breakpoint.  If this is an installed breakpoint, we
-	// need to back the PC up to the breakpoint PC.
-	var regs syscall.PtraceRegs
-	err := t.ptraceGetRegs(&regs)
-	if err != nil {
-		return stopped, err
-	}
-
-	b, ok := t.proc.breakpoints[uintptr(regs.PC())-uintptr(len(bpinst386))]
-	if !ok {
-		// We must have hit a breakpoint that was actually in
-		// the program.  Leave the IP where it is so we don't
-		// re-execute the breakpoint instruction.  Expose the
-		// fact that we stopped with a SIGTRAP.
-		return stoppedSignal, nil
-	}
-
-	t.breakpoint = b
-	t.logTrace("at breakpoint %v, backing up PC from %#x", b, regs.PC())
-
-	regs.SetPC(uint64(b.pc))
-	err = t.ptraceSetRegs(&regs)
-	if err != nil {
-		return stopped, err
-	}
-	return stoppedBreakpoint, nil
-}
-
-// doPtraceClone handles SIGTRAP debug events with a PTRACE_EVENT_CLONE
-// cause.  It initializes the new thread, adds it to the process, and
-// returns the appropriate thread state for the existing thread.
-func (ev *debugEvent) doPtraceClone() (threadState, os.Error) {
-	t := ev.t
-
-	// Get the TID of the new thread
-	tid, err := t.ptraceGetEventMsg()
-	if err != nil {
-		return stopped, err
-	}
-
-	nt, err := t.proc.newThread(int(tid), syscall.SIGSTOP, true)
-	if err != nil {
-		return stopped, err
-	}
-
-	// Remember the thread
-	t.newThread = nt
-
-	return stoppedThreadCreate, nil
-}
-
-// doPtraceExit handles SIGTRAP debug events with a PTRACE_EVENT_EXIT
-// cause.  It sets up the thread's state, but does not remove it from
-// the process.  A later WIFEXITED debug event will remove it from the
-// process.
-func (ev *debugEvent) doPtraceExit() (threadState, os.Error) {
-	t := ev.t
-
-	// Get exit status
-	exitStatus, err := t.ptraceGetEventMsg()
-	if err != nil {
-		return stopped, err
-	}
-	ws := syscall.WaitStatus(exitStatus)
-	t.logTrace("exited with %v", ws)
-	switch {
-	case ws.Exited():
-		t.exitStatus = ws.ExitStatus()
-	case ws.Signaled():
-		t.signal = ws.Signal()
-	}
-
-	// We still need to continue this thread and wait on this
-	// thread's WIFEXITED event.  We'll delete it then.
-	return stoppedExiting, nil
-}
-
-// process handles a debug event.  It modifies any thread or process
-// state as necessary, uninstalls breakpoints if necessary, and stops
-// any running threads.
-func (ev *debugEvent) process() os.Error {
-	if ev.err != nil {
-		return ev.err
-	}
-
-	t := ev.t
-	t.exitStatus = -1
-	t.signal = -1
-
-	// Decode wait status.
-	var state threadState
-	switch {
-	case ev.Stopped():
-		state = stoppedSignal
-		t.signal = ev.StopSignal()
-		t.logTrace("stopped with %v", ev)
-		if ev.StopSignal() == syscall.SIGTRAP {
-			// What caused the debug trap?
-			var err os.Error
-			switch cause := ev.TrapCause(); cause {
-			case 0:
-				// Breakpoint or single stepping
-				state, err = ev.doTrap()
-
-			case syscall.PTRACE_EVENT_CLONE:
-				state, err = ev.doPtraceClone()
-
-			case syscall.PTRACE_EVENT_EXIT:
-				state, err = ev.doPtraceExit()
-
-			default:
-				t.warn("Unknown trap cause %d", cause)
-			}
-
-			if err != nil {
-				t.setState(stopped)
-				t.warn("failed to handle trap %v: %v", ev, err)
-			}
-		}
-
-	case ev.Exited():
-		state = exited
-		t.proc.threads[t.tid] = nil, false
-		t.logTrace("exited %v", ev)
-		// We should have gotten the exit status in
-		// PTRACE_EVENT_EXIT, but just in case.
-		t.exitStatus = ev.ExitStatus()
-
-	case ev.Signaled():
-		state = exited
-		t.proc.threads[t.tid] = nil, false
-		t.logTrace("signaled %v", ev)
-		// Again, this should be redundant.
-		t.signal = ev.Signal()
-
-	default:
-		panic(fmt.Sprintf("Unexpected wait status %v", ev.Waitmsg))
-	}
-
-	// If we sent a SIGSTOP to the thread (indicated by state
-	// Stopping), we might have raced with a different type of
-	// stop.  If we didn't get the stop we expected, then the
-	// SIGSTOP we sent is now queued up, so we should ignore the
-	// next one we get.
-	if t.state == stopping && ev.StopSignal() != syscall.SIGSTOP {
-		t.ignoreNextSigstop = true
-	}
-
-	// TODO(austin) If we're in state stopping and get a SIGSTOP,
-	// set state stopped instead of stoppedSignal.
-
-	t.setState(state)
-
-	if t.proc.someRunningThread() == nil {
-		// Nothing is running, uninstall breakpoints
-		return t.proc.uninstallBreakpoints()
-	}
-	// Stop any other running threads
-	return t.proc.stopAsync()
-}
-
-// onStop adds a handler for state transitions from running to
-// non-running states.  The handler will be called from the monitor
-// thread.
-//
-// Must be called from the monitor thread.
-func (t *thread) onStop(handle func(), onErr func(os.Error)) {
-	// TODO(austin) This is rather inefficient for things like
-	// stepping all threads during a continue.  Maybe move
-	// transitionHandlers to the thread, or have both per-thread
-	// and per-process transition handlers.
-	h := &transitionHandler{nil, onErr}
-	h.handle = func(st *thread, old, new threadState) {
-		if t == st && old.isRunning() && !new.isRunning() {
-			handle()
-		} else {
-			t.proc.transitionHandlers.Push(h)
-		}
-	}
-	t.proc.transitionHandlers.Push(h)
-}
-
-/*
- * Event monitor
- */
-
-// monitor handles debug events and debug requests for p, exiting when
-// there are no threads left in p.
-func (p *process) monitor() {
-	var err os.Error
-
-	// Linux requires that all ptrace calls come from the thread
-	// that originally attached.  Prevent the Go scheduler from
-	// migrating us to other OS threads.
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
-
-	hadThreads := false
-	for err == nil {
-		p.ready <- true
-		select {
-		case event := <-p.debugEvents:
-			err = event.process()
-
-		case req := <-p.debugReqs:
-			req.res <- req.f()
-
-		case err = <-p.stopReq:
-			break
-		}
-
-		if len(p.threads) == 0 {
-			if err == nil && hadThreads {
-				p.logTrace("no more threads; monitor exiting")
-				err = ProcessExited{}
-			}
-		} else {
-			hadThreads = true
-		}
-	}
-
-	// Abort waiting handlers
-	// TODO(austin) How do I stop the wait threads?
-	for _, h := range p.transitionHandlers {
-		h := h.(*transitionHandler)
-		h.onErr(err)
-	}
-
-	// Indicate that the monitor cannot receive any more messages
-	p.err = err
-	close(p.ready)
-}
-
-// do executes f in the monitor thread (and, thus, atomically with
-// respect to thread state changes).  f must not block.
-//
-// Must NOT be called from the monitor thread.
-func (p *process) do(f func() os.Error) os.Error {
-	if !<-p.ready {
-		return p.err
-	}
-	req := &debugReq{f, make(chan os.Error)}
-	p.debugReqs <- req
-	return <-req.res
-}
-
-// stopMonitor stops the monitor with the given error.  If the monitor
-// is already stopped, does nothing.
-func (p *process) stopMonitor(err os.Error) {
-	if err == nil {
-		panic("cannot stop the monitor with no error")
-	}
-	if <-p.ready {
-		p.stopReq <- err
-	}
-}
-
-/*
- * Public thread interface
- */
-
-func (t *thread) Regs() (Regs, os.Error) {
-	var regs syscall.PtraceRegs
-
-	err := t.proc.do(func() os.Error {
-		if !t.state.isStopped() {
-			return &badState{t, "cannot get registers", t.state}
-		}
-		return t.ptraceGetRegs(&regs)
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	setter := func(r *syscall.PtraceRegs) os.Error {
-		return t.proc.do(func() os.Error {
-			if !t.state.isStopped() {
-				return &badState{t, "cannot get registers", t.state}
-			}
-			return t.ptraceSetRegs(r)
-		})
-	}
-	return newRegs(&regs, setter), nil
-}
-
-func (t *thread) Peek(addr Word, out []byte) (int, os.Error) {
-	var c int
-
-	err := t.proc.do(func() os.Error {
-		if !t.state.isStopped() {
-			return &badState{t, "cannot peek text", t.state}
-		}
-
-		var err os.Error
-		c, err = t.ptracePeekText(uintptr(addr), out)
-		return err
-	})
-
-	return c, err
-}
-
-func (t *thread) Poke(addr Word, out []byte) (int, os.Error) {
-	var c int
-
-	err := t.proc.do(func() os.Error {
-		if !t.state.isStopped() {
-			return &badState{t, "cannot poke text", t.state}
-		}
-
-		var err os.Error
-		c, err = t.ptracePokeText(uintptr(addr), out)
-		return err
-	})
-
-	return c, err
-}
-
-// stepAsync starts this thread single stepping.  When the single step
-// is complete, it will send nil on the given channel.  If an error
-// occurs while setting up the single step, it returns that error.  If
-// an error occurs while waiting for the single step to complete, it
-// sends that error on the channel.
-func (t *thread) stepAsync(ready chan os.Error) os.Error {
-	if err := t.ptraceStep(); err != nil {
-		return err
-	}
-	t.setState(singleStepping)
-	t.onStop(func() { ready <- nil },
-		func(err os.Error) { ready <- err })
-	return nil
-}
-
-func (t *thread) Step() os.Error {
-	t.logTrace("Step {")
-	defer t.logTrace("}")
-
-	ready := make(chan os.Error)
-
-	err := t.proc.do(func() os.Error {
-		if !t.state.isStopped() {
-			return &badState{t, "cannot single step", t.state}
-		}
-		return t.stepAsync(ready)
-	})
-	if err != nil {
-		return err
-	}
-
-	err = <-ready
-	return err
-}
-
-// TODO(austin) We should probably get this via C's strsignal.
-var sigNames = [...]string{
-	"SIGEXIT", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL",
-	"SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL",
-	"SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM",
-	"SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP",
-	"SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU",
-	"SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGPOLL",
-	"SIGPWR", "SIGSYS",
-}
-
-// sigName returns the symbolic name for the given signal number.  If
-// the signal number is invalid, returns "<invalid>".
-func sigName(signal int) string {
-	if signal < 0 || signal >= len(sigNames) {
-		return "<invalid>"
-	}
-	return sigNames[signal]
-}
-
-func (t *thread) Stopped() (Cause, os.Error) {
-	var c Cause
-	err := t.proc.do(func() os.Error {
-		switch t.state {
-		case stopped:
-			c = Stopped{}
-
-		case stoppedBreakpoint:
-			c = Breakpoint(t.breakpoint.pc)
-
-		case stoppedSignal:
-			c = Signal(sigName(t.signal))
-
-		case stoppedThreadCreate:
-			c = &ThreadCreate{t.newThread}
-
-		case stoppedExiting, exiting, exited:
-			if t.signal == -1 {
-				c = &ThreadExit{t.exitStatus, ""}
-			} else {
-				c = &ThreadExit{t.exitStatus, sigName(t.signal)}
-			}
-
-		default:
-			return &badState{t, "cannot get stop cause", t.state}
-		}
-		return nil
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	return c, nil
-}
-
-func (p *process) Threads() []Thread {
-	var res []Thread
-
-	p.do(func() os.Error {
-		res = make([]Thread, len(p.threads))
-		i := 0
-		for _, t := range p.threads {
-			// Exclude zombie threads.
-			st := t.state
-			if st == exiting || st == exited || st == detached {
-				continue
-			}
-
-			res[i] = t
-			i++
-		}
-		res = res[0:i]
-		return nil
-	})
-	return res
-}
-
-func (p *process) AddBreakpoint(pc Word) os.Error {
-	return p.do(func() os.Error {
-		if t := p.someRunningThread(); t != nil {
-			return &badState{t, "cannot add breakpoint", t.state}
-		}
-		if _, ok := p.breakpoints[uintptr(pc)]; ok {
-			return breakpointExistsError(pc)
-		}
-		p.breakpoints[uintptr(pc)] = &breakpoint{pc: uintptr(pc)}
-		return nil
-	})
-}
-
-func (p *process) RemoveBreakpoint(pc Word) os.Error {
-	return p.do(func() os.Error {
-		if t := p.someRunningThread(); t != nil {
-			return &badState{t, "cannot remove breakpoint", t.state}
-		}
-		if _, ok := p.breakpoints[uintptr(pc)]; !ok {
-			return noBreakpointError(pc)
-		}
-		p.breakpoints[uintptr(pc)] = nil, false
-		return nil
-	})
-}
-
-func (p *process) Continue() os.Error {
-	// Single step any threads that are stopped at breakpoints so
-	// we can reinstall breakpoints.
-	var ready chan os.Error
-	count := 0
-
-	err := p.do(func() os.Error {
-		// We make the ready channel big enough to hold all
-		// ready message so we don't jam up the monitor if we
-		// stop listening (e.g., if there's an error).
-		ready = make(chan os.Error, len(p.threads))
-
-		for _, t := range p.threads {
-			if !t.state.isStopped() {
-				continue
-			}
-
-			// We use the breakpoint map directly here
-			// instead of checking the stop cause because
-			// it could have been stopped at a breakpoint
-			// for some other reason, or the breakpoint
-			// could have been added since it was stopped.
-			var regs syscall.PtraceRegs
-			err := t.ptraceGetRegs(&regs)
-			if err != nil {
-				return err
-			}
-			if b, ok := p.breakpoints[uintptr(regs.PC())]; ok {
-				t.logTrace("stepping over breakpoint %v", b)
-				if err := t.stepAsync(ready); err != nil {
-					return err
-				}
-				count++
-			}
-		}
-		return nil
-	})
-	if err != nil {
-		p.stopMonitor(err)
-		return err
-	}
-
-	// Wait for single stepping threads
-	for count > 0 {
-		err = <-ready
-		if err != nil {
-			p.stopMonitor(err)
-			return err
-		}
-		count--
-	}
-
-	// Continue all threads
-	err = p.do(func() os.Error {
-		if err := p.installBreakpoints(); err != nil {
-			return err
-		}
-
-		for _, t := range p.threads {
-			var err os.Error
-			switch {
-			case !t.state.isStopped():
-				continue
-
-			case t.state == stoppedSignal && t.signal != syscall.SIGSTOP && t.signal != syscall.SIGTRAP:
-				t.logTrace("continuing with signal %d", t.signal)
-				err = t.ptraceContWithSignal(t.signal)
-
-			default:
-				t.logTrace("continuing")
-				err = t.ptraceCont()
-			}
-			if err != nil {
-				return err
-			}
-			if t.state == stoppedExiting {
-				t.setState(exiting)
-			} else {
-				t.setState(running)
-			}
-		}
-		return nil
-	})
-	if err != nil {
-		// TODO(austin) Do we need to stop the monitor with
-		// this error atomically with the do-routine above?
-		p.stopMonitor(err)
-		return err
-	}
-
-	return nil
-}
-
-func (p *process) WaitStop() os.Error {
-	// We need a non-blocking ready channel for the case where all
-	// threads are already stopped.
-	ready := make(chan os.Error, 1)
-
-	err := p.do(func() os.Error {
-		// Are all of the threads already stopped?
-		if p.someRunningThread() == nil {
-			ready <- nil
-			return nil
-		}
-
-		// Monitor state transitions
-		h := &transitionHandler{}
-		h.handle = func(st *thread, old, new threadState) {
-			if !new.isRunning() {
-				if p.someRunningThread() == nil {
-					ready <- nil
-					return
-				}
-			}
-			p.transitionHandlers.Push(h)
-		}
-		h.onErr = func(err os.Error) { ready <- err }
-		p.transitionHandlers.Push(h)
-		return nil
-	})
-	if err != nil {
-		return err
-	}
-
-	return <-ready
-}
-
-func (p *process) Stop() os.Error {
-	err := p.do(func() os.Error { return p.stopAsync() })
-	if err != nil {
-		return err
-	}
-
-	return p.WaitStop()
-}
-
-func (p *process) Detach() os.Error {
-	if err := p.Stop(); err != nil {
-		return err
-	}
-
-	err := p.do(func() os.Error {
-		if err := p.uninstallBreakpoints(); err != nil {
-			return err
-		}
-
-		for pid, t := range p.threads {
-			if t.state.isStopped() {
-				// We can't detach from zombies.
-				if err := t.ptraceDetach(); err != nil {
-					return err
-				}
-			}
-			t.setState(detached)
-			p.threads[pid] = nil, false
-		}
-		return nil
-	})
-	// TODO(austin) Wait for monitor thread to exit?
-	return err
-}
-
-// newThread creates a new thread object and waits for its initial
-// signal.  If cloned is true, this thread was cloned from a thread we
-// are already attached to.
-//
-// Must be run from the monitor thread.
-func (p *process) newThread(tid int, signal int, cloned bool) (*thread, os.Error) {
-	t := &thread{tid: tid, proc: p, state: stopped}
-
-	// Get the signal from the thread
-	// TODO(austin) Thread might already be stopped if we're attaching.
-	w, err := os.Wait(tid, syscall.WALL)
-	if err != nil {
-		return nil, err
-	}
-	if w.Pid != tid || w.StopSignal() != signal {
-		return nil, &newThreadError{w, tid, signal}
-	}
-
-	if !cloned {
-		err = t.ptraceSetOptions(syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEEXIT)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	p.threads[tid] = t
-
-	return t, nil
-}
-
-// attachThread attaches a running thread to the process.
-//
-// Must NOT be run from the monitor thread.
-func (p *process) attachThread(tid int) (*thread, os.Error) {
-	p.logTrace("attaching to thread %d", tid)
-	var thr *thread
-	err := p.do(func() os.Error {
-		errno := syscall.PtraceAttach(tid)
-		if errno != 0 {
-			return os.NewSyscallError("ptrace(ATTACH)", errno)
-		}
-
-		var err os.Error
-		thr, err = p.newThread(tid, syscall.SIGSTOP, false)
-		return err
-	})
-	return thr, err
-}
-
-// attachAllThreads attaches to all threads in a process.
-func (p *process) attachAllThreads() os.Error {
-	taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task"
-	taskDir, err := os.Open(taskPath)
-	if err != nil {
-		return err
-	}
-	defer taskDir.Close()
-
-	// We stop threads as we attach to them; however, because new
-	// threads can appear while we're looping over all of them, we
-	// have to repeatedly scan until we know we're attached to all
-	// of them.
-	for again := true; again; {
-		again = false
-
-		tids, err := taskDir.Readdirnames(-1)
-		if err != nil {
-			return err
-		}
-
-		for _, tidStr := range tids {
-			tid, err := strconv.Atoi(tidStr)
-			if err != nil {
-				return err
-			}
-			if _, ok := p.threads[tid]; ok {
-				continue
-			}
-
-			_, err = p.attachThread(tid)
-			if err != nil {
-				// There could have been a race, or
-				// this process could be a zombie.
-				statFile, err2 := ioutil.ReadFile(taskPath + "/" + tidStr + "/stat")
-				if err2 != nil {
-					switch err2 := err2.(type) {
-					case *os.PathError:
-						if err2.Error == os.ENOENT {
-							// Raced with thread exit
-							p.logTrace("raced with thread %d exit", tid)
-							continue
-						}
-					}
-					// Return the original error
-					return err
-				}
-
-				statParts := strings.SplitN(string(statFile), " ", 4)
-				if len(statParts) > 2 && statParts[2] == "Z" {
-					// tid is a zombie
-					p.logTrace("thread %d is a zombie", tid)
-					continue
-				}
-
-				// Return the original error
-				return err
-			}
-			again = true
-		}
-	}
-
-	return nil
-}
-
-// newProcess creates a new process object and starts its monitor thread.
-func newProcess(pid int) *process {
-	p := &process{
-		pid:         pid,
-		threads:     make(map[int]*thread),
-		breakpoints: make(map[uintptr]*breakpoint),
-		ready:       make(chan bool, 1),
-		debugEvents: make(chan *debugEvent),
-		debugReqs:   make(chan *debugReq),
-		stopReq:     make(chan os.Error),
-	}
-
-	go p.monitor()
-
-	return p
-}
-
-// Attach attaches to process pid and stops all of its threads.
-func Attach(pid int) (Process, os.Error) {
-	p := newProcess(pid)
-
-	// Attach to all threads
-	err := p.attachAllThreads()
-	if err != nil {
-		p.Detach()
-		// TODO(austin) Detach stopped the monitor already
-		//p.stopMonitor(err);
-		return nil, err
-	}
-
-	return p, nil
-}
-
-// StartProcess forks the current process and execs argv0, stopping the
-// new process after the exec syscall.  See os.StartProcess for additional
-// details.
-func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
-	sysattr := &syscall.ProcAttr{
-		Dir: attr.Dir,
-		Env: attr.Env,
-		Sys: &syscall.SysProcAttr{
-			Ptrace: true,
-		},
-	}
-	p := newProcess(-1)
-
-	// Create array of integer (system) fds.
-	intfd := make([]int, len(attr.Files))
-	for i, f := range attr.Files {
-		if f == nil {
-			intfd[i] = -1
-		} else {
-			intfd[i] = f.Fd()
-		}
-	}
-	sysattr.Files = intfd
-
-	// Fork from the monitor thread so we get the right tracer pid.
-	err := p.do(func() os.Error {
-		pid, _, errno := syscall.StartProcess(argv0, argv, sysattr)
-		if errno != 0 {
-			return &os.PathError{"fork/exec", argv0, os.Errno(errno)}
-		}
-		p.pid = pid
-
-		// The process will raise SIGTRAP when it reaches execve.
-		_, err := p.newThread(pid, syscall.SIGTRAP, false)
-		return err
-	})
-	if err != nil {
-		p.stopMonitor(err)
-		return nil, err
-	}
-
-	return p, nil
-}
diff --git a/src/pkg/debug/proc/proc_windows.go b/src/pkg/debug/proc/proc_windows.go
deleted file mode 100644
index 661474b..0000000
--- a/src/pkg/debug/proc/proc_windows.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-import "os"
-
-// Process tracing is not supported on windows yet.
-
-func Attach(pid int) (Process, os.Error) {
-	return nil, os.NewError("debug/proc not implemented on windows")
-}
-
-func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
-	return Attach(0)
-}
diff --git a/src/pkg/debug/proc/ptrace-nptl.txt b/src/pkg/debug/proc/ptrace-nptl.txt
deleted file mode 100644
index 62cbf77..0000000
--- a/src/pkg/debug/proc/ptrace-nptl.txt
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-ptrace and NTPL, the missing manpage
-
-== Signals ==
-
-A signal sent to a ptrace'd process or thread causes only the thread
-that receives it to stop and report to the attached process.
-
-Use tgkill to target a signal (for example, SIGSTOP) at a particular
-thread.  If you use kill, the signal could be delivered to another
-thread in the same process.
-
-Note that SIGSTOP differs from its usual behavior when a process is
-being traced.  Usually, a SIGSTOP sent to any thread in a thread group
-will stop all threads in the thread group.  When a thread is traced,
-however, a SIGSTOP affects only the receiving thread (and any other
-threads in the thread group that are not traced).
-
-SIGKILL behaves like it does for non-traced processes.  It affects all
-threads in the process and terminates them without the WSTOPSIG event
-generated by other signals.  However, if PTRACE_O_TRACEEXIT is set,
-the attached process will still receive PTRACE_EVENT_EXIT events
-before receiving WIFSIGNALED events.
-
-See "Following thread death" for a caveat regarding signal delivery to
-zombie threads.
-
-== Waiting on threads ==
-
-Cloned threads in ptrace'd processes are treated similarly to cloned
-threads in your own process.  Thus, you must use the __WALL option in
-order to receive notifications from threads created by the child
-process.  Similarly, the __WCLONE option will wait only on
-notifications from threads created by the child process and *not* on
-notifications from the initial child thread.
-
-Even when waiting on a specific thread's PID using waitpid or similar,
-__WALL or __WCLONE is necessary or waitpid will return ECHILD.
-
-== Attaching to existing threads ==
-
-libthread_db (which gdb uses), attaches to existing threads by pulling
-the pthread data structures out of the traced process.  The much
-easier way is to traverse the /proc/PID/task directory, though it's
-unclear how the semantics of these two approaches differ.
-
-Unfortunately, if the main thread has exited (but the overall process
-has not), it sticks around as a zombie process.  This zombie will
-appear in the /proc/PID/task directory, but trying to attach to it
-will yield EPERM.  In this case, the third field of the
-/proc/PID/task/PID/stat file will be "Z".  Attempting to open the stat
-file is also a convenient way to detect races between listing the task
-directory and the thread exiting.  Coincidentally, gdb will simply
-fail to attach to a process whose main thread is a zombie.
-
-Because new threads may be created while the debugger is in the
-process of attaching to existing threads, the debugger must repeatedly
-re-list the task directory until it has attached to (and thus stopped)
-every thread listed.
-
-In order to follow new threads created by existing threads,
-PTRACE_O_TRACECLONE must be set on each thread attached to.
-
-== Following new threads ==
-
-With the child process stopped, use PTRACE_SETOPTIONS to set the
-PTRACE_O_TRACECLONE option.  This option is per-thread, and thus must
-be set on each existing thread individually.  When an existing thread
-with PTRACE_O_TRACECLONE set spawns a new thread, the existing thread
-will stop with (SIGTRAP | PTRACE_EVENT_CLONE << 8) and the PID of the
-new thread can be retrieved with PTRACE_GETEVENTMSG on the creating
-thread.  At this time, the new thread will exist, but will initially
-be stopped with a SIGSTOP.  The new thread will automatically be
-traced and will inherit the PTRACE_O_TRACECLONE option from its
-parent.  The attached process should wait on the new thread to receive
-the SIGSTOP notification.
-
-When using waitpid(-1, ...), don't rely on the parent thread reporting
-a SIGTRAP before receiving the SIGSTOP from the new child thread.
-
-Without PTRACE_O_TRACECLONE, newly cloned threads will not be
-ptrace'd.  As a result, signals received by new threads will be
-handled in the usual way, which may affect the parent and in turn
-appear to the attached process, but attributed to the parent (possibly
-in unexpected ways).
-
-== Following thread death ==
-
-If any thread with the PTRACE_O_TRACEEXIT option set exits (either by
-returning or pthread_exit'ing), the tracing process will receive an
-immediate PTRACE_EVENT_EXIT.  At this point, the thread will still
-exist.  The exit status, encoded as for wait, can be queried using
-PTRACE_GETEVENTMSG on the exiting thread's PID.  The thread should be
-continued so it can actually exit, after which its wait behavior is
-the same as for a thread without the PTRACE_O_TRACEEXIT option.
-
-If a non-main thread exits (either by returning or pthread_exit'ing),
-its corresponding process will also exit, producing a WIFEXITED event
-(after the process is continued from a possible PTRACE_EVENT_EXIT
-event).  It is *not* necessary for another thread to ptrace_join for
-this to happen.
-
-If the main thread exits by returning, then all threads will exit,
-first generating a PTRACE_EVENT_EXIT event for each thread if
-appropriate, then producing a WIFEXITED event for each thread.
-
-If the main thread exits using pthread_exit, then it enters a
-non-waitable zombie state.  It will still produce an immediate
-PTRACE_O_TRACEEXIT event, but the WIFEXITED event will be delayed
-until the entire process exits.  This state exists so that shells
-don't think the process is done until all of the threads have exited.
-Unfortunately, signals cannot be delivered to non-waitable zombies.
-Most notably, SIGSTOP cannot be delivered; as a result, when you
-broadcast SIGSTOP to all of the threads, you must not wait for
-non-waitable zombies to stop.  Furthermore, any ptrace command on a
-non-waitable zombie, including PTRACE_DETACH, will return ESRCH.
-
-== Multi-threaded debuggers ==
-
-If the debugger itself is multi-threaded, ptrace calls must come from
-the same thread that originally attached to the remote thread.  The
-kernel simply compares the PID of the caller of ptrace against the
-tracer PID of the process passed to ptrace.  Because each debugger
-thread has a different PID, calling ptrace from a different thread
-might as well be calling it from a different process and the kernel
-will return ESRCH.
-
-wait, on the other hand, does not have this restriction.  Any debugger
-thread can wait on any thread in the attached process.
diff --git a/src/pkg/debug/proc/regs_darwin_386.go b/src/pkg/debug/proc/regs_darwin_386.go
deleted file mode 100644
index 60c9ac7..0000000
--- a/src/pkg/debug/proc/regs_darwin_386.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/src/pkg/debug/proc/regs_darwin_amd64.go b/src/pkg/debug/proc/regs_darwin_amd64.go
deleted file mode 100644
index 60c9ac7..0000000
--- a/src/pkg/debug/proc/regs_darwin_amd64.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/src/pkg/debug/proc/regs_freebsd_386.go b/src/pkg/debug/proc/regs_freebsd_386.go
deleted file mode 100644
index 60c9ac7..0000000
--- a/src/pkg/debug/proc/regs_freebsd_386.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/src/pkg/debug/proc/regs_freebsd_amd64.go b/src/pkg/debug/proc/regs_freebsd_amd64.go
deleted file mode 100644
index 60c9ac7..0000000
--- a/src/pkg/debug/proc/regs_freebsd_amd64.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/src/pkg/debug/proc/regs_linux_386.go b/src/pkg/debug/proc/regs_linux_386.go
deleted file mode 100644
index b4a9769..0000000
--- a/src/pkg/debug/proc/regs_linux_386.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-import (
-	"os"
-	"strconv"
-	"syscall"
-)
-
-type _386Regs struct {
-	syscall.PtraceRegs
-	setter func(*syscall.PtraceRegs) os.Error
-}
-
-var names = []string{
-	"eax",
-	"ebx",
-	"ecx",
-	"edx",
-	"esi",
-	"edi",
-	"ebp",
-	"esp",
-	"eip",
-	"eflags",
-	"cs",
-	"ss",
-	"ds",
-	"es",
-	"fs",
-	"gs",
-}
-
-func (r *_386Regs) PC() Word { return Word(r.Eip) }
-
-func (r *_386Regs) SetPC(val Word) os.Error {
-	r.Eip = int32(val)
-	return r.setter(&r.PtraceRegs)
-}
-
-func (r *_386Regs) Link() Word {
-	// TODO(austin)
-	panic("No link register")
-}
-
-func (r *_386Regs) SetLink(val Word) os.Error { panic("No link register") }
-
-func (r *_386Regs) SP() Word { return Word(r.Esp) }
-
-func (r *_386Regs) SetSP(val Word) os.Error {
-	r.Esp = int32(val)
-	return r.setter(&r.PtraceRegs)
-}
-
-func (r *_386Regs) Names() []string { return names }
-
-func (r *_386Regs) Get(i int) Word {
-	switch i {
-	case 0:
-		return Word(uint32(r.Eax))
-	case 1:
-		return Word(uint32(r.Ebx))
-	case 2:
-		return Word(uint32(r.Ecx))
-	case 3:
-		return Word(uint32(r.Edx))
-	case 4:
-		return Word(uint32(r.Esi))
-	case 5:
-		return Word(uint32(r.Edi))
-	case 6:
-		return Word(uint32(r.Ebp))
-	case 7:
-		return Word(uint32(r.Esp))
-	case 8:
-		return Word(uint32(r.Eip))
-	case 9:
-		return Word(uint32(r.Eflags))
-	case 10:
-		return Word(r.Xcs)
-	case 11:
-		return Word(r.Xss)
-	case 12:
-		return Word(r.Xds)
-	case 13:
-		return Word(r.Xes)
-	case 14:
-		return Word(r.Xfs)
-	case 15:
-		return Word(r.Xgs)
-	}
-	panic("invalid register index " + strconv.Itoa(i))
-}
-
-func (r *_386Regs) Set(i int, val Word) os.Error {
-	switch i {
-	case 0:
-		r.Eax = int32(val)
-	case 1:
-		r.Ebx = int32(val)
-	case 2:
-		r.Ecx = int32(val)
-	case 3:
-		r.Edx = int32(val)
-	case 4:
-		r.Esi = int32(val)
-	case 5:
-		r.Edi = int32(val)
-	case 6:
-		r.Ebp = int32(val)
-	case 7:
-		r.Esp = int32(val)
-	case 8:
-		r.Eip = int32(val)
-	case 9:
-		r.Eflags = int32(val)
-	case 10:
-		r.Xcs = int32(val)
-	case 11:
-		r.Xss = int32(val)
-	case 12:
-		r.Xds = int32(val)
-	case 13:
-		r.Xes = int32(val)
-	case 14:
-		r.Xfs = int32(val)
-	case 15:
-		r.Xgs = int32(val)
-	default:
-		panic("invalid register index " + strconv.Itoa(i))
-	}
-	return r.setter(&r.PtraceRegs)
-}
-
-func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
-	res := _386Regs{}
-	res.PtraceRegs = *regs
-	res.setter = setter
-	return &res
-}
diff --git a/src/pkg/debug/proc/regs_linux_amd64.go b/src/pkg/debug/proc/regs_linux_amd64.go
deleted file mode 100644
index 381be29..0000000
--- a/src/pkg/debug/proc/regs_linux_amd64.go
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-import (
-	"os"
-	"strconv"
-	"syscall"
-)
-
-type amd64Regs struct {
-	syscall.PtraceRegs
-	setter func(*syscall.PtraceRegs) os.Error
-}
-
-var names = [...]string{
-	"rax",
-	"rbx",
-	"rcx",
-	"rdx",
-	"rsi",
-	"rdi",
-	"rbp",
-	"rsp",
-	"r8",
-	"r9",
-	"r10",
-	"r11",
-	"r12",
-	"r13",
-	"r14",
-	"r15",
-	"rip",
-	"eflags",
-	"cs",
-	"ss",
-	"ds",
-	"es",
-	"fs",
-	"gs",
-
-	// PtraceRegs contains these registers, but I don't think
-	// they're actually meaningful.
-	//"orig_rax",
-	//"fs_base",
-	//"gs_base",
-}
-
-func (r *amd64Regs) PC() Word { return Word(r.Rip) }
-
-func (r *amd64Regs) SetPC(val Word) os.Error {
-	r.Rip = uint64(val)
-	return r.setter(&r.PtraceRegs)
-}
-
-func (r *amd64Regs) Link() Word {
-	// TODO(austin)
-	panic("No link register")
-}
-
-func (r *amd64Regs) SetLink(val Word) os.Error {
-	panic("No link register")
-}
-
-func (r *amd64Regs) SP() Word { return Word(r.Rsp) }
-
-func (r *amd64Regs) SetSP(val Word) os.Error {
-	r.Rsp = uint64(val)
-	return r.setter(&r.PtraceRegs)
-}
-
-func (r *amd64Regs) Names() []string { return names[0:] }
-
-func (r *amd64Regs) Get(i int) Word {
-	switch i {
-	case 0:
-		return Word(r.Rax)
-	case 1:
-		return Word(r.Rbx)
-	case 2:
-		return Word(r.Rcx)
-	case 3:
-		return Word(r.Rdx)
-	case 4:
-		return Word(r.Rsi)
-	case 5:
-		return Word(r.Rdi)
-	case 6:
-		return Word(r.Rbp)
-	case 7:
-		return Word(r.Rsp)
-	case 8:
-		return Word(r.R8)
-	case 9:
-		return Word(r.R9)
-	case 10:
-		return Word(r.R10)
-	case 11:
-		return Word(r.R11)
-	case 12:
-		return Word(r.R12)
-	case 13:
-		return Word(r.R13)
-	case 14:
-		return Word(r.R14)
-	case 15:
-		return Word(r.R15)
-	case 16:
-		return Word(r.Rip)
-	case 17:
-		return Word(r.Eflags)
-	case 18:
-		return Word(r.Cs)
-	case 19:
-		return Word(r.Ss)
-	case 20:
-		return Word(r.Ds)
-	case 21:
-		return Word(r.Es)
-	case 22:
-		return Word(r.Fs)
-	case 23:
-		return Word(r.Gs)
-	}
-	panic("invalid register index " + strconv.Itoa(i))
-}
-
-func (r *amd64Regs) Set(i int, val Word) os.Error {
-	switch i {
-	case 0:
-		r.Rax = uint64(val)
-	case 1:
-		r.Rbx = uint64(val)
-	case 2:
-		r.Rcx = uint64(val)
-	case 3:
-		r.Rdx = uint64(val)
-	case 4:
-		r.Rsi = uint64(val)
-	case 5:
-		r.Rdi = uint64(val)
-	case 6:
-		r.Rbp = uint64(val)
-	case 7:
-		r.Rsp = uint64(val)
-	case 8:
-		r.R8 = uint64(val)
-	case 9:
-		r.R9 = uint64(val)
-	case 10:
-		r.R10 = uint64(val)
-	case 11:
-		r.R11 = uint64(val)
-	case 12:
-		r.R12 = uint64(val)
-	case 13:
-		r.R13 = uint64(val)
-	case 14:
-		r.R14 = uint64(val)
-	case 15:
-		r.R15 = uint64(val)
-	case 16:
-		r.Rip = uint64(val)
-	case 17:
-		r.Eflags = uint64(val)
-	case 18:
-		r.Cs = uint64(val)
-	case 19:
-		r.Ss = uint64(val)
-	case 20:
-		r.Ds = uint64(val)
-	case 21:
-		r.Es = uint64(val)
-	case 22:
-		r.Fs = uint64(val)
-	case 23:
-		r.Gs = uint64(val)
-	default:
-		panic("invalid register index " + strconv.Itoa(i))
-	}
-	return r.setter(&r.PtraceRegs)
-}
-
-func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
-	res := amd64Regs{}
-	res.PtraceRegs = *regs
-	res.setter = setter
-	return &res
-}
diff --git a/src/pkg/debug/proc/regs_linux_arm.go b/src/pkg/debug/proc/regs_linux_arm.go
deleted file mode 100644
index ec78cbc..0000000
--- a/src/pkg/debug/proc/regs_linux_arm.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
-
-import (
-	"os"
-	"syscall"
-)
-
-// TODO(kaib): add support
-
-type armRegs struct{}
-
-func (r *armRegs) PC() Word { return Word(0) }
-
-func (r *armRegs) SetPC(val Word) os.Error { return nil }
-
-func (r *armRegs) Link() Word { return Word(0) }
-
-func (r *armRegs) SetLink(val Word) os.Error { return nil }
-
-func (r *armRegs) SP() Word { return Word(0) }
-
-func (r *armRegs) SetSP(val Word) os.Error { return nil }
-
-func (r *armRegs) Names() []string { return nil }
-
-func (r *armRegs) Get(i int) Word { return Word(0) }
-
-func (r *armRegs) Set(i int, val Word) os.Error {
-	return nil
-}
-
-func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
-	res := armRegs{}
-	return &res
-}
diff --git a/src/pkg/debug/proc/regs_windows_386.go b/src/pkg/debug/proc/regs_windows_386.go
deleted file mode 100644
index 60c9ac7..0000000
--- a/src/pkg/debug/proc/regs_windows_386.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/src/pkg/debug/proc/regs_windows_amd64.go b/src/pkg/debug/proc/regs_windows_amd64.go
deleted file mode 100644
index 60c9ac7..0000000
--- a/src/pkg/debug/proc/regs_windows_amd64.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/src/pkg/ebnf/ebnf.go b/src/pkg/ebnf/ebnf.go
index 661afdd..69da117 100644
--- a/src/pkg/ebnf/ebnf.go
+++ b/src/pkg/ebnf/ebnf.go
@@ -30,7 +30,6 @@ import (
 	"utf8"
 )
 
-
 // ----------------------------------------------------------------------------
 // Internal representation
 
@@ -100,7 +99,6 @@ type (
 	Grammar map[string]*Production
 )
 
-
 func (x Alternative) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Alternative
 func (x Sequence) Pos() token.Pos    { return x[0].Pos() } // the parser always generates non-empty Sequences
 func (x *Name) Pos() token.Pos       { return x.StringPos }
@@ -112,7 +110,6 @@ func (x *Repetition) Pos() token.Pos { return x.Lbrace }
 func (x *Bad) Pos() token.Pos        { return x.TokPos }
 func (x *Production) Pos() token.Pos { return x.Name.Pos() }
 
-
 // ----------------------------------------------------------------------------
 // Grammar verification
 
@@ -121,7 +118,6 @@ func isLexical(name string) bool {
 	return !unicode.IsUpper(ch)
 }
 
-
 type verifier struct {
 	fset *token.FileSet
 	scanner.ErrorVector
@@ -130,12 +126,10 @@ type verifier struct {
 	grammar  Grammar
 }
 
-
 func (v *verifier) error(pos token.Pos, msg string) {
 	v.Error(v.fset.Position(pos), msg)
 }
 
-
 func (v *verifier) push(prod *Production) {
 	name := prod.Name.String
 	if _, found := v.reached[name]; !found {
@@ -144,7 +138,6 @@ func (v *verifier) push(prod *Production) {
 	}
 }
 
-
 func (v *verifier) verifyChar(x *Token) int {
 	s := x.String
 	if utf8.RuneCountInString(s) != 1 {
@@ -155,7 +148,6 @@ func (v *verifier) verifyChar(x *Token) int {
 	return ch
 }
 
-
 func (v *verifier) verifyExpr(expr Expression, lexical bool) {
 	switch x := expr.(type) {
 	case nil:
@@ -200,7 +192,6 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
 	}
 }
 
-
 func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
 	// find root production
 	root, found := grammar[start]
@@ -240,7 +231,6 @@ func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
 	}
 }
 
-
 // Verify checks that:
 //	- all productions used are defined
 //	- all productions defined are used when beginning at start
diff --git a/src/pkg/ebnf/ebnf_test.go b/src/pkg/ebnf/ebnf_test.go
index 3030174..b086fac 100644
--- a/src/pkg/ebnf/ebnf_test.go
+++ b/src/pkg/ebnf/ebnf_test.go
@@ -10,10 +10,8 @@ import (
 	"testing"
 )
 
-
 var fset = token.NewFileSet()
 
-
 var goodGrammars = []string{
 	`Program = .`,
 
@@ -37,7 +35,6 @@ var goodGrammars = []string{
 	 ti = "b" .`,
 }
 
-
 var badGrammars = []string{
 	`Program = | .`,
 	`Program = | b .`,
@@ -49,7 +46,6 @@ var badGrammars = []string{
 	`Program = {} .`,
 }
 
-
 func checkGood(t *testing.T, filename string, src []byte) {
 	grammar, err := Parse(fset, filename, src)
 	if err != nil {
@@ -60,7 +56,6 @@ func checkGood(t *testing.T, filename string, src []byte) {
 	}
 }
 
-
 func checkBad(t *testing.T, filename string, src []byte) {
 	_, err := Parse(fset, filename, src)
 	if err == nil {
@@ -68,7 +63,6 @@ func checkBad(t *testing.T, filename string, src []byte) {
 	}
 }
 
-
 func TestGrammars(t *testing.T) {
 	for _, src := range goodGrammars {
 		checkGood(t, "", []byte(src))
@@ -78,12 +72,10 @@ func TestGrammars(t *testing.T) {
 	}
 }
 
-
 var files = []string{
 // TODO(gri) add some test files
 }
 
-
 func TestFiles(t *testing.T) {
 	for _, filename := range files {
 		src, err := ioutil.ReadFile(filename)
diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go
index ede4f70..ef2fac0 100644
--- a/src/pkg/ebnf/parser.go
+++ b/src/pkg/ebnf/parser.go
@@ -11,7 +11,6 @@ import (
 	"strconv"
 )
 
-
 type parser struct {
 	fset *token.FileSet
 	scanner.ErrorVector
@@ -21,7 +20,6 @@ type parser struct {
 	lit     string      // token literal
 }
 
-
 func (p *parser) next() {
 	p.pos, p.tok, p.lit = p.scanner.Scan()
 	if p.tok.IsKeyword() {
@@ -31,12 +29,10 @@ func (p *parser) next() {
 	}
 }
 
-
 func (p *parser) error(pos token.Pos, msg string) {
 	p.Error(p.fset.Position(pos), msg)
 }
 
-
 func (p *parser) errorExpected(pos token.Pos, msg string) {
 	msg = "expected " + msg
 	if pos == p.pos {
@@ -50,7 +46,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
 	p.error(pos, msg)
 }
 
-
 func (p *parser) expect(tok token.Token) token.Pos {
 	pos := p.pos
 	if p.tok != tok {
@@ -60,7 +55,6 @@ func (p *parser) expect(tok token.Token) token.Pos {
 	return pos
 }
 
-
 func (p *parser) parseIdentifier() *Name {
 	pos := p.pos
 	name := p.lit
@@ -68,7 +62,6 @@ func (p *parser) parseIdentifier() *Name {
 	return &Name{pos, name}
 }
 
-
 func (p *parser) parseToken() *Token {
 	pos := p.pos
 	value := ""
@@ -84,7 +77,6 @@ func (p *parser) parseToken() *Token {
 	return &Token{pos, value}
 }
 
-
 // ParseTerm returns nil if no term was found.
 func (p *parser) parseTerm() (x Expression) {
 	pos := p.pos
@@ -121,7 +113,6 @@ func (p *parser) parseTerm() (x Expression) {
 	return x
 }
 
-
 func (p *parser) parseSequence() Expression {
 	var list Sequence
 
@@ -141,7 +132,6 @@ func (p *parser) parseSequence() Expression {
 	return list
 }
 
-
 func (p *parser) parseExpression() Expression {
 	var list Alternative
 
@@ -162,7 +152,6 @@ func (p *parser) parseExpression() Expression {
 	return list
 }
 
-
 func (p *parser) parseProduction() *Production {
 	name := p.parseIdentifier()
 	p.expect(token.ASSIGN)
@@ -174,7 +163,6 @@ func (p *parser) parseProduction() *Production {
 	return &Production{name, expr}
 }
 
-
 func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar {
 	// initialize parser
 	p.fset = fset
@@ -196,7 +184,6 @@ func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar
 	return grammar
 }
 
-
 // Parse parses a set of EBNF productions from source src.
 // It returns a set of productions. Errors are reported
 // for incorrect syntax and if a production is declared
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
index 792e4dc..3fa1c2b 100644
--- a/src/pkg/encoding/base32/base32_test.go
+++ b/src/pkg/encoding/base32/base32_test.go
@@ -25,7 +25,6 @@ var pairs = []testpair{
 	{"fooba", "MZXW6YTB"},
 	{"foobar", "MZXW6YTBOI======"},
 
-
 	// Wikipedia examples, converted to base32
 	{"sure.", "ON2XEZJO"},
 	{"sure", "ON2XEZI="},
diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
index 47cdedd..e7ea8b0 100644
--- a/src/pkg/encoding/hex/hex.go
+++ b/src/pkg/encoding/hex/hex.go
@@ -42,7 +42,6 @@ func (e InvalidHexCharError) String() string {
 	return "invalid hex char: " + strconv.Itoa(int(e))
 }
 
-
 func DecodedLen(x int) int { return x / 2 }
 
 // Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go
index ebe57ed..12689b5 100644
--- a/src/pkg/encoding/pem/pem.go
+++ b/src/pkg/encoding/pem/pem.go
@@ -97,7 +97,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
 
 	for {
 		// This loop terminates because getLine's second result is
-		// always smaller than it's argument.
+		// always smaller than its argument.
 		if len(rest) == 0 {
 			return nil, data
 		}
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
index 5b988d5..3b20f20 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/exec/exec.go
@@ -332,13 +332,14 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
 	}
 	c.Stdin = pr
 	c.closeAfterStart = append(c.closeAfterStart, pr)
-	c.closeAfterWait = append(c.closeAfterStart, pw)
+	c.closeAfterWait = append(c.closeAfterWait, pw)
 	return pw, nil
 }
 
 // StdoutPipe returns a pipe that will be connected to the command's
 // standard output when the command starts.
-func (c *Cmd) StdoutPipe() (io.Reader, os.Error) {
+// The pipe will be closed automatically after Wait sees the command exit.
+func (c *Cmd) StdoutPipe() (io.ReadCloser, os.Error) {
 	if c.Stdout != nil {
 		return nil, os.NewError("exec: Stdout already set")
 	}
@@ -351,13 +352,14 @@ func (c *Cmd) StdoutPipe() (io.Reader, os.Error) {
 	}
 	c.Stdout = pw
 	c.closeAfterStart = append(c.closeAfterStart, pw)
-	c.closeAfterWait = append(c.closeAfterStart, pr)
+	c.closeAfterWait = append(c.closeAfterWait, pr)
 	return pr, nil
 }
 
 // StderrPipe returns a pipe that will be connected to the command's
 // standard error when the command starts.
-func (c *Cmd) StderrPipe() (io.Reader, os.Error) {
+// The pipe will be closed automatically after Wait sees the command exit.
+func (c *Cmd) StderrPipe() (io.ReadCloser, os.Error) {
 	if c.Stderr != nil {
 		return nil, os.NewError("exec: Stderr already set")
 	}
@@ -370,6 +372,6 @@ func (c *Cmd) StderrPipe() (io.Reader, os.Error) {
 	}
 	c.Stderr = pw
 	c.closeAfterStart = append(c.closeAfterStart, pw)
-	c.closeAfterWait = append(c.closeAfterStart, pr)
+	c.closeAfterWait = append(c.closeAfterWait, pr)
 	return pr, nil
 }
diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go
index f6cebb9..242120f 100644
--- a/src/pkg/exec/exec_test.go
+++ b/src/pkg/exec/exec_test.go
@@ -68,7 +68,6 @@ func TestCatGoodAndBadFile(t *testing.T) {
 	}
 }
 
-
 func TestNoExistBinary(t *testing.T) {
 	// Can't run a non-existent binary
 	err := Command("/no-exist-binary").Run()
diff --git a/src/pkg/exp/datafmt/datafmt.go b/src/pkg/exp/datafmt/datafmt.go
index 10e4b54..6d7e764 100644
--- a/src/pkg/exp/datafmt/datafmt.go
+++ b/src/pkg/exp/datafmt/datafmt.go
@@ -211,7 +211,6 @@ import (
 	"runtime"
 )
 
-
 // ----------------------------------------------------------------------------
 // Format representation
 
@@ -228,13 +227,11 @@ import (
 //
 type Formatter func(state *State, value interface{}, ruleName string) bool
 
-
 // A FormatterMap is a set of custom formatters.
 // It maps a rule name to a formatter function.
 //
 type FormatterMap map[string]Formatter
 
-
 // A parsed format expression is built from the following nodes.
 //
 type (
@@ -269,13 +266,11 @@ type (
 	}
 )
 
-
 // A Format is the result of parsing a format specification.
 // The format may be applied repeatedly to format values.
 //
 type Format map[string]expr
 
-
 // ----------------------------------------------------------------------------
 // Formatting
 
@@ -293,7 +288,6 @@ type Environment interface {
 	Copy() Environment
 }
 
-
 // State represents the current formatting state.
 // It is provided as argument to custom formatters.
 //
@@ -309,7 +303,6 @@ type State struct {
 	separator expr           // possibly nil
 }
 
-
 func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	s := new(State)
 	s.fmt = fmt
@@ -317,12 +310,12 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	s.errors = errors
 	s.linePos = token.Position{Line: 1}
 
-	// if we have a default rule, cache it's expression for fast access
+	// if we have a default rule, cache its expression for fast access
 	if x, found := fmt["default"]; found {
 		s.default_ = x
 	}
 
-	// if we have a global separator rule, cache it's expression for fast access
+	// if we have a global separator rule, cache its expression for fast access
 	if x, found := fmt["/"]; found {
 		s.separator = x
 	}
@@ -330,17 +323,14 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State {
 	return s
 }
 
-
 // Env returns the environment passed to Format.Apply.
 func (s *State) Env() interface{} { return s.env }
 
-
 // LinePos returns the position of the current line beginning
 // in the state's output buffer. Line numbers start at 1.
 //
 func (s *State) LinePos() token.Position { return s.linePos }
 
-
 // Pos returns the position of the next byte to be written to the
 // output buffer. Line numbers start at 1.
 //
@@ -349,7 +339,6 @@ func (s *State) Pos() token.Position {
 	return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
 }
 
-
 // Write writes data to the output buffer, inserting the indentation
 // string after each newline or form feed character. It cannot return an error.
 //
@@ -371,7 +360,6 @@ func (s *State) Write(data []byte) (int, os.Error) {
 	return n + n3, nil
 }
 
-
 type checkpoint struct {
 	env       Environment
 	hasOutput bool
@@ -379,7 +367,6 @@ type checkpoint struct {
 	linePos   token.Position
 }
 
-
 func (s *State) save() checkpoint {
 	saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
 	if s.env != nil {
@@ -388,19 +375,16 @@ func (s *State) save() checkpoint {
 	return saved
 }
 
-
 func (s *State) restore(m checkpoint) {
 	s.env = m.env
 	s.output.Truncate(m.outputLen)
 }
 
-
 func (s *State) error(msg string) {
 	s.errors <- os.NewError(msg)
 	runtime.Goexit()
 }
 
-
 // TODO At the moment, unnamed types are simply mapped to the default
 //      names below. For instance, all unnamed arrays are mapped to
 //      'array' which is not really sufficient. Eventually one may want
@@ -440,7 +424,6 @@ func (s *State) getFormat(name string) expr {
 	return nil
 }
 
-
 // eval applies a format expression fexpr to a value. If the expression
 // evaluates internally to a non-nil []byte, that slice is appended to
 // the state's output buffer and eval returns true. Otherwise, eval
@@ -653,7 +636,6 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
 	return false
 }
 
-
 // Eval formats each argument according to the format
 // f and returns the resulting []byte and os.Error. If
 // an error occurred, the []byte contains the partially
@@ -688,7 +670,6 @@ func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
 	return s.output.Bytes(), err
 }
 
-
 // ----------------------------------------------------------------------------
 // Convenience functions
 
@@ -705,7 +686,6 @@ func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int,
 	return w.Write(data)
 }
 
-
 // Print formats each argument according to the format f
 // and writes to standard output. The result is the total
 // number of bytes written and an os.Error, if any.
@@ -714,7 +694,6 @@ func (f Format) Print(args ...interface{}) (int, os.Error) {
 	return f.Fprint(os.Stdout, nil, args...)
 }
 
-
 // Sprint formats each argument according to the format f
 // and returns the resulting string. If an error occurs
 // during formatting, the result string contains the
diff --git a/src/pkg/exp/datafmt/datafmt_test.go b/src/pkg/exp/datafmt/datafmt_test.go
index d7c70b2..87d0716 100644
--- a/src/pkg/exp/datafmt/datafmt_test.go
+++ b/src/pkg/exp/datafmt/datafmt_test.go
@@ -10,10 +10,8 @@ import (
 	"go/token"
 )
 
-
 var fset = token.NewFileSet()
 
-
 func parse(t *testing.T, form string, fmap FormatterMap) Format {
 	f, err := Parse(fset, "", []byte(form), fmap)
 	if err != nil {
@@ -23,7 +21,6 @@ func parse(t *testing.T, form string, fmap FormatterMap) Format {
 	return f
 }
 
-
 func verify(t *testing.T, f Format, expected string, args ...interface{}) {
 	if f == nil {
 		return // allow other tests to run
@@ -36,7 +33,6 @@ func verify(t *testing.T, f Format, expected string, args ...interface{}) {
 	}
 }
 
-
 func formatter(s *State, value interface{}, rule_name string) bool {
 	switch rule_name {
 	case "/":
@@ -62,7 +58,6 @@ func formatter(s *State, value interface{}, rule_name string) bool {
 	return false
 }
 
-
 func TestCustomFormatters(t *testing.T) {
 	fmap0 := FormatterMap{"/": formatter}
 	fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter}
@@ -92,7 +87,6 @@ func TestCustomFormatters(t *testing.T) {
 	// TODO needs more tests
 }
 
-
 // ----------------------------------------------------------------------------
 // Formatting of basic and simple composite types
 
@@ -109,7 +103,6 @@ func check(t *testing.T, form, expected string, args ...interface{}) {
 	}
 }
 
-
 func TestBasicTypes(t *testing.T) {
 	check(t, ``, ``)
 	check(t, `bool=":%v"`, `:true:false`, true, false)
@@ -144,7 +137,6 @@ func TestBasicTypes(t *testing.T) {
 	check(t, `float64="%g"`, fs, float64(f))
 }
 
-
 func TestArrayTypes(t *testing.T) {
 	var a0 [10]int
 	check(t, `array="array";`, `array`, a0)
@@ -159,7 +151,6 @@ func TestArrayTypes(t *testing.T) {
 	check(t, `array={* / ", "}; interface=*; string="bar"; default="%v";`, `42, bar, 3.14`, a2)
 }
 
-
 func TestChanTypes(t *testing.T) {
 	var c0 chan int
 	check(t, `chan="chan"`, `chan`, c0)
@@ -170,7 +161,6 @@ func TestChanTypes(t *testing.T) {
 	// check(t, `chan=*`, `42`, c1);  // reflection support for chans incomplete
 }
 
-
 func TestFuncTypes(t *testing.T) {
 	var f0 func() int
 	check(t, `func="func"`, `func`, f0)
@@ -180,7 +170,6 @@ func TestFuncTypes(t *testing.T) {
 	// check(t, `func=*`, `42`, f1);  // reflection support for funcs incomplete
 }
 
-
 func TestMapTypes(t *testing.T) {
 	var m0 map[string]int
 	check(t, `map="map"`, `map`, m0)
@@ -190,7 +179,6 @@ func TestMapTypes(t *testing.T) {
 	// check(t, `map=*`, ``, m1);  // reflection support for maps incomplete
 }
 
-
 func TestPointerTypes(t *testing.T) {
 	var p0 *int
 	check(t, `ptr="ptr"`, `ptr`, p0)
@@ -203,7 +191,6 @@ func TestPointerTypes(t *testing.T) {
 	check(t, `ptr=*; int="%d"`, `99991`, p1)
 }
 
-
 func TestDefaultRule(t *testing.T) {
 	check(t, `default="%v"`, `42foo3.14`, 42, "foo", 3.14)
 	check(t, `default="%v"; int="%x"`, `abcdef`, 10, 11, 12, 13, 14, 15)
@@ -211,13 +198,11 @@ func TestDefaultRule(t *testing.T) {
 	check(t, `default="%x"; int=@:default`, `abcdef`, 10, 11, 12, 13, 14, 15)
 }
 
-
 func TestGlobalSeparatorRule(t *testing.T) {
 	check(t, `int="%d"; / ="-"`, `1-2-3-4`, 1, 2, 3, 4)
 	check(t, `int="%x%x"; / ="*"`, `aa*aa`, 10, 10)
 }
 
-
 // ----------------------------------------------------------------------------
 // Formatting of a struct
 
@@ -231,7 +216,6 @@ const F1 = `datafmt "datafmt";` +
 
 func TestStruct1(t *testing.T) { check(t, F1, "<42>", T1{42}) }
 
-
 // ----------------------------------------------------------------------------
 // Formatting of a struct with an optional field (ptr)
 
@@ -256,7 +240,6 @@ func TestStruct2(t *testing.T) {
 	check(t, F2b, "fooempty", T2{"foo", nil})
 }
 
-
 // ----------------------------------------------------------------------------
 // Formatting of a struct with a repetitive field (slice)
 
@@ -285,7 +268,6 @@ func TestStruct3(t *testing.T) {
 	check(t, F3b, "bal: 2-3-5", T3{"bal", []int{2, 3, 5}})
 }
 
-
 // ----------------------------------------------------------------------------
 // Formatting of a struct with alternative field
 
@@ -318,7 +300,6 @@ func TestStruct4(t *testing.T) {
 	check(t, F4b, "<2, 3, 7>", T4{nil, []int{2, 3, 7}})
 }
 
-
 // ----------------------------------------------------------------------------
 // Formatting a struct (documentation example)
 
@@ -338,7 +319,6 @@ func TestStructPoint(t *testing.T) {
 	check(t, FPoint, "---foo---{3, 0xf}", p)
 }
 
-
 // ----------------------------------------------------------------------------
 // Formatting a slice (documentation example)
 
@@ -347,5 +327,4 @@ const FSlice = `int = "%b";` +
 
 func TestSlice(t *testing.T) { check(t, FSlice, "10, 11, 101, 111", []int{2, 3, 5, 7}) }
 
-
 // TODO add more tests
diff --git a/src/pkg/exp/datafmt/parser.go b/src/pkg/exp/datafmt/parser.go
index 7dedb53..45d7d50 100644
--- a/src/pkg/exp/datafmt/parser.go
+++ b/src/pkg/exp/datafmt/parser.go
@@ -28,7 +28,6 @@ type parser struct {
 	rules map[string]expr   // RuleName -> Expression
 }
 
-
 func (p *parser) next() {
 	p.pos, p.tok, p.lit = p.scanner.Scan()
 	switch p.tok {
@@ -39,7 +38,6 @@ func (p *parser) next() {
 	}
 }
 
-
 func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
 	p.ErrorVector.Reset()
 	p.file = fset.AddFile(filename, fset.Base(), len(src))
@@ -49,12 +47,10 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
 	p.rules = make(map[string]expr)
 }
 
-
 func (p *parser) error(pos token.Pos, msg string) {
 	p.Error(p.file.Position(pos), msg)
 }
 
-
 func (p *parser) errorExpected(pos token.Pos, msg string) {
 	msg = "expected " + msg
 	if pos == p.pos {
@@ -68,7 +64,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
 	p.error(pos, msg)
 }
 
-
 func (p *parser) expect(tok token.Token) token.Pos {
 	pos := p.pos
 	if p.tok != tok {
@@ -78,14 +73,12 @@ func (p *parser) expect(tok token.Token) token.Pos {
 	return pos
 }
 
-
 func (p *parser) parseIdentifier() string {
 	name := p.lit
 	p.expect(token.IDENT)
 	return name
 }
 
-
 func (p *parser) parseTypeName() (string, bool) {
 	pos := p.pos
 	name, isIdent := p.parseIdentifier(), true
@@ -102,7 +95,6 @@ func (p *parser) parseTypeName() (string, bool) {
 	return name, isIdent
 }
 
-
 // Parses a rule name and returns it. If the rule name is
 // a package-qualified type name, the package name is resolved.
 // The 2nd result value is true iff the rule name consists of a
@@ -126,7 +118,6 @@ func (p *parser) parseRuleName() (string, bool) {
 	return name, isIdent
 }
 
-
 func (p *parser) parseString() string {
 	s := ""
 	if p.tok == token.STRING {
@@ -142,7 +133,6 @@ func (p *parser) parseString() string {
 	return s
 }
 
-
 func (p *parser) parseLiteral() literal {
 	s := []byte(p.parseString())
 
@@ -176,7 +166,6 @@ func (p *parser) parseLiteral() literal {
 	return lit
 }
 
-
 func (p *parser) parseField() expr {
 	var fname string
 	switch p.tok {
@@ -204,7 +193,6 @@ func (p *parser) parseField() expr {
 	return &field{fname, ruleName}
 }
 
-
 func (p *parser) parseOperand() (x expr) {
 	switch p.tok {
 	case token.STRING:
@@ -242,7 +230,6 @@ func (p *parser) parseOperand() (x expr) {
 	return x
 }
 
-
 func (p *parser) parseSequence() expr {
 	var list vector.Vector
 
@@ -266,7 +253,6 @@ func (p *parser) parseSequence() expr {
 	return seq
 }
 
-
 func (p *parser) parseExpression() expr {
 	var list vector.Vector
 
@@ -297,7 +283,6 @@ func (p *parser) parseExpression() expr {
 	return alt
 }
 
-
 func (p *parser) parseFormat() {
 	for p.tok != token.EOF {
 		pos := p.pos
@@ -343,7 +328,6 @@ func (p *parser) parseFormat() {
 	p.expect(token.EOF)
 }
 
-
 func remap(p *parser, name string) string {
 	i := strings.Index(name, ".")
 	if i >= 0 {
@@ -359,7 +343,6 @@ func remap(p *parser, name string) string {
 	return name
 }
 
-
 // Parse parses a set of format productions from source src. Custom
 // formatters may be provided via a map of formatter functions. If
 // there are no errors, the result is a Format and the error is nil.
diff --git a/src/pkg/exp/eval/Makefile b/src/pkg/exp/eval/Makefile
deleted file mode 100644
index 872316c..0000000
--- a/src/pkg/exp/eval/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=exp/eval
-GOFILES=\
-	abort.go\
-	bridge.go\
-	compiler.go\
-	expr.go\
-	expr1.go\
-	func.go\
-	scope.go\
-	stmt.go\
-	type.go\
-	typec.go\
-	value.go\
-	world.go\
-
-include ../../../Make.pkg
-
-main.$O: main.go $(pkgdir)/$(TARG).a
-	$(GC) $<
-
-eval: main.$O
-	$(LD) -o $@ $<
-
-gen.$O: gen.go
-	$(GC) $<
-
-generate: gen.$O
-	$(LD) -o $@ $<;\
-	./generate > expr1.go;\
-	gofmt -w expr1.go
-
diff --git a/src/pkg/exp/eval/abort.go b/src/pkg/exp/eval/abort.go
deleted file mode 100644
index 22e17ce..0000000
--- a/src/pkg/exp/eval/abort.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"fmt"
-	"os"
-	"runtime"
-)
-
-// Abort aborts the thread's current computation,
-// causing the innermost Try to return err.
-func (t *Thread) Abort(err os.Error) {
-	if t.abort == nil {
-		panic("abort: " + err.String())
-	}
-	t.abort <- err
-	runtime.Goexit()
-}
-
-// Try executes a computation; if the computation
-// Aborts, Try returns the error passed to abort.
-func (t *Thread) Try(f func(t *Thread)) os.Error {
-	oc := t.abort
-	c := make(chan os.Error)
-	t.abort = c
-	go func() {
-		f(t)
-		c <- nil
-	}()
-	err := <-c
-	t.abort = oc
-	return err
-}
-
-type DivByZeroError struct{}
-
-func (DivByZeroError) String() string { return "divide by zero" }
-
-type NilPointerError struct{}
-
-func (NilPointerError) String() string { return "nil pointer dereference" }
-
-type IndexError struct {
-	Idx, Len int64
-}
-
-func (e IndexError) String() string {
-	if e.Idx < 0 {
-		return fmt.Sprintf("negative index: %d", e.Idx)
-	}
-	return fmt.Sprintf("index %d exceeds length %d", e.Idx, e.Len)
-}
-
-type SliceError struct {
-	Lo, Hi, Cap int64
-}
-
-func (e SliceError) String() string {
-	return fmt.Sprintf("slice [%d:%d]; cap %d", e.Lo, e.Hi, e.Cap)
-}
-
-type KeyError struct {
-	Key interface{}
-}
-
-func (e KeyError) String() string { return fmt.Sprintf("key '%v' not found in map", e.Key) }
-
-type NegativeLengthError struct {
-	Len int64
-}
-
-func (e NegativeLengthError) String() string {
-	return fmt.Sprintf("negative length: %d", e.Len)
-}
-
-type NegativeCapacityError struct {
-	Len int64
-}
-
-func (e NegativeCapacityError) String() string {
-	return fmt.Sprintf("negative capacity: %d", e.Len)
-}
diff --git a/src/pkg/exp/eval/bridge.go b/src/pkg/exp/eval/bridge.go
deleted file mode 100644
index f31d9ab..0000000
--- a/src/pkg/exp/eval/bridge.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"log"
-	"go/token"
-	"reflect"
-)
-
-/*
- * Type bridging
- */
-
-var (
-	evalTypes   = make(map[reflect.Type]Type)
-	nativeTypes = make(map[Type]reflect.Type)
-)
-
-// TypeFromNative converts a regular Go type into a the corresponding
-// interpreter Type.
-func TypeFromNative(t reflect.Type) Type {
-	if et, ok := evalTypes[t]; ok {
-		return et
-	}
-
-	var nt *NamedType
-	if t.Name() != "" {
-		name := t.PkgPath() + "·" + t.Name()
-		nt = &NamedType{token.NoPos, name, nil, true, make(map[string]Method)}
-		evalTypes[t] = nt
-	}
-
-	var et Type
-	switch t.Kind() {
-	case reflect.Bool:
-		et = BoolType
-
-	case reflect.Float32:
-		et = Float32Type
-	case reflect.Float64:
-		et = Float64Type
-
-	case reflect.Int16:
-		et = Int16Type
-	case reflect.Int32:
-		et = Int32Type
-	case reflect.Int64:
-		et = Int64Type
-	case reflect.Int8:
-		et = Int8Type
-	case reflect.Int:
-		et = IntType
-
-	case reflect.Uint16:
-		et = Uint16Type
-	case reflect.Uint32:
-		et = Uint32Type
-	case reflect.Uint64:
-		et = Uint64Type
-	case reflect.Uint8:
-		et = Uint8Type
-	case reflect.Uint:
-		et = UintType
-	case reflect.Uintptr:
-		et = UintptrType
-
-	case reflect.String:
-		et = StringType
-	case reflect.Array:
-		et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()))
-	case reflect.Chan:
-		log.Panicf("%T not implemented", t)
-	case reflect.Func:
-		nin := t.NumIn()
-		// Variadic functions have DotDotDotType at the end
-		variadic := t.IsVariadic()
-		if variadic {
-			nin--
-		}
-		in := make([]Type, nin)
-		for i := range in {
-			in[i] = TypeFromNative(t.In(i))
-		}
-		out := make([]Type, t.NumOut())
-		for i := range out {
-			out[i] = TypeFromNative(t.Out(i))
-		}
-		et = NewFuncType(in, variadic, out)
-	case reflect.Interface:
-		log.Panicf("%T not implemented", t)
-	case reflect.Map:
-		log.Panicf("%T not implemented", t)
-	case reflect.Ptr:
-		et = NewPtrType(TypeFromNative(t.Elem()))
-	case reflect.Slice:
-		et = NewSliceType(TypeFromNative(t.Elem()))
-	case reflect.Struct:
-		n := t.NumField()
-		fields := make([]StructField, n)
-		for i := 0; i < n; i++ {
-			sf := t.Field(i)
-			// TODO(austin) What to do about private fields?
-			fields[i].Name = sf.Name
-			fields[i].Type = TypeFromNative(sf.Type)
-			fields[i].Anonymous = sf.Anonymous
-		}
-		et = NewStructType(fields)
-	case reflect.UnsafePointer:
-		log.Panicf("%T not implemented", t)
-	default:
-		log.Panicf("unexpected reflect.Type: %T", t)
-	}
-
-	if nt != nil {
-		if _, ok := et.(*NamedType); !ok {
-			nt.Complete(et)
-			et = nt
-		}
-	}
-
-	nativeTypes[et] = t
-	evalTypes[t] = et
-
-	return et
-}
-
-// TypeOfNative returns the interpreter Type of a regular Go value.
-func TypeOfNative(v interface{}) Type { return TypeFromNative(reflect.TypeOf(v)) }
-
-/*
- * Function bridging
- */
-
-type nativeFunc struct {
-	fn      func(*Thread, []Value, []Value)
-	in, out int
-}
-
-func (f *nativeFunc) NewFrame() *Frame {
-	vars := make([]Value, f.in+f.out)
-	return &Frame{nil, vars}
-}
-
-func (f *nativeFunc) Call(t *Thread) { f.fn(t, t.f.Vars[0:f.in], t.f.Vars[f.in:f.in+f.out]) }
-
-// FuncFromNative creates an interpreter function from a native
-// function that takes its in and out arguments as slices of
-// interpreter Value's.  While somewhat inconvenient, this avoids
-// value marshalling.
-func FuncFromNative(fn func(*Thread, []Value, []Value), t *FuncType) FuncValue {
-	return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}}
-}
-
-// FuncFromNativeTyped is like FuncFromNative, but constructs the
-// function type from a function pointer using reflection.  Typically,
-// the type will be given as a nil pointer to a function with the
-// desired signature.
-func FuncFromNativeTyped(fn func(*Thread, []Value, []Value), t interface{}) (*FuncType, FuncValue) {
-	ft := TypeOfNative(t).(*FuncType)
-	return ft, FuncFromNative(fn, ft)
-}
diff --git a/src/pkg/exp/eval/compiler.go b/src/pkg/exp/eval/compiler.go
deleted file mode 100644
index 9d2923b..0000000
--- a/src/pkg/exp/eval/compiler.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"fmt"
-	"go/scanner"
-	"go/token"
-)
-
-
-// A compiler captures information used throughout an entire
-// compilation.  Currently it includes only the error handler.
-//
-// TODO(austin) This might actually represent package level, in which
-// case it should be package compiler.
-type compiler struct {
-	fset         *token.FileSet
-	errors       scanner.ErrorHandler
-	numErrors    int
-	silentErrors int
-}
-
-func (a *compiler) diagAt(pos token.Pos, format string, args ...interface{}) {
-	a.errors.Error(a.fset.Position(pos), fmt.Sprintf(format, args...))
-	a.numErrors++
-}
-
-func (a *compiler) numError() int { return a.numErrors + a.silentErrors }
-
-// The universal scope
-func newUniverse() *Scope {
-	sc := &Scope{nil, 0}
-	sc.block = &block{
-		offset: 0,
-		scope:  sc,
-		global: true,
-		defs:   make(map[string]Def),
-	}
-	return sc
-}
-
-var universe *Scope = newUniverse()
-
-
-// TODO(austin) These can all go in stmt.go now
-type label struct {
-	name string
-	desc string
-	// The PC goto statements should jump to, or nil if this label
-	// cannot be goto'd (such as an anonymous for loop label).
-	gotoPC *uint
-	// The PC break statements should jump to, or nil if a break
-	// statement is invalid.
-	breakPC *uint
-	// The PC continue statements should jump to, or nil if a
-	// continue statement is invalid.
-	continuePC *uint
-	// The position where this label was resolved.  If it has not
-	// been resolved yet, an invalid position.
-	resolved token.Pos
-	// The position where this label was first jumped to.
-	used token.Pos
-}
-
-// A funcCompiler captures information used throughout the compilation
-// of a single function body.
-type funcCompiler struct {
-	*compiler
-	fnType *FuncType
-	// Whether the out variables are named.  This affects what
-	// kinds of return statements are legal.
-	outVarsNamed bool
-	*codeBuf
-	flow   *flowBuf
-	labels map[string]*label
-}
-
-// A blockCompiler captures information used throughout the compilation
-// of a single block within a function.
-type blockCompiler struct {
-	*funcCompiler
-	block *block
-	// The label of this block, used for finding break and
-	// continue labels.
-	label *label
-	// The blockCompiler for the block enclosing this one, or nil
-	// for a function-level block.
-	parent *blockCompiler
-}
diff --git a/src/pkg/exp/eval/eval b/src/pkg/exp/eval/eval
deleted file mode 100755
index 20231f2..0000000
Binary files a/src/pkg/exp/eval/eval and /dev/null differ
diff --git a/src/pkg/exp/eval/eval_test.go b/src/pkg/exp/eval/eval_test.go
deleted file mode 100644
index 541d3fe..0000000
--- a/src/pkg/exp/eval/eval_test.go
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"big"
-	"flag"
-	"fmt"
-	"go/token"
-	"log"
-	"os"
-	"reflect"
-	"regexp"
-	"testing"
-)
-
-// All tests are done using the same file set.
-var fset = token.NewFileSet()
-
-// Print each statement or expression before parsing it
-var noisy = false
-
-func init() { flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests") }
-
-/*
- * Generic statement/expression test framework
- */
-
-type test []job
-
-type job struct {
-	code  string
-	cerr  string
-	rterr string
-	val   Value
-	noval bool
-}
-
-func runTests(t *testing.T, baseName string, tests []test) {
-	delta := 1
-	if testing.Short() {
-		delta = 16
-	}
-	for i := 0; i < len(tests); i += delta {
-		name := fmt.Sprintf("%s[%d]", baseName, i)
-		tests[i].run(t, name)
-	}
-}
-
-func (a test) run(t *testing.T, name string) {
-	w := newTestWorld()
-	for _, j := range a {
-		src := j.code + ";" // trailing semicolon to finish statement
-		if noisy {
-			println("code:", src)
-		}
-
-		code, err := w.Compile(fset, src)
-		if err != nil {
-			if j.cerr == "" {
-				t.Errorf("%s: Compile %s: %v", name, src, err)
-				break
-			}
-			if !match(t, err, j.cerr) {
-				t.Errorf("%s: Compile %s = error %s; want %v", name, src, err, j.cerr)
-				break
-			}
-			continue
-		}
-		if j.cerr != "" {
-			t.Errorf("%s: Compile %s succeeded; want %s", name, src, j.cerr)
-			break
-		}
-
-		val, err := code.Run()
-		if err != nil {
-			if j.rterr == "" {
-				t.Errorf("%s: Run %s: %v", name, src, err)
-				break
-			}
-			if !match(t, err, j.rterr) {
-				t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr)
-				break
-			}
-			continue
-		}
-		if j.rterr != "" {
-			t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr)
-			break
-		}
-
-		if !j.noval && !reflect.DeepEqual(val, j.val) {
-			t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val)
-		}
-	}
-}
-
-func match(t *testing.T, err os.Error, pat string) bool {
-	ok, err1 := regexp.MatchString(pat, err.String())
-	if err1 != nil {
-		t.Fatalf("compile regexp %s: %v", pat, err1)
-	}
-	return ok
-}
-
-
-/*
- * Test constructors
- */
-
-// Expression compile error
-func CErr(expr string, cerr string) test { return test([]job{{code: expr, cerr: cerr}}) }
-
-// Expression runtime error
-func RErr(expr string, rterr string) test { return test([]job{{code: expr, rterr: rterr}}) }
-
-// Expression value
-func Val(expr string, val interface{}) test {
-	return test([]job{{code: expr, val: toValue(val)}})
-}
-
-// Statement runs without error
-func Run(stmts string) test { return test([]job{{code: stmts, noval: true}}) }
-
-// Two statements without error.
-// TODO(rsc): Should be possible with Run but the parser
-// won't let us do both top-level and non-top-level statements.
-func Run2(stmt1, stmt2 string) test {
-	return test([]job{{code: stmt1, noval: true}, {code: stmt2, noval: true}})
-}
-
-// Statement runs and test one expression's value
-func Val1(stmts string, expr1 string, val1 interface{}) test {
-	return test([]job{
-		{code: stmts, noval: true},
-		{code: expr1, val: toValue(val1)},
-	})
-}
-
-// Statement runs and test two expressions' values
-func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
-	return test([]job{
-		{code: stmts, noval: true},
-		{code: expr1, val: toValue(val1)},
-		{code: expr2, val: toValue(val2)},
-	})
-}
-
-/*
- * Value constructors
- */
-
-type vstruct []interface{}
-
-type varray []interface{}
-
-type vslice struct {
-	arr      varray
-	len, cap int
-}
-
-func toValue(val interface{}) Value {
-	switch val := val.(type) {
-	case bool:
-		r := boolV(val)
-		return &r
-	case uint8:
-		r := uint8V(val)
-		return &r
-	case uint:
-		r := uintV(val)
-		return &r
-	case int:
-		r := intV(val)
-		return &r
-	case *big.Int:
-		return &idealIntV{val}
-	case float64:
-		r := float64V(val)
-		return &r
-	case *big.Rat:
-		return &idealFloatV{val}
-	case string:
-		r := stringV(val)
-		return &r
-	case vstruct:
-		elems := make([]Value, len(val))
-		for i, e := range val {
-			elems[i] = toValue(e)
-		}
-		r := structV(elems)
-		return &r
-	case varray:
-		elems := make([]Value, len(val))
-		for i, e := range val {
-			elems[i] = toValue(e)
-		}
-		r := arrayV(elems)
-		return &r
-	case vslice:
-		return &sliceV{Slice{toValue(val.arr).(ArrayValue), int64(val.len), int64(val.cap)}}
-	case Func:
-		return &funcV{val}
-	}
-	log.Panicf("toValue(%T) not implemented", val)
-	panic("unreachable")
-}
-
-/*
- * Default test scope
- */
-
-type testFunc struct{}
-
-func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
-
-func (*testFunc) Call(t *Thread) {
-	n := t.f.Vars[0].(IntValue).Get(t)
-
-	res := n + 1
-
-	t.f.Vars[1].(IntValue).Set(t, res)
-}
-
-type oneTwoFunc struct{}
-
-func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
-
-func (*oneTwoFunc) Call(t *Thread) {
-	t.f.Vars[0].(IntValue).Set(t, 1)
-	t.f.Vars[1].(IntValue).Set(t, 2)
-}
-
-type voidFunc struct{}
-
-func (*voidFunc) NewFrame() *Frame { return &Frame{nil, []Value{}} }
-
-func (*voidFunc) Call(t *Thread) {}
-
-func newTestWorld() *World {
-	w := NewWorld()
-
-	def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) }
-
-	w.DefineConst("c", IdealIntType, toValue(big.NewInt(1)))
-	def("i", IntType, 1)
-	def("i2", IntType, 2)
-	def("u", UintType, uint(1))
-	def("f", Float64Type, 1.0)
-	def("s", StringType, "abc")
-	def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1})
-	def("ai", NewArrayType(2, IntType), varray{1, 2})
-	def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}})
-	def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}})
-	def("fn", NewFuncType([]Type{IntType}, false, []Type{IntType}), &testFunc{})
-	def("oneTwo", NewFuncType([]Type{}, false, []Type{IntType, IntType}), &oneTwoFunc{})
-	def("void", NewFuncType([]Type{}, false, []Type{}), &voidFunc{})
-	def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3})
-
-	return w
-}
diff --git a/src/pkg/exp/eval/expr.go b/src/pkg/exp/eval/expr.go
deleted file mode 100644
index 14a0659..0000000
--- a/src/pkg/exp/eval/expr.go
+++ /dev/null
@@ -1,2015 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"big"
-	"fmt"
-	"go/ast"
-	"go/token"
-	"log"
-	"strconv"
-	"strings"
-	"os"
-)
-
-var (
-	idealZero = big.NewInt(0)
-	idealOne  = big.NewInt(1)
-)
-
-// An expr is the result of compiling an expression.  It stores the
-// type of the expression and its evaluator function.
-type expr struct {
-	*exprInfo
-	t Type
-
-	// Evaluate this node as the given type.
-	eval interface{}
-
-	// Map index expressions permit special forms of assignment,
-	// for which we need to know the Map and key.
-	evalMapValue func(t *Thread) (Map, interface{})
-
-	// Evaluate to the "address of" this value; that is, the
-	// settable Value object.  nil for expressions whose address
-	// cannot be taken.
-	evalAddr func(t *Thread) Value
-
-	// Execute this expression as a statement.  Only expressions
-	// that are valid expression statements should set this.
-	exec func(t *Thread)
-
-	// If this expression is a type, this is its compiled type.
-	// This is only permitted in the function position of a call
-	// expression.  In this case, t should be nil.
-	valType Type
-
-	// A short string describing this expression for error
-	// messages.
-	desc string
-}
-
-// exprInfo stores information needed to compile any expression node.
-// Each expr also stores its exprInfo so further expressions can be
-// compiled from it.
-type exprInfo struct {
-	*compiler
-	pos token.Pos
-}
-
-func (a *exprInfo) newExpr(t Type, desc string) *expr {
-	return &expr{exprInfo: a, t: t, desc: desc}
-}
-
-func (a *exprInfo) diag(format string, args ...interface{}) {
-	a.diagAt(a.pos, format, args...)
-}
-
-func (a *exprInfo) diagOpType(op token.Token, vt Type) {
-	a.diag("illegal operand type for '%v' operator\n\t%v", op, vt)
-}
-
-func (a *exprInfo) diagOpTypes(op token.Token, lt Type, rt Type) {
-	a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt)
-}
-
-/*
- * Common expression manipulations
- */
-
-// a.convertTo(t) converts the value of the analyzed expression a,
-// which must be a constant, ideal number, to a new analyzed
-// expression with a constant value of type t.
-//
-// TODO(austin) Rename to resolveIdeal or something?
-func (a *expr) convertTo(t Type) *expr {
-	if !a.t.isIdeal() {
-		log.Panicf("attempted to convert from %v, expected ideal", a.t)
-	}
-
-	var rat *big.Rat
-
-	// XXX(Spec)  The spec says "It is erroneous".
-	//
-	// It is an error to assign a value with a non-zero fractional
-	// part to an integer, or if the assignment would overflow or
-	// underflow, or in general if the value cannot be represented
-	// by the type of the variable.
-	switch a.t {
-	case IdealFloatType:
-		rat = a.asIdealFloat()()
-		if t.isInteger() && !rat.IsInt() {
-			a.diag("constant %v truncated to integer", rat.FloatString(6))
-			return nil
-		}
-	case IdealIntType:
-		i := a.asIdealInt()()
-		rat = new(big.Rat).SetInt(i)
-	default:
-		log.Panicf("unexpected ideal type %v", a.t)
-	}
-
-	// Check bounds
-	if t, ok := t.lit().(BoundedType); ok {
-		if rat.Cmp(t.minVal()) < 0 {
-			a.diag("constant %v underflows %v", rat.FloatString(6), t)
-			return nil
-		}
-		if rat.Cmp(t.maxVal()) > 0 {
-			a.diag("constant %v overflows %v", rat.FloatString(6), t)
-			return nil
-		}
-	}
-
-	// Convert rat to type t.
-	res := a.newExpr(t, a.desc)
-	switch t := t.lit().(type) {
-	case *uintType:
-		n, d := rat.Num(), rat.Denom()
-		f := new(big.Int).Quo(n, d)
-		f = f.Abs(f)
-		v := uint64(f.Int64())
-		res.eval = func(*Thread) uint64 { return v }
-	case *intType:
-		n, d := rat.Num(), rat.Denom()
-		f := new(big.Int).Quo(n, d)
-		v := f.Int64()
-		res.eval = func(*Thread) int64 { return v }
-	case *idealIntType:
-		n, d := rat.Num(), rat.Denom()
-		f := new(big.Int).Quo(n, d)
-		res.eval = func() *big.Int { return f }
-	case *floatType:
-		n, d := rat.Num(), rat.Denom()
-		v := float64(n.Int64()) / float64(d.Int64())
-		res.eval = func(*Thread) float64 { return v }
-	case *idealFloatType:
-		res.eval = func() *big.Rat { return rat }
-	default:
-		log.Panicf("cannot convert to type %T", t)
-	}
-
-	return res
-}
-
-// convertToInt converts this expression to an integer, if possible,
-// or produces an error if not.  This accepts ideal ints, uints, and
-// ints.  If max is not -1, produces an error if possible if the value
-// exceeds max.  If negErr is not "", produces an error if possible if
-// the value is negative.
-func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr {
-	switch a.t.lit().(type) {
-	case *idealIntType:
-		val := a.asIdealInt()()
-		if negErr != "" && val.Sign() < 0 {
-			a.diag("negative %s: %s", negErr, val)
-			return nil
-		}
-		bound := max
-		if negErr == "slice" {
-			bound++
-		}
-		if max != -1 && val.Cmp(big.NewInt(bound)) >= 0 {
-			a.diag("index %s exceeds length %d", val, max)
-			return nil
-		}
-		return a.convertTo(IntType)
-
-	case *uintType:
-		// Convert to int
-		na := a.newExpr(IntType, a.desc)
-		af := a.asUint()
-		na.eval = func(t *Thread) int64 { return int64(af(t)) }
-		return na
-
-	case *intType:
-		// Good as is
-		return a
-	}
-
-	a.diag("illegal operand type for %s\n\t%v", errOp, a.t)
-	return nil
-}
-
-// derefArray returns an expression of array type if the given
-// expression is a *array type.  Otherwise, returns the given
-// expression.
-func (a *expr) derefArray() *expr {
-	if pt, ok := a.t.lit().(*PtrType); ok {
-		if _, ok := pt.Elem.lit().(*ArrayType); ok {
-			deref := a.compileStarExpr(a)
-			if deref == nil {
-				log.Panicf("failed to dereference *array")
-			}
-			return deref
-		}
-	}
-	return a
-}
-
-/*
- * Assignments
- */
-
-// An assignCompiler compiles assignment operations.  Anything other
-// than short declarations should use the compileAssign wrapper.
-//
-// There are three valid types of assignment:
-// 1) T = T
-//    Assigning a single expression with single-valued type to a
-//    single-valued type.
-// 2) MT = T, T, ...
-//    Assigning multiple expressions with single-valued types to a
-//    multi-valued type.
-// 3) MT = MT
-//    Assigning a single expression with multi-valued type to a
-//    multi-valued type.
-type assignCompiler struct {
-	*compiler
-	pos token.Pos
-	// The RHS expressions.  This may include nil's for
-	// expressions that failed to compile.
-	rs []*expr
-	// The (possibly unary) MultiType of the RHS.
-	rmt *MultiType
-	// Whether this is an unpack assignment (case 3).
-	isUnpack bool
-	// Whether map special assignment forms are allowed.
-	allowMap bool
-	// Whether this is a "r, ok = a[x]" assignment.
-	isMapUnpack bool
-	// The operation name to use in error messages, such as
-	// "assignment" or "function call".
-	errOp string
-	// The name to use for positions in error messages, such as
-	// "argument".
-	errPosName string
-}
-
-// Type check the RHS of an assignment, returning a new assignCompiler
-// and indicating if the type check succeeded.  This always returns an
-// assignCompiler with rmt set, but if type checking fails, slots in
-// the MultiType may be nil.  If rs contains nil's, type checking will
-// fail and these expressions given a nil type.
-func (a *compiler) checkAssign(pos token.Pos, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) {
-	c := &assignCompiler{
-		compiler:   a,
-		pos:        pos,
-		rs:         rs,
-		errOp:      errOp,
-		errPosName: errPosName,
-	}
-
-	// Is this an unpack?
-	if len(rs) == 1 && rs[0] != nil {
-		if rmt, isUnpack := rs[0].t.(*MultiType); isUnpack {
-			c.rmt = rmt
-			c.isUnpack = true
-			return c, true
-		}
-	}
-
-	// Create MultiType for RHS and check that all RHS expressions
-	// are single-valued.
-	rts := make([]Type, len(rs))
-	ok := true
-	for i, r := range rs {
-		if r == nil {
-			ok = false
-			continue
-		}
-
-		if _, isMT := r.t.(*MultiType); isMT {
-			r.diag("multi-valued expression not allowed in %s", errOp)
-			ok = false
-			continue
-		}
-
-		rts[i] = r.t
-	}
-
-	c.rmt = NewMultiType(rts)
-	return c, ok
-}
-
-func (a *assignCompiler) allowMapForms(nls int) {
-	a.allowMap = true
-
-	// Update unpacking info if this is r, ok = a[x]
-	if nls == 2 && len(a.rs) == 1 && a.rs[0] != nil && a.rs[0].evalMapValue != nil {
-		a.isUnpack = true
-		a.rmt = NewMultiType([]Type{a.rs[0].t, BoolType})
-		a.isMapUnpack = true
-	}
-}
-
-// compile type checks and compiles an assignment operation, returning
-// a function that expects an l-value and the frame in which to
-// evaluate the RHS expressions.  The l-value must have exactly the
-// type given by lt.  Returns nil if type checking fails.
-func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) {
-	lmt, isMT := lt.(*MultiType)
-	rmt, isUnpack := a.rmt, a.isUnpack
-
-	// Create unary MultiType for single LHS
-	if !isMT {
-		lmt = NewMultiType([]Type{lt})
-	}
-
-	// Check that the assignment count matches
-	lcount := len(lmt.Elems)
-	rcount := len(rmt.Elems)
-	if lcount != rcount {
-		msg := "not enough"
-		pos := a.pos
-		if rcount > lcount {
-			msg = "too many"
-			if lcount > 0 {
-				pos = a.rs[lcount-1].pos
-			}
-		}
-		a.diagAt(pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt)
-		return nil
-	}
-
-	bad := false
-
-	// If this is an unpack, create a temporary to store the
-	// multi-value and replace the RHS with expressions to pull
-	// out values from the temporary.  Technically, this is only
-	// necessary when we need to perform assignment conversions.
-	var effect func(*Thread)
-	if isUnpack {
-		// This leaks a slot, but is definitely safe.
-		temp := b.DefineTemp(a.rmt)
-		tempIdx := temp.Index
-		if tempIdx < 0 {
-			panic(fmt.Sprintln("tempidx", tempIdx))
-		}
-		if a.isMapUnpack {
-			rf := a.rs[0].evalMapValue
-			vt := a.rmt.Elems[0]
-			effect = func(t *Thread) {
-				m, k := rf(t)
-				v := m.Elem(t, k)
-				found := boolV(true)
-				if v == nil {
-					found = boolV(false)
-					v = vt.Zero()
-				}
-				t.f.Vars[tempIdx] = multiV([]Value{v, &found})
-			}
-		} else {
-			rf := a.rs[0].asMulti()
-			effect = func(t *Thread) { t.f.Vars[tempIdx] = multiV(rf(t)) }
-		}
-		orig := a.rs[0]
-		a.rs = make([]*expr, len(a.rmt.Elems))
-		for i, t := range a.rmt.Elems {
-			if t.isIdeal() {
-				log.Panicf("Right side of unpack contains ideal: %s", rmt)
-			}
-			a.rs[i] = orig.newExpr(t, orig.desc)
-			index := i
-			a.rs[i].genValue(func(t *Thread) Value { return t.f.Vars[tempIdx].(multiV)[index] })
-		}
-	}
-	// Now len(a.rs) == len(a.rmt) and we've reduced any unpacking
-	// to multi-assignment.
-
-	// TODO(austin) Deal with assignment special cases.
-
-	// Values of any type may always be assigned to variables of
-	// compatible static type.
-	for i, lt := range lmt.Elems {
-		rt := rmt.Elems[i]
-
-		// When [an ideal is] (used in an expression) assigned
-		// to a variable or typed constant, the destination
-		// must be able to represent the assigned value.
-		if rt.isIdeal() {
-			a.rs[i] = a.rs[i].convertTo(lmt.Elems[i])
-			if a.rs[i] == nil {
-				bad = true
-				continue
-			}
-			rt = a.rs[i].t
-		}
-
-		// A pointer p to an array can be assigned to a slice
-		// variable v with compatible element type if the type
-		// of p or v is unnamed.
-		if rpt, ok := rt.lit().(*PtrType); ok {
-			if at, ok := rpt.Elem.lit().(*ArrayType); ok {
-				if lst, ok := lt.lit().(*SliceType); ok {
-					if lst.Elem.compat(at.Elem, false) && (rt.lit() == Type(rt) || lt.lit() == Type(lt)) {
-						rf := a.rs[i].asPtr()
-						a.rs[i] = a.rs[i].newExpr(lt, a.rs[i].desc)
-						len := at.Len
-						a.rs[i].eval = func(t *Thread) Slice { return Slice{rf(t).(ArrayValue), len, len} }
-						rt = a.rs[i].t
-					}
-				}
-			}
-		}
-
-		if !lt.compat(rt, false) {
-			if len(a.rs) == 1 {
-				a.rs[0].diag("illegal operand types for %s\n\t%v\n\t%v", a.errOp, lt, rt)
-			} else {
-				a.rs[i].diag("illegal operand types in %s %d of %s\n\t%v\n\t%v", a.errPosName, i+1, a.errOp, lt, rt)
-			}
-			bad = true
-		}
-	}
-	if bad {
-		return nil
-	}
-
-	// Compile
-	if !isMT {
-		// Case 1
-		return genAssign(lt, a.rs[0])
-	}
-	// Case 2 or 3
-	as := make([]func(lv Value, t *Thread), len(a.rs))
-	for i, r := range a.rs {
-		as[i] = genAssign(lmt.Elems[i], r)
-	}
-	return func(lv Value, t *Thread) {
-		if effect != nil {
-			effect(t)
-		}
-		lmv := lv.(multiV)
-		for i, a := range as {
-			a(lmv[i], t)
-		}
-	}
-}
-
-// compileAssign compiles an assignment operation without the full
-// generality of an assignCompiler.  See assignCompiler for a
-// description of the arguments.
-func (a *compiler) compileAssign(pos token.Pos, b *block, lt Type, rs []*expr, errOp, errPosName string) func(Value, *Thread) {
-	ac, ok := a.checkAssign(pos, rs, errOp, errPosName)
-	if !ok {
-		return nil
-	}
-	return ac.compile(b, lt)
-}
-
-/*
- * Expression compiler
- */
-
-// An exprCompiler stores information used throughout the compilation
-// of a single expression.  It does not embed funcCompiler because
-// expressions can appear at top level.
-type exprCompiler struct {
-	*compiler
-	// The block this expression is being compiled in.
-	block *block
-	// Whether this expression is used in a constant context.
-	constant bool
-}
-
-// compile compiles an expression AST.  callCtx should be true if this
-// AST is in the function position of a function call node; it allows
-// the returned expression to be a type or a built-in function (which
-// otherwise result in errors).
-func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
-	ei := &exprInfo{a.compiler, x.Pos()}
-
-	switch x := x.(type) {
-	// Literals
-	case *ast.BasicLit:
-		switch x.Kind {
-		case token.INT:
-			return ei.compileIntLit(string(x.Value))
-		case token.FLOAT:
-			return ei.compileFloatLit(string(x.Value))
-		case token.CHAR:
-			return ei.compileCharLit(string(x.Value))
-		case token.STRING:
-			return ei.compileStringLit(string(x.Value))
-		default:
-			log.Panicf("unexpected basic literal type %v", x.Kind)
-		}
-
-	case *ast.CompositeLit:
-		goto notimpl
-
-	case *ast.FuncLit:
-		decl := ei.compileFuncType(a.block, x.Type)
-		if decl == nil {
-			// TODO(austin) Try compiling the body,
-			// perhaps with dummy argument definitions
-			return nil
-		}
-		fn := ei.compileFunc(a.block, decl, x.Body)
-		if fn == nil {
-			return nil
-		}
-		if a.constant {
-			a.diagAt(x.Pos(), "function literal used in constant expression")
-			return nil
-		}
-		return ei.compileFuncLit(decl, fn)
-
-	// Types
-	case *ast.ArrayType:
-		// TODO(austin) Use a multi-type case
-		goto typeexpr
-
-	case *ast.ChanType:
-		goto typeexpr
-
-	case *ast.Ellipsis:
-		goto typeexpr
-
-	case *ast.FuncType:
-		goto typeexpr
-
-	case *ast.InterfaceType:
-		goto typeexpr
-
-	case *ast.MapType:
-		goto typeexpr
-
-	// Remaining expressions
-	case *ast.BadExpr:
-		// Error already reported by parser
-		a.silentErrors++
-		return nil
-
-	case *ast.BinaryExpr:
-		l, r := a.compile(x.X, false), a.compile(x.Y, false)
-		if l == nil || r == nil {
-			return nil
-		}
-		return ei.compileBinaryExpr(x.Op, l, r)
-
-	case *ast.CallExpr:
-		l := a.compile(x.Fun, true)
-		args := make([]*expr, len(x.Args))
-		bad := false
-		for i, arg := range x.Args {
-			if i == 0 && l != nil && (l.t == Type(makeType) || l.t == Type(newType)) {
-				argei := &exprInfo{a.compiler, arg.Pos()}
-				args[i] = argei.exprFromType(a.compileType(a.block, arg))
-			} else {
-				args[i] = a.compile(arg, false)
-			}
-			if args[i] == nil {
-				bad = true
-			}
-		}
-		if bad || l == nil {
-			return nil
-		}
-		if a.constant {
-			a.diagAt(x.Pos(), "function call in constant context")
-			return nil
-		}
-
-		if l.valType != nil {
-			a.diagAt(x.Pos(), "type conversions not implemented")
-			return nil
-		} else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" {
-			return ei.compileBuiltinCallExpr(a.block, ft, args)
-		} else {
-			return ei.compileCallExpr(a.block, l, args)
-		}
-
-	case *ast.Ident:
-		return ei.compileIdent(a.block, a.constant, callCtx, x.Name)
-
-	case *ast.IndexExpr:
-		l, r := a.compile(x.X, false), a.compile(x.Index, false)
-		if l == nil || r == nil {
-			return nil
-		}
-		return ei.compileIndexExpr(l, r)
-
-	case *ast.SliceExpr:
-		var lo, hi *expr
-		arr := a.compile(x.X, false)
-		if x.Low == nil {
-			// beginning was omitted, so we need to provide it
-			ei := &exprInfo{a.compiler, x.Pos()}
-			lo = ei.compileIntLit("0")
-		} else {
-			lo = a.compile(x.Low, false)
-		}
-		if x.High == nil {
-			// End was omitted, so we need to compute len(x.X)
-			ei := &exprInfo{a.compiler, x.Pos()}
-			hi = ei.compileBuiltinCallExpr(a.block, lenType, []*expr{arr})
-		} else {
-			hi = a.compile(x.High, false)
-		}
-		if arr == nil || lo == nil || hi == nil {
-			return nil
-		}
-		return ei.compileSliceExpr(arr, lo, hi)
-
-	case *ast.KeyValueExpr:
-		goto notimpl
-
-	case *ast.ParenExpr:
-		return a.compile(x.X, callCtx)
-
-	case *ast.SelectorExpr:
-		v := a.compile(x.X, false)
-		if v == nil {
-			return nil
-		}
-		return ei.compileSelectorExpr(v, x.Sel.Name)
-
-	case *ast.StarExpr:
-		// We pass down our call context because this could be
-		// a pointer type (and thus a type conversion)
-		v := a.compile(x.X, callCtx)
-		if v == nil {
-			return nil
-		}
-		if v.valType != nil {
-			// Turns out this was a pointer type, not a dereference
-			return ei.exprFromType(NewPtrType(v.valType))
-		}
-		return ei.compileStarExpr(v)
-
-	case *ast.StructType:
-		goto notimpl
-
-	case *ast.TypeAssertExpr:
-		goto notimpl
-
-	case *ast.UnaryExpr:
-		v := a.compile(x.X, false)
-		if v == nil {
-			return nil
-		}
-		return ei.compileUnaryExpr(x.Op, v)
-	}
-	log.Panicf("unexpected ast node type %T", x)
-	panic("unreachable")
-
-typeexpr:
-	if !callCtx {
-		a.diagAt(x.Pos(), "type used as expression")
-		return nil
-	}
-	return ei.exprFromType(a.compileType(a.block, x))
-
-notimpl:
-	a.diagAt(x.Pos(), "%T expression node not implemented", x)
-	return nil
-}
-
-func (a *exprInfo) exprFromType(t Type) *expr {
-	if t == nil {
-		return nil
-	}
-	expr := a.newExpr(nil, "type")
-	expr.valType = t
-	return expr
-}
-
-func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name string) *expr {
-	bl, level, def := b.Lookup(name)
-	if def == nil {
-		a.diag("%s: undefined", name)
-		return nil
-	}
-	switch def := def.(type) {
-	case *Constant:
-		expr := a.newExpr(def.Type, "constant")
-		if ft, ok := def.Type.(*FuncType); ok && ft.builtin != "" {
-			// XXX(Spec) I don't think anything says that
-			// built-in functions can't be used as values.
-			if !callCtx {
-				a.diag("built-in function %s cannot be used as a value", ft.builtin)
-				return nil
-			}
-			// Otherwise, we leave the evaluators empty
-			// because this is handled specially
-		} else {
-			expr.genConstant(def.Value)
-		}
-		return expr
-	case *Variable:
-		if constant {
-			a.diag("variable %s used in constant expression", name)
-			return nil
-		}
-		if bl.global {
-			return a.compileGlobalVariable(def)
-		}
-		return a.compileVariable(level, def)
-	case Type:
-		if callCtx {
-			return a.exprFromType(def)
-		}
-		a.diag("type %v used as expression", name)
-		return nil
-	}
-	log.Panicf("name %s has unknown type %T", name, def)
-	panic("unreachable")
-}
-
-func (a *exprInfo) compileVariable(level int, v *Variable) *expr {
-	if v.Type == nil {
-		// Placeholder definition from an earlier error
-		a.silentErrors++
-		return nil
-	}
-	expr := a.newExpr(v.Type, "variable")
-	expr.genIdentOp(level, v.Index)
-	return expr
-}
-
-func (a *exprInfo) compileGlobalVariable(v *Variable) *expr {
-	if v.Type == nil {
-		// Placeholder definition from an earlier error
-		a.silentErrors++
-		return nil
-	}
-	if v.Init == nil {
-		v.Init = v.Type.Zero()
-	}
-	expr := a.newExpr(v.Type, "variable")
-	val := v.Init
-	expr.genValue(func(t *Thread) Value { return val })
-	return expr
-}
-
-func (a *exprInfo) compileIdealInt(i *big.Int, desc string) *expr {
-	expr := a.newExpr(IdealIntType, desc)
-	expr.eval = func() *big.Int { return i }
-	return expr
-}
-
-func (a *exprInfo) compileIntLit(lit string) *expr {
-	i, _ := new(big.Int).SetString(lit, 0)
-	return a.compileIdealInt(i, "integer literal")
-}
-
-func (a *exprInfo) compileCharLit(lit string) *expr {
-	if lit[0] != '\'' {
-		// Caught by parser
-		a.silentErrors++
-		return nil
-	}
-	v, _, tail, err := strconv.UnquoteChar(lit[1:], '\'')
-	if err != nil || tail != "'" {
-		// Caught by parser
-		a.silentErrors++
-		return nil
-	}
-	return a.compileIdealInt(big.NewInt(int64(v)), "character literal")
-}
-
-func (a *exprInfo) compileFloatLit(lit string) *expr {
-	f, ok := new(big.Rat).SetString(lit)
-	if !ok {
-		log.Panicf("malformed float literal %s at %v passed parser", lit, a.pos)
-	}
-	expr := a.newExpr(IdealFloatType, "float literal")
-	expr.eval = func() *big.Rat { return f }
-	return expr
-}
-
-func (a *exprInfo) compileString(s string) *expr {
-	// Ideal strings don't have a named type but they are
-	// compatible with type string.
-
-	// TODO(austin) Use unnamed string type.
-	expr := a.newExpr(StringType, "string literal")
-	expr.eval = func(*Thread) string { return s }
-	return expr
-}
-
-func (a *exprInfo) compileStringLit(lit string) *expr {
-	s, err := strconv.Unquote(lit)
-	if err != nil {
-		a.diag("illegal string literal, %v", err)
-		return nil
-	}
-	return a.compileString(s)
-}
-
-func (a *exprInfo) compileStringList(list []*expr) *expr {
-	ss := make([]string, len(list))
-	for i, s := range list {
-		ss[i] = s.asString()(nil)
-	}
-	return a.compileString(strings.Join(ss, ""))
-}
-
-func (a *exprInfo) compileFuncLit(decl *FuncDecl, fn func(*Thread) Func) *expr {
-	expr := a.newExpr(decl.Type, "function literal")
-	expr.eval = fn
-	return expr
-}
-
-func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr {
-	// mark marks a field that matches the selector name.  It
-	// tracks the best depth found so far and whether more than
-	// one field has been found at that depth.
-	bestDepth := -1
-	ambig := false
-	amberr := ""
-	mark := func(depth int, pathName string) {
-		switch {
-		case bestDepth == -1 || depth < bestDepth:
-			bestDepth = depth
-			ambig = false
-			amberr = ""
-
-		case depth == bestDepth:
-			ambig = true
-
-		default:
-			log.Panicf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth)
-		}
-		amberr += "\n\t" + pathName[1:]
-	}
-
-	visited := make(map[Type]bool)
-
-	// find recursively searches for the named field, starting at
-	// type t.  If it finds the named field, it returns a function
-	// which takes an expr that represents a value of type 't' and
-	// returns an expr that retrieves the named field.  We delay
-	// expr construction to avoid producing lots of useless expr's
-	// as we search.
-	//
-	// TODO(austin) Now that the expression compiler works on
-	// semantic values instead of AST's, there should be a much
-	// better way of doing this.
-	var find func(Type, int, string) func(*expr) *expr
-	find = func(t Type, depth int, pathName string) func(*expr) *expr {
-		// Don't bother looking if we've found something shallower
-		if bestDepth != -1 && bestDepth < depth {
-			return nil
-		}
-
-		// Don't check the same type twice and avoid loops
-		if visited[t] {
-			return nil
-		}
-		visited[t] = true
-
-		// Implicit dereference
-		deref := false
-		if ti, ok := t.(*PtrType); ok {
-			deref = true
-			t = ti.Elem
-		}
-
-		// If it's a named type, look for methods
-		if ti, ok := t.(*NamedType); ok {
-			_, ok := ti.methods[name]
-			if ok {
-				mark(depth, pathName+"."+name)
-				log.Panic("Methods not implemented")
-			}
-			t = ti.Def
-		}
-
-		// If it's a struct type, check fields and embedded types
-		var builder func(*expr) *expr
-		if t, ok := t.(*StructType); ok {
-			for i, f := range t.Elems {
-				var sub func(*expr) *expr
-				switch {
-				case f.Name == name:
-					mark(depth, pathName+"."+name)
-					sub = func(e *expr) *expr { return e }
-
-				case f.Anonymous:
-					sub = find(f.Type, depth+1, pathName+"."+f.Name)
-					if sub == nil {
-						continue
-					}
-
-				default:
-					continue
-				}
-
-				// We found something.  Create a
-				// builder for accessing this field.
-				ft := f.Type
-				index := i
-				builder = func(parent *expr) *expr {
-					if deref {
-						parent = a.compileStarExpr(parent)
-					}
-					expr := a.newExpr(ft, "selector expression")
-					pf := parent.asStruct()
-					evalAddr := func(t *Thread) Value { return pf(t).Field(t, index) }
-					expr.genValue(evalAddr)
-					return sub(expr)
-				}
-			}
-		}
-
-		return builder
-	}
-
-	builder := find(v.t, 0, "")
-	if builder == nil {
-		a.diag("type %v has no field or method %s", v.t, name)
-		return nil
-	}
-	if ambig {
-		a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr)
-		return nil
-	}
-
-	return builder(v)
-}
-
-func (a *exprInfo) compileSliceExpr(arr, lo, hi *expr) *expr {
-	// Type check object
-	arr = arr.derefArray()
-
-	var at Type
-	var maxIndex int64 = -1
-
-	switch lt := arr.t.lit().(type) {
-	case *ArrayType:
-		at = NewSliceType(lt.Elem)
-		maxIndex = lt.Len
-
-	case *SliceType:
-		at = lt
-
-	case *stringType:
-		at = lt
-
-	default:
-		a.diag("cannot slice %v", arr.t)
-		return nil
-	}
-
-	// Type check index and convert to int
-	// XXX(Spec) It's unclear if ideal floats with no
-	// fractional part are allowed here.  6g allows it.  I
-	// believe that's wrong.
-	lo = lo.convertToInt(maxIndex, "slice", "slice")
-	hi = hi.convertToInt(maxIndex, "slice", "slice")
-	if lo == nil || hi == nil {
-		return nil
-	}
-
-	expr := a.newExpr(at, "slice expression")
-
-	// Compile
-	lof := lo.asInt()
-	hif := hi.asInt()
-	switch lt := arr.t.lit().(type) {
-	case *ArrayType:
-		arrf := arr.asArray()
-		bound := lt.Len
-		expr.eval = func(t *Thread) Slice {
-			arr, lo, hi := arrf(t), lof(t), hif(t)
-			if lo > hi || hi > bound || lo < 0 {
-				t.Abort(SliceError{lo, hi, bound})
-			}
-			return Slice{arr.Sub(lo, bound-lo), hi - lo, bound - lo}
-		}
-
-	case *SliceType:
-		arrf := arr.asSlice()
-		expr.eval = func(t *Thread) Slice {
-			arr, lo, hi := arrf(t), lof(t), hif(t)
-			if lo > hi || hi > arr.Cap || lo < 0 {
-				t.Abort(SliceError{lo, hi, arr.Cap})
-			}
-			return Slice{arr.Base.Sub(lo, arr.Cap-lo), hi - lo, arr.Cap - lo}
-		}
-
-	case *stringType:
-		arrf := arr.asString()
-		// TODO(austin) This pulls over the whole string in a
-		// remote setting, instead of creating a substring backed
-		// by remote memory.
-		expr.eval = func(t *Thread) string {
-			arr, lo, hi := arrf(t), lof(t), hif(t)
-			if lo > hi || hi > int64(len(arr)) || lo < 0 {
-				t.Abort(SliceError{lo, hi, int64(len(arr))})
-			}
-			return arr[lo:hi]
-		}
-
-	default:
-		log.Panicf("unexpected left operand type %T", arr.t.lit())
-	}
-
-	return expr
-}
-
-func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
-	// Type check object
-	l = l.derefArray()
-
-	var at Type
-	intIndex := false
-	var maxIndex int64 = -1
-
-	switch lt := l.t.lit().(type) {
-	case *ArrayType:
-		at = lt.Elem
-		intIndex = true
-		maxIndex = lt.Len
-
-	case *SliceType:
-		at = lt.Elem
-		intIndex = true
-
-	case *stringType:
-		at = Uint8Type
-		intIndex = true
-
-	case *MapType:
-		at = lt.Elem
-		if r.t.isIdeal() {
-			r = r.convertTo(lt.Key)
-			if r == nil {
-				return nil
-			}
-		}
-		if !lt.Key.compat(r.t, false) {
-			a.diag("cannot use %s as index into %s", r.t, lt)
-			return nil
-		}
-
-	default:
-		a.diag("cannot index into %v", l.t)
-		return nil
-	}
-
-	// Type check index and convert to int if necessary
-	if intIndex {
-		// XXX(Spec) It's unclear if ideal floats with no
-		// fractional part are allowed here.  6g allows it.  I
-		// believe that's wrong.
-		r = r.convertToInt(maxIndex, "index", "index")
-		if r == nil {
-			return nil
-		}
-	}
-
-	expr := a.newExpr(at, "index expression")
-
-	// Compile
-	switch lt := l.t.lit().(type) {
-	case *ArrayType:
-		lf := l.asArray()
-		rf := r.asInt()
-		bound := lt.Len
-		expr.genValue(func(t *Thread) Value {
-			l, r := lf(t), rf(t)
-			if r < 0 || r >= bound {
-				t.Abort(IndexError{r, bound})
-			}
-			return l.Elem(t, r)
-		})
-
-	case *SliceType:
-		lf := l.asSlice()
-		rf := r.asInt()
-		expr.genValue(func(t *Thread) Value {
-			l, r := lf(t), rf(t)
-			if l.Base == nil {
-				t.Abort(NilPointerError{})
-			}
-			if r < 0 || r >= l.Len {
-				t.Abort(IndexError{r, l.Len})
-			}
-			return l.Base.Elem(t, r)
-		})
-
-	case *stringType:
-		lf := l.asString()
-		rf := r.asInt()
-		// TODO(austin) This pulls over the whole string in a
-		// remote setting, instead of just the one character.
-		expr.eval = func(t *Thread) uint64 {
-			l, r := lf(t), rf(t)
-			if r < 0 || r >= int64(len(l)) {
-				t.Abort(IndexError{r, int64(len(l))})
-			}
-			return uint64(l[r])
-		}
-
-	case *MapType:
-		lf := l.asMap()
-		rf := r.asInterface()
-		expr.genValue(func(t *Thread) Value {
-			m := lf(t)
-			k := rf(t)
-			if m == nil {
-				t.Abort(NilPointerError{})
-			}
-			e := m.Elem(t, k)
-			if e == nil {
-				t.Abort(KeyError{k})
-			}
-			return e
-		})
-		// genValue makes things addressable, but map values
-		// aren't addressable.
-		expr.evalAddr = nil
-		expr.evalMapValue = func(t *Thread) (Map, interface{}) {
-			// TODO(austin) Key check?  nil check?
-			return lf(t), rf(t)
-		}
-
-	default:
-		log.Panicf("unexpected left operand type %T", l.t.lit())
-	}
-
-	return expr
-}
-
-func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr {
-	// TODO(austin) Variadic functions.
-
-	// Type check
-
-	// XXX(Spec) Calling a named function type is okay.  I really
-	// think there needs to be a general discussion of named
-	// types.  A named type creates a new, distinct type, but the
-	// type of that type is still whatever it's defined to.  Thus,
-	// in "type Foo int", Foo is still an integer type and in
-	// "type Foo func()", Foo is a function type.
-	lt, ok := l.t.lit().(*FuncType)
-	if !ok {
-		a.diag("cannot call non-function type %v", l.t)
-		return nil
-	}
-
-	// The arguments must be single-valued expressions assignment
-	// compatible with the parameters of F.
-	//
-	// XXX(Spec) The spec is wrong.  It can also be a single
-	// multi-valued expression.
-	nin := len(lt.In)
-	assign := a.compileAssign(a.pos, b, NewMultiType(lt.In), as, "function call", "argument")
-	if assign == nil {
-		return nil
-	}
-
-	var t Type
-	nout := len(lt.Out)
-	switch nout {
-	case 0:
-		t = EmptyType
-	case 1:
-		t = lt.Out[0]
-	default:
-		t = NewMultiType(lt.Out)
-	}
-	expr := a.newExpr(t, "function call")
-
-	// Gather argument and out types to initialize frame variables
-	vts := make([]Type, nin+nout)
-	copy(vts, lt.In)
-	copy(vts[nin:], lt.Out)
-
-	// Compile
-	lf := l.asFunc()
-	call := func(t *Thread) []Value {
-		fun := lf(t)
-		fr := fun.NewFrame()
-		for i, t := range vts {
-			fr.Vars[i] = t.Zero()
-		}
-		assign(multiV(fr.Vars[0:nin]), t)
-		oldf := t.f
-		t.f = fr
-		fun.Call(t)
-		t.f = oldf
-		return fr.Vars[nin : nin+nout]
-	}
-	expr.genFuncCall(call)
-
-	return expr
-}
-
-func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *expr {
-	checkCount := func(min, max int) bool {
-		if len(as) < min {
-			a.diag("not enough arguments to %s", ft.builtin)
-			return false
-		} else if len(as) > max {
-			a.diag("too many arguments to %s", ft.builtin)
-			return false
-		}
-		return true
-	}
-
-	switch ft {
-	case capType:
-		if !checkCount(1, 1) {
-			return nil
-		}
-		arg := as[0].derefArray()
-		expr := a.newExpr(IntType, "function call")
-		switch t := arg.t.lit().(type) {
-		case *ArrayType:
-			// TODO(austin) It would be nice if this could
-			// be a constant int.
-			v := t.Len
-			expr.eval = func(t *Thread) int64 { return v }
-
-		case *SliceType:
-			vf := arg.asSlice()
-			expr.eval = func(t *Thread) int64 { return vf(t).Cap }
-
-		//case *ChanType:
-
-		default:
-			a.diag("illegal argument type for cap function\n\t%v", arg.t)
-			return nil
-		}
-		return expr
-
-	case copyType:
-		if !checkCount(2, 2) {
-			return nil
-		}
-		src := as[1]
-		dst := as[0]
-		if src.t != dst.t {
-			a.diag("arguments to built-in function 'copy' must have same type\nsrc: %s\ndst: %s\n", src.t, dst.t)
-			return nil
-		}
-		if _, ok := src.t.lit().(*SliceType); !ok {
-			a.diag("src argument to 'copy' must be a slice (got: %s)", src.t)
-			return nil
-		}
-		if _, ok := dst.t.lit().(*SliceType); !ok {
-			a.diag("dst argument to 'copy' must be a slice (got: %s)", dst.t)
-			return nil
-		}
-		expr := a.newExpr(IntType, "function call")
-		srcf := src.asSlice()
-		dstf := dst.asSlice()
-		expr.eval = func(t *Thread) int64 {
-			src, dst := srcf(t), dstf(t)
-			nelems := src.Len
-			if nelems > dst.Len {
-				nelems = dst.Len
-			}
-			dst.Base.Sub(0, nelems).Assign(t, src.Base.Sub(0, nelems))
-			return nelems
-		}
-		return expr
-
-	case lenType:
-		if !checkCount(1, 1) {
-			return nil
-		}
-		arg := as[0].derefArray()
-		expr := a.newExpr(IntType, "function call")
-		switch t := arg.t.lit().(type) {
-		case *stringType:
-			vf := arg.asString()
-			expr.eval = func(t *Thread) int64 { return int64(len(vf(t))) }
-
-		case *ArrayType:
-			// TODO(austin) It would be nice if this could
-			// be a constant int.
-			v := t.Len
-			expr.eval = func(t *Thread) int64 { return v }
-
-		case *SliceType:
-			vf := arg.asSlice()
-			expr.eval = func(t *Thread) int64 { return vf(t).Len }
-
-		case *MapType:
-			vf := arg.asMap()
-			expr.eval = func(t *Thread) int64 {
-				// XXX(Spec) What's the len of an
-				// uninitialized map?
-				m := vf(t)
-				if m == nil {
-					return 0
-				}
-				return m.Len(t)
-			}
-
-		//case *ChanType:
-
-		default:
-			a.diag("illegal argument type for len function\n\t%v", arg.t)
-			return nil
-		}
-		return expr
-
-	case makeType:
-		if !checkCount(1, 3) {
-			return nil
-		}
-		// XXX(Spec) What are the types of the
-		// arguments?  Do they have to be ints?  6g
-		// accepts any integral type.
-		var lenexpr, capexpr *expr
-		var lenf, capf func(*Thread) int64
-		if len(as) > 1 {
-			lenexpr = as[1].convertToInt(-1, "length", "make function")
-			if lenexpr == nil {
-				return nil
-			}
-			lenf = lenexpr.asInt()
-		}
-		if len(as) > 2 {
-			capexpr = as[2].convertToInt(-1, "capacity", "make function")
-			if capexpr == nil {
-				return nil
-			}
-			capf = capexpr.asInt()
-		}
-
-		switch t := as[0].valType.lit().(type) {
-		case *SliceType:
-			// A new, initialized slice value for a given
-			// element type T is made using the built-in
-			// function make, which takes a slice type and
-			// parameters specifying the length and
-			// optionally the capacity.
-			if !checkCount(2, 3) {
-				return nil
-			}
-			et := t.Elem
-			expr := a.newExpr(t, "function call")
-			expr.eval = func(t *Thread) Slice {
-				l := lenf(t)
-				// XXX(Spec) What if len or cap is
-				// negative?  The runtime panics.
-				if l < 0 {
-					t.Abort(NegativeLengthError{l})
-				}
-				c := l
-				if capf != nil {
-					c = capf(t)
-					if c < 0 {
-						t.Abort(NegativeCapacityError{c})
-					}
-					// XXX(Spec) What happens if
-					// len > cap?  The runtime
-					// sets cap to len.
-					if l > c {
-						c = l
-					}
-				}
-				base := arrayV(make([]Value, c))
-				for i := int64(0); i < c; i++ {
-					base[i] = et.Zero()
-				}
-				return Slice{&base, l, c}
-			}
-			return expr
-
-		case *MapType:
-			// A new, empty map value is made using the
-			// built-in function make, which takes the map
-			// type and an optional capacity hint as
-			// arguments.
-			if !checkCount(1, 2) {
-				return nil
-			}
-			expr := a.newExpr(t, "function call")
-			expr.eval = func(t *Thread) Map {
-				if lenf == nil {
-					return make(evalMap)
-				}
-				l := lenf(t)
-				return make(evalMap, l)
-			}
-			return expr
-
-		//case *ChanType:
-
-		default:
-			a.diag("illegal argument type for make function\n\t%v", as[0].valType)
-			return nil
-		}
-
-	case closeType, closedType:
-		a.diag("built-in function %s not implemented", ft.builtin)
-		return nil
-
-	case newType:
-		if !checkCount(1, 1) {
-			return nil
-		}
-
-		t := as[0].valType
-		expr := a.newExpr(NewPtrType(t), "new")
-		expr.eval = func(*Thread) Value { return t.Zero() }
-		return expr
-
-	case panicType, printType, printlnType:
-		evals := make([]func(*Thread) interface{}, len(as))
-		for i, x := range as {
-			evals[i] = x.asInterface()
-		}
-		spaces := ft == printlnType
-		newline := ft != printType
-		printer := func(t *Thread) {
-			for i, eval := range evals {
-				if i > 0 && spaces {
-					print(" ")
-				}
-				v := eval(t)
-				type stringer interface {
-					String() string
-				}
-				switch v1 := v.(type) {
-				case bool:
-					print(v1)
-				case uint64:
-					print(v1)
-				case int64:
-					print(v1)
-				case float64:
-					print(v1)
-				case string:
-					print(v1)
-				case stringer:
-					print(v1.String())
-				default:
-					print("???")
-				}
-			}
-			if newline {
-				print("\n")
-			}
-		}
-		expr := a.newExpr(EmptyType, "print")
-		expr.exec = printer
-		if ft == panicType {
-			expr.exec = func(t *Thread) {
-				printer(t)
-				t.Abort(os.NewError("panic"))
-			}
-		}
-		return expr
-	}
-
-	log.Panicf("unexpected built-in function '%s'", ft.builtin)
-	panic("unreachable")
-}
-
-func (a *exprInfo) compileStarExpr(v *expr) *expr {
-	switch vt := v.t.lit().(type) {
-	case *PtrType:
-		expr := a.newExpr(vt.Elem, "indirect expression")
-		vf := v.asPtr()
-		expr.genValue(func(t *Thread) Value {
-			v := vf(t)
-			if v == nil {
-				t.Abort(NilPointerError{})
-			}
-			return v
-		})
-		return expr
-	}
-
-	a.diagOpType(token.MUL, v.t)
-	return nil
-}
-
-var unaryOpDescs = make(map[token.Token]string)
-
-func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
-	// Type check
-	var t Type
-	switch op {
-	case token.ADD, token.SUB:
-		if !v.t.isInteger() && !v.t.isFloat() {
-			a.diagOpType(op, v.t)
-			return nil
-		}
-		t = v.t
-
-	case token.NOT:
-		if !v.t.isBoolean() {
-			a.diagOpType(op, v.t)
-			return nil
-		}
-		t = BoolType
-
-	case token.XOR:
-		if !v.t.isInteger() {
-			a.diagOpType(op, v.t)
-			return nil
-		}
-		t = v.t
-
-	case token.AND:
-		// The unary prefix address-of operator & generates
-		// the address of its operand, which must be a
-		// variable, pointer indirection, field selector, or
-		// array or slice indexing operation.
-		if v.evalAddr == nil {
-			a.diag("cannot take the address of %s", v.desc)
-			return nil
-		}
-
-		// TODO(austin) Implement "It is illegal to take the
-		// address of a function result variable" once I have
-		// function result variables.
-
-		t = NewPtrType(v.t)
-
-	case token.ARROW:
-		log.Panicf("Unary op %v not implemented", op)
-
-	default:
-		log.Panicf("unknown unary operator %v", op)
-	}
-
-	desc, ok := unaryOpDescs[op]
-	if !ok {
-		desc = "unary " + op.String() + " expression"
-		unaryOpDescs[op] = desc
-	}
-
-	// Compile
-	expr := a.newExpr(t, desc)
-	switch op {
-	case token.ADD:
-		// Just compile it out
-		expr = v
-		expr.desc = desc
-
-	case token.SUB:
-		expr.genUnaryOpNeg(v)
-
-	case token.NOT:
-		expr.genUnaryOpNot(v)
-
-	case token.XOR:
-		expr.genUnaryOpXor(v)
-
-	case token.AND:
-		vf := v.evalAddr
-		expr.eval = func(t *Thread) Value { return vf(t) }
-
-	default:
-		log.Panicf("Compilation of unary op %v not implemented", op)
-	}
-
-	return expr
-}
-
-var binOpDescs = make(map[token.Token]string)
-
-func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
-	// Save the original types of l.t and r.t for error messages.
-	origlt := l.t
-	origrt := r.t
-
-	// XXX(Spec) What is the exact definition of a "named type"?
-
-	// XXX(Spec) Arithmetic operators: "Integer types" apparently
-	// means all types compatible with basic integer types, though
-	// this is never explained.  Likewise for float types, etc.
-	// This relates to the missing explanation of named types.
-
-	// XXX(Spec) Operators: "If both operands are ideal numbers,
-	// the conversion is to ideal floats if one of the operands is
-	// an ideal float (relevant for / and %)."  How is that
-	// relevant only for / and %?  If I add an ideal int and an
-	// ideal float, I get an ideal float.
-
-	if op != token.SHL && op != token.SHR {
-		// Except in shift expressions, if one operand has
-		// numeric type and the other operand is an ideal
-		// number, the ideal number is converted to match the
-		// type of the other operand.
-		if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() {
-			r = r.convertTo(l.t)
-		} else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() {
-			l = l.convertTo(r.t)
-		}
-		if l == nil || r == nil {
-			return nil
-		}
-
-		// Except in shift expressions, if both operands are
-		// ideal numbers and one is an ideal float, the other
-		// is converted to ideal float.
-		if l.t.isIdeal() && r.t.isIdeal() {
-			if l.t.isInteger() && r.t.isFloat() {
-				l = l.convertTo(r.t)
-			} else if l.t.isFloat() && r.t.isInteger() {
-				r = r.convertTo(l.t)
-			}
-			if l == nil || r == nil {
-				return nil
-			}
-		}
-	}
-
-	// Useful type predicates
-	// TODO(austin) CL 33668 mandates identical types except for comparisons.
-	compat := func() bool { return l.t.compat(r.t, false) }
-	integers := func() bool { return l.t.isInteger() && r.t.isInteger() }
-	floats := func() bool { return l.t.isFloat() && r.t.isFloat() }
-	strings := func() bool {
-		// TODO(austin) Deal with named types
-		return l.t == StringType && r.t == StringType
-	}
-	booleans := func() bool { return l.t.isBoolean() && r.t.isBoolean() }
-
-	// Type check
-	var t Type
-	switch op {
-	case token.ADD:
-		if !compat() || (!integers() && !floats() && !strings()) {
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-		t = l.t
-
-	case token.SUB, token.MUL, token.QUO:
-		if !compat() || (!integers() && !floats()) {
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-		t = l.t
-
-	case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
-		if !compat() || !integers() {
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-		t = l.t
-
-	case token.SHL, token.SHR:
-		// XXX(Spec) Is it okay for the right operand to be an
-		// ideal float with no fractional part?  "The right
-		// operand in a shift operation must be always be of
-		// unsigned integer type or an ideal number that can
-		// be safely converted into an unsigned integer type
-		// (§Arithmetic operators)" suggests so and 6g agrees.
-
-		if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) {
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-
-		// The right operand in a shift operation must be
-		// always be of unsigned integer type or an ideal
-		// number that can be safely converted into an
-		// unsigned integer type.
-		if r.t.isIdeal() {
-			r2 := r.convertTo(UintType)
-			if r2 == nil {
-				return nil
-			}
-
-			// If the left operand is not ideal, convert
-			// the right to not ideal.
-			if !l.t.isIdeal() {
-				r = r2
-			}
-
-			// If both are ideal, but the right side isn't
-			// an ideal int, convert it to simplify things.
-			if l.t.isIdeal() && !r.t.isInteger() {
-				r = r.convertTo(IdealIntType)
-				if r == nil {
-					log.Panicf("conversion to uintType succeeded, but conversion to idealIntType failed")
-				}
-			}
-		} else if _, ok := r.t.lit().(*uintType); !ok {
-			a.diag("right operand of shift must be unsigned")
-			return nil
-		}
-
-		if l.t.isIdeal() && !r.t.isIdeal() {
-			// XXX(Spec) What is the meaning of "ideal >>
-			// non-ideal"?  Russ says the ideal should be
-			// converted to an int.  6g propagates the
-			// type down from assignments as a hint.
-
-			l = l.convertTo(IntType)
-			if l == nil {
-				return nil
-			}
-		}
-
-		// At this point, we should have one of three cases:
-		// 1) uint SHIFT uint
-		// 2) int SHIFT uint
-		// 3) ideal int SHIFT ideal int
-
-		t = l.t
-
-	case token.LOR, token.LAND:
-		if !booleans() {
-			return nil
-		}
-		// XXX(Spec) There's no mention of *which* boolean
-		// type the logical operators return.  From poking at
-		// 6g, it appears to be the named boolean type, NOT
-		// the type of the left operand, and NOT an unnamed
-		// boolean type.
-
-		t = BoolType
-
-	case token.ARROW:
-		// The operands in channel sends differ in type: one
-		// is always a channel and the other is a variable or
-		// value of the channel's element type.
-		log.Panic("Binary op <- not implemented")
-		t = BoolType
-
-	case token.LSS, token.GTR, token.LEQ, token.GEQ:
-		// XXX(Spec) It's really unclear what types which
-		// comparison operators apply to.  I feel like the
-		// text is trying to paint a Venn diagram for me,
-		// which it's really pretty simple: <, <=, >, >= apply
-		// only to numeric types and strings.  == and != apply
-		// to everything except arrays and structs, and there
-		// are some restrictions on when it applies to slices.
-
-		if !compat() || (!integers() && !floats() && !strings()) {
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-		t = BoolType
-
-	case token.EQL, token.NEQ:
-		// XXX(Spec) The rules for type checking comparison
-		// operators are spread across three places that all
-		// partially overlap with each other: the Comparison
-		// Compatibility section, the Operators section, and
-		// the Comparison Operators section.  The Operators
-		// section should just say that operators require
-		// identical types (as it does currently) except that
-		// there a few special cases for comparison, which are
-		// described in section X.  Currently it includes just
-		// one of the four special cases.  The Comparison
-		// Compatibility section and the Comparison Operators
-		// section should either be merged, or at least the
-		// Comparison Compatibility section should be
-		// exclusively about type checking and the Comparison
-		// Operators section should be exclusively about
-		// semantics.
-
-		// XXX(Spec) Comparison operators: "All comparison
-		// operators apply to basic types except bools."  This
-		// is very difficult to parse.  It's explained much
-		// better in the Comparison Compatibility section.
-
-		// XXX(Spec) Comparison compatibility: "Function
-		// values are equal if they refer to the same
-		// function." is rather vague.  It should probably be
-		// similar to the way the rule for map values is
-		// written: Function values are equal if they were
-		// created by the same execution of a function literal
-		// or refer to the same function declaration.  This is
-		// *almost* but not quite what 6g implements.  If a
-		// function literals does not capture any variables,
-		// then multiple executions of it will result in the
-		// same closure.  Russ says he'll change that.
-
-		// TODO(austin) Deal with remaining special cases
-
-		if !compat() {
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-		// Arrays and structs may not be compared to anything.
-		switch l.t.(type) {
-		case *ArrayType, *StructType:
-			a.diagOpTypes(op, origlt, origrt)
-			return nil
-		}
-		t = BoolType
-
-	default:
-		log.Panicf("unknown binary operator %v", op)
-	}
-
-	desc, ok := binOpDescs[op]
-	if !ok {
-		desc = op.String() + " expression"
-		binOpDescs[op] = desc
-	}
-
-	// Check for ideal divide by zero
-	switch op {
-	case token.QUO, token.REM:
-		if r.t.isIdeal() {
-			if (r.t.isInteger() && r.asIdealInt()().Sign() == 0) ||
-				(r.t.isFloat() && r.asIdealFloat()().Sign() == 0) {
-				a.diag("divide by zero")
-				return nil
-			}
-		}
-	}
-
-	// Compile
-	expr := a.newExpr(t, desc)
-	switch op {
-	case token.ADD:
-		expr.genBinOpAdd(l, r)
-
-	case token.SUB:
-		expr.genBinOpSub(l, r)
-
-	case token.MUL:
-		expr.genBinOpMul(l, r)
-
-	case token.QUO:
-		expr.genBinOpQuo(l, r)
-
-	case token.REM:
-		expr.genBinOpRem(l, r)
-
-	case token.AND:
-		expr.genBinOpAnd(l, r)
-
-	case token.OR:
-		expr.genBinOpOr(l, r)
-
-	case token.XOR:
-		expr.genBinOpXor(l, r)
-
-	case token.AND_NOT:
-		expr.genBinOpAndNot(l, r)
-
-	case token.SHL:
-		if l.t.isIdeal() {
-			lv := l.asIdealInt()()
-			rv := r.asIdealInt()()
-			const maxShift = 99999
-			if rv.Cmp(big.NewInt(maxShift)) > 0 {
-				a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift)
-				expr.t = nil
-				return nil
-			}
-			val := new(big.Int).Lsh(lv, uint(rv.Int64()))
-			expr.eval = func() *big.Int { return val }
-		} else {
-			expr.genBinOpShl(l, r)
-		}
-
-	case token.SHR:
-		if l.t.isIdeal() {
-			lv := l.asIdealInt()()
-			rv := r.asIdealInt()()
-			val := new(big.Int).Rsh(lv, uint(rv.Int64()))
-			expr.eval = func() *big.Int { return val }
-		} else {
-			expr.genBinOpShr(l, r)
-		}
-
-	case token.LSS:
-		expr.genBinOpLss(l, r)
-
-	case token.GTR:
-		expr.genBinOpGtr(l, r)
-
-	case token.LEQ:
-		expr.genBinOpLeq(l, r)
-
-	case token.GEQ:
-		expr.genBinOpGeq(l, r)
-
-	case token.EQL:
-		expr.genBinOpEql(l, r)
-
-	case token.NEQ:
-		expr.genBinOpNeq(l, r)
-
-	case token.LAND:
-		expr.genBinOpLogAnd(l, r)
-
-	case token.LOR:
-		expr.genBinOpLogOr(l, r)
-
-	default:
-		log.Panicf("Compilation of binary op %v not implemented", op)
-	}
-
-	return expr
-}
-
-// TODO(austin) This is a hack to eliminate a circular dependency
-// between type.go and expr.go
-func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
-	lenExpr := a.compileExpr(b, true, expr)
-	if lenExpr == nil {
-		return 0, false
-	}
-
-	// XXX(Spec) Are ideal floats with no fractional part okay?
-	if lenExpr.t.isIdeal() {
-		lenExpr = lenExpr.convertTo(IntType)
-		if lenExpr == nil {
-			return 0, false
-		}
-	}
-
-	if !lenExpr.t.isInteger() {
-		a.diagAt(expr.Pos(), "array size must be an integer")
-		return 0, false
-	}
-
-	switch lenExpr.t.lit().(type) {
-	case *intType:
-		return lenExpr.asInt()(nil), true
-	case *uintType:
-		return int64(lenExpr.asUint()(nil)), true
-	}
-	log.Panicf("unexpected integer type %T", lenExpr.t)
-	return 0, false
-}
-
-func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
-	ec := &exprCompiler{a, b, constant}
-	nerr := a.numError()
-	e := ec.compile(expr, false)
-	if e == nil && nerr == a.numError() {
-		log.Panicf("expression compilation failed without reporting errors")
-	}
-	return e
-}
-
-// extractEffect separates out any effects that the expression may
-// have, returning a function that will perform those effects and a
-// new exprCompiler that is guaranteed to be side-effect free.  These
-// are the moral equivalents of "temp := expr" and "temp" (or "temp :=
-// &expr" and "*temp" for addressable exprs).  Because this creates a
-// temporary variable, the caller should create a temporary block for
-// the compilation of this expression and the evaluation of the
-// results.
-func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
-	// Create "&a" if a is addressable
-	rhs := a
-	if a.evalAddr != nil {
-		rhs = a.compileUnaryExpr(token.AND, rhs)
-	}
-
-	// Create temp
-	ac, ok := a.checkAssign(a.pos, []*expr{rhs}, errOp, "")
-	if !ok {
-		return nil, nil
-	}
-	if len(ac.rmt.Elems) != 1 {
-		a.diag("multi-valued expression not allowed in %s", errOp)
-		return nil, nil
-	}
-	tempType := ac.rmt.Elems[0]
-	if tempType.isIdeal() {
-		// It's too bad we have to duplicate this rule.
-		switch {
-		case tempType.isInteger():
-			tempType = IntType
-		case tempType.isFloat():
-			tempType = Float64Type
-		default:
-			log.Panicf("unexpected ideal type %v", tempType)
-		}
-	}
-	temp := b.DefineTemp(tempType)
-	tempIdx := temp.Index
-
-	// Create "temp := rhs"
-	assign := ac.compile(b, tempType)
-	if assign == nil {
-		log.Panicf("compileAssign type check failed")
-	}
-
-	effect := func(t *Thread) {
-		tempVal := tempType.Zero()
-		t.f.Vars[tempIdx] = tempVal
-		assign(tempVal, t)
-	}
-
-	// Generate "temp" or "*temp"
-	getTemp := a.compileVariable(0, temp)
-	if a.evalAddr == nil {
-		return effect, getTemp
-	}
-
-	deref := a.compileStarExpr(getTemp)
-	if deref == nil {
-		return nil, nil
-	}
-	return effect, deref
-}
diff --git a/src/pkg/exp/eval/expr1.go b/src/pkg/exp/eval/expr1.go
deleted file mode 100755
index 5d0e500..0000000
--- a/src/pkg/exp/eval/expr1.go
+++ /dev/null
@@ -1,1874 +0,0 @@
-// This file is machine generated by gen.go.
-// 6g gen.go && 6l gen.6 && ./6.out >expr1.go
-
-package eval
-
-import (
-	"big"
-	"log"
-)
-
-/*
- * "As" functions.  These retrieve evaluator functions from an
- * expr, panicking if the requested evaluator has the wrong type.
- */
-func (a *expr) asBool() func(*Thread) bool {
-	return a.eval.(func(*Thread) bool)
-}
-func (a *expr) asUint() func(*Thread) uint64 {
-	return a.eval.(func(*Thread) uint64)
-}
-func (a *expr) asInt() func(*Thread) int64 {
-	return a.eval.(func(*Thread) int64)
-}
-func (a *expr) asIdealInt() func() *big.Int {
-	return a.eval.(func() *big.Int)
-}
-func (a *expr) asFloat() func(*Thread) float64 {
-	return a.eval.(func(*Thread) float64)
-}
-func (a *expr) asIdealFloat() func() *big.Rat {
-	return a.eval.(func() *big.Rat)
-}
-func (a *expr) asString() func(*Thread) string {
-	return a.eval.(func(*Thread) string)
-}
-func (a *expr) asArray() func(*Thread) ArrayValue {
-	return a.eval.(func(*Thread) ArrayValue)
-}
-func (a *expr) asStruct() func(*Thread) StructValue {
-	return a.eval.(func(*Thread) StructValue)
-}
-func (a *expr) asPtr() func(*Thread) Value {
-	return a.eval.(func(*Thread) Value)
-}
-func (a *expr) asFunc() func(*Thread) Func {
-	return a.eval.(func(*Thread) Func)
-}
-func (a *expr) asSlice() func(*Thread) Slice {
-	return a.eval.(func(*Thread) Slice)
-}
-func (a *expr) asMap() func(*Thread) Map {
-	return a.eval.(func(*Thread) Map)
-}
-func (a *expr) asMulti() func(*Thread) []Value {
-	return a.eval.(func(*Thread) []Value)
-}
-
-func (a *expr) asInterface() func(*Thread) interface{} {
-	switch sf := a.eval.(type) {
-	case func(t *Thread) bool:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) uint64:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) int64:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func() *big.Int:
-		return func(*Thread) interface{} { return sf() }
-	case func(t *Thread) float64:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func() *big.Rat:
-		return func(*Thread) interface{} { return sf() }
-	case func(t *Thread) string:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) ArrayValue:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) StructValue:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) Value:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) Func:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) Slice:
-		return func(t *Thread) interface{} { return sf(t) }
-	case func(t *Thread) Map:
-		return func(t *Thread) interface{} { return sf(t) }
-	default:
-		log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos)
-	}
-	panic("fail")
-}
-
-/*
- * Operator generators.
- */
-
-func (a *expr) genConstant(v Value) {
-	switch a.t.lit().(type) {
-	case *boolType:
-		a.eval = func(t *Thread) bool { return v.(BoolValue).Get(t) }
-	case *uintType:
-		a.eval = func(t *Thread) uint64 { return v.(UintValue).Get(t) }
-	case *intType:
-		a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) }
-	case *idealIntType:
-		val := v.(IdealIntValue).Get()
-		a.eval = func() *big.Int { return val }
-	case *floatType:
-		a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) }
-	case *idealFloatType:
-		val := v.(IdealFloatValue).Get()
-		a.eval = func() *big.Rat { return val }
-	case *stringType:
-		a.eval = func(t *Thread) string { return v.(StringValue).Get(t) }
-	case *ArrayType:
-		a.eval = func(t *Thread) ArrayValue { return v.(ArrayValue).Get(t) }
-	case *StructType:
-		a.eval = func(t *Thread) StructValue { return v.(StructValue).Get(t) }
-	case *PtrType:
-		a.eval = func(t *Thread) Value { return v.(PtrValue).Get(t) }
-	case *FuncType:
-		a.eval = func(t *Thread) Func { return v.(FuncValue).Get(t) }
-	case *SliceType:
-		a.eval = func(t *Thread) Slice { return v.(SliceValue).Get(t) }
-	case *MapType:
-		a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) }
-	default:
-		log.Panicf("unexpected constant type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genIdentOp(level, index int) {
-	a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) }
-	switch a.t.lit().(type) {
-	case *boolType:
-		a.eval = func(t *Thread) bool { return t.f.Get(level, index).(BoolValue).Get(t) }
-	case *uintType:
-		a.eval = func(t *Thread) uint64 { return t.f.Get(level, index).(UintValue).Get(t) }
-	case *intType:
-		a.eval = func(t *Thread) int64 { return t.f.Get(level, index).(IntValue).Get(t) }
-	case *floatType:
-		a.eval = func(t *Thread) float64 { return t.f.Get(level, index).(FloatValue).Get(t) }
-	case *stringType:
-		a.eval = func(t *Thread) string { return t.f.Get(level, index).(StringValue).Get(t) }
-	case *ArrayType:
-		a.eval = func(t *Thread) ArrayValue { return t.f.Get(level, index).(ArrayValue).Get(t) }
-	case *StructType:
-		a.eval = func(t *Thread) StructValue { return t.f.Get(level, index).(StructValue).Get(t) }
-	case *PtrType:
-		a.eval = func(t *Thread) Value { return t.f.Get(level, index).(PtrValue).Get(t) }
-	case *FuncType:
-		a.eval = func(t *Thread) Func { return t.f.Get(level, index).(FuncValue).Get(t) }
-	case *SliceType:
-		a.eval = func(t *Thread) Slice { return t.f.Get(level, index).(SliceValue).Get(t) }
-	case *MapType:
-		a.eval = func(t *Thread) Map { return t.f.Get(level, index).(MapValue).Get(t) }
-	default:
-		log.Panicf("unexpected identifier type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genFuncCall(call func(t *Thread) []Value) {
-	a.exec = func(t *Thread) { call(t) }
-	switch a.t.lit().(type) {
-	case *boolType:
-		a.eval = func(t *Thread) bool { return call(t)[0].(BoolValue).Get(t) }
-	case *uintType:
-		a.eval = func(t *Thread) uint64 { return call(t)[0].(UintValue).Get(t) }
-	case *intType:
-		a.eval = func(t *Thread) int64 { return call(t)[0].(IntValue).Get(t) }
-	case *floatType:
-		a.eval = func(t *Thread) float64 { return call(t)[0].(FloatValue).Get(t) }
-	case *stringType:
-		a.eval = func(t *Thread) string { return call(t)[0].(StringValue).Get(t) }
-	case *ArrayType:
-		a.eval = func(t *Thread) ArrayValue { return call(t)[0].(ArrayValue).Get(t) }
-	case *StructType:
-		a.eval = func(t *Thread) StructValue { return call(t)[0].(StructValue).Get(t) }
-	case *PtrType:
-		a.eval = func(t *Thread) Value { return call(t)[0].(PtrValue).Get(t) }
-	case *FuncType:
-		a.eval = func(t *Thread) Func { return call(t)[0].(FuncValue).Get(t) }
-	case *SliceType:
-		a.eval = func(t *Thread) Slice { return call(t)[0].(SliceValue).Get(t) }
-	case *MapType:
-		a.eval = func(t *Thread) Map { return call(t)[0].(MapValue).Get(t) }
-	case *MultiType:
-		a.eval = func(t *Thread) []Value { return call(t) }
-	default:
-		log.Panicf("unexpected result type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genValue(vf func(*Thread) Value) {
-	a.evalAddr = vf
-	switch a.t.lit().(type) {
-	case *boolType:
-		a.eval = func(t *Thread) bool { return vf(t).(BoolValue).Get(t) }
-	case *uintType:
-		a.eval = func(t *Thread) uint64 { return vf(t).(UintValue).Get(t) }
-	case *intType:
-		a.eval = func(t *Thread) int64 { return vf(t).(IntValue).Get(t) }
-	case *floatType:
-		a.eval = func(t *Thread) float64 { return vf(t).(FloatValue).Get(t) }
-	case *stringType:
-		a.eval = func(t *Thread) string { return vf(t).(StringValue).Get(t) }
-	case *ArrayType:
-		a.eval = func(t *Thread) ArrayValue { return vf(t).(ArrayValue).Get(t) }
-	case *StructType:
-		a.eval = func(t *Thread) StructValue { return vf(t).(StructValue).Get(t) }
-	case *PtrType:
-		a.eval = func(t *Thread) Value { return vf(t).(PtrValue).Get(t) }
-	case *FuncType:
-		a.eval = func(t *Thread) Func { return vf(t).(FuncValue).Get(t) }
-	case *SliceType:
-		a.eval = func(t *Thread) Slice { return vf(t).(SliceValue).Get(t) }
-	case *MapType:
-		a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) }
-	default:
-		log.Panicf("unexpected result type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genUnaryOpNeg(v *expr) {
-	switch a.t.lit().(type) {
-	case *uintType:
-		vf := v.asUint()
-		a.eval = func(t *Thread) uint64 { v := vf(t); return -v }
-	case *intType:
-		vf := v.asInt()
-		a.eval = func(t *Thread) int64 { v := vf(t); return -v }
-	case *idealIntType:
-		val := v.asIdealInt()()
-		val.Neg(val)
-		a.eval = func() *big.Int { return val }
-	case *floatType:
-		vf := v.asFloat()
-		a.eval = func(t *Thread) float64 { v := vf(t); return -v }
-	case *idealFloatType:
-		val := v.asIdealFloat()()
-		val.Neg(val)
-		a.eval = func() *big.Rat { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genUnaryOpNot(v *expr) {
-	switch a.t.lit().(type) {
-	case *boolType:
-		vf := v.asBool()
-		a.eval = func(t *Thread) bool { v := vf(t); return !v }
-	default:
-		log.Panicf("unexpected type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genUnaryOpXor(v *expr) {
-	switch a.t.lit().(type) {
-	case *uintType:
-		vf := v.asUint()
-		a.eval = func(t *Thread) uint64 { v := vf(t); return ^v }
-	case *intType:
-		vf := v.asInt()
-		a.eval = func(t *Thread) int64 { v := vf(t); return ^v }
-	case *idealIntType:
-		val := v.asIdealInt()()
-		val.Not(val)
-		a.eval = func() *big.Int { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpLogAnd(l, r *expr) {
-	lf := l.asBool()
-	rf := r.asBool()
-	a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
-}
-
-func (a *expr) genBinOpLogOr(l, r *expr) {
-	lf := l.asBool()
-	rf := r.asBool()
-	a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
-}
-
-func (a *expr) genBinOpAdd(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l + r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l + r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l + r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l + r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l + r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l + r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l + r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l + r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l + r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l + r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Add(l, r)
-		a.eval = func() *big.Int { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		switch t.Bits {
-		case 32:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				ret = l + r
-				return float64(float32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				ret = l + r
-				return float64(float64(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Add(l, r)
-		a.eval = func() *big.Rat { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) string {
-			l, r := lf(t), rf(t)
-			return l + r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpSub(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l - r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l - r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l - r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l - r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l - r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l - r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l - r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l - r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l - r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l - r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Sub(l, r)
-		a.eval = func() *big.Int { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		switch t.Bits {
-		case 32:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				ret = l - r
-				return float64(float32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				ret = l - r
-				return float64(float64(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Sub(l, r)
-		a.eval = func() *big.Rat { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpMul(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l * r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l * r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l * r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l * r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l * r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l * r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l * r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l * r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l * r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l * r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Mul(l, r)
-		a.eval = func() *big.Int { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		switch t.Bits {
-		case 32:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				ret = l * r
-				return float64(float32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				ret = l * r
-				return float64(float64(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Mul(l, r)
-		a.eval = func() *big.Rat { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpQuo(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Quo(l, r)
-		a.eval = func() *big.Int { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		switch t.Bits {
-		case 32:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return float64(float32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) float64 {
-				l, r := lf(t), rf(t)
-				var ret float64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l / r
-				return float64(float64(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Quo(l, r)
-		a.eval = func() *big.Rat { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpRem(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				if r == 0 {
-					t.Abort(DivByZeroError{})
-				}
-				ret = l % r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Rem(l, r)
-		a.eval = func() *big.Int { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpAnd(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l & r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l & r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l & r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l & r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l & r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l & r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l & r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l & r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l & r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l & r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.And(l, r)
-		a.eval = func() *big.Int { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpOr(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l | r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l | r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l | r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l | r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l | r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l | r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l | r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l | r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l | r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l | r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Or(l, r)
-		a.eval = func() *big.Int { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpXor(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l ^ r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l ^ r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l ^ r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l ^ r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l ^ r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l ^ r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l ^ r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l ^ r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l ^ r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l ^ r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Xor(l, r)
-		a.eval = func() *big.Int { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpAndNot(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l &^ r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l &^ r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l &^ r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l &^ r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l &^ r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l &^ r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l &^ r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l &^ r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l &^ r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l &^ r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.AndNot(l, r)
-		a.eval = func() *big.Int { return val }
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpShl(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l << r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l << r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l << r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l << r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l << r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l << r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l << r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l << r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l << r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l << r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpShr(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l >> r
-				return uint64(uint8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l >> r
-				return uint64(uint16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l >> r
-				return uint64(uint32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l >> r
-				return uint64(uint64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) uint64 {
-				l, r := lf(t), rf(t)
-				var ret uint64
-				ret = l >> r
-				return uint64(uint(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asUint()
-		switch t.Bits {
-		case 8:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l >> r
-				return int64(int8(ret))
-			}
-		case 16:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l >> r
-				return int64(int16(ret))
-			}
-		case 32:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l >> r
-				return int64(int32(ret))
-			}
-		case 64:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l >> r
-				return int64(int64(ret))
-			}
-		case 0:
-			a.eval = func(t *Thread) int64 {
-				l, r := lf(t), rf(t)
-				var ret int64
-				ret = l >> r
-				return int64(int(ret))
-			}
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpLss(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l < r
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l < r
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Cmp(r) < 0
-		a.eval = func(t *Thread) bool { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l < r
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Cmp(r) < 0
-		a.eval = func(t *Thread) bool { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l < r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpGtr(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l > r
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l > r
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Cmp(r) > 0
-		a.eval = func(t *Thread) bool { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l > r
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Cmp(r) > 0
-		a.eval = func(t *Thread) bool { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l > r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpLeq(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l <= r
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l <= r
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Cmp(r) <= 0
-		a.eval = func(t *Thread) bool { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l <= r
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Cmp(r) <= 0
-		a.eval = func(t *Thread) bool { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l <= r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpGeq(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l >= r
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l >= r
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Cmp(r) >= 0
-		a.eval = func(t *Thread) bool { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l >= r
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Cmp(r) >= 0
-		a.eval = func(t *Thread) bool { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l >= r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpEql(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *boolType:
-		lf := l.asBool()
-		rf := r.asBool()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Cmp(r) == 0
-		a.eval = func(t *Thread) bool { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Cmp(r) == 0
-		a.eval = func(t *Thread) bool { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *PtrType:
-		lf := l.asPtr()
-		rf := r.asPtr()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *FuncType:
-		lf := l.asFunc()
-		rf := r.asFunc()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	case *MapType:
-		lf := l.asMap()
-		rf := r.asMap()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l == r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func (a *expr) genBinOpNeq(l, r *expr) {
-	switch t := l.t.lit().(type) {
-	case *boolType:
-		lf := l.asBool()
-		rf := r.asBool()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *uintType:
-		lf := l.asUint()
-		rf := r.asUint()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *intType:
-		lf := l.asInt()
-		rf := r.asInt()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *idealIntType:
-		l := l.asIdealInt()()
-		r := r.asIdealInt()()
-		val := l.Cmp(r) != 0
-		a.eval = func(t *Thread) bool { return val }
-	case *floatType:
-		lf := l.asFloat()
-		rf := r.asFloat()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *idealFloatType:
-		l := l.asIdealFloat()()
-		r := r.asIdealFloat()()
-		val := l.Cmp(r) != 0
-		a.eval = func(t *Thread) bool { return val }
-	case *stringType:
-		lf := l.asString()
-		rf := r.asString()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *PtrType:
-		lf := l.asPtr()
-		rf := r.asPtr()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *FuncType:
-		lf := l.asFunc()
-		rf := r.asFunc()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	case *MapType:
-		lf := l.asMap()
-		rf := r.asMap()
-		a.eval = func(t *Thread) bool {
-			l, r := lf(t), rf(t)
-			return l != r
-		}
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-func genAssign(lt Type, r *expr) func(lv Value, t *Thread) {
-	switch lt.lit().(type) {
-	case *boolType:
-		rf := r.asBool()
-		return func(lv Value, t *Thread) { lv.(BoolValue).Set(t, rf(t)) }
-	case *uintType:
-		rf := r.asUint()
-		return func(lv Value, t *Thread) { lv.(UintValue).Set(t, rf(t)) }
-	case *intType:
-		rf := r.asInt()
-		return func(lv Value, t *Thread) { lv.(IntValue).Set(t, rf(t)) }
-	case *floatType:
-		rf := r.asFloat()
-		return func(lv Value, t *Thread) { lv.(FloatValue).Set(t, rf(t)) }
-	case *stringType:
-		rf := r.asString()
-		return func(lv Value, t *Thread) { lv.(StringValue).Set(t, rf(t)) }
-	case *ArrayType:
-		rf := r.asArray()
-		return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
-	case *StructType:
-		rf := r.asStruct()
-		return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
-	case *PtrType:
-		rf := r.asPtr()
-		return func(lv Value, t *Thread) { lv.(PtrValue).Set(t, rf(t)) }
-	case *FuncType:
-		rf := r.asFunc()
-		return func(lv Value, t *Thread) { lv.(FuncValue).Set(t, rf(t)) }
-	case *SliceType:
-		rf := r.asSlice()
-		return func(lv Value, t *Thread) { lv.(SliceValue).Set(t, rf(t)) }
-	case *MapType:
-		rf := r.asMap()
-		return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) }
-	default:
-		log.Panicf("unexpected left operand type %v at %v", lt, r.pos)
-	}
-	panic("fail")
-}
diff --git a/src/pkg/exp/eval/expr_test.go b/src/pkg/exp/eval/expr_test.go
deleted file mode 100644
index 0dbce43..0000000
--- a/src/pkg/exp/eval/expr_test.go
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"big"
-	"testing"
-)
-
-var undefined = "undefined"
-var typeAsExpr = "type .* used as expression"
-var badCharLit = "character literal"
-var unknownEscape = "unknown escape sequence"
-var opTypes = "illegal (operand|argument) type|cannot index into"
-var badAddrOf = "cannot take the address"
-var constantTruncated = "constant [^ ]* truncated"
-var constantUnderflows = "constant [^ ]* underflows"
-var constantOverflows = "constant [^ ]* overflows"
-var implLimit = "implementation limit"
-var mustBeUnsigned = "must be unsigned"
-var divByZero = "divide by zero"
-
-var hugeInteger = new(big.Int).Lsh(idealOne, 64)
-
-var exprTests = []test{
-	Val("i", 1),
-	CErr("zzz", undefined),
-	// TODO(austin) Test variable in constant context
-	//CErr("t", typeAsExpr),
-
-	Val("'a'", big.NewInt('a')),
-	Val("'\\uffff'", big.NewInt('\uffff')),
-	Val("'\\n'", big.NewInt('\n')),
-	CErr("''+x", badCharLit),
-	// Produces two parse errors
-	//CErr("'''", ""),
-	CErr("'\n'", badCharLit),
-	CErr("'\\z'", unknownEscape),
-	CErr("'ab'", badCharLit),
-
-	Val("1.0", big.NewRat(1, 1)),
-	Val("1.", big.NewRat(1, 1)),
-	Val(".1", big.NewRat(1, 10)),
-	Val("1e2", big.NewRat(100, 1)),
-
-	Val("\"abc\"", "abc"),
-	Val("\"\"", ""),
-	Val("\"\\n\\\"\"", "\n\""),
-	CErr("\"\\z\"", unknownEscape),
-	CErr("\"abc", "string not terminated"),
-
-	Val("(i)", 1),
-
-	Val("ai[0]", 1),
-	Val("(&ai)[0]", 1),
-	Val("ai[1]", 2),
-	Val("ai[i]", 2),
-	Val("ai[u]", 2),
-	CErr("ai[f]", opTypes),
-	CErr("ai[0][0]", opTypes),
-	CErr("ai[2]", "index 2 exceeds"),
-	CErr("ai[1+1]", "index 2 exceeds"),
-	CErr("ai[-1]", "negative index"),
-	RErr("ai[i+i]", "index 2 exceeds"),
-	RErr("ai[-i]", "negative index"),
-	CErr("i[0]", opTypes),
-	CErr("f[0]", opTypes),
-
-	Val("aai[0][0]", 1),
-	Val("aai[1][1]", 4),
-	CErr("aai[2][0]", "index 2 exceeds"),
-	CErr("aai[0][2]", "index 2 exceeds"),
-
-	Val("sli[0]", 1),
-	Val("sli[1]", 2),
-	CErr("sli[-1]", "negative index"),
-	RErr("sli[-i]", "negative index"),
-	RErr("sli[2]", "index 2 exceeds"),
-
-	Val("s[0]", uint8('a')),
-	Val("s[1]", uint8('b')),
-	CErr("s[-1]", "negative index"),
-	RErr("s[-i]", "negative index"),
-	RErr("s[3]", "index 3 exceeds"),
-
-	Val("ai[0:2]", vslice{varray{1, 2}, 2, 2}),
-	Val("ai[0:1]", vslice{varray{1, 2}, 1, 2}),
-	Val("ai[0:]", vslice{varray{1, 2}, 2, 2}),
-	Val("ai[i:]", vslice{varray{2}, 1, 1}),
-
-	Val("sli[0:2]", vslice{varray{1, 2, 3}, 2, 3}),
-	Val("sli[0:i]", vslice{varray{1, 2, 3}, 1, 3}),
-	Val("sli[1:]", vslice{varray{2, 3}, 1, 2}),
-
-	CErr("1(2)", "cannot call"),
-	CErr("fn(1,2)", "too many"),
-	CErr("fn()", "not enough"),
-	CErr("fn(true)", opTypes),
-	CErr("fn(true)", "function call"),
-	// Single argument functions don't say which argument.
-	//CErr("fn(true)", "argument 1"),
-	Val("fn(1)", 2),
-	Val("fn(1.0)", 2),
-	CErr("fn(1.5)", constantTruncated),
-	Val("fn(i)", 2),
-	CErr("fn(u)", opTypes),
-
-	CErr("void()+2", opTypes),
-	CErr("oneTwo()+2", opTypes),
-
-	Val("cap(ai)", 2),
-	Val("cap(&ai)", 2),
-	Val("cap(aai)", 2),
-	Val("cap(sli)", 3),
-	CErr("cap(0)", opTypes),
-	CErr("cap(i)", opTypes),
-	CErr("cap(s)", opTypes),
-
-	Val("len(s)", 3),
-	Val("len(ai)", 2),
-	Val("len(&ai)", 2),
-	Val("len(ai[0:])", 2),
-	Val("len(ai[1:])", 1),
-	Val("len(ai[2:])", 0),
-	Val("len(aai)", 2),
-	Val("len(sli)", 2),
-	Val("len(sli[0:])", 2),
-	Val("len(sli[1:])", 1),
-	Val("len(sli[2:])", 0),
-	// TODO(austin) Test len of map
-	CErr("len(0)", opTypes),
-	CErr("len(i)", opTypes),
-
-	CErr("*i", opTypes),
-	Val("*&i", 1),
-	Val("*&(i)", 1),
-	CErr("&1", badAddrOf),
-	CErr("&c", badAddrOf),
-	Val("*(&ai[0])", 1),
-
-	Val("+1", big.NewInt(+1)),
-	Val("+1.0", big.NewRat(1, 1)),
-	Val("01.5", big.NewRat(15, 10)),
-	CErr("+\"x\"", opTypes),
-
-	Val("-42", big.NewInt(-42)),
-	Val("-i", -1),
-	Val("-f", -1.0),
-	// 6g bug?
-	//Val("-(f-1)", -0.0),
-	CErr("-\"x\"", opTypes),
-
-	// TODO(austin) Test unary !
-
-	Val("^2", big.NewInt(^2)),
-	Val("^(-2)", big.NewInt(^(-2))),
-	CErr("^2.0", opTypes),
-	CErr("^2.5", opTypes),
-	Val("^i", ^1),
-	Val("^u", ^uint(1)),
-	CErr("^f", opTypes),
-
-	Val("1+i", 2),
-	Val("1+u", uint(2)),
-	Val("3.0+i", 4),
-	Val("1+1", big.NewInt(2)),
-	Val("f+f", 2.0),
-	Val("1+f", 2.0),
-	Val("1.0+1", big.NewRat(2, 1)),
-	Val("\"abc\" + \"def\"", "abcdef"),
-	CErr("i+u", opTypes),
-	CErr("-1+u", constantUnderflows),
-	// TODO(austin) Test named types
-
-	Val("2-1", big.NewInt(1)),
-	Val("2.0-1", big.NewRat(1, 1)),
-	Val("f-2", -1.0),
-	Val("-0.0", big.NewRat(0, 1)),
-	Val("2*2", big.NewInt(4)),
-	Val("2*i", 2),
-	Val("3/2", big.NewInt(1)),
-	Val("3/i", 3),
-	CErr("1/0", divByZero),
-	CErr("1.0/0", divByZero),
-	RErr("i/0", divByZero),
-	Val("3%2", big.NewInt(1)),
-	Val("i%2", 1),
-	CErr("3%0", divByZero),
-	CErr("3.0%0", opTypes),
-	RErr("i%0", divByZero),
-
-	// Examples from "Arithmetic operators"
-	Val("5/3", big.NewInt(1)),
-	Val("(i+4)/(i+2)", 1),
-	Val("5%3", big.NewInt(2)),
-	Val("(i+4)%(i+2)", 2),
-	Val("-5/3", big.NewInt(-1)),
-	Val("(i-6)/(i+2)", -1),
-	Val("-5%3", big.NewInt(-2)),
-	Val("(i-6)%(i+2)", -2),
-	Val("5/-3", big.NewInt(-1)),
-	Val("(i+4)/(i-4)", -1),
-	Val("5%-3", big.NewInt(2)),
-	Val("(i+4)%(i-4)", 2),
-	Val("-5/-3", big.NewInt(1)),
-	Val("(i-6)/(i-4)", 1),
-	Val("-5%-3", big.NewInt(-2)),
-	Val("(i-6)%(i-4)", -2),
-
-	// Examples from "Arithmetic operators"
-	Val("11/4", big.NewInt(2)),
-	Val("(i+10)/4", 2),
-	Val("11%4", big.NewInt(3)),
-	Val("(i+10)%4", 3),
-	Val("11>>2", big.NewInt(2)),
-	Val("(i+10)>>2", 2),
-	Val("11&3", big.NewInt(3)),
-	Val("(i+10)&3", 3),
-	Val("-11/4", big.NewInt(-2)),
-	Val("(i-12)/4", -2),
-	Val("-11%4", big.NewInt(-3)),
-	Val("(i-12)%4", -3),
-	Val("-11>>2", big.NewInt(-3)),
-	Val("(i-12)>>2", -3),
-	Val("-11&3", big.NewInt(1)),
-	Val("(i-12)&3", 1),
-
-	// TODO(austin) Test bit ops
-
-	// For shift, we try nearly every combination of positive
-	// ideal int, negative ideal int, big ideal int, ideal
-	// fractional float, ideal non-fractional float, int, uint,
-	// and float.
-	Val("2<<2", big.NewInt(2<<2)),
-	CErr("2<<(-1)", constantUnderflows),
-	CErr("2<<0x10000000000000000", constantOverflows),
-	CErr("2<<2.5", constantTruncated),
-	Val("2<<2.0", big.NewInt(2<<2.0)),
-	CErr("2<<i", mustBeUnsigned),
-	Val("2<<u", 2<<1),
-	CErr("2<<f", opTypes),
-
-	Val("-2<<2", big.NewInt(-2<<2)),
-	CErr("-2<<(-1)", constantUnderflows),
-	CErr("-2<<0x10000000000000000", constantOverflows),
-	CErr("-2<<2.5", constantTruncated),
-	Val("-2<<2.0", big.NewInt(-2<<2.0)),
-	CErr("-2<<i", mustBeUnsigned),
-	Val("-2<<u", -2<<1),
-	CErr("-2<<f", opTypes),
-
-	Val("0x10000000000000000<<2", new(big.Int).Lsh(hugeInteger, 2)),
-	CErr("0x10000000000000000<<(-1)", constantUnderflows),
-	CErr("0x10000000000000000<<0x10000000000000000", constantOverflows),
-	CErr("0x10000000000000000<<2.5", constantTruncated),
-	Val("0x10000000000000000<<2.0", new(big.Int).Lsh(hugeInteger, 2)),
-	CErr("0x10000000000000000<<i", mustBeUnsigned),
-	CErr("0x10000000000000000<<u", constantOverflows),
-	CErr("0x10000000000000000<<f", opTypes),
-
-	CErr("2.5<<2", opTypes),
-	CErr("2.0<<2", opTypes),
-
-	Val("i<<2", 1<<2),
-	CErr("i<<(-1)", constantUnderflows),
-	CErr("i<<0x10000000000000000", constantOverflows),
-	CErr("i<<2.5", constantTruncated),
-	Val("i<<2.0", 1<<2),
-	CErr("i<<i", mustBeUnsigned),
-	Val("i<<u", 1<<1),
-	CErr("i<<f", opTypes),
-	Val("i<<u", 1<<1),
-
-	Val("u<<2", uint(1<<2)),
-	CErr("u<<(-1)", constantUnderflows),
-	CErr("u<<0x10000000000000000", constantOverflows),
-	CErr("u<<2.5", constantTruncated),
-	Val("u<<2.0", uint(1<<2)),
-	CErr("u<<i", mustBeUnsigned),
-	Val("u<<u", uint(1<<1)),
-	CErr("u<<f", opTypes),
-	Val("u<<u", uint(1<<1)),
-
-	CErr("f<<2", opTypes),
-
-	// <, <=, >, >=
-	Val("1<2", 1 < 2),
-	Val("1<=2", 1 <= 2),
-	Val("2<=2", 2 <= 2),
-	Val("1>2", 1 > 2),
-	Val("1>=2", 1 >= 2),
-	Val("2>=2", 2 >= 2),
-
-	Val("i<2", 1 < 2),
-	Val("i<=2", 1 <= 2),
-	Val("i+1<=2", 2 <= 2),
-	Val("i>2", 1 > 2),
-	Val("i>=2", 1 >= 2),
-	Val("i+1>=2", 2 >= 2),
-
-	Val("u<2", 1 < 2),
-	Val("f<2", 1 < 2),
-
-	Val("s<\"b\"", true),
-	Val("s<\"a\"", false),
-	Val("s<=\"abc\"", true),
-	Val("s>\"aa\"", true),
-	Val("s>\"ac\"", false),
-	Val("s>=\"abc\"", true),
-
-	CErr("i<u", opTypes),
-	CErr("i<f", opTypes),
-	CErr("i<s", opTypes),
-	CErr("&i<&i", opTypes),
-	CErr("ai<ai", opTypes),
-
-	// ==, !=
-	Val("1==1", true),
-	Val("1!=1", false),
-	Val("1==2", false),
-	Val("1!=2", true),
-
-	Val("1.0==1", true),
-	Val("1.5==1", false),
-
-	Val("i==1", true),
-	Val("i!=1", false),
-	Val("i==2", false),
-	Val("i!=2", true),
-
-	Val("u==1", true),
-	Val("f==1", true),
-
-	Val("s==\"abc\"", true),
-	Val("s!=\"abc\"", false),
-	Val("s==\"abcd\"", false),
-	Val("s!=\"abcd\"", true),
-
-	Val("&i==&i", true),
-	Val("&i==&i2", false),
-
-	Val("fn==fn", true),
-	Val("fn==func(int)int{return 0}", false),
-
-	CErr("i==u", opTypes),
-	CErr("i==f", opTypes),
-	CErr("&i==&f", opTypes),
-	CErr("ai==ai", opTypes),
-	CErr("t==t", opTypes),
-	CErr("fn==oneTwo", opTypes),
-}
-
-func TestExpr(t *testing.T) { runTests(t, "exprTests", exprTests) }
diff --git a/src/pkg/exp/eval/func.go b/src/pkg/exp/eval/func.go
deleted file mode 100644
index cb1b579..0000000
--- a/src/pkg/exp/eval/func.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import "os"
-
-/*
- * Virtual machine
- */
-
-type Thread struct {
-	abort chan os.Error
-	pc    uint
-	// The execution frame of this function.  This remains the
-	// same throughout a function invocation.
-	f *Frame
-}
-
-type code []func(*Thread)
-
-func (i code) exec(t *Thread) {
-	opc := t.pc
-	t.pc = 0
-	l := uint(len(i))
-	for t.pc < l {
-		pc := t.pc
-		t.pc++
-		i[pc](t)
-	}
-	t.pc = opc
-}
-
-/*
- * Code buffer
- */
-
-type codeBuf struct {
-	instrs code
-}
-
-func newCodeBuf() *codeBuf { return &codeBuf{make(code, 0, 16)} }
-
-func (b *codeBuf) push(instr func(*Thread)) {
-	b.instrs = append(b.instrs, instr)
-}
-
-func (b *codeBuf) nextPC() uint { return uint(len(b.instrs)) }
-
-func (b *codeBuf) get() code {
-	// Freeze this buffer into an array of exactly the right size
-	a := make(code, len(b.instrs))
-	copy(a, b.instrs)
-	return code(a)
-}
-
-/*
- * User-defined functions
- */
-
-type evalFunc struct {
-	outer     *Frame
-	frameSize int
-	code      code
-}
-
-func (f *evalFunc) NewFrame() *Frame { return f.outer.child(f.frameSize) }
-
-func (f *evalFunc) Call(t *Thread) { f.code.exec(t) }
diff --git a/src/pkg/exp/eval/gen.go b/src/pkg/exp/eval/gen.go
deleted file mode 100644
index 1e00bdc..0000000
--- a/src/pkg/exp/eval/gen.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-// generate operator implementations
-
-import (
-	"log"
-	"os"
-	"template"
-)
-
-type Op struct {
-	Name        string
-	Expr        string
-	Body        string // overrides Expr
-	ConstExpr   string
-	AsRightName string
-	ReturnType  string
-	Types       []*Type
-}
-
-type Size struct {
-	Bits  int
-	Sized string
-}
-
-type Type struct {
-	Repr      string
-	Value     string
-	Native    string
-	As        string
-	IsIdeal   bool
-	HasAssign bool
-	Sizes     []Size
-}
-
-var (
-	boolType = &Type{Repr: "*boolType", Value: "BoolValue", Native: "bool", As: "asBool"}
-	uintType = &Type{Repr: "*uintType", Value: "UintValue", Native: "uint64", As: "asUint",
-		Sizes: []Size{{8, "uint8"}, {16, "uint16"}, {32, "uint32"}, {64, "uint64"}, {0, "uint"}},
-	}
-	intType = &Type{Repr: "*intType", Value: "IntValue", Native: "int64", As: "asInt",
-		Sizes: []Size{{8, "int8"}, {16, "int16"}, {32, "int32"}, {64, "int64"}, {0, "int"}},
-	}
-	idealIntType = &Type{Repr: "*idealIntType", Value: "IdealIntValue", Native: "*big.Int", As: "asIdealInt", IsIdeal: true}
-	floatType    = &Type{Repr: "*floatType", Value: "FloatValue", Native: "float64", As: "asFloat",
-		Sizes: []Size{{32, "float32"}, {64, "float64"}},
-	}
-	idealFloatType = &Type{Repr: "*idealFloatType", Value: "IdealFloatValue", Native: "*big.Rat", As: "asIdealFloat", IsIdeal: true}
-	stringType     = &Type{Repr: "*stringType", Value: "StringValue", Native: "string", As: "asString"}
-	arrayType      = &Type{Repr: "*ArrayType", Value: "ArrayValue", Native: "ArrayValue", As: "asArray", HasAssign: true}
-	structType     = &Type{Repr: "*StructType", Value: "StructValue", Native: "StructValue", As: "asStruct", HasAssign: true}
-	ptrType        = &Type{Repr: "*PtrType", Value: "PtrValue", Native: "Value", As: "asPtr"}
-	funcType       = &Type{Repr: "*FuncType", Value: "FuncValue", Native: "Func", As: "asFunc"}
-	sliceType      = &Type{Repr: "*SliceType", Value: "SliceValue", Native: "Slice", As: "asSlice"}
-	mapType        = &Type{Repr: "*MapType", Value: "MapValue", Native: "Map", As: "asMap"}
-
-	all = []*Type{
-		boolType,
-		uintType,
-		intType,
-		idealIntType,
-		floatType,
-		idealFloatType,
-		stringType,
-		arrayType,
-		structType,
-		ptrType,
-		funcType,
-		sliceType,
-		mapType,
-	}
-	bools     = all[0:1]
-	integers  = all[1:4]
-	shiftable = all[1:3]
-	numbers   = all[1:6]
-	addable   = all[1:7]
-	cmpable   = []*Type{
-		boolType,
-		uintType,
-		intType,
-		idealIntType,
-		floatType,
-		idealFloatType,
-		stringType,
-		ptrType,
-		funcType,
-		mapType,
-	}
-)
-
-var unOps = []Op{
-	{Name: "Neg", Expr: "-v", ConstExpr: "val.Neg(val)", Types: numbers},
-	{Name: "Not", Expr: "!v", Types: bools},
-	{Name: "Xor", Expr: "^v", ConstExpr: "val.Not(val)", Types: integers},
-}
-
-var binOps = []Op{
-	{Name: "Add", Expr: "l + r", ConstExpr: "l.Add(l, r)", Types: addable},
-	{Name: "Sub", Expr: "l - r", ConstExpr: "l.Sub(l, r)", Types: numbers},
-	{Name: "Mul", Expr: "l * r", ConstExpr: "l.Mul(l, r)", Types: numbers},
-	{Name: "Quo",
-		Body:      "if r == 0 { t.Abort(DivByZeroError{}) }; ret =  l / r",
-		ConstExpr: "l.Quo(l, r)",
-		Types:     numbers,
-	},
-	{Name: "Rem",
-		Body:      "if r == 0 { t.Abort(DivByZeroError{}) }; ret = l % r",
-		ConstExpr: "l.Rem(l, r)",
-		Types:     integers,
-	},
-	{Name: "And", Expr: "l & r", ConstExpr: "l.And(l, r)", Types: integers},
-	{Name: "Or", Expr: "l | r", ConstExpr: "l.Or(l, r)", Types: integers},
-	{Name: "Xor", Expr: "l ^ r", ConstExpr: "l.Xor(l, r)", Types: integers},
-	{Name: "AndNot", Expr: "l &^ r", ConstExpr: "l.AndNot(l, r)", Types: integers},
-	{Name: "Shl", Expr: "l << r", ConstExpr: "l.Lsh(l, uint(r.Value()))",
-		AsRightName: "asUint", Types: shiftable,
-	},
-	{Name: "Shr", Expr: "l >> r", ConstExpr: "new(big.Int).Rsh(l, uint(r.Value()))",
-		AsRightName: "asUint", Types: shiftable,
-	},
-	{Name: "Lss", Expr: "l < r", ConstExpr: "l.Cmp(r) < 0", ReturnType: "bool", Types: addable},
-	{Name: "Gtr", Expr: "l > r", ConstExpr: "l.Cmp(r) > 0", ReturnType: "bool", Types: addable},
-	{Name: "Leq", Expr: "l <= r", ConstExpr: "l.Cmp(r) <= 0", ReturnType: "bool", Types: addable},
-	{Name: "Geq", Expr: "l >= r", ConstExpr: "l.Cmp(r) >= 0", ReturnType: "bool", Types: addable},
-	{Name: "Eql", Expr: "l == r", ConstExpr: "l.Cmp(r) == 0", ReturnType: "bool", Types: cmpable},
-	{Name: "Neq", Expr: "l != r", ConstExpr: "l.Cmp(r) != 0", ReturnType: "bool", Types: cmpable},
-}
-
-type Data struct {
-	UnaryOps  []Op
-	BinaryOps []Op
-	Types     []*Type
-}
-
-var data = Data{
-	unOps,
-	binOps,
-	all,
-}
-
-const templateStr = `
-// This file is machine generated by gen.go.
-// 6g gen.go && 6l gen.6 && ./6.out >expr1.go
-
-package eval
-
-import (
-	"big"
-	"log"
-)
-
-/*
- * "As" functions.  These retrieve evaluator functions from an
- * expr, panicking if the requested evaluator has the wrong type.
- */
-«.repeated section Types»
-«.section IsIdeal»
-func (a *expr) «As»() (func() «Native») {
-	return a.eval.(func()(«Native»))
-}
-«.or»
-func (a *expr) «As»() (func(*Thread) «Native») {
-	return a.eval.(func(*Thread)(«Native»))
-}
-«.end»
-«.end»
-func (a *expr) asMulti() (func(*Thread) []Value) {
-	return a.eval.(func(*Thread)[]Value)
-}
-
-func (a *expr) asInterface() (func(*Thread) interface{}) {
-	switch sf := a.eval.(type) {
-«.repeated section Types»
-«.section IsIdeal»
-	case func()«Native»:
-		return func(*Thread) interface{} { return sf() }
-«.or»
-	case func(t *Thread)«Native»:
-		return func(t *Thread) interface{} { return sf(t) }
-«.end»
-«.end»
-	default:
-		log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos)
-	}
-	panic("fail")
-}
-
-/*
- * Operator generators.
- */
-
-func (a *expr) genConstant(v Value) {
-	switch a.t.lit().(type) {
-«.repeated section Types»
-	case «Repr»:
-«.section IsIdeal»
-		val := v.(«Value»).Get()
-		a.eval = func() «Native» { return val }
-«.or»
-		a.eval = func(t *Thread) «Native» { return v.(«Value»).Get(t) }
-«.end»
-«.end»
-	default:
-		log.Panicf("unexpected constant type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genIdentOp(level, index int) {
-	a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) }
-	switch a.t.lit().(type) {
-«.repeated section Types»
-«.section IsIdeal»
-«.or»
-	case «Repr»:
-		a.eval = func(t *Thread) «Native» { return t.f.Get(level, index).(«Value»).Get(t) }
-«.end»
-«.end»
-	default:
-		log.Panicf("unexpected identifier type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genFuncCall(call func(t *Thread) []Value) {
-	a.exec = func(t *Thread) { call(t)}
-	switch a.t.lit().(type) {
-«.repeated section Types»
-«.section IsIdeal»
-«.or»
-	case «Repr»:
-		a.eval = func(t *Thread) «Native» { return call(t)[0].(«Value»).Get(t) }
-«.end»
-«.end»
-	case *MultiType:
-		a.eval = func(t *Thread) []Value { return call(t) }
-	default:
-		log.Panicf("unexpected result type %v at %v", a.t, a.pos)
-	}
-}
-
-func (a *expr) genValue(vf func(*Thread) Value) {
-	a.evalAddr = vf
-	switch a.t.lit().(type) {
-«.repeated section Types»
-«.section IsIdeal»
-«.or»
-	case «Repr»:
-		a.eval = func(t *Thread) «Native» { return vf(t).(«Value»).Get(t) }
-«.end»
-«.end»
-	default:
-		log.Panicf("unexpected result type %v at %v", a.t, a.pos)
-	}
-}
-
-«.repeated section UnaryOps»
-func (a *expr) genUnaryOp«Name»(v *expr) {
-	switch a.t.lit().(type) {
-«.repeated section Types»
-	case «Repr»:
-«.section IsIdeal»
-		val := v.«As»()()
-		«ConstExpr»
-		a.eval = func() «Native» { return val }
-«.or»
-		vf := v.«As»()
-		a.eval = func(t *Thread) «Native» { v := vf(t); return «Expr» }
-«.end»
-«.end»
-	default:
-		log.Panicf("unexpected type %v at %v", a.t, a.pos)
-	}
-}
-
-«.end»
-func (a *expr) genBinOpLogAnd(l, r *expr) {
-	lf := l.asBool()
-	rf := r.asBool()
-	a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
-}
-
-func (a *expr) genBinOpLogOr(l, r *expr) {
-	lf := l.asBool()
-	rf := r.asBool()
-	a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
-}
-
-«.repeated section BinaryOps»
-func (a *expr) genBinOp«Name»(l, r *expr) {
-	switch t := l.t.lit().(type) {
-«.repeated section Types»
-	case «Repr»:
-	«.section IsIdeal»
-		l := l.«As»()()
-		r := r.«As»()()
-		val := «ConstExpr»
-		«.section ReturnType»
-		a.eval = func(t *Thread) «ReturnType» { return val }
-		«.or»
-		a.eval = func() «Native» { return val }
-		«.end»
-	«.or»
-		lf := l.«As»()
-		rf := r.«.section AsRightName»«@»«.or»«As»«.end»()
-		«.section ReturnType»
-		a.eval = func(t *Thread) «@» {
-			l, r := lf(t), rf(t)
-			return «Expr»
-		}
-		«.or»
-		«.section Sizes»
-		switch t.Bits {
-		«.repeated section @»
-		case «Bits»:
-			a.eval = func(t *Thread) «Native» {
-				l, r := lf(t), rf(t)
-				var ret «Native»
-				«.section Body»
-				«Body»
-				«.or»
-				ret = «Expr»
-				«.end»
-				return «Native»(«Sized»(ret))
-			}
-		«.end»
-		default:
-			log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
-		}
-		«.or»
-		a.eval = func(t *Thread) «Native» {
-			l, r := lf(t), rf(t)
-			return «Expr»
-		}
-		«.end»
-		«.end»
-	«.end»
-	«.end»
-	default:
-		log.Panicf("unexpected type %v at %v", l.t, a.pos)
-	}
-}
-
-«.end»
-func genAssign(lt Type, r *expr) (func(lv Value, t *Thread)) {
-	switch lt.lit().(type) {
-«.repeated section Types»
-«.section IsIdeal»
-«.or»
-	case «Repr»:
-		rf := r.«As»()
-		return func(lv Value, t *Thread) { «.section HasAssign»lv.Assign(t, rf(t))«.or»lv.(«Value»).Set(t, rf(t))«.end» }
-«.end»
-«.end»
-	default:
-		log.Panicf("unexpected left operand type %v at %v", lt, r.pos)
-	}
-	panic("fail")
-}
-`
-
-func main() {
-	t := template.New(nil)
-	t.SetDelims("«", "»")
-	err := t.Parse(templateStr)
-	if err != nil {
-		log.Fatal(err)
-	}
-	err = t.Execute(os.Stdout, data)
-	if err != nil {
-		log.Fatal(err)
-	}
-}
diff --git a/src/pkg/exp/eval/main.go b/src/pkg/exp/eval/main.go
deleted file mode 100644
index d87e8f2..0000000
--- a/src/pkg/exp/eval/main.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
-	"bufio"
-	"exp/eval"
-	"flag"
-	"go/parser"
-	"go/scanner"
-	"go/token"
-	"io/ioutil"
-	"os"
-)
-
-var fset = token.NewFileSet()
-var filename = flag.String("f", "", "file to run")
-
-func main() {
-	flag.Parse()
-	w := eval.NewWorld()
-	if *filename != "" {
-		data, err := ioutil.ReadFile(*filename)
-		if err != nil {
-			println(err.String())
-			os.Exit(1)
-		}
-		file, err := parser.ParseFile(fset, *filename, data, 0)
-		if err != nil {
-			println(err.String())
-			os.Exit(1)
-		}
-		code, err := w.CompileDeclList(fset, file.Decls)
-		if err != nil {
-			if list, ok := err.(scanner.ErrorList); ok {
-				for _, e := range list {
-					println(e.String())
-				}
-			} else {
-				println(err.String())
-			}
-			os.Exit(1)
-		}
-		_, err = code.Run()
-		if err != nil {
-			println(err.String())
-			os.Exit(1)
-		}
-		code, err = w.Compile(fset, "init()")
-		if code != nil {
-			_, err := code.Run()
-			if err != nil {
-				println(err.String())
-				os.Exit(1)
-			}
-		}
-		code, err = w.Compile(fset, "main()")
-		if err != nil {
-			println(err.String())
-			os.Exit(1)
-		}
-		_, err = code.Run()
-		if err != nil {
-			println(err.String())
-			os.Exit(1)
-		}
-		os.Exit(0)
-	}
-
-	r := bufio.NewReader(os.Stdin)
-	for {
-		print("; ")
-		line, err := r.ReadString('\n')
-		if err != nil {
-			break
-		}
-		code, err := w.Compile(fset, line)
-		if err != nil {
-			println(err.String())
-			continue
-		}
-		v, err := code.Run()
-		if err != nil {
-			println(err.String())
-			continue
-		}
-		if v != nil {
-			println(v.String())
-		}
-	}
-}
diff --git a/src/pkg/exp/eval/scope.go b/src/pkg/exp/eval/scope.go
deleted file mode 100644
index 66305de..0000000
--- a/src/pkg/exp/eval/scope.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"go/token"
-	"log"
-)
-
-/*
- * Blocks and scopes
- */
-
-// A definition can be a *Variable, *Constant, or Type.
-type Def interface {
-	Pos() token.Pos
-}
-
-type Variable struct {
-	VarPos token.Pos
-	// Index of this variable in the Frame structure
-	Index int
-	// Static type of this variable
-	Type Type
-	// Value of this variable.  This is only used by Scope.NewFrame;
-	// therefore, it is useful for global scopes but cannot be used
-	// in function scopes.
-	Init Value
-}
-
-func (v *Variable) Pos() token.Pos {
-	return v.VarPos
-}
-
-type Constant struct {
-	ConstPos token.Pos
-	Type     Type
-	Value    Value
-}
-
-func (c *Constant) Pos() token.Pos {
-	return c.ConstPos
-}
-
-// A block represents a definition block in which a name may not be
-// defined more than once.
-type block struct {
-	// The block enclosing this one, including blocks in other
-	// scopes.
-	outer *block
-	// The nested block currently being compiled, or nil.
-	inner *block
-	// The Scope containing this block.
-	scope *Scope
-	// The Variables, Constants, and Types defined in this block.
-	defs map[string]Def
-	// The index of the first variable defined in this block.
-	// This must be greater than the index of any variable defined
-	// in any parent of this block within the same Scope at the
-	// time this block is entered.
-	offset int
-	// The number of Variables defined in this block.
-	numVars int
-	// If global, do not allocate new vars and consts in
-	// the frame; assume that the refs will be compiled in
-	// using defs[name].Init.
-	global bool
-}
-
-// A Scope is the compile-time analogue of a Frame, which captures
-// some subtree of blocks.
-type Scope struct {
-	// The root block of this scope.
-	*block
-	// The maximum number of variables required at any point in
-	// this Scope.  This determines the number of slots needed in
-	// Frame's created from this Scope at run-time.
-	maxVars int
-}
-
-func (b *block) enterChild() *block {
-	if b.inner != nil && b.inner.scope == b.scope {
-		log.Panic("Failed to exit child block before entering another child")
-	}
-	sub := &block{
-		outer:  b,
-		scope:  b.scope,
-		defs:   make(map[string]Def),
-		offset: b.offset + b.numVars,
-	}
-	b.inner = sub
-	return sub
-}
-
-func (b *block) exit() {
-	if b.outer == nil {
-		log.Panic("Cannot exit top-level block")
-	}
-	if b.outer.scope == b.scope {
-		if b.outer.inner != b {
-			log.Panic("Already exited block")
-		}
-		if b.inner != nil && b.inner.scope == b.scope {
-			log.Panic("Exit of parent block without exit of child block")
-		}
-	}
-	b.outer.inner = nil
-}
-
-func (b *block) ChildScope() *Scope {
-	if b.inner != nil && b.inner.scope == b.scope {
-		log.Panic("Failed to exit child block before entering a child scope")
-	}
-	sub := b.enterChild()
-	sub.offset = 0
-	sub.scope = &Scope{sub, 0}
-	return sub.scope
-}
-
-func (b *block) DefineVar(name string, pos token.Pos, t Type) (*Variable, Def) {
-	if prev, ok := b.defs[name]; ok {
-		return nil, prev
-	}
-	v := b.defineSlot(t, false)
-	v.VarPos = pos
-	b.defs[name] = v
-	return v, nil
-}
-
-func (b *block) DefineTemp(t Type) *Variable { return b.defineSlot(t, true) }
-
-func (b *block) defineSlot(t Type, temp bool) *Variable {
-	if b.inner != nil && b.inner.scope == b.scope {
-		log.Panic("Failed to exit child block before defining variable")
-	}
-	index := -1
-	if !b.global || temp {
-		index = b.offset + b.numVars
-		b.numVars++
-		if index >= b.scope.maxVars {
-			b.scope.maxVars = index + 1
-		}
-	}
-	v := &Variable{token.NoPos, index, t, nil}
-	return v
-}
-
-func (b *block) DefineConst(name string, pos token.Pos, t Type, v Value) (*Constant, Def) {
-	if prev, ok := b.defs[name]; ok {
-		return nil, prev
-	}
-	c := &Constant{pos, t, v}
-	b.defs[name] = c
-	return c, nil
-}
-
-func (b *block) DefineType(name string, pos token.Pos, t Type) Type {
-	if _, ok := b.defs[name]; ok {
-		return nil
-	}
-	nt := &NamedType{pos, name, nil, true, make(map[string]Method)}
-	if t != nil {
-		nt.Complete(t)
-	}
-	b.defs[name] = nt
-	return nt
-}
-
-func (b *block) Lookup(name string) (bl *block, level int, def Def) {
-	for b != nil {
-		if d, ok := b.defs[name]; ok {
-			return b, level, d
-		}
-		if b.outer != nil && b.scope != b.outer.scope {
-			level++
-		}
-		b = b.outer
-	}
-	return nil, 0, nil
-}
-
-func (s *Scope) NewFrame(outer *Frame) *Frame { return outer.child(s.maxVars) }
-
-/*
- * Frames
- */
-
-type Frame struct {
-	Outer *Frame
-	Vars  []Value
-}
-
-func (f *Frame) Get(level int, index int) Value {
-	for ; level > 0; level-- {
-		f = f.Outer
-	}
-	return f.Vars[index]
-}
-
-func (f *Frame) child(numVars int) *Frame {
-	// TODO(austin) This is probably rather expensive.  All values
-	// require heap allocation and zeroing them when we execute a
-	// definition typically requires some computation.
-	return &Frame{f, make([]Value, numVars)}
-}
diff --git a/src/pkg/exp/eval/stmt.go b/src/pkg/exp/eval/stmt.go
deleted file mode 100644
index 57bf20e..0000000
--- a/src/pkg/exp/eval/stmt.go
+++ /dev/null
@@ -1,1299 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"big"
-	"log"
-	"go/ast"
-	"go/token"
-)
-
-const (
-	returnPC = ^uint(0)
-	badPC    = ^uint(1)
-)
-
-/*
- * Statement compiler
- */
-
-type stmtCompiler struct {
-	*blockCompiler
-	pos token.Pos
-	// This statement's label, or nil if it is not labeled.
-	stmtLabel *label
-}
-
-func (a *stmtCompiler) diag(format string, args ...interface{}) {
-	a.diagAt(a.pos, format, args...)
-}
-
-/*
- * Flow checker
- */
-
-type flowEnt struct {
-	// Whether this flow entry is conditional.  If true, flow can
-	// continue to the next PC.
-	cond bool
-	// True if this will terminate flow (e.g., a return statement).
-	// cond must be false and jumps must be nil if this is true.
-	term bool
-	// PC's that can be reached from this flow entry.
-	jumps []*uint
-	// Whether this flow entry has been visited by reachesEnd.
-	visited bool
-}
-
-type flowBlock struct {
-	// If this is a goto, the target label.
-	target string
-	// The inner-most block containing definitions.
-	block *block
-	// The numVars from each block leading to the root of the
-	// scope, starting at block.
-	numVars []int
-}
-
-type flowBuf struct {
-	cb *codeBuf
-	// ents is a map from PC's to flow entries.  Any PC missing
-	// from this map is assumed to reach only PC+1.
-	ents map[uint]*flowEnt
-	// gotos is a map from goto positions to information on the
-	// block at the point of the goto.
-	gotos map[token.Pos]*flowBlock
-	// labels is a map from label name to information on the block
-	// at the point of the label.  labels are tracked by name,
-	// since multiple labels at the same PC can have different
-	// blocks.
-	labels map[string]*flowBlock
-}
-
-func newFlowBuf(cb *codeBuf) *flowBuf {
-	return &flowBuf{cb, make(map[uint]*flowEnt), make(map[token.Pos]*flowBlock), make(map[string]*flowBlock)}
-}
-
-// put creates a flow control point for the next PC in the code buffer.
-// This should be done before pushing the instruction into the code buffer.
-func (f *flowBuf) put(cond bool, term bool, jumps []*uint) {
-	pc := f.cb.nextPC()
-	if ent, ok := f.ents[pc]; ok {
-		log.Panicf("Flow entry already exists at PC %d: %+v", pc, ent)
-	}
-	f.ents[pc] = &flowEnt{cond, term, jumps, false}
-}
-
-// putTerm creates a flow control point at the next PC that
-// unconditionally terminates execution.
-func (f *flowBuf) putTerm() { f.put(false, true, nil) }
-
-// put1 creates a flow control point at the next PC that jumps to one
-// PC and, if cond is true, can also continue to the PC following the
-// next PC.
-func (f *flowBuf) put1(cond bool, jumpPC *uint) {
-	f.put(cond, false, []*uint{jumpPC})
-}
-
-func newFlowBlock(target string, b *block) *flowBlock {
-	// Find the inner-most block containing definitions
-	for b.numVars == 0 && b.outer != nil && b.outer.scope == b.scope {
-		b = b.outer
-	}
-
-	// Count parents leading to the root of the scope
-	n := 0
-	for bp := b; bp.scope == b.scope; bp = bp.outer {
-		n++
-	}
-
-	// Capture numVars from each block to the root of the scope
-	numVars := make([]int, n)
-	i := 0
-	for bp := b; i < n; bp = bp.outer {
-		numVars[i] = bp.numVars
-		i++
-	}
-
-	return &flowBlock{target, b, numVars}
-}
-
-// putGoto captures the block at a goto statement.  This should be
-// called in addition to putting a flow control point.
-func (f *flowBuf) putGoto(pos token.Pos, target string, b *block) {
-	f.gotos[pos] = newFlowBlock(target, b)
-}
-
-// putLabel captures the block at a label.
-func (f *flowBuf) putLabel(name string, b *block) {
-	f.labels[name] = newFlowBlock("", b)
-}
-
-// reachesEnd returns true if the end of f's code buffer can be
-// reached from the given program counter.  Error reporting is the
-// caller's responsibility.
-func (f *flowBuf) reachesEnd(pc uint) bool {
-	endPC := f.cb.nextPC()
-	if pc > endPC {
-		log.Panicf("Reached bad PC %d past end PC %d", pc, endPC)
-	}
-
-	for ; pc < endPC; pc++ {
-		ent, ok := f.ents[pc]
-		if !ok {
-			continue
-		}
-
-		if ent.visited {
-			return false
-		}
-		ent.visited = true
-
-		if ent.term {
-			return false
-		}
-
-		// If anything can reach the end, we can reach the end
-		// from pc.
-		for _, j := range ent.jumps {
-			if f.reachesEnd(*j) {
-				return true
-			}
-		}
-		// If the jump was conditional, we can reach the next
-		// PC, so try reaching the end from it.
-		if ent.cond {
-			continue
-		}
-		return false
-	}
-	return true
-}
-
-// gotosObeyScopes returns true if no goto statement causes any
-// variables to come into scope that were not in scope at the point of
-// the goto.  Reports any errors using the given compiler.
-func (f *flowBuf) gotosObeyScopes(a *compiler) {
-	for pos, src := range f.gotos {
-		tgt := f.labels[src.target]
-
-		// The target block must be a parent of this block
-		numVars := src.numVars
-		b := src.block
-		for len(numVars) > 0 && b != tgt.block {
-			b = b.outer
-			numVars = numVars[1:]
-		}
-		if b != tgt.block {
-			// We jumped into a deeper block
-			a.diagAt(pos, "goto causes variables to come into scope")
-			return
-		}
-
-		// There must be no variables in the target block that
-		// did not exist at the jump
-		tgtNumVars := tgt.numVars
-		for i := range numVars {
-			if tgtNumVars[i] > numVars[i] {
-				a.diagAt(pos, "goto causes variables to come into scope")
-				return
-			}
-		}
-	}
-}
-
-/*
- * Statement generation helpers
- */
-
-func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
-	v, prev := a.block.DefineVar(ident.Name, ident.Pos(), t)
-	if prev != nil {
-		if prev.Pos().IsValid() {
-			a.diagAt(ident.Pos(), "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name, a.fset.Position(prev.Pos()))
-		} else {
-			a.diagAt(ident.Pos(), "variable %s redeclared in this block", ident.Name)
-		}
-		return nil
-	}
-
-	// Initialize the variable
-	index := v.Index
-	if v.Index >= 0 {
-		a.push(func(v *Thread) { v.f.Vars[index] = t.Zero() })
-	}
-	return v
-}
-
-// TODO(austin) Move doAssign to here
-
-/*
- * Statement compiler
- */
-
-func (a *stmtCompiler) compile(s ast.Stmt) {
-	if a.block.inner != nil {
-		log.Panic("Child scope still entered")
-	}
-
-	notimpl := false
-	switch s := s.(type) {
-	case *ast.BadStmt:
-		// Error already reported by parser.
-		a.silentErrors++
-
-	case *ast.DeclStmt:
-		a.compileDeclStmt(s)
-
-	case *ast.EmptyStmt:
-		// Do nothing.
-
-	case *ast.LabeledStmt:
-		a.compileLabeledStmt(s)
-
-	case *ast.ExprStmt:
-		a.compileExprStmt(s)
-
-	case *ast.IncDecStmt:
-		a.compileIncDecStmt(s)
-
-	case *ast.AssignStmt:
-		a.compileAssignStmt(s)
-
-	case *ast.GoStmt:
-		notimpl = true
-
-	case *ast.DeferStmt:
-		notimpl = true
-
-	case *ast.ReturnStmt:
-		a.compileReturnStmt(s)
-
-	case *ast.BranchStmt:
-		a.compileBranchStmt(s)
-
-	case *ast.BlockStmt:
-		a.compileBlockStmt(s)
-
-	case *ast.IfStmt:
-		a.compileIfStmt(s)
-
-	case *ast.CaseClause:
-		a.diag("case clause outside switch")
-
-	case *ast.SwitchStmt:
-		a.compileSwitchStmt(s)
-
-	case *ast.TypeSwitchStmt:
-		notimpl = true
-
-	case *ast.CommClause:
-		notimpl = true
-
-	case *ast.SelectStmt:
-		notimpl = true
-
-	case *ast.ForStmt:
-		a.compileForStmt(s)
-
-	case *ast.RangeStmt:
-		notimpl = true
-
-	default:
-		log.Panicf("unexpected ast node type %T", s)
-	}
-
-	if notimpl {
-		a.diag("%T statement node not implemented", s)
-	}
-
-	if a.block.inner != nil {
-		log.Panic("Forgot to exit child scope")
-	}
-}
-
-func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
-	switch decl := s.Decl.(type) {
-	case *ast.BadDecl:
-		// Do nothing.  Already reported by parser.
-		a.silentErrors++
-
-	case *ast.FuncDecl:
-		if !a.block.global {
-			log.Panic("FuncDecl at statement level")
-		}
-
-	case *ast.GenDecl:
-		if decl.Tok == token.IMPORT && !a.block.global {
-			log.Panic("import at statement level")
-		}
-
-	default:
-		log.Panicf("Unexpected Decl type %T", s.Decl)
-	}
-	a.compileDecl(s.Decl)
-}
-
-func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) {
-	for _, spec := range decl.Specs {
-		spec := spec.(*ast.ValueSpec)
-		if spec.Values == nil {
-			// Declaration without assignment
-			if spec.Type == nil {
-				// Parser should have caught
-				log.Panic("Type and Values nil")
-			}
-			t := a.compileType(a.block, spec.Type)
-			// Define placeholders even if type compile failed
-			for _, n := range spec.Names {
-				a.defineVar(n, t)
-			}
-		} else {
-			// Declaration with assignment
-			lhs := make([]ast.Expr, len(spec.Names))
-			for i, n := range spec.Names {
-				lhs[i] = n
-			}
-			a.doAssign(lhs, spec.Values, decl.Tok, spec.Type)
-		}
-	}
-}
-
-func (a *stmtCompiler) compileDecl(decl ast.Decl) {
-	switch d := decl.(type) {
-	case *ast.BadDecl:
-		// Do nothing.  Already reported by parser.
-		a.silentErrors++
-
-	case *ast.FuncDecl:
-		decl := a.compileFuncType(a.block, d.Type)
-		if decl == nil {
-			return
-		}
-		// Declare and initialize v before compiling func
-		// so that body can refer to itself.
-		c, prev := a.block.DefineConst(d.Name.Name, a.pos, decl.Type, decl.Type.Zero())
-		if prev != nil {
-			pos := prev.Pos()
-			if pos.IsValid() {
-				a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name, a.fset.Position(pos))
-			} else {
-				a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block", d.Name.Name)
-			}
-		}
-		fn := a.compileFunc(a.block, decl, d.Body)
-		if c == nil || fn == nil {
-			return
-		}
-		var zeroThread Thread
-		c.Value.(FuncValue).Set(nil, fn(&zeroThread))
-
-	case *ast.GenDecl:
-		switch d.Tok {
-		case token.IMPORT:
-			log.Panicf("%v not implemented", d.Tok)
-		case token.CONST:
-			log.Panicf("%v not implemented", d.Tok)
-		case token.TYPE:
-			a.compileTypeDecl(a.block, d)
-		case token.VAR:
-			a.compileVarDecl(d)
-		}
-
-	default:
-		log.Panicf("Unexpected Decl type %T", decl)
-	}
-}
-
-func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
-	// Define label
-	l, ok := a.labels[s.Label.Name]
-	if ok {
-		if l.resolved.IsValid() {
-			a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name, a.fset.Position(l.resolved))
-		}
-	} else {
-		pc := badPC
-		l = &label{name: s.Label.Name, gotoPC: &pc}
-		a.labels[l.name] = l
-	}
-	l.desc = "regular label"
-	l.resolved = s.Pos()
-
-	// Set goto PC
-	*l.gotoPC = a.nextPC()
-
-	// Define flow entry so we can check for jumps over declarations.
-	a.flow.putLabel(l.name, a.block)
-
-	// Compile the statement.  Reuse our stmtCompiler for simplicity.
-	sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l}
-	sc.compile(s.Stmt)
-}
-
-func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) {
-	bc := a.enterChild()
-	defer bc.exit()
-
-	e := a.compileExpr(bc.block, false, s.X)
-	if e == nil {
-		return
-	}
-
-	if e.exec == nil {
-		a.diag("%s cannot be used as expression statement", e.desc)
-		return
-	}
-
-	a.push(e.exec)
-}
-
-func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
-	// Create temporary block for extractEffect
-	bc := a.enterChild()
-	defer bc.exit()
-
-	l := a.compileExpr(bc.block, false, s.X)
-	if l == nil {
-		return
-	}
-
-	if l.evalAddr == nil {
-		l.diag("cannot assign to %s", l.desc)
-		return
-	}
-	if !(l.t.isInteger() || l.t.isFloat()) {
-		l.diagOpType(s.Tok, l.t)
-		return
-	}
-
-	var op token.Token
-	var desc string
-	switch s.Tok {
-	case token.INC:
-		op = token.ADD
-		desc = "increment statement"
-	case token.DEC:
-		op = token.SUB
-		desc = "decrement statement"
-	default:
-		log.Panicf("Unexpected IncDec token %v", s.Tok)
-	}
-
-	effect, l := l.extractEffect(bc.block, desc)
-
-	one := l.newExpr(IdealIntType, "constant")
-	one.pos = s.Pos()
-	one.eval = func() *big.Int { return big.NewInt(1) }
-
-	binop := l.compileBinaryExpr(op, l, one)
-	if binop == nil {
-		return
-	}
-
-	assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "")
-	if assign == nil {
-		log.Panicf("compileAssign type check failed")
-	}
-
-	lf := l.evalAddr
-	a.push(func(v *Thread) {
-		effect(v)
-		assign(lf(v), v)
-	})
-}
-
-func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
-	nerr := a.numError()
-
-	// Compile right side first so we have the types when
-	// compiling the left side and so we don't see definitions
-	// made on the left side.
-	rs := make([]*expr, len(rhs))
-	for i, re := range rhs {
-		rs[i] = a.compileExpr(a.block, false, re)
-	}
-
-	errOp := "assignment"
-	if tok == token.DEFINE || tok == token.VAR {
-		errOp = "declaration"
-	}
-	ac, ok := a.checkAssign(a.pos, rs, errOp, "value")
-	ac.allowMapForms(len(lhs))
-
-	// If this is a definition and the LHS is too big, we won't be
-	// able to produce the usual error message because we can't
-	// begin to infer the types of the LHS.
-	if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
-		a.diag("not enough values for definition")
-	}
-
-	// Compile left type if there is one
-	var declType Type
-	if declTypeExpr != nil {
-		declType = a.compileType(a.block, declTypeExpr)
-	}
-
-	// Compile left side
-	ls := make([]*expr, len(lhs))
-	nDefs := 0
-	for i, le := range lhs {
-		// If this is a definition, get the identifier and its type
-		var ident *ast.Ident
-		var lt Type
-		switch tok {
-		case token.DEFINE:
-			// Check that it's an identifier
-			ident, ok = le.(*ast.Ident)
-			if !ok {
-				a.diagAt(le.Pos(), "left side of := must be a name")
-				// Suppress new definitions errors
-				nDefs++
-				continue
-			}
-
-			// Is this simply an assignment?
-			if _, ok := a.block.defs[ident.Name]; ok {
-				ident = nil
-				break
-			}
-			nDefs++
-
-		case token.VAR:
-			ident = le.(*ast.Ident)
-		}
-
-		// If it's a definition, get or infer its type.
-		if ident != nil {
-			// Compute the identifier's type from the RHS
-			// type.  We use the computed MultiType so we
-			// don't have to worry about unpacking.
-			switch {
-			case declTypeExpr != nil:
-				// We have a declaration type, use it.
-				// If declType is nil, we gave an
-				// error when we compiled it.
-				lt = declType
-
-			case i >= len(ac.rmt.Elems):
-				// Define a placeholder.  We already
-				// gave the "not enough" error above.
-				lt = nil
-
-			case ac.rmt.Elems[i] == nil:
-				// We gave the error when we compiled
-				// the RHS.
-				lt = nil
-
-			case ac.rmt.Elems[i].isIdeal():
-				// If the type is absent and the
-				// corresponding expression is a
-				// constant expression of ideal
-				// integer or ideal float type, the
-				// type of the declared variable is
-				// int or float respectively.
-				switch {
-				case ac.rmt.Elems[i].isInteger():
-					lt = IntType
-				case ac.rmt.Elems[i].isFloat():
-					lt = Float64Type
-				default:
-					log.Panicf("unexpected ideal type %v", rs[i].t)
-				}
-
-			default:
-				lt = ac.rmt.Elems[i]
-			}
-		}
-
-		// If it's a definition, define the identifier
-		if ident != nil {
-			if a.defineVar(ident, lt) == nil {
-				continue
-			}
-		}
-
-		// Compile LHS
-		ls[i] = a.compileExpr(a.block, false, le)
-		if ls[i] == nil {
-			continue
-		}
-
-		if ls[i].evalMapValue != nil {
-			// Map indexes are not generally addressable,
-			// but they are assignable.
-			//
-			// TODO(austin) Now that the expression
-			// compiler uses semantic values, this might
-			// be easier to implement as a function call.
-			sub := ls[i]
-			ls[i] = ls[i].newExpr(sub.t, sub.desc)
-			ls[i].evalMapValue = sub.evalMapValue
-			mvf := sub.evalMapValue
-			et := sub.t
-			ls[i].evalAddr = func(t *Thread) Value {
-				m, k := mvf(t)
-				e := m.Elem(t, k)
-				if e == nil {
-					e = et.Zero()
-					m.SetElem(t, k, e)
-				}
-				return e
-			}
-		} else if ls[i].evalAddr == nil {
-			ls[i].diag("cannot assign to %s", ls[i].desc)
-			continue
-		}
-	}
-
-	// A short variable declaration may redeclare variables
-	// provided they were originally declared in the same block
-	// with the same type, and at least one of the variables is
-	// new.
-	if tok == token.DEFINE && nDefs == 0 {
-		a.diag("at least one new variable must be declared")
-		return
-	}
-
-	// If there have been errors, our arrays are full of nil's so
-	// get out of here now.
-	if nerr != a.numError() {
-		return
-	}
-
-	// Check for 'a[x] = r, ok'
-	if len(ls) == 1 && len(rs) == 2 && ls[0].evalMapValue != nil {
-		a.diag("a[x] = r, ok form not implemented")
-		return
-	}
-
-	// Create assigner
-	var lt Type
-	n := len(lhs)
-	if n == 1 {
-		lt = ls[0].t
-	} else {
-		lts := make([]Type, len(ls))
-		for i, l := range ls {
-			if l != nil {
-				lts[i] = l.t
-			}
-		}
-		lt = NewMultiType(lts)
-	}
-	bc := a.enterChild()
-	defer bc.exit()
-	assign := ac.compile(bc.block, lt)
-	if assign == nil {
-		return
-	}
-
-	// Compile
-	if n == 1 {
-		// Don't need temporaries and can avoid []Value.
-		lf := ls[0].evalAddr
-		a.push(func(t *Thread) { assign(lf(t), t) })
-	} else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) {
-		// Don't need temporaries
-		lfs := make([]func(*Thread) Value, n)
-		for i, l := range ls {
-			lfs[i] = l.evalAddr
-		}
-		a.push(func(t *Thread) {
-			dest := make([]Value, n)
-			for i, lf := range lfs {
-				dest[i] = lf(t)
-			}
-			assign(multiV(dest), t)
-		})
-	} else {
-		// Need temporaries
-		lmt := lt.(*MultiType)
-		lfs := make([]func(*Thread) Value, n)
-		for i, l := range ls {
-			lfs[i] = l.evalAddr
-		}
-		a.push(func(t *Thread) {
-			temp := lmt.Zero().(multiV)
-			assign(temp, t)
-			// Copy to destination
-			for i := 0; i < n; i++ {
-				// TODO(austin) Need to evaluate LHS
-				// before RHS
-				lfs[i](t).Assign(t, temp[i])
-			}
-		})
-	}
-}
-
-var assignOpToOp = map[token.Token]token.Token{
-	token.ADD_ASSIGN: token.ADD,
-	token.SUB_ASSIGN: token.SUB,
-	token.MUL_ASSIGN: token.MUL,
-	token.QUO_ASSIGN: token.QUO,
-	token.REM_ASSIGN: token.REM,
-
-	token.AND_ASSIGN:     token.AND,
-	token.OR_ASSIGN:      token.OR,
-	token.XOR_ASSIGN:     token.XOR,
-	token.SHL_ASSIGN:     token.SHL,
-	token.SHR_ASSIGN:     token.SHR,
-	token.AND_NOT_ASSIGN: token.AND_NOT,
-}
-
-func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
-	if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
-		a.diag("tuple assignment cannot be combined with an arithmetic operation")
-		return
-	}
-
-	// Create temporary block for extractEffect
-	bc := a.enterChild()
-	defer bc.exit()
-
-	l := a.compileExpr(bc.block, false, s.Lhs[0])
-	r := a.compileExpr(bc.block, false, s.Rhs[0])
-	if l == nil || r == nil {
-		return
-	}
-
-	if l.evalAddr == nil {
-		l.diag("cannot assign to %s", l.desc)
-		return
-	}
-
-	effect, l := l.extractEffect(bc.block, "operator-assignment")
-
-	binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r)
-	if binop == nil {
-		return
-	}
-
-	assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value")
-	if assign == nil {
-		log.Panicf("compileAssign type check failed")
-	}
-
-	lf := l.evalAddr
-	a.push(func(t *Thread) {
-		effect(t)
-		assign(lf(t), t)
-	})
-}
-
-func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
-	switch s.Tok {
-	case token.ASSIGN, token.DEFINE:
-		a.doAssign(s.Lhs, s.Rhs, s.Tok, nil)
-
-	default:
-		a.doAssignOp(s)
-	}
-}
-
-func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
-	if a.fnType == nil {
-		a.diag("cannot return at the top level")
-		return
-	}
-
-	if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) {
-		// Simple case.  Simply exit from the function.
-		a.flow.putTerm()
-		a.push(func(v *Thread) { v.pc = returnPC })
-		return
-	}
-
-	bc := a.enterChild()
-	defer bc.exit()
-
-	// Compile expressions
-	bad := false
-	rs := make([]*expr, len(s.Results))
-	for i, re := range s.Results {
-		rs[i] = a.compileExpr(bc.block, false, re)
-		if rs[i] == nil {
-			bad = true
-		}
-	}
-	if bad {
-		return
-	}
-
-	// Create assigner
-
-	// However, if the expression list in the "return" statement
-	// is a single call to a multi-valued function, the values
-	// returned from the called function will be returned from
-	// this one.
-	assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value")
-
-	// XXX(Spec) "The result types of the current function and the
-	// called function must match."  Match is fuzzy.  It should
-	// say that they must be assignment compatible.
-
-	// Compile
-	start := len(a.fnType.In)
-	nout := len(a.fnType.Out)
-	a.flow.putTerm()
-	a.push(func(t *Thread) {
-		assign(multiV(t.f.Vars[start:start+nout]), t)
-		t.pc = returnPC
-	})
-}
-
-func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
-	bc := a.blockCompiler
-	for ; bc != nil; bc = bc.parent {
-		if bc.label == nil {
-			continue
-		}
-		l := bc.label
-		if name == nil && pred(l) {
-			return l
-		}
-		if name != nil && l.name == name.Name {
-			if !pred(l) {
-				a.diag("cannot %s to %s %s", errOp, l.desc, l.name)
-				return nil
-			}
-			return l
-		}
-	}
-	if name == nil {
-		a.diag("%s outside %s", errOp, errCtx)
-	} else {
-		a.diag("%s label %s not defined", errOp, name.Name)
-	}
-	return nil
-}
-
-func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
-	var pc *uint
-
-	switch s.Tok {
-	case token.BREAK:
-		l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select")
-		if l == nil {
-			return
-		}
-		pc = l.breakPC
-
-	case token.CONTINUE:
-		l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop")
-		if l == nil {
-			return
-		}
-		pc = l.continuePC
-
-	case token.GOTO:
-		l, ok := a.labels[s.Label.Name]
-		if !ok {
-			pc := badPC
-			l = &label{name: s.Label.Name, desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
-			a.labels[l.name] = l
-		}
-
-		pc = l.gotoPC
-		a.flow.putGoto(s.Pos(), l.name, a.block)
-
-	case token.FALLTHROUGH:
-		a.diag("fallthrough outside switch")
-		return
-
-	default:
-		log.Panicf("Unexpected branch token %v", s.Tok)
-	}
-
-	a.flow.put1(false, pc)
-	a.push(func(v *Thread) { v.pc = *pc })
-}
-
-func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) {
-	bc := a.enterChild()
-	bc.compileStmts(s)
-	bc.exit()
-}
-
-func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
-	// The scope of any variables declared by [the init] statement
-	// extends to the end of the "if" statement and the variables
-	// are initialized once before the statement is entered.
-	//
-	// XXX(Spec) What this really wants to say is that there's an
-	// implicit scope wrapping every if, for, and switch
-	// statement.  This is subtly different from what it actually
-	// says when there's a non-block else clause, because that
-	// else claus has to execute in a scope that is *not* the
-	// surrounding scope.
-	bc := a.enterChild()
-	defer bc.exit()
-
-	// Compile init statement, if any
-	if s.Init != nil {
-		bc.compileStmt(s.Init)
-	}
-
-	elsePC := badPC
-	endPC := badPC
-
-	// Compile condition, if any.  If there is no condition, we
-	// fall through to the body.
-	if s.Cond != nil {
-		e := bc.compileExpr(bc.block, false, s.Cond)
-		switch {
-		case e == nil:
-			// Error reported by compileExpr
-		case !e.t.isBoolean():
-			e.diag("'if' condition must be boolean\n\t%v", e.t)
-		default:
-			eval := e.asBool()
-			a.flow.put1(true, &elsePC)
-			a.push(func(t *Thread) {
-				if !eval(t) {
-					t.pc = elsePC
-				}
-			})
-		}
-	}
-
-	// Compile body
-	body := bc.enterChild()
-	body.compileStmts(s.Body)
-	body.exit()
-
-	// Compile else
-	if s.Else != nil {
-		// Skip over else if we executed the body
-		a.flow.put1(false, &endPC)
-		a.push(func(v *Thread) { v.pc = endPC })
-		elsePC = a.nextPC()
-		bc.compileStmt(s.Else)
-	} else {
-		elsePC = a.nextPC()
-	}
-	endPC = a.nextPC()
-}
-
-func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
-	// Create implicit scope around switch
-	bc := a.enterChild()
-	defer bc.exit()
-
-	// Compile init statement, if any
-	if s.Init != nil {
-		bc.compileStmt(s.Init)
-	}
-
-	// Compile condition, if any, and extract its effects
-	var cond *expr
-	condbc := bc.enterChild()
-	if s.Tag != nil {
-		e := condbc.compileExpr(condbc.block, false, s.Tag)
-		if e != nil {
-			var effect func(*Thread)
-			effect, cond = e.extractEffect(condbc.block, "switch")
-			a.push(effect)
-		}
-	}
-
-	// Count cases
-	ncases := 0
-	hasDefault := false
-	for _, c := range s.Body.List {
-		clause, ok := c.(*ast.CaseClause)
-		if !ok {
-			a.diagAt(clause.Pos(), "switch statement must contain case clauses")
-			continue
-		}
-		if clause.List == nil {
-			if hasDefault {
-				a.diagAt(clause.Pos(), "switch statement contains more than one default case")
-			}
-			hasDefault = true
-		} else {
-			ncases += len(clause.List)
-		}
-	}
-
-	// Compile case expressions
-	cases := make([]func(*Thread) bool, ncases)
-	i := 0
-	for _, c := range s.Body.List {
-		clause, ok := c.(*ast.CaseClause)
-		if !ok {
-			continue
-		}
-		for _, v := range clause.List {
-			e := condbc.compileExpr(condbc.block, false, v)
-			switch {
-			case e == nil:
-				// Error reported by compileExpr
-			case cond == nil && !e.t.isBoolean():
-				a.diagAt(v.Pos(), "'case' condition must be boolean")
-			case cond == nil:
-				cases[i] = e.asBool()
-			case cond != nil:
-				// Create comparison
-				// TOOD(austin) This produces bad error messages
-				compare := e.compileBinaryExpr(token.EQL, cond, e)
-				if compare != nil {
-					cases[i] = compare.asBool()
-				}
-			}
-			i++
-		}
-	}
-
-	// Emit condition
-	casePCs := make([]*uint, ncases+1)
-	endPC := badPC
-
-	a.flow.put(false, false, casePCs)
-	a.push(func(t *Thread) {
-		for i, c := range cases {
-			if c(t) {
-				t.pc = *casePCs[i]
-				return
-			}
-		}
-		t.pc = *casePCs[ncases]
-	})
-	condbc.exit()
-
-	// Compile cases
-	i = 0
-	for _, c := range s.Body.List {
-		clause, ok := c.(*ast.CaseClause)
-		if !ok {
-			continue
-		}
-
-		// Save jump PC's
-		pc := a.nextPC()
-		if clause.List != nil {
-			for _ = range clause.List {
-				casePCs[i] = &pc
-				i++
-			}
-		} else {
-			// Default clause
-			casePCs[ncases] = &pc
-		}
-
-		// Compile body
-		fall := false
-		for j, s := range clause.Body {
-			if br, ok := s.(*ast.BranchStmt); ok && br.Tok == token.FALLTHROUGH {
-				// println("Found fallthrough");
-				// It may be used only as the final
-				// non-empty statement in a case or
-				// default clause in an expression
-				// "switch" statement.
-				for _, s2 := range clause.Body[j+1:] {
-					// XXX(Spec) 6g also considers
-					// empty blocks to be empty
-					// statements.
-					if _, ok := s2.(*ast.EmptyStmt); !ok {
-						a.diagAt(s.Pos(), "fallthrough statement must be final statement in case")
-						break
-					}
-				}
-				fall = true
-			} else {
-				bc.compileStmt(s)
-			}
-		}
-		// Jump out of switch, unless there was a fallthrough
-		if !fall {
-			a.flow.put1(false, &endPC)
-			a.push(func(v *Thread) { v.pc = endPC })
-		}
-	}
-
-	// Get end PC
-	endPC = a.nextPC()
-	if !hasDefault {
-		casePCs[ncases] = &endPC
-	}
-}
-
-func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
-	// Wrap the entire for in a block.
-	bc := a.enterChild()
-	defer bc.exit()
-
-	// Compile init statement, if any
-	if s.Init != nil {
-		bc.compileStmt(s.Init)
-	}
-
-	bodyPC := badPC
-	postPC := badPC
-	checkPC := badPC
-	endPC := badPC
-
-	// Jump to condition check.  We generate slightly less code by
-	// placing the condition check after the body.
-	a.flow.put1(false, &checkPC)
-	a.push(func(v *Thread) { v.pc = checkPC })
-
-	// Compile body
-	bodyPC = a.nextPC()
-	body := bc.enterChild()
-	if a.stmtLabel != nil {
-		body.label = a.stmtLabel
-	} else {
-		body.label = &label{resolved: s.Pos()}
-	}
-	body.label.desc = "for loop"
-	body.label.breakPC = &endPC
-	body.label.continuePC = &postPC
-	body.compileStmts(s.Body)
-	body.exit()
-
-	// Compile post, if any
-	postPC = a.nextPC()
-	if s.Post != nil {
-		// TODO(austin) Does the parser disallow short
-		// declarations in s.Post?
-		bc.compileStmt(s.Post)
-	}
-
-	// Compile condition check, if any
-	checkPC = a.nextPC()
-	if s.Cond == nil {
-		// If the condition is absent, it is equivalent to true.
-		a.flow.put1(false, &bodyPC)
-		a.push(func(v *Thread) { v.pc = bodyPC })
-	} else {
-		e := bc.compileExpr(bc.block, false, s.Cond)
-		switch {
-		case e == nil:
-			// Error reported by compileExpr
-		case !e.t.isBoolean():
-			a.diag("'for' condition must be boolean\n\t%v", e.t)
-		default:
-			eval := e.asBool()
-			a.flow.put1(true, &bodyPC)
-			a.push(func(t *Thread) {
-				if eval(t) {
-					t.pc = bodyPC
-				}
-			})
-		}
-	}
-
-	endPC = a.nextPC()
-}
-
-/*
- * Block compiler
- */
-
-func (a *blockCompiler) compileStmt(s ast.Stmt) {
-	sc := &stmtCompiler{a, s.Pos(), nil}
-	sc.compile(s)
-}
-
-func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
-	for _, sub := range block.List {
-		a.compileStmt(sub)
-	}
-}
-
-func (a *blockCompiler) enterChild() *blockCompiler {
-	block := a.block.enterChild()
-	return &blockCompiler{
-		funcCompiler: a.funcCompiler,
-		block:        block,
-		parent:       a,
-	}
-}
-
-func (a *blockCompiler) exit() { a.block.exit() }
-
-/*
- * Function compiler
- */
-
-func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) func(*Thread) Func {
-	// Create body scope
-	//
-	// The scope of a parameter or result is the body of the
-	// corresponding function.
-	bodyScope := b.ChildScope()
-	defer bodyScope.exit()
-	for i, t := range decl.Type.In {
-		if decl.InNames[i] != nil {
-			bodyScope.DefineVar(decl.InNames[i].Name, decl.InNames[i].Pos(), t)
-		} else {
-			bodyScope.DefineTemp(t)
-		}
-	}
-	for i, t := range decl.Type.Out {
-		if decl.OutNames[i] != nil {
-			bodyScope.DefineVar(decl.OutNames[i].Name, decl.OutNames[i].Pos(), t)
-		} else {
-			bodyScope.DefineTemp(t)
-		}
-	}
-
-	// Create block context
-	cb := newCodeBuf()
-	fc := &funcCompiler{
-		compiler:     a,
-		fnType:       decl.Type,
-		outVarsNamed: len(decl.OutNames) > 0 && decl.OutNames[0] != nil,
-		codeBuf:      cb,
-		flow:         newFlowBuf(cb),
-		labels:       make(map[string]*label),
-	}
-	bc := &blockCompiler{
-		funcCompiler: fc,
-		block:        bodyScope.block,
-	}
-
-	// Compile body
-	nerr := a.numError()
-	bc.compileStmts(body)
-	fc.checkLabels()
-	if nerr != a.numError() {
-		return nil
-	}
-
-	// Check that the body returned if necessary.  We only check
-	// this if there were no errors compiling the body.
-	if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) {
-		// XXX(Spec) Not specified.
-		a.diagAt(body.Rbrace, "function ends without a return statement")
-		return nil
-	}
-
-	code := fc.get()
-	maxVars := bodyScope.maxVars
-	return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} }
-}
-
-// Checks that labels were resolved and that all jumps obey scoping
-// rules.  Reports an error and set fc.err if any check fails.
-func (a *funcCompiler) checkLabels() {
-	nerr := a.numError()
-	for _, l := range a.labels {
-		if !l.resolved.IsValid() {
-			a.diagAt(l.used, "label %s not defined", l.name)
-		}
-	}
-	if nerr != a.numError() {
-		// Don't check scopes if we have unresolved labels
-		return
-	}
-
-	// Executing the "goto" statement must not cause any variables
-	// to come into scope that were not already in scope at the
-	// point of the goto.
-	a.flow.gotosObeyScopes(a.compiler)
-}
diff --git a/src/pkg/exp/eval/stmt_test.go b/src/pkg/exp/eval/stmt_test.go
deleted file mode 100644
index a8a3e16..0000000
--- a/src/pkg/exp/eval/stmt_test.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import "testing"
-
-var atLeastOneDecl = "at least one new variable must be declared"
-
-var stmtTests = []test{
-	// Short declarations
-	Val1("x := i", "x", 1),
-	Val1("x := f", "x", 1.0),
-	// Type defaulting
-	Val1("a := 42", "a", 42),
-	Val1("a := 1.0", "a", 1.0),
-	// Parallel assignment
-	Val2("a, b := 1, 2", "a", 1, "b", 2),
-	Val2("a, i := 1, 2", "a", 1, "i", 2),
-	CErr("a, i := 1, f", opTypes),
-	CErr("a, b := 1, 2, 3", "too many"),
-	CErr("a := 1, 2", "too many"),
-	CErr("a, b := 1", "not enough"),
-	// Mixed declarations
-	CErr("i := 1", atLeastOneDecl),
-	CErr("i, u := 1, 2", atLeastOneDecl),
-	Val2("i, x := 2, f", "i", 2, "x", 1.0),
-	// Various errors
-	CErr("1 := 2", "expected identifier"),
-	CErr("c, a := 1, 1", "cannot assign"),
-	// Unpacking
-	Val2("x, y := oneTwo()", "x", 1, "y", 2),
-	CErr("x := oneTwo()", "too many"),
-	CErr("x, y, z := oneTwo()", "not enough"),
-	CErr("x, y := oneTwo(), 2", "multi-valued"),
-	CErr("x := oneTwo()+2", opTypes),
-	// TOOD(austin) This error message is weird
-	CErr("x := void()", "not enough"),
-	// Placeholders
-	CErr("x := 1+\"x\"; i=x+1", opTypes),
-
-	// Assignment
-	Val1("i = 2", "i", 2),
-	Val1("(i) = 2", "i", 2),
-	CErr("1 = 2", "cannot assign"),
-	CErr("1-1 = 2", "- expression"),
-	Val1("i = 2.0", "i", 2),
-	CErr("i = 2.2", constantTruncated),
-	CErr("u = -2", constantUnderflows),
-	CErr("i = f", opTypes),
-	CErr("i, u = 0, f", opTypes),
-	CErr("i, u = 0, f", "value 2"),
-	Val2("i, i2 = i2, i", "i", 2, "i2", 1),
-	CErr("c = 1", "cannot assign"),
-
-	Val1("x := &i; *x = 2", "i", 2),
-
-	Val1("ai[0] = 42", "ai", varray{42, 2}),
-	Val1("aai[1] = ai; ai[0] = 42", "aai", varray{varray{1, 2}, varray{1, 2}}),
-	Val1("aai = aai2", "aai", varray{varray{5, 6}, varray{7, 8}}),
-
-	// Assignment conversions
-	Run("var sl []int; sl = &ai"),
-	CErr("type ST []int; type AT *[2]int; var x AT = &ai; var y ST = x", opTypes),
-	Run("type ST []int; var y ST = &ai"),
-	Run("type AT *[2]int; var x AT = &ai; var y []int = x"),
-
-	// Op-assignment
-	Val1("i += 2", "i", 3),
-	Val("i", 1),
-	Val1("f += 2", "f", 3.0),
-	CErr("2 += 2", "cannot assign"),
-	CErr("i, j += 2", "cannot be combined"),
-	CErr("i += 2, 3", "cannot be combined"),
-	Val2("s2 := s; s += \"def\"", "s2", "abc", "s", "abcdef"),
-	CErr("s += 1", opTypes),
-	// Single evaluation
-	Val2("ai[func()int{i+=1;return 0}()] *= 3; i2 = ai[0]", "i", 2, "i2", 3),
-
-	// Type declarations
-	// Identifiers
-	Run("type T int"),
-	CErr("type T x", "undefined"),
-	CErr("type T c", "constant"),
-	CErr("type T i", "variable"),
-	CErr("type T T", "recursive"),
-	CErr("type T x; type U T; var v U; v = 1", "undefined"),
-	// Pointer types
-	Run("type T *int"),
-	Run("type T *T"),
-	// Array types
-	Run("type T [5]int"),
-	Run("type T [c+42/2]int"),
-	Run("type T [2.0]int"),
-	CErr("type T [i]int", "constant expression"),
-	CErr("type T [2.5]int", constantTruncated),
-	CErr("type T [-1]int", "negative"),
-	CErr("type T [2]T", "recursive"),
-	// Struct types
-	Run("type T struct { a int; b int }"),
-	Run("type T struct { a int; int }"),
-	Run("type T struct { x *T }"),
-	Run("type T int; type U struct { T }"),
-	CErr("type T *int; type U struct { T }", "embedded.*pointer"),
-	CErr("type T *struct { T }", "embedded.*pointer"),
-	CErr("type T struct { a int; a int }", " a .*redeclared.*:1:17"),
-	CErr("type T struct { int; int }", "int .*redeclared.*:1:17"),
-	CErr("type T struct { int int; int }", "int .*redeclared.*:1:17"),
-	Run("type T struct { x *struct { T } }"),
-	CErr("type T struct { x struct { T } }", "recursive"),
-	CErr("type T struct { x }; type U struct { T }", "undefined"),
-	// Function types
-	Run("type T func()"),
-	Run("type T func(a, b int) int"),
-	Run("type T func(a, b int) (x int, y int)"),
-	Run("type T func(a, a int) (a int, a int)"),
-	Run("type T func(a, b int) (x, y int)"),
-	Run("type T func(int, int) (int, int)"),
-	CErr("type T func(x); type U T", "undefined"),
-	CErr("type T func(a T)", "recursive"),
-	// Interface types
-	Run("type T interface {x(a, b int) int}"),
-	Run("type T interface {x(a, b int) int}; type U interface {T; y(c int)}"),
-	CErr("type T interface {x(a int); x()}", "method x redeclared"),
-	CErr("type T interface {x()}; type U interface {T; x()}", "method x redeclared"),
-	CErr("type T int; type U interface {T}", "embedded type"),
-	// Parens
-	Run("type T (int)"),
-
-	// Variable declarations
-	Val2("var x int", "i", 1, "x", 0),
-	Val1("var x = 1", "x", 1),
-	Val1("var x = 1.0", "x", 1.0),
-	Val1("var x int = 1.0", "x", 1),
-	// Placeholders
-	CErr("var x foo; x = 1", "undefined"),
-	CErr("var x foo = 1; x = 1", "undefined"),
-	// Redeclaration
-	CErr("var i, x int", " i .*redeclared"),
-	CErr("var x int; var x int", " x .*redeclared.*:1:5"),
-
-	// Expression statements
-	CErr("x := func(){ 1-1 }", "expression statement"),
-	CErr("x := func(){ 1-1 }", "- expression"),
-	Val1("fn(2)", "i", 1),
-
-	// IncDec statements
-	Val1("i++", "i", 2),
-	Val1("i--", "i", 0),
-	Val1("u++", "u", uint(2)),
-	Val1("u--", "u", uint(0)),
-	Val1("f++", "f", 2.0),
-	Val1("f--", "f", 0.0),
-	// Single evaluation
-	Val2("ai[func()int{i+=1;return 0}()]++; i2 = ai[0]", "i", 2, "i2", 2),
-	// Operand types
-	CErr("s++", opTypes),
-	CErr("s++", "'\\+\\+'"),
-	CErr("2++", "cannot assign"),
-	CErr("c++", "cannot assign"),
-
-	// Function scoping
-	Val1("fn1 := func() { i=2 }; fn1()", "i", 2),
-	Val1("fn1 := func() { i:=2 }; fn1()", "i", 1),
-	Val2("fn1 := func() int { i=2; i:=3; i=4; return i }; x := fn1()", "i", 2, "x", 4),
-
-	// Basic returns
-	CErr("fn1 := func() int {}", "return"),
-	Run("fn1 := func() {}"),
-	CErr("fn1 := func() (r int) {}", "return"),
-	Val1("fn1 := func() (r int) {return}; i = fn1()", "i", 0),
-	Val1("fn1 := func() (r int) {r = 2; return}; i = fn1()", "i", 2),
-	Val1("fn1 := func() (r int) {return 2}; i = fn1()", "i", 2),
-	Val1("fn1 := func(int) int {return 2}; i = fn1(1)", "i", 2),
-
-	// Multi-valued returns
-	Val2("fn1 := func() (bool, int) {return true, 2}; x, y := fn1()", "x", true, "y", 2),
-	CErr("fn1 := func() int {return}", "not enough values"),
-	CErr("fn1 := func() int {return 1,2}", "too many values"),
-	CErr("fn1 := func() {return 1}", "too many values"),
-	CErr("fn1 := func() (int,int,int) {return 1,2}", "not enough values"),
-	Val2("fn1 := func() (int, int) {return oneTwo()}; x, y := fn1()", "x", 1, "y", 2),
-	CErr("fn1 := func() int {return oneTwo()}", "too many values"),
-	CErr("fn1 := func() (int,int,int) {return oneTwo()}", "not enough values"),
-	Val1("fn1 := func(x,y int) int {return x+y}; x := fn1(oneTwo())", "x", 3),
-
-	// Return control flow
-	Val2("fn1 := func(x *int) bool { *x = 2; return true; *x = 3; }; x := fn1(&i)", "i", 2, "x", true),
-
-	// Break/continue/goto/fallthrough
-	CErr("break", "outside"),
-	CErr("break foo", "break.*foo.*not defined"),
-	CErr("continue", "outside"),
-	CErr("continue foo", "continue.*foo.*not defined"),
-	CErr("fallthrough", "outside"),
-	CErr("goto foo", "foo.*not defined"),
-	CErr(" foo: foo:;", "foo.*redeclared.*:1:2"),
-	Val1("i+=2; goto L; i+=4; L: i+=8", "i", 1+2+8),
-	// Return checking
-	CErr("fn1 := func() int { goto L; return 1; L: }", "return"),
-	Run("fn1 := func() int { L: goto L; i = 2 }"),
-	Run("fn1 := func() int { return 1; L: goto L }"),
-	// Scope checking
-	Run("fn1 := func() { { L: x:=1 }; goto L }"),
-	CErr("fn1 := func() { { x:=1; L: }; goto L }", "into scope"),
-	CErr("fn1 := func() { goto L; x:=1; L: }", "into scope"),
-	Run("fn1 := func() { goto L; { L: x:=1 } }"),
-	CErr("fn1 := func() { goto L; { x:=1; L: } }", "into scope"),
-
-	// Blocks
-	CErr("fn1 := func() int {{}}", "return"),
-	Val1("fn1 := func() bool { { return true } }; b := fn1()", "b", true),
-
-	// If
-	Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
-	Val2("if false { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
-	Val2("if i == i2 { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
-	// Omit optional parts
-	Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
-	Val2("if true { i = 2 }; i2 = 4", "i", 2, "i2", 4),
-	Val2("if false { i = 2 }; i2 = 4", "i", 1, "i2", 4),
-	// Init
-	Val2("if x := true; x { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
-	Val2("if x := false; x { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
-	// Statement else
-	Val2("if true { i = 2 } else i = 3; i2 = 4", "i", 2, "i2", 4),
-	Val2("if false { i = 2 } else i = 3; i2 = 4", "i", 3, "i2", 4),
-	// Scoping
-	Val2("if true { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
-	Val2("if false { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
-	Val2("if false { i := 2 } else i := 3; i2 = i", "i", 1, "i2", 1),
-	CErr("if true { x := 2 }; x = 4", undefined),
-	Val2("if i := 2; true { i2 = i; i := 3 }", "i", 1, "i2", 2),
-	Val2("if i := 2; false {} else { i2 = i; i := 3 }", "i", 1, "i2", 2),
-	// Return checking
-	Run("fn1 := func() int { if true { return 1 } else { return 2 } }"),
-	Run("fn1 := func() int { if true { return 1 } else return 2 }"),
-	CErr("fn1 := func() int { if true { return 1 } else { } }", "return"),
-	CErr("fn1 := func() int { if true { } else { return 1 } }", "return"),
-	CErr("fn1 := func() int { if true { } else return 1 }", "return"),
-	CErr("fn1 := func() int { if true { } else { } }", "return"),
-	CErr("fn1 := func() int { if true { return 1 } }", "return"),
-	CErr("fn1 := func() int { if true { } }", "return"),
-	Run("fn1 := func() int { if true { }; return 1 }"),
-	CErr("fn1 := func() int { if true { } }", "return"),
-	CErr("fn1 := func() int { if true { } else { return 2 } }", "return"),
-	Run("fn1 := func() int { if true { return 1 }; return 0 }"),
-	Run("fn1 := func() int { if true { return 1 } else { }; return 0 }"),
-	Run("fn1 := func() int { if true { return 1 } else { }; return 0 }"),
-
-	// Switch
-	Val1("switch { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+4),
-	Val1("switch { default: i += 2; case false: i += 4; case true: i += 8 }", "i", 1+8),
-	CErr("switch { default: i += 2; default: i += 4 }", "more than one"),
-	Val1("switch false { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+2),
-	CErr("switch s { case 1: }", opTypes),
-	CErr("switch ai { case ai: i += 2 }", opTypes),
-	Val1("switch 1.0 { case 1: i += 2; case 2: i += 4 }", "i", 1+2),
-	Val1("switch 1.5 { case 1: i += 2; case 2: i += 4 }", "i", 1),
-	CErr("switch oneTwo() {}", "multi-valued expression"),
-	Val1("switch 2 { case 1: i += 2; fallthrough; case 2: i += 4; fallthrough; case 3: i += 8; fallthrough }", "i", 1+4+8),
-	Val1("switch 5 { case 1: i += 2; fallthrough; default: i += 4; fallthrough; case 2: i += 8; fallthrough; case 3: i += 16; fallthrough }", "i", 1+4+8+16),
-	CErr("switch { case true: fallthrough; i += 2 }", "final statement"),
-	Val1("switch { case true: i += 2; fallthrough; ; ; case false: i += 4 }", "i", 1+2+4),
-	Val1("switch 2 { case 0, 1: i += 2; case 2, 3: i += 4 }", "i", 1+4),
-	Val2("switch func()int{i2++;return 5}() { case 1, 2: i += 2; case 4, 5: i += 4 }", "i", 1+4, "i2", 3),
-	Run("switch i { case i: }"),
-	// TODO(austin) Why doesn't this fail?
-	//CErr("case 1:", "XXX"),
-
-	// For
-	Val2("for x := 1; x < 5; x++ { i+=x }; i2 = 4", "i", 11, "i2", 4),
-	Val2("for x := 1; x < 5; x++ { i+=x; break; i++ }; i2 = 4", "i", 2, "i2", 4),
-	Val2("for x := 1; x < 5; x++ { i+=x; continue; i++ }; i2 = 4", "i", 11, "i2", 4),
-	Val2("for i = 2; false; i = 3 { i = 4 }; i2 = 4", "i", 2, "i2", 4),
-	Val2("for i < 5 { i++ }; i2 = 4", "i", 5, "i2", 4),
-	Val2("for i < 0 { i++ }; i2 = 4", "i", 1, "i2", 4),
-	// Scoping
-	Val2("for i := 2; true; { i2 = i; i := 3; break }", "i", 1, "i2", 2),
-	// Labeled break/continue
-	Val1("L1: for { L2: for { i+=2; break L1; i+=4 }; i+=8 }", "i", 1+2),
-	Val1("L1: for { L2: for { i+=2; break L2; i+=4 }; i+=8; break; i+=16 }", "i", 1+2+8),
-	CErr("L1: { for { break L1 } }", "break.*not defined"),
-	CErr("L1: for {}; for { break L1 }", "break.*not defined"),
-	CErr("L1:; for { break L1 }", "break.*not defined"),
-	Val2("L1: for i = 0; i < 2; i++ { L2: for { i2++; continue L1; i2++ } }", "i", 2, "i2", 4),
-	CErr("L1: { for { continue L1 } }", "continue.*not defined"),
-	CErr("L1:; for { continue L1 }", "continue.*not defined"),
-	// Return checking
-	Run("fn1 := func() int{ for {} }"),
-	CErr("fn1 := func() int{ for true {} }", "return"),
-	CErr("fn1 := func() int{ for true {return 1} }", "return"),
-	CErr("fn1 := func() int{ for {break} }", "return"),
-	Run("fn1 := func() int{ for { for {break} } }"),
-	CErr("fn1 := func() int{ L1: for { for {break L1} } }", "return"),
-	Run("fn1 := func() int{ for true {}; return 1 }"),
-
-	// Selectors
-	Val1("var x struct { a int; b int }; x.a = 42; i = x.a", "i", 42),
-	Val1("type T struct { x int }; var y struct { T }; y.x = 42; i = y.x", "i", 42),
-	Val2("type T struct { x int }; var y struct { T; x int }; y.x = 42; i = y.x; i2 = y.T.x", "i", 42, "i2", 0),
-	Run("type T struct { x int }; var y struct { *T }; a := func(){i=y.x}"),
-	CErr("type T struct { x int }; var x T; x.y = 42", "no field"),
-	CErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"),
-	CErr("type T struct { *T }; var x T; x.foo", "no field"),
-
-	Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 }; return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946),
-
-	// Make slice
-	Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0),
-	Val2("x := make([]int, 2); x[1] = 42; i, i2 = x[0], x[1]", "i", 0, "i2", 42),
-	RErr("x := make([]int, 2); x[-i] = 42", "negative index"),
-	RErr("x := make([]int, 2); x[2] = 42", "index 2 exceeds"),
-	Val2("x := make([]int, 2, 3); i, i2 = len(x), cap(x)", "i", 2, "i2", 3),
-	Val2("x := make([]int, 3, 2); i, i2 = len(x), cap(x)", "i", 3, "i2", 3),
-	RErr("x := make([]int, -i)", "negative length"),
-	RErr("x := make([]int, 2, -i)", "negative capacity"),
-	RErr("x := make([]int, 2, 3); x[2] = 42", "index 2 exceeds"),
-	CErr("x := make([]int, 2, 3, 4)", "too many"),
-	CErr("x := make([]int)", "not enough"),
-
-	// TODO(austin) Test make map
-
-	// Maps
-	Val1("x := make(map[int] int); x[1] = 42; i = x[1]", "i", 42),
-	Val2("x := make(map[int] int); x[1] = 42; i, y := x[1]", "i", 42, "y", true),
-	Val2("x := make(map[int] int); x[1] = 42; i, y := x[2]", "i", 0, "y", false),
-	// Not implemented
-	//Val1("x := make(map[int] int); x[1] = 42, true; i = x[1]", "i", 42),
-	//Val2("x := make(map[int] int); x[1] = 42; x[1] = 42, false; i, y := x[1]", "i", 0, "y", false),
-	Run("var x int; a := make(map[int] int); a[0], x = 1, 2"),
-	CErr("x := make(map[int] int); (func(a,b int){})(x[0])", "not enough"),
-	CErr("x := make(map[int] int); x[1] = oneTwo()", "too many"),
-	RErr("x := make(map[int] int); i = x[1]", "key '1' not found"),
-
-	// Functions
-	Val2("func fib(n int) int { if n <= 2 { return n }; return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89),
-	Run("func f1(){}"),
-	Run2("func f1(){}", "f1()"),
-}
-
-func TestStmt(t *testing.T) { runTests(t, "stmtTests", stmtTests) }
diff --git a/src/pkg/exp/eval/test.bash b/src/pkg/exp/eval/test.bash
deleted file mode 100755
index 50b61fd..0000000
--- a/src/pkg/exp/eval/test.bash
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Run the interpreter against all the Go test programs
-# that begin with the magic
-#	// $G $D/$F.go && $L $F.$A && ./$A.out
-# line and do not contain imports.
-
-set -e
-
-gomake
-6g main.go && 6l main.6
-(
-for i in $(egrep -l '// \$G (\$D/)?\$F\.go \&\& \$L \$F\.\$A && \./\$A\.out' "$GOROOT"/test/*.go "$GOROOT"/test/*/*.go)
-do
-	if grep '^import' $i >/dev/null 2>&1
-	then
-		true
-	else
-		if "$GOROOT"/usr/austin/eval/6.out -f $i >/tmp/out 2>&1 && ! test -s /tmp/out
-		then
-			echo PASS $i
-		else
-			echo FAIL $i
-			(
-				echo '>>> ' $i
-				cat /tmp/out
-				echo
-			) 1>&3
-		fi
-	fi
-done | (tee /dev/fd/2 | awk '{print $1}' | sort | uniq -c) 2>&1
-) 3>test.log
diff --git a/src/pkg/exp/eval/type.go b/src/pkg/exp/eval/type.go
deleted file mode 100644
index 8a93d8a..0000000
--- a/src/pkg/exp/eval/type.go
+++ /dev/null
@@ -1,1252 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"big"
-	"go/ast"
-	"go/token"
-	"log"
-	"reflect"
-	"sort"
-	"unsafe" // For Sizeof
-)
-
-
-// XXX(Spec) The type compatibility section is very confusing because
-// it makes it seem like there are three distinct types of
-// compatibility: plain compatibility, assignment compatibility, and
-// comparison compatibility.  As I understand it, there's really only
-// assignment compatibility and comparison and conversion have some
-// restrictions and have special meaning in some cases where the types
-// are not otherwise assignment compatible.  The comparison
-// compatibility section is almost all about the semantics of
-// comparison, not the type checking of it, so it would make much more
-// sense in the comparison operators section.  The compatibility and
-// assignment compatibility sections should be rolled into one.
-
-type Type interface {
-	// compat returns whether this type is compatible with another
-	// type.  If conv is false, this is normal compatibility,
-	// where two named types are compatible only if they are the
-	// same named type.  If conv if true, this is conversion
-	// compatibility, where two named types are conversion
-	// compatible if their definitions are conversion compatible.
-	//
-	// TODO(austin) Deal with recursive types
-	compat(o Type, conv bool) bool
-	// lit returns this type's literal.  If this is a named type,
-	// this is the unnamed underlying type.  Otherwise, this is an
-	// identity operation.
-	lit() Type
-	// isBoolean returns true if this is a boolean type.
-	isBoolean() bool
-	// isInteger returns true if this is an integer type.
-	isInteger() bool
-	// isFloat returns true if this is a floating type.
-	isFloat() bool
-	// isIdeal returns true if this is an ideal int or float.
-	isIdeal() bool
-	// Zero returns a new zero value of this type.
-	Zero() Value
-	// String returns the string representation of this type.
-	String() string
-	// The position where this type was defined, if any.
-	Pos() token.Pos
-}
-
-type BoundedType interface {
-	Type
-	// minVal returns the smallest value of this type.
-	minVal() *big.Rat
-	// maxVal returns the largest value of this type.
-	maxVal() *big.Rat
-}
-
-var universePos = token.NoPos
-
-/*
- * Type array maps.  These are used to memoize composite types.
- */
-
-type typeArrayMapEntry struct {
-	key  []Type
-	v    interface{}
-	next *typeArrayMapEntry
-}
-
-type typeArrayMap map[uintptr]*typeArrayMapEntry
-
-func hashTypeArray(key []Type) uintptr {
-	hash := uintptr(0)
-	for _, t := range key {
-		hash = hash * 33
-		if t == nil {
-			continue
-		}
-		addr := reflect.ValueOf(t).Pointer()
-		hash ^= addr
-	}
-	return hash
-}
-
-func newTypeArrayMap() typeArrayMap { return make(map[uintptr]*typeArrayMapEntry) }
-
-func (m typeArrayMap) Get(key []Type) interface{} {
-	ent, ok := m[hashTypeArray(key)]
-	if !ok {
-		return nil
-	}
-
-nextEnt:
-	for ; ent != nil; ent = ent.next {
-		if len(key) != len(ent.key) {
-			continue
-		}
-		for i := 0; i < len(key); i++ {
-			if key[i] != ent.key[i] {
-				continue nextEnt
-			}
-		}
-		// Found it
-		return ent.v
-	}
-
-	return nil
-}
-
-func (m typeArrayMap) Put(key []Type, v interface{}) interface{} {
-	hash := hashTypeArray(key)
-	ent := m[hash]
-
-	new := &typeArrayMapEntry{key, v, ent}
-	m[hash] = new
-	return v
-}
-
-/*
- * Common type
- */
-
-type commonType struct{}
-
-func (commonType) isBoolean() bool { return false }
-
-func (commonType) isInteger() bool { return false }
-
-func (commonType) isFloat() bool { return false }
-
-func (commonType) isIdeal() bool { return false }
-
-func (commonType) Pos() token.Pos { return token.NoPos }
-
-/*
- * Bool
- */
-
-type boolType struct {
-	commonType
-}
-
-var BoolType = universe.DefineType("bool", universePos, &boolType{})
-
-func (t *boolType) compat(o Type, conv bool) bool {
-	_, ok := o.lit().(*boolType)
-	return ok
-}
-
-func (t *boolType) lit() Type { return t }
-
-func (t *boolType) isBoolean() bool { return true }
-
-func (boolType) String() string {
-	// Use angle brackets as a convention for printing the
-	// underlying, unnamed type.  This should only show up in
-	// debug output.
-	return "<bool>"
-}
-
-func (t *boolType) Zero() Value {
-	res := boolV(false)
-	return &res
-}
-
-/*
- * Uint
- */
-
-type uintType struct {
-	commonType
-
-	// 0 for architecture-dependent types
-	Bits uint
-	// true for uintptr, false for all others
-	Ptr  bool
-	name string
-}
-
-var (
-	Uint8Type  = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"})
-	Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"})
-	Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"})
-	Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"})
-
-	UintType    = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"})
-	UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"})
-)
-
-func (t *uintType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*uintType)
-	return ok && t == t2
-}
-
-func (t *uintType) lit() Type { return t }
-
-func (t *uintType) isInteger() bool { return true }
-
-func (t *uintType) String() string { return "<" + t.name + ">" }
-
-func (t *uintType) Zero() Value {
-	switch t.Bits {
-	case 0:
-		if t.Ptr {
-			res := uintptrV(0)
-			return &res
-		} else {
-			res := uintV(0)
-			return &res
-		}
-	case 8:
-		res := uint8V(0)
-		return &res
-	case 16:
-		res := uint16V(0)
-		return &res
-	case 32:
-		res := uint32V(0)
-		return &res
-	case 64:
-		res := uint64V(0)
-		return &res
-	}
-	panic("unexpected uint bit count")
-}
-
-func (t *uintType) minVal() *big.Rat { return big.NewRat(0, 1) }
-
-func (t *uintType) maxVal() *big.Rat {
-	bits := t.Bits
-	if bits == 0 {
-		if t.Ptr {
-			bits = uint(8 * unsafe.Sizeof(uintptr(0)))
-		} else {
-			bits = uint(8 * unsafe.Sizeof(uint(0)))
-		}
-	}
-	numer := big.NewInt(1)
-	numer.Lsh(numer, bits)
-	numer.Sub(numer, idealOne)
-	return new(big.Rat).SetInt(numer)
-}
-
-/*
- * Int
- */
-
-type intType struct {
-	commonType
-
-	// XXX(Spec) Numeric types: "There is also a set of
-	// architecture-independent basic numeric types whose size
-	// depends on the architecture."  Should that be
-	// architecture-dependent?
-
-	// 0 for architecture-dependent types
-	Bits uint
-	name string
-}
-
-var (
-	Int8Type  = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"})
-	Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"})
-	Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"})
-	Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"})
-
-	IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"})
-)
-
-func (t *intType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*intType)
-	return ok && t == t2
-}
-
-func (t *intType) lit() Type { return t }
-
-func (t *intType) isInteger() bool { return true }
-
-func (t *intType) String() string { return "<" + t.name + ">" }
-
-func (t *intType) Zero() Value {
-	switch t.Bits {
-	case 8:
-		res := int8V(0)
-		return &res
-	case 16:
-		res := int16V(0)
-		return &res
-	case 32:
-		res := int32V(0)
-		return &res
-	case 64:
-		res := int64V(0)
-		return &res
-
-	case 0:
-		res := intV(0)
-		return &res
-	}
-	panic("unexpected int bit count")
-}
-
-func (t *intType) minVal() *big.Rat {
-	bits := t.Bits
-	if bits == 0 {
-		bits = uint(8 * unsafe.Sizeof(int(0)))
-	}
-	numer := big.NewInt(-1)
-	numer.Lsh(numer, bits-1)
-	return new(big.Rat).SetInt(numer)
-}
-
-func (t *intType) maxVal() *big.Rat {
-	bits := t.Bits
-	if bits == 0 {
-		bits = uint(8 * unsafe.Sizeof(int(0)))
-	}
-	numer := big.NewInt(1)
-	numer.Lsh(numer, bits-1)
-	numer.Sub(numer, idealOne)
-	return new(big.Rat).SetInt(numer)
-}
-
-/*
- * Ideal int
- */
-
-type idealIntType struct {
-	commonType
-}
-
-var IdealIntType Type = &idealIntType{}
-
-func (t *idealIntType) compat(o Type, conv bool) bool {
-	_, ok := o.lit().(*idealIntType)
-	return ok
-}
-
-func (t *idealIntType) lit() Type { return t }
-
-func (t *idealIntType) isInteger() bool { return true }
-
-func (t *idealIntType) isIdeal() bool { return true }
-
-func (t *idealIntType) String() string { return "ideal integer" }
-
-func (t *idealIntType) Zero() Value { return &idealIntV{idealZero} }
-
-/*
- * Float
- */
-
-type floatType struct {
-	commonType
-
-	// 0 for architecture-dependent type
-	Bits uint
-
-	name string
-}
-
-var (
-	Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"})
-	Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"})
-)
-
-func (t *floatType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*floatType)
-	return ok && t == t2
-}
-
-func (t *floatType) lit() Type { return t }
-
-func (t *floatType) isFloat() bool { return true }
-
-func (t *floatType) String() string { return "<" + t.name + ">" }
-
-func (t *floatType) Zero() Value {
-	switch t.Bits {
-	case 32:
-		res := float32V(0)
-		return &res
-	case 64:
-		res := float64V(0)
-		return &res
-	}
-	panic("unexpected float bit count")
-}
-
-var maxFloat32Val *big.Rat
-var maxFloat64Val *big.Rat
-var minFloat32Val *big.Rat
-var minFloat64Val *big.Rat
-
-func (t *floatType) minVal() *big.Rat {
-	bits := t.Bits
-	switch bits {
-	case 32:
-		return minFloat32Val
-	case 64:
-		return minFloat64Val
-	}
-	log.Panicf("unexpected floating point bit count: %d", bits)
-	panic("unreachable")
-}
-
-func (t *floatType) maxVal() *big.Rat {
-	bits := t.Bits
-	switch bits {
-	case 32:
-		return maxFloat32Val
-	case 64:
-		return maxFloat64Val
-	}
-	log.Panicf("unexpected floating point bit count: %d", bits)
-	panic("unreachable")
-}
-
-/*
- * Ideal float
- */
-
-type idealFloatType struct {
-	commonType
-}
-
-var IdealFloatType Type = &idealFloatType{}
-
-func (t *idealFloatType) compat(o Type, conv bool) bool {
-	_, ok := o.lit().(*idealFloatType)
-	return ok
-}
-
-func (t *idealFloatType) lit() Type { return t }
-
-func (t *idealFloatType) isFloat() bool { return true }
-
-func (t *idealFloatType) isIdeal() bool { return true }
-
-func (t *idealFloatType) String() string { return "ideal float" }
-
-func (t *idealFloatType) Zero() Value { return &idealFloatV{big.NewRat(0, 1)} }
-
-/*
- * String
- */
-
-type stringType struct {
-	commonType
-}
-
-var StringType = universe.DefineType("string", universePos, &stringType{})
-
-func (t *stringType) compat(o Type, conv bool) bool {
-	_, ok := o.lit().(*stringType)
-	return ok
-}
-
-func (t *stringType) lit() Type { return t }
-
-func (t *stringType) String() string { return "<string>" }
-
-func (t *stringType) Zero() Value {
-	res := stringV("")
-	return &res
-}
-
-/*
- * Array
- */
-
-type ArrayType struct {
-	commonType
-	Len  int64
-	Elem Type
-}
-
-var arrayTypes = make(map[int64]map[Type]*ArrayType)
-
-// Two array types are identical if they have identical element types
-// and the same array length.
-
-func NewArrayType(len int64, elem Type) *ArrayType {
-	ts, ok := arrayTypes[len]
-	if !ok {
-		ts = make(map[Type]*ArrayType)
-		arrayTypes[len] = ts
-	}
-	t, ok := ts[elem]
-	if !ok {
-		t = &ArrayType{commonType{}, len, elem}
-		ts[elem] = t
-	}
-	return t
-}
-
-func (t *ArrayType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*ArrayType)
-	if !ok {
-		return false
-	}
-	return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv)
-}
-
-func (t *ArrayType) lit() Type { return t }
-
-func (t *ArrayType) String() string { return "[]" + t.Elem.String() }
-
-func (t *ArrayType) Zero() Value {
-	res := arrayV(make([]Value, t.Len))
-	// TODO(austin) It's unfortunate that each element is
-	// separately heap allocated.  We could add ZeroArray to
-	// everything, though that doesn't help with multidimensional
-	// arrays.  Or we could do something unsafe.  We'll have this
-	// same problem with structs.
-	for i := int64(0); i < t.Len; i++ {
-		res[i] = t.Elem.Zero()
-	}
-	return &res
-}
-
-/*
- * Struct
- */
-
-type StructField struct {
-	Name      string
-	Type      Type
-	Anonymous bool
-}
-
-type StructType struct {
-	commonType
-	Elems []StructField
-}
-
-var structTypes = newTypeArrayMap()
-
-// Two struct types are identical if they have the same sequence of
-// fields, and if corresponding fields have the same names and
-// identical types. Two anonymous fields are considered to have the
-// same name.
-
-func NewStructType(fields []StructField) *StructType {
-	// Start by looking up just the types
-	fts := make([]Type, len(fields))
-	for i, f := range fields {
-		fts[i] = f.Type
-	}
-	tMapI := structTypes.Get(fts)
-	if tMapI == nil {
-		tMapI = structTypes.Put(fts, make(map[string]*StructType))
-	}
-	tMap := tMapI.(map[string]*StructType)
-
-	// Construct key for field names
-	key := ""
-	for _, f := range fields {
-		// XXX(Spec) It's not clear if struct { T } and struct
-		// { T T } are either identical or compatible.  The
-		// "Struct Types" section says that the name of that
-		// field is "T", which suggests that they are
-		// identical, but it really means that it's the name
-		// for the purpose of selector expressions and nothing
-		// else.  We decided that they should be neither
-		// identical or compatible.
-		if f.Anonymous {
-			key += "!"
-		}
-		key += f.Name + " "
-	}
-
-	// XXX(Spec) Do the tags also have to be identical for the
-	// types to be identical?  I certainly hope so, because
-	// otherwise, this is the only case where two distinct type
-	// objects can represent identical types.
-
-	t, ok := tMap[key]
-	if !ok {
-		// Create new struct type
-		t = &StructType{commonType{}, fields}
-		tMap[key] = t
-	}
-	return t
-}
-
-func (t *StructType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*StructType)
-	if !ok {
-		return false
-	}
-	if len(t.Elems) != len(t2.Elems) {
-		return false
-	}
-	for i, e := range t.Elems {
-		e2 := t2.Elems[i]
-		// XXX(Spec) An anonymous and a non-anonymous field
-		// are neither identical nor compatible.
-		if e.Anonymous != e2.Anonymous ||
-			(!e.Anonymous && e.Name != e2.Name) ||
-			!e.Type.compat(e2.Type, conv) {
-			return false
-		}
-	}
-	return true
-}
-
-func (t *StructType) lit() Type { return t }
-
-func (t *StructType) String() string {
-	s := "struct {"
-	for i, f := range t.Elems {
-		if i > 0 {
-			s += "; "
-		}
-		if !f.Anonymous {
-			s += f.Name + " "
-		}
-		s += f.Type.String()
-	}
-	return s + "}"
-}
-
-func (t *StructType) Zero() Value {
-	res := structV(make([]Value, len(t.Elems)))
-	for i, f := range t.Elems {
-		res[i] = f.Type.Zero()
-	}
-	return &res
-}
-
-/*
- * Pointer
- */
-
-type PtrType struct {
-	commonType
-	Elem Type
-}
-
-var ptrTypes = make(map[Type]*PtrType)
-
-// Two pointer types are identical if they have identical base types.
-
-func NewPtrType(elem Type) *PtrType {
-	t, ok := ptrTypes[elem]
-	if !ok {
-		t = &PtrType{commonType{}, elem}
-		ptrTypes[elem] = t
-	}
-	return t
-}
-
-func (t *PtrType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*PtrType)
-	if !ok {
-		return false
-	}
-	return t.Elem.compat(t2.Elem, conv)
-}
-
-func (t *PtrType) lit() Type { return t }
-
-func (t *PtrType) String() string { return "*" + t.Elem.String() }
-
-func (t *PtrType) Zero() Value { return &ptrV{nil} }
-
-/*
- * Function
- */
-
-type FuncType struct {
-	commonType
-	// TODO(austin) Separate receiver Type for methods?
-	In       []Type
-	Variadic bool
-	Out      []Type
-	builtin  string
-}
-
-var funcTypes = newTypeArrayMap()
-var variadicFuncTypes = newTypeArrayMap()
-
-// Create singleton function types for magic built-in functions
-var (
-	capType     = &FuncType{builtin: "cap"}
-	closeType   = &FuncType{builtin: "close"}
-	closedType  = &FuncType{builtin: "closed"}
-	lenType     = &FuncType{builtin: "len"}
-	makeType    = &FuncType{builtin: "make"}
-	newType     = &FuncType{builtin: "new"}
-	panicType   = &FuncType{builtin: "panic"}
-	printType   = &FuncType{builtin: "print"}
-	printlnType = &FuncType{builtin: "println"}
-	copyType    = &FuncType{builtin: "copy"}
-)
-
-// Two function types are identical if they have the same number of
-// parameters and result values and if corresponding parameter and
-// result types are identical. All "..." parameters have identical
-// type. Parameter and result names are not required to match.
-
-func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
-	inMap := funcTypes
-	if variadic {
-		inMap = variadicFuncTypes
-	}
-
-	outMapI := inMap.Get(in)
-	if outMapI == nil {
-		outMapI = inMap.Put(in, newTypeArrayMap())
-	}
-	outMap := outMapI.(typeArrayMap)
-
-	tI := outMap.Get(out)
-	if tI != nil {
-		return tI.(*FuncType)
-	}
-
-	t := &FuncType{commonType{}, in, variadic, out, ""}
-	outMap.Put(out, t)
-	return t
-}
-
-func (t *FuncType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*FuncType)
-	if !ok {
-		return false
-	}
-	if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) {
-		return false
-	}
-	for i := range t.In {
-		if !t.In[i].compat(t2.In[i], conv) {
-			return false
-		}
-	}
-	for i := range t.Out {
-		if !t.Out[i].compat(t2.Out[i], conv) {
-			return false
-		}
-	}
-	return true
-}
-
-func (t *FuncType) lit() Type { return t }
-
-func typeListString(ts []Type, ns []*ast.Ident) string {
-	s := ""
-	for i, t := range ts {
-		if i > 0 {
-			s += ", "
-		}
-		if ns != nil && ns[i] != nil {
-			s += ns[i].Name + " "
-		}
-		if t == nil {
-			// Some places use nil types to represent errors
-			s += "<none>"
-		} else {
-			s += t.String()
-		}
-	}
-	return s
-}
-
-func (t *FuncType) String() string {
-	if t.builtin != "" {
-		return "built-in function " + t.builtin
-	}
-	args := typeListString(t.In, nil)
-	if t.Variadic {
-		if len(args) > 0 {
-			args += ", "
-		}
-		args += "..."
-	}
-	s := "func(" + args + ")"
-	if len(t.Out) > 0 {
-		s += " (" + typeListString(t.Out, nil) + ")"
-	}
-	return s
-}
-
-func (t *FuncType) Zero() Value { return &funcV{nil} }
-
-type FuncDecl struct {
-	Type *FuncType
-	Name *ast.Ident // nil for function literals
-	// InNames will be one longer than Type.In if this function is
-	// variadic.
-	InNames  []*ast.Ident
-	OutNames []*ast.Ident
-}
-
-func (t *FuncDecl) String() string {
-	s := "func"
-	if t.Name != nil {
-		s += " " + t.Name.Name
-	}
-	s += funcTypeString(t.Type, t.InNames, t.OutNames)
-	return s
-}
-
-func funcTypeString(ft *FuncType, ins []*ast.Ident, outs []*ast.Ident) string {
-	s := "("
-	s += typeListString(ft.In, ins)
-	if ft.Variadic {
-		if len(ft.In) > 0 {
-			s += ", "
-		}
-		s += "..."
-	}
-	s += ")"
-	if len(ft.Out) > 0 {
-		s += " (" + typeListString(ft.Out, outs) + ")"
-	}
-	return s
-}
-
-/*
- * Interface
- */
-
-// TODO(austin) Interface values, types, and type compilation are
-// implemented, but none of the type checking or semantics of
-// interfaces are.
-
-type InterfaceType struct {
-	commonType
-	// TODO(austin) This should be a map from names to
-	// *FuncType's.  We only need the sorted list for generating
-	// the type map key.  It's detrimental for everything else.
-	methods []IMethod
-}
-
-type IMethod struct {
-	Name string
-	Type *FuncType
-}
-
-var interfaceTypes = newTypeArrayMap()
-
-func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType {
-	// Count methods of embedded interfaces
-	nMethods := len(methods)
-	for _, e := range embeds {
-		nMethods += len(e.methods)
-	}
-
-	// Combine methods
-	allMethods := make([]IMethod, nMethods)
-	copy(allMethods, methods)
-	n := len(methods)
-	for _, e := range embeds {
-		for _, m := range e.methods {
-			allMethods[n] = m
-			n++
-		}
-	}
-
-	// Sort methods
-	sort.Sort(iMethodSorter(allMethods))
-
-	mts := make([]Type, len(allMethods))
-	for i, m := range methods {
-		mts[i] = m.Type
-	}
-	tMapI := interfaceTypes.Get(mts)
-	if tMapI == nil {
-		tMapI = interfaceTypes.Put(mts, make(map[string]*InterfaceType))
-	}
-	tMap := tMapI.(map[string]*InterfaceType)
-
-	key := ""
-	for _, m := range allMethods {
-		key += m.Name + " "
-	}
-
-	t, ok := tMap[key]
-	if !ok {
-		t = &InterfaceType{commonType{}, allMethods}
-		tMap[key] = t
-	}
-	return t
-}
-
-type iMethodSorter []IMethod
-
-func (s iMethodSorter) Less(a, b int) bool { return s[a].Name < s[b].Name }
-
-func (s iMethodSorter) Swap(a, b int) { s[a], s[b] = s[b], s[a] }
-
-func (s iMethodSorter) Len() int { return len(s) }
-
-func (t *InterfaceType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*InterfaceType)
-	if !ok {
-		return false
-	}
-	if len(t.methods) != len(t2.methods) {
-		return false
-	}
-	for i, e := range t.methods {
-		e2 := t2.methods[i]
-		if e.Name != e2.Name || !e.Type.compat(e2.Type, conv) {
-			return false
-		}
-	}
-	return true
-}
-
-func (t *InterfaceType) lit() Type { return t }
-
-func (t *InterfaceType) String() string {
-	// TODO(austin) Instead of showing embedded interfaces, this
-	// shows their methods.
-	s := "interface {"
-	for i, m := range t.methods {
-		if i > 0 {
-			s += "; "
-		}
-		s += m.Name + funcTypeString(m.Type, nil, nil)
-	}
-	return s + "}"
-}
-
-// implementedBy tests if o implements t, returning nil, true if it does.
-// Otherwise, it returns a method of t that o is missing and false.
-func (t *InterfaceType) implementedBy(o Type) (*IMethod, bool) {
-	if len(t.methods) == 0 {
-		return nil, true
-	}
-
-	// The methods of a named interface types are those of the
-	// underlying type.
-	if it, ok := o.lit().(*InterfaceType); ok {
-		o = it
-	}
-
-	// XXX(Spec) Interface types: "A type implements any interface
-	// comprising any subset of its methods" It's unclear if
-	// methods must have identical or compatible types.  6g
-	// requires identical types.
-
-	switch o := o.(type) {
-	case *NamedType:
-		for _, tm := range t.methods {
-			sm, ok := o.methods[tm.Name]
-			if !ok || sm.decl.Type != tm.Type {
-				return &tm, false
-			}
-		}
-		return nil, true
-
-	case *InterfaceType:
-		var ti, oi int
-		for ti < len(t.methods) && oi < len(o.methods) {
-			tm, om := &t.methods[ti], &o.methods[oi]
-			switch {
-			case tm.Name == om.Name:
-				if tm.Type != om.Type {
-					return tm, false
-				}
-				ti++
-				oi++
-			case tm.Name > om.Name:
-				oi++
-			default:
-				return tm, false
-			}
-		}
-		if ti < len(t.methods) {
-			return &t.methods[ti], false
-		}
-		return nil, true
-	}
-
-	return &t.methods[0], false
-}
-
-func (t *InterfaceType) Zero() Value { return &interfaceV{} }
-
-/*
- * Slice
- */
-
-type SliceType struct {
-	commonType
-	Elem Type
-}
-
-var sliceTypes = make(map[Type]*SliceType)
-
-// Two slice types are identical if they have identical element types.
-
-func NewSliceType(elem Type) *SliceType {
-	t, ok := sliceTypes[elem]
-	if !ok {
-		t = &SliceType{commonType{}, elem}
-		sliceTypes[elem] = t
-	}
-	return t
-}
-
-func (t *SliceType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*SliceType)
-	if !ok {
-		return false
-	}
-	return t.Elem.compat(t2.Elem, conv)
-}
-
-func (t *SliceType) lit() Type { return t }
-
-func (t *SliceType) String() string { return "[]" + t.Elem.String() }
-
-func (t *SliceType) Zero() Value {
-	// The value of an uninitialized slice is nil. The length and
-	// capacity of a nil slice are 0.
-	return &sliceV{Slice{nil, 0, 0}}
-}
-
-/*
- * Map type
- */
-
-type MapType struct {
-	commonType
-	Key  Type
-	Elem Type
-}
-
-var mapTypes = make(map[Type]map[Type]*MapType)
-
-func NewMapType(key Type, elem Type) *MapType {
-	ts, ok := mapTypes[key]
-	if !ok {
-		ts = make(map[Type]*MapType)
-		mapTypes[key] = ts
-	}
-	t, ok := ts[elem]
-	if !ok {
-		t = &MapType{commonType{}, key, elem}
-		ts[elem] = t
-	}
-	return t
-}
-
-func (t *MapType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*MapType)
-	if !ok {
-		return false
-	}
-	return t.Elem.compat(t2.Elem, conv) && t.Key.compat(t2.Key, conv)
-}
-
-func (t *MapType) lit() Type { return t }
-
-func (t *MapType) String() string { return "map[" + t.Key.String() + "] " + t.Elem.String() }
-
-func (t *MapType) Zero() Value {
-	// The value of an uninitialized map is nil.
-	return &mapV{nil}
-}
-
-/*
-type ChanType struct {
-	// TODO(austin)
-}
-*/
-
-/*
- * Named types
- */
-
-type Method struct {
-	decl *FuncDecl
-	fn   Func
-}
-
-type NamedType struct {
-	NamePos token.Pos
-	Name    string
-	// Underlying type.  If incomplete is true, this will be nil.
-	// If incomplete is false and this is still nil, then this is
-	// a placeholder type representing an error.
-	Def Type
-	// True while this type is being defined.
-	incomplete bool
-	methods    map[string]Method
-}
-
-// TODO(austin) This is temporarily needed by the debugger's remote
-// type parser.  This should only be possible with block.DefineType.
-func NewNamedType(name string) *NamedType {
-	return &NamedType{token.NoPos, name, nil, true, make(map[string]Method)}
-}
-
-func (t *NamedType) Pos() token.Pos {
-	return t.NamePos
-}
-
-func (t *NamedType) Complete(def Type) {
-	if !t.incomplete {
-		log.Panicf("cannot complete already completed NamedType %+v", *t)
-	}
-	// We strip the name from def because multiple levels of
-	// naming are useless.
-	if ndef, ok := def.(*NamedType); ok {
-		def = ndef.Def
-	}
-	t.Def = def
-	t.incomplete = false
-}
-
-func (t *NamedType) compat(o Type, conv bool) bool {
-	t2, ok := o.(*NamedType)
-	if ok {
-		if conv {
-			// Two named types are conversion compatible
-			// if their literals are conversion
-			// compatible.
-			return t.Def.compat(t2.Def, conv)
-		} else {
-			// Two named types are compatible if their
-			// type names originate in the same type
-			// declaration.
-			return t == t2
-		}
-	}
-	// A named and an unnamed type are compatible if the
-	// respective type literals are compatible.
-	return o.compat(t.Def, conv)
-}
-
-func (t *NamedType) lit() Type { return t.Def.lit() }
-
-func (t *NamedType) isBoolean() bool { return t.Def.isBoolean() }
-
-func (t *NamedType) isInteger() bool { return t.Def.isInteger() }
-
-func (t *NamedType) isFloat() bool { return t.Def.isFloat() }
-
-func (t *NamedType) isIdeal() bool { return false }
-
-func (t *NamedType) String() string { return t.Name }
-
-func (t *NamedType) Zero() Value { return t.Def.Zero() }
-
-/*
- * Multi-valued type
- */
-
-// MultiType is a special type used for multi-valued expressions, akin
-// to a tuple type.  It's not generally accessible within the
-// language.
-type MultiType struct {
-	commonType
-	Elems []Type
-}
-
-var multiTypes = newTypeArrayMap()
-
-func NewMultiType(elems []Type) *MultiType {
-	if t := multiTypes.Get(elems); t != nil {
-		return t.(*MultiType)
-	}
-
-	t := &MultiType{commonType{}, elems}
-	multiTypes.Put(elems, t)
-	return t
-}
-
-func (t *MultiType) compat(o Type, conv bool) bool {
-	t2, ok := o.lit().(*MultiType)
-	if !ok {
-		return false
-	}
-	if len(t.Elems) != len(t2.Elems) {
-		return false
-	}
-	for i := range t.Elems {
-		if !t.Elems[i].compat(t2.Elems[i], conv) {
-			return false
-		}
-	}
-	return true
-}
-
-var EmptyType Type = NewMultiType([]Type{})
-
-func (t *MultiType) lit() Type { return t }
-
-func (t *MultiType) String() string {
-	if len(t.Elems) == 0 {
-		return "<none>"
-	}
-	return typeListString(t.Elems, nil)
-}
-
-func (t *MultiType) Zero() Value {
-	res := make([]Value, len(t.Elems))
-	for i, t := range t.Elems {
-		res[i] = t.Zero()
-	}
-	return multiV(res)
-}
-
-/*
- * Initialize the universe
- */
-
-func init() {
-	numer := big.NewInt(0xffffff)
-	numer.Lsh(numer, 127-23)
-	maxFloat32Val = new(big.Rat).SetInt(numer)
-	numer.SetInt64(0x1fffffffffffff)
-	numer.Lsh(numer, 1023-52)
-	maxFloat64Val = new(big.Rat).SetInt(numer)
-	minFloat32Val = new(big.Rat).Neg(maxFloat32Val)
-	minFloat64Val = new(big.Rat).Neg(maxFloat64Val)
-
-	// To avoid portability issues all numeric types are distinct
-	// except byte, which is an alias for uint8.
-
-	// Make byte an alias for the named type uint8.  Type aliases
-	// are otherwise impossible in Go, so just hack it here.
-	universe.defs["byte"] = universe.defs["uint8"]
-
-	// Built-in functions
-	universe.DefineConst("cap", universePos, capType, nil)
-	universe.DefineConst("close", universePos, closeType, nil)
-	universe.DefineConst("closed", universePos, closedType, nil)
-	universe.DefineConst("copy", universePos, copyType, nil)
-	universe.DefineConst("len", universePos, lenType, nil)
-	universe.DefineConst("make", universePos, makeType, nil)
-	universe.DefineConst("new", universePos, newType, nil)
-	universe.DefineConst("panic", universePos, panicType, nil)
-	universe.DefineConst("print", universePos, printType, nil)
-	universe.DefineConst("println", universePos, printlnType, nil)
-}
diff --git a/src/pkg/exp/eval/typec.go b/src/pkg/exp/eval/typec.go
deleted file mode 100644
index 0ed24a8..0000000
--- a/src/pkg/exp/eval/typec.go
+++ /dev/null
@@ -1,409 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"go/ast"
-	"go/token"
-	"log"
-)
-
-
-/*
- * Type compiler
- */
-
-type typeCompiler struct {
-	*compiler
-	block *block
-	// Check to be performed after a type declaration is compiled.
-	//
-	// TODO(austin) This will probably have to change after we
-	// eliminate forward declarations.
-	lateCheck func() bool
-}
-
-func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
-	_, _, def := a.block.Lookup(x.Name)
-	if def == nil {
-		a.diagAt(x.Pos(), "%s: undefined", x.Name)
-		return nil
-	}
-	switch def := def.(type) {
-	case *Constant:
-		a.diagAt(x.Pos(), "constant %v used as type", x.Name)
-		return nil
-	case *Variable:
-		a.diagAt(x.Pos(), "variable %v used as type", x.Name)
-		return nil
-	case *NamedType:
-		if !allowRec && def.incomplete {
-			a.diagAt(x.Pos(), "illegal recursive type")
-			return nil
-		}
-		if !def.incomplete && def.Def == nil {
-			// Placeholder type from an earlier error
-			return nil
-		}
-		return def
-	case Type:
-		return def
-	}
-	log.Panicf("name %s has unknown type %T", x.Name, def)
-	return nil
-}
-
-func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
-	// Compile element type
-	elem := a.compileType(x.Elt, allowRec)
-
-	// Compile length expression
-	if x.Len == nil {
-		if elem == nil {
-			return nil
-		}
-		return NewSliceType(elem)
-	}
-
-	if _, ok := x.Len.(*ast.Ellipsis); ok {
-		a.diagAt(x.Len.Pos(), "... array initializers not implemented")
-		return nil
-	}
-	l, ok := a.compileArrayLen(a.block, x.Len)
-	if !ok {
-		return nil
-	}
-	if l < 0 {
-		a.diagAt(x.Len.Pos(), "array length must be non-negative")
-		return nil
-	}
-	if elem == nil {
-		return nil
-	}
-
-	return NewArrayType(l, elem)
-}
-
-func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Pos, bool) {
-	n := fields.NumFields()
-	ts := make([]Type, n)
-	ns := make([]*ast.Ident, n)
-	ps := make([]token.Pos, n)
-	bad := false
-
-	if fields != nil {
-		i := 0
-		for _, f := range fields.List {
-			t := a.compileType(f.Type, allowRec)
-			if t == nil {
-				bad = true
-			}
-			if f.Names == nil {
-				ns[i] = nil
-				ts[i] = t
-				ps[i] = f.Type.Pos()
-				i++
-				continue
-			}
-			for _, n := range f.Names {
-				ns[i] = n
-				ts[i] = t
-				ps[i] = n.Pos()
-				i++
-			}
-		}
-	}
-
-	return ts, ns, ps, bad
-}
-
-func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
-	ts, names, poss, bad := a.compileFields(x.Fields, allowRec)
-
-	// XXX(Spec) The spec claims that field identifiers must be
-	// unique, but 6g only checks this when they are accessed.  I
-	// think the spec is better in this regard: if I write two
-	// fields with the same name in the same struct type, clearly
-	// that's a mistake.  This definition does *not* descend into
-	// anonymous fields, so it doesn't matter if those change.
-	// There's separate language in the spec about checking
-	// uniqueness of field names inherited from anonymous fields
-	// at use time.
-	fields := make([]StructField, len(ts))
-	nameSet := make(map[string]token.Pos, len(ts))
-	for i := range fields {
-		// Compute field name and check anonymous fields
-		var name string
-		if names[i] != nil {
-			name = names[i].Name
-		} else {
-			if ts[i] == nil {
-				continue
-			}
-
-			var nt *NamedType
-			// [For anonymous fields,] the unqualified
-			// type name acts as the field identifier.
-			switch t := ts[i].(type) {
-			case *NamedType:
-				name = t.Name
-				nt = t
-			case *PtrType:
-				switch t := t.Elem.(type) {
-				case *NamedType:
-					name = t.Name
-					nt = t
-				}
-			}
-			// [An anonymous field] must be specified as a
-			// type name T or as a pointer to a type name
-			// *T, and T itself, may not be a pointer or
-			// interface type.
-			if nt == nil {
-				a.diagAt(poss[i], "embedded type must T or *T, where T is a named type")
-				bad = true
-				continue
-			}
-			// The check for embedded pointer types must
-			// be deferred because of things like
-			//  type T *struct { T }
-			lateCheck := a.lateCheck
-			a.lateCheck = func() bool {
-				if _, ok := nt.lit().(*PtrType); ok {
-					a.diagAt(poss[i], "embedded type %v is a pointer type", nt)
-					return false
-				}
-				return lateCheck()
-			}
-		}
-
-		// Check name uniqueness
-		if prev, ok := nameSet[name]; ok {
-			a.diagAt(poss[i], "field %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
-			bad = true
-			continue
-		}
-		nameSet[name] = poss[i]
-
-		// Create field
-		fields[i].Name = name
-		fields[i].Type = ts[i]
-		fields[i].Anonymous = (names[i] == nil)
-	}
-
-	if bad {
-		return nil
-	}
-
-	return NewStructType(fields)
-}
-
-func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
-	elem := a.compileType(x.X, true)
-	if elem == nil {
-		return nil
-	}
-	return NewPtrType(elem)
-}
-
-func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
-	// TODO(austin) Variadic function types
-
-	// The types of parameters and results must be complete.
-	//
-	// TODO(austin) It's not clear they actually have to be complete.
-	in, inNames, _, inBad := a.compileFields(x.Params, allowRec)
-	out, outNames, _, outBad := a.compileFields(x.Results, allowRec)
-
-	if inBad || outBad {
-		return nil
-	}
-	return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames}
-}
-
-func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType {
-	ts, names, poss, bad := a.compileFields(x.Methods, allowRec)
-
-	methods := make([]IMethod, len(ts))
-	nameSet := make(map[string]token.Pos, len(ts))
-	embeds := make([]*InterfaceType, len(ts))
-
-	var nm, ne int
-	for i := range ts {
-		if ts[i] == nil {
-			continue
-		}
-
-		if names[i] != nil {
-			name := names[i].Name
-			methods[nm].Name = name
-			methods[nm].Type = ts[i].(*FuncType)
-			nm++
-			if prev, ok := nameSet[name]; ok {
-				a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
-				bad = true
-				continue
-			}
-			nameSet[name] = poss[i]
-		} else {
-			// Embedded interface
-			it, ok := ts[i].lit().(*InterfaceType)
-			if !ok {
-				a.diagAt(poss[i], "embedded type must be an interface")
-				bad = true
-				continue
-			}
-			embeds[ne] = it
-			ne++
-			for _, m := range it.methods {
-				if prev, ok := nameSet[m.Name]; ok {
-					a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, a.fset.Position(prev))
-					bad = true
-					continue
-				}
-				nameSet[m.Name] = poss[i]
-			}
-		}
-	}
-
-	if bad {
-		return nil
-	}
-
-	methods = methods[0:nm]
-	embeds = embeds[0:ne]
-
-	return NewInterfaceType(methods, embeds)
-}
-
-func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
-	key := a.compileType(x.Key, true)
-	val := a.compileType(x.Value, true)
-	if key == nil || val == nil {
-		return nil
-	}
-	// XXX(Spec) The Map types section explicitly lists all types
-	// that can be map keys except for function types.
-	switch key.lit().(type) {
-	case *StructType:
-		a.diagAt(x.Pos(), "map key cannot be a struct type")
-		return nil
-	case *ArrayType:
-		a.diagAt(x.Pos(), "map key cannot be an array type")
-		return nil
-	case *SliceType:
-		a.diagAt(x.Pos(), "map key cannot be a slice type")
-		return nil
-	}
-	return NewMapType(key, val)
-}
-
-func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
-	switch x := x.(type) {
-	case *ast.BadExpr:
-		// Error already reported by parser
-		a.silentErrors++
-		return nil
-
-	case *ast.Ident:
-		return a.compileIdent(x, allowRec)
-
-	case *ast.ArrayType:
-		return a.compileArrayType(x, allowRec)
-
-	case *ast.StructType:
-		return a.compileStructType(x, allowRec)
-
-	case *ast.StarExpr:
-		return a.compilePtrType(x)
-
-	case *ast.FuncType:
-		fd := a.compileFuncType(x, allowRec)
-		if fd == nil {
-			return nil
-		}
-		return fd.Type
-
-	case *ast.InterfaceType:
-		return a.compileInterfaceType(x, allowRec)
-
-	case *ast.MapType:
-		return a.compileMapType(x)
-
-	case *ast.ChanType:
-		goto notimpl
-
-	case *ast.ParenExpr:
-		return a.compileType(x.X, allowRec)
-
-	case *ast.Ellipsis:
-		a.diagAt(x.Pos(), "illegal use of ellipsis")
-		return nil
-	}
-	a.diagAt(x.Pos(), "expression used as type")
-	return nil
-
-notimpl:
-	a.diagAt(x.Pos(), "compileType: %T not implemented", x)
-	return nil
-}
-
-/*
- * Type compiler interface
- */
-
-func noLateCheck() bool { return true }
-
-func (a *compiler) compileType(b *block, typ ast.Expr) Type {
-	tc := &typeCompiler{a, b, noLateCheck}
-	t := tc.compileType(typ, false)
-	if !tc.lateCheck() {
-		t = nil
-	}
-	return t
-}
-
-func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
-	ok := true
-	for _, spec := range decl.Specs {
-		spec := spec.(*ast.TypeSpec)
-		// Create incomplete type for this type
-		nt := b.DefineType(spec.Name.Name, spec.Name.Pos(), nil)
-		if nt != nil {
-			nt.(*NamedType).incomplete = true
-		}
-		// Compile type
-		tc := &typeCompiler{a, b, noLateCheck}
-		t := tc.compileType(spec.Type, false)
-		if t == nil {
-			// Create a placeholder type
-			ok = false
-		}
-		// Fill incomplete type
-		if nt != nil {
-			nt.(*NamedType).Complete(t)
-		}
-		// Perform late type checking with complete type
-		if !tc.lateCheck() {
-			ok = false
-			if nt != nil {
-				// Make the type a placeholder
-				nt.(*NamedType).Def = nil
-			}
-		}
-	}
-	return ok
-}
-
-func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
-	tc := &typeCompiler{a, b, noLateCheck}
-	res := tc.compileFuncType(typ, false)
-	if res != nil {
-		if !tc.lateCheck() {
-			res = nil
-		}
-	}
-	return res
-}
diff --git a/src/pkg/exp/eval/value.go b/src/pkg/exp/eval/value.go
deleted file mode 100644
index daa6918..0000000
--- a/src/pkg/exp/eval/value.go
+++ /dev/null
@@ -1,586 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
-	"big"
-	"fmt"
-)
-
-type Value interface {
-	String() string
-	// Assign copies another value into this one.  It should
-	// assume that the other value satisfies the same specific
-	// value interface (BoolValue, etc.), but must not assume
-	// anything about its specific type.
-	Assign(t *Thread, o Value)
-}
-
-type BoolValue interface {
-	Value
-	Get(*Thread) bool
-	Set(*Thread, bool)
-}
-
-type UintValue interface {
-	Value
-	Get(*Thread) uint64
-	Set(*Thread, uint64)
-}
-
-type IntValue interface {
-	Value
-	Get(*Thread) int64
-	Set(*Thread, int64)
-}
-
-// TODO(austin) IdealIntValue and IdealFloatValue should not exist
-// because ideals are not l-values.
-type IdealIntValue interface {
-	Value
-	Get() *big.Int
-}
-
-type FloatValue interface {
-	Value
-	Get(*Thread) float64
-	Set(*Thread, float64)
-}
-
-type IdealFloatValue interface {
-	Value
-	Get() *big.Rat
-}
-
-type StringValue interface {
-	Value
-	Get(*Thread) string
-	Set(*Thread, string)
-}
-
-type ArrayValue interface {
-	Value
-	// TODO(austin) Get() is here for uniformity, but is
-	// completely useless.  If a lot of other types have similarly
-	// useless Get methods, just special-case these uses.
-	Get(*Thread) ArrayValue
-	Elem(*Thread, int64) Value
-	// Sub returns an ArrayValue backed by the same array that
-	// starts from element i and has length len.
-	Sub(i int64, len int64) ArrayValue
-}
-
-type StructValue interface {
-	Value
-	// TODO(austin) This is another useless Get()
-	Get(*Thread) StructValue
-	Field(*Thread, int) Value
-}
-
-type PtrValue interface {
-	Value
-	Get(*Thread) Value
-	Set(*Thread, Value)
-}
-
-type Func interface {
-	NewFrame() *Frame
-	Call(*Thread)
-}
-
-type FuncValue interface {
-	Value
-	Get(*Thread) Func
-	Set(*Thread, Func)
-}
-
-type Interface struct {
-	Type  Type
-	Value Value
-}
-
-type InterfaceValue interface {
-	Value
-	Get(*Thread) Interface
-	Set(*Thread, Interface)
-}
-
-type Slice struct {
-	Base     ArrayValue
-	Len, Cap int64
-}
-
-type SliceValue interface {
-	Value
-	Get(*Thread) Slice
-	Set(*Thread, Slice)
-}
-
-type Map interface {
-	Len(*Thread) int64
-	// Retrieve an element from the map, returning nil if it does
-	// not exist.
-	Elem(t *Thread, key interface{}) Value
-	// Set an entry in the map.  If val is nil, delete the entry.
-	SetElem(t *Thread, key interface{}, val Value)
-	// TODO(austin)  Perhaps there should be an iterator interface instead.
-	Iter(func(key interface{}, val Value) bool)
-}
-
-type MapValue interface {
-	Value
-	Get(*Thread) Map
-	Set(*Thread, Map)
-}
-
-/*
- * Bool
- */
-
-type boolV bool
-
-func (v *boolV) String() string { return fmt.Sprint(*v) }
-
-func (v *boolV) Assign(t *Thread, o Value) { *v = boolV(o.(BoolValue).Get(t)) }
-
-func (v *boolV) Get(*Thread) bool { return bool(*v) }
-
-func (v *boolV) Set(t *Thread, x bool) { *v = boolV(x) }
-
-/*
- * Uint
- */
-
-type uint8V uint8
-
-func (v *uint8V) String() string { return fmt.Sprint(*v) }
-
-func (v *uint8V) Assign(t *Thread, o Value) { *v = uint8V(o.(UintValue).Get(t)) }
-
-func (v *uint8V) Get(*Thread) uint64 { return uint64(*v) }
-
-func (v *uint8V) Set(t *Thread, x uint64) { *v = uint8V(x) }
-
-type uint16V uint16
-
-func (v *uint16V) String() string { return fmt.Sprint(*v) }
-
-func (v *uint16V) Assign(t *Thread, o Value) { *v = uint16V(o.(UintValue).Get(t)) }
-
-func (v *uint16V) Get(*Thread) uint64 { return uint64(*v) }
-
-func (v *uint16V) Set(t *Thread, x uint64) { *v = uint16V(x) }
-
-type uint32V uint32
-
-func (v *uint32V) String() string { return fmt.Sprint(*v) }
-
-func (v *uint32V) Assign(t *Thread, o Value) { *v = uint32V(o.(UintValue).Get(t)) }
-
-func (v *uint32V) Get(*Thread) uint64 { return uint64(*v) }
-
-func (v *uint32V) Set(t *Thread, x uint64) { *v = uint32V(x) }
-
-type uint64V uint64
-
-func (v *uint64V) String() string { return fmt.Sprint(*v) }
-
-func (v *uint64V) Assign(t *Thread, o Value) { *v = uint64V(o.(UintValue).Get(t)) }
-
-func (v *uint64V) Get(*Thread) uint64 { return uint64(*v) }
-
-func (v *uint64V) Set(t *Thread, x uint64) { *v = uint64V(x) }
-
-type uintV uint
-
-func (v *uintV) String() string { return fmt.Sprint(*v) }
-
-func (v *uintV) Assign(t *Thread, o Value) { *v = uintV(o.(UintValue).Get(t)) }
-
-func (v *uintV) Get(*Thread) uint64 { return uint64(*v) }
-
-func (v *uintV) Set(t *Thread, x uint64) { *v = uintV(x) }
-
-type uintptrV uintptr
-
-func (v *uintptrV) String() string { return fmt.Sprint(*v) }
-
-func (v *uintptrV) Assign(t *Thread, o Value) { *v = uintptrV(o.(UintValue).Get(t)) }
-
-func (v *uintptrV) Get(*Thread) uint64 { return uint64(*v) }
-
-func (v *uintptrV) Set(t *Thread, x uint64) { *v = uintptrV(x) }
-
-/*
- * Int
- */
-
-type int8V int8
-
-func (v *int8V) String() string { return fmt.Sprint(*v) }
-
-func (v *int8V) Assign(t *Thread, o Value) { *v = int8V(o.(IntValue).Get(t)) }
-
-func (v *int8V) Get(*Thread) int64 { return int64(*v) }
-
-func (v *int8V) Set(t *Thread, x int64) { *v = int8V(x) }
-
-type int16V int16
-
-func (v *int16V) String() string { return fmt.Sprint(*v) }
-
-func (v *int16V) Assign(t *Thread, o Value) { *v = int16V(o.(IntValue).Get(t)) }
-
-func (v *int16V) Get(*Thread) int64 { return int64(*v) }
-
-func (v *int16V) Set(t *Thread, x int64) { *v = int16V(x) }
-
-type int32V int32
-
-func (v *int32V) String() string { return fmt.Sprint(*v) }
-
-func (v *int32V) Assign(t *Thread, o Value) { *v = int32V(o.(IntValue).Get(t)) }
-
-func (v *int32V) Get(*Thread) int64 { return int64(*v) }
-
-func (v *int32V) Set(t *Thread, x int64) { *v = int32V(x) }
-
-type int64V int64
-
-func (v *int64V) String() string { return fmt.Sprint(*v) }
-
-func (v *int64V) Assign(t *Thread, o Value) { *v = int64V(o.(IntValue).Get(t)) }
-
-func (v *int64V) Get(*Thread) int64 { return int64(*v) }
-
-func (v *int64V) Set(t *Thread, x int64) { *v = int64V(x) }
-
-type intV int
-
-func (v *intV) String() string { return fmt.Sprint(*v) }
-
-func (v *intV) Assign(t *Thread, o Value) { *v = intV(o.(IntValue).Get(t)) }
-
-func (v *intV) Get(*Thread) int64 { return int64(*v) }
-
-func (v *intV) Set(t *Thread, x int64) { *v = intV(x) }
-
-/*
- * Ideal int
- */
-
-type idealIntV struct {
-	V *big.Int
-}
-
-func (v *idealIntV) String() string { return v.V.String() }
-
-func (v *idealIntV) Assign(t *Thread, o Value) {
-	v.V = o.(IdealIntValue).Get()
-}
-
-func (v *idealIntV) Get() *big.Int { return v.V }
-
-/*
- * Float
- */
-
-type float32V float32
-
-func (v *float32V) String() string { return fmt.Sprint(*v) }
-
-func (v *float32V) Assign(t *Thread, o Value) { *v = float32V(o.(FloatValue).Get(t)) }
-
-func (v *float32V) Get(*Thread) float64 { return float64(*v) }
-
-func (v *float32V) Set(t *Thread, x float64) { *v = float32V(x) }
-
-type float64V float64
-
-func (v *float64V) String() string { return fmt.Sprint(*v) }
-
-func (v *float64V) Assign(t *Thread, o Value) { *v = float64V(o.(FloatValue).Get(t)) }
-
-func (v *float64V) Get(*Thread) float64 { return float64(*v) }
-
-func (v *float64V) Set(t *Thread, x float64) { *v = float64V(x) }
-
-/*
- * Ideal float
- */
-
-type idealFloatV struct {
-	V *big.Rat
-}
-
-func (v *idealFloatV) String() string { return v.V.FloatString(6) }
-
-func (v *idealFloatV) Assign(t *Thread, o Value) {
-	v.V = o.(IdealFloatValue).Get()
-}
-
-func (v *idealFloatV) Get() *big.Rat { return v.V }
-
-/*
- * String
- */
-
-type stringV string
-
-func (v *stringV) String() string { return fmt.Sprint(*v) }
-
-func (v *stringV) Assign(t *Thread, o Value) { *v = stringV(o.(StringValue).Get(t)) }
-
-func (v *stringV) Get(*Thread) string { return string(*v) }
-
-func (v *stringV) Set(t *Thread, x string) { *v = stringV(x) }
-
-/*
- * Array
- */
-
-type arrayV []Value
-
-func (v *arrayV) String() string {
-	res := "{"
-	for i, e := range *v {
-		if i > 0 {
-			res += ", "
-		}
-		res += e.String()
-	}
-	return res + "}"
-}
-
-func (v *arrayV) Assign(t *Thread, o Value) {
-	oa := o.(ArrayValue)
-	l := int64(len(*v))
-	for i := int64(0); i < l; i++ {
-		(*v)[i].Assign(t, oa.Elem(t, i))
-	}
-}
-
-func (v *arrayV) Get(*Thread) ArrayValue { return v }
-
-func (v *arrayV) Elem(t *Thread, i int64) Value {
-	return (*v)[i]
-}
-
-func (v *arrayV) Sub(i int64, len int64) ArrayValue {
-	res := (*v)[i : i+len]
-	return &res
-}
-
-/*
- * Struct
- */
-
-type structV []Value
-
-// TODO(austin) Should these methods (and arrayV's) be on structV
-// instead of *structV?
-func (v *structV) String() string {
-	res := "{"
-	for i, v := range *v {
-		if i > 0 {
-			res += ", "
-		}
-		res += v.String()
-	}
-	return res + "}"
-}
-
-func (v *structV) Assign(t *Thread, o Value) {
-	oa := o.(StructValue)
-	l := len(*v)
-	for i := 0; i < l; i++ {
-		(*v)[i].Assign(t, oa.Field(t, i))
-	}
-}
-
-func (v *structV) Get(*Thread) StructValue { return v }
-
-func (v *structV) Field(t *Thread, i int) Value {
-	return (*v)[i]
-}
-
-/*
- * Pointer
- */
-
-type ptrV struct {
-	// nil if the pointer is nil
-	target Value
-}
-
-func (v *ptrV) String() string {
-	if v.target == nil {
-		return "<nil>"
-	}
-	return "&" + v.target.String()
-}
-
-func (v *ptrV) Assign(t *Thread, o Value) { v.target = o.(PtrValue).Get(t) }
-
-func (v *ptrV) Get(*Thread) Value { return v.target }
-
-func (v *ptrV) Set(t *Thread, x Value) { v.target = x }
-
-/*
- * Functions
- */
-
-type funcV struct {
-	target Func
-}
-
-func (v *funcV) String() string {
-	// TODO(austin) Rob wants to see the definition
-	return "func {...}"
-}
-
-func (v *funcV) Assign(t *Thread, o Value) { v.target = o.(FuncValue).Get(t) }
-
-func (v *funcV) Get(*Thread) Func { return v.target }
-
-func (v *funcV) Set(t *Thread, x Func) { v.target = x }
-
-/*
- * Interfaces
- */
-
-type interfaceV struct {
-	Interface
-}
-
-func (v *interfaceV) String() string {
-	if v.Type == nil || v.Value == nil {
-		return "<nil>"
-	}
-	return v.Value.String()
-}
-
-func (v *interfaceV) Assign(t *Thread, o Value) {
-	v.Interface = o.(InterfaceValue).Get(t)
-}
-
-func (v *interfaceV) Get(*Thread) Interface { return v.Interface }
-
-func (v *interfaceV) Set(t *Thread, x Interface) {
-	v.Interface = x
-}
-
-/*
- * Slices
- */
-
-type sliceV struct {
-	Slice
-}
-
-func (v *sliceV) String() string {
-	if v.Base == nil {
-		return "<nil>"
-	}
-	return v.Base.Sub(0, v.Len).String()
-}
-
-func (v *sliceV) Assign(t *Thread, o Value) { v.Slice = o.(SliceValue).Get(t) }
-
-func (v *sliceV) Get(*Thread) Slice { return v.Slice }
-
-func (v *sliceV) Set(t *Thread, x Slice) { v.Slice = x }
-
-/*
- * Maps
- */
-
-type mapV struct {
-	target Map
-}
-
-func (v *mapV) String() string {
-	if v.target == nil {
-		return "<nil>"
-	}
-	res := "map["
-	i := 0
-	v.target.Iter(func(key interface{}, val Value) bool {
-		if i > 0 {
-			res += ", "
-		}
-		i++
-		res += fmt.Sprint(key) + ":" + val.String()
-		return true
-	})
-	return res + "]"
-}
-
-func (v *mapV) Assign(t *Thread, o Value) { v.target = o.(MapValue).Get(t) }
-
-func (v *mapV) Get(*Thread) Map { return v.target }
-
-func (v *mapV) Set(t *Thread, x Map) { v.target = x }
-
-type evalMap map[interface{}]Value
-
-func (m evalMap) Len(t *Thread) int64 { return int64(len(m)) }
-
-func (m evalMap) Elem(t *Thread, key interface{}) Value {
-	return m[key]
-}
-
-func (m evalMap) SetElem(t *Thread, key interface{}, val Value) {
-	if val == nil {
-		m[key] = nil, false
-	} else {
-		m[key] = val
-	}
-}
-
-func (m evalMap) Iter(cb func(key interface{}, val Value) bool) {
-	for k, v := range m {
-		if !cb(k, v) {
-			break
-		}
-	}
-}
-
-/*
- * Multi-values
- */
-
-type multiV []Value
-
-func (v multiV) String() string {
-	res := "("
-	for i, v := range v {
-		if i > 0 {
-			res += ", "
-		}
-		res += v.String()
-	}
-	return res + ")"
-}
-
-func (v multiV) Assign(t *Thread, o Value) {
-	omv := o.(multiV)
-	for i := range v {
-		v[i].Assign(t, omv[i])
-	}
-}
-
-/*
- * Universal constants
- */
-
-func init() {
-	s := universe
-
-	true := boolV(true)
-	s.DefineConst("true", universePos, BoolType, &true)
-	false := boolV(false)
-	s.DefineConst("false", universePos, BoolType, &false)
-}
diff --git a/src/pkg/exp/eval/world.go b/src/pkg/exp/eval/world.go
deleted file mode 100644
index a5f6ac7..0000000
--- a/src/pkg/exp/eval/world.go
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package eval is the beginning of an interpreter for Go.
-// It can run simple Go programs but does not implement
-// interface values or packages.
-package eval
-
-import (
-	"go/ast"
-	"go/parser"
-	"go/scanner"
-	"go/token"
-	"os"
-)
-
-type World struct {
-	scope *Scope
-	frame *Frame
-}
-
-func NewWorld() *World {
-	w := new(World)
-	w.scope = universe.ChildScope()
-	w.scope.global = true // this block's vars allocate directly
-	return w
-}
-
-type Code interface {
-	// The type of the value Run returns, or nil if Run returns nil.
-	Type() Type
-
-	// Run runs the code; if the code is a single expression
-	// with a value, it returns the value; otherwise it returns nil.
-	Run() (Value, os.Error)
-}
-
-type stmtCode struct {
-	w    *World
-	code code
-}
-
-func (w *World) CompileStmtList(fset *token.FileSet, stmts []ast.Stmt) (Code, os.Error) {
-	if len(stmts) == 1 {
-		if s, ok := stmts[0].(*ast.ExprStmt); ok {
-			return w.CompileExpr(fset, s.X)
-		}
-	}
-	errors := new(scanner.ErrorVector)
-	cc := &compiler{fset, errors, 0, 0}
-	cb := newCodeBuf()
-	fc := &funcCompiler{
-		compiler:     cc,
-		fnType:       nil,
-		outVarsNamed: false,
-		codeBuf:      cb,
-		flow:         newFlowBuf(cb),
-		labels:       make(map[string]*label),
-	}
-	bc := &blockCompiler{
-		funcCompiler: fc,
-		block:        w.scope.block,
-	}
-	nerr := cc.numError()
-	for _, stmt := range stmts {
-		bc.compileStmt(stmt)
-	}
-	fc.checkLabels()
-	if nerr != cc.numError() {
-		return nil, errors.GetError(scanner.Sorted)
-	}
-	return &stmtCode{w, fc.get()}, nil
-}
-
-func (w *World) CompileDeclList(fset *token.FileSet, decls []ast.Decl) (Code, os.Error) {
-	stmts := make([]ast.Stmt, len(decls))
-	for i, d := range decls {
-		stmts[i] = &ast.DeclStmt{d}
-	}
-	return w.CompileStmtList(fset, stmts)
-}
-
-func (s *stmtCode) Type() Type { return nil }
-
-func (s *stmtCode) Run() (Value, os.Error) {
-	t := new(Thread)
-	t.f = s.w.scope.NewFrame(nil)
-	return nil, t.Try(func(t *Thread) { s.code.exec(t) })
-}
-
-type exprCode struct {
-	w    *World
-	e    *expr
-	eval func(Value, *Thread)
-}
-
-func (w *World) CompileExpr(fset *token.FileSet, e ast.Expr) (Code, os.Error) {
-	errors := new(scanner.ErrorVector)
-	cc := &compiler{fset, errors, 0, 0}
-
-	ec := cc.compileExpr(w.scope.block, false, e)
-	if ec == nil {
-		return nil, errors.GetError(scanner.Sorted)
-	}
-	var eval func(Value, *Thread)
-	switch t := ec.t.(type) {
-	case *idealIntType:
-		// nothing
-	case *idealFloatType:
-		// nothing
-	default:
-		if tm, ok := t.(*MultiType); ok && len(tm.Elems) == 0 {
-			return &stmtCode{w, code{ec.exec}}, nil
-		}
-		eval = genAssign(ec.t, ec)
-	}
-	return &exprCode{w, ec, eval}, nil
-}
-
-func (e *exprCode) Type() Type { return e.e.t }
-
-func (e *exprCode) Run() (Value, os.Error) {
-	t := new(Thread)
-	t.f = e.w.scope.NewFrame(nil)
-	switch e.e.t.(type) {
-	case *idealIntType:
-		return &idealIntV{e.e.asIdealInt()()}, nil
-	case *idealFloatType:
-		return &idealFloatV{e.e.asIdealFloat()()}, nil
-	}
-	v := e.e.t.Zero()
-	eval := e.eval
-	err := t.Try(func(t *Thread) { eval(v, t) })
-	return v, err
-}
-
-func (w *World) Compile(fset *token.FileSet, text string) (Code, os.Error) {
-	stmts, err := parser.ParseStmtList(fset, "input", text)
-	if err == nil {
-		return w.CompileStmtList(fset, stmts)
-	}
-
-	// Otherwise try as DeclList.
-	decls, err1 := parser.ParseDeclList(fset, "input", text)
-	if err1 == nil {
-		return w.CompileDeclList(fset, decls)
-	}
-
-	// Have to pick an error.
-	// Parsing as statement list admits more forms,
-	// its error is more likely to be useful.
-	return nil, err
-}
-
-type RedefinitionError struct {
-	Name string
-	Prev Def
-}
-
-func (e *RedefinitionError) String() string {
-	res := "identifier " + e.Name + " redeclared"
-	pos := e.Prev.Pos()
-	if pos.IsValid() {
-		// TODO: fix this - currently this code is not reached by the tests
-		//       need to get a file set (fset) from somewhere
-		//res += "; previous declaration at " + fset.Position(pos).String()
-		panic(0)
-	}
-	return res
-}
-
-func (w *World) DefineConst(name string, t Type, val Value) os.Error {
-	_, prev := w.scope.DefineConst(name, token.NoPos, t, val)
-	if prev != nil {
-		return &RedefinitionError{name, prev}
-	}
-	return nil
-}
-
-func (w *World) DefineVar(name string, t Type, val Value) os.Error {
-	v, prev := w.scope.DefineVar(name, token.NoPos, t)
-	if prev != nil {
-		return &RedefinitionError{name, prev}
-	}
-	v.Init = val
-	return nil
-}
diff --git a/src/pkg/exp/gui/x11/conn.go b/src/pkg/exp/gui/x11/conn.go
index bc7ca63..1d23781 100644
--- a/src/pkg/exp/gui/x11/conn.go
+++ b/src/pkg/exp/gui/x11/conn.go
@@ -85,25 +85,26 @@ func (c *conn) writeSocket() {
 
 		for y := b.Min.Y; y < b.Max.Y; y++ {
 			setU32LE(c.flushBuf0[16:20], uint32(y<<16))
-			if _, err := c.w.Write(c.flushBuf0[0:24]); err != nil {
+			if _, err := c.w.Write(c.flushBuf0[:24]); err != nil {
 				if err != os.EOF {
 					log.Println("x11:", err.String())
 				}
 				return
 			}
-			p := c.img.Pix[y*c.img.Stride : (y+1)*c.img.Stride]
-			for x := b.Min.X; x < b.Max.X; {
-				nx := b.Max.X - x
-				if nx > len(c.flushBuf1)/4 {
-					nx = len(c.flushBuf1) / 4
+			p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
+			for x, dx := 0, 4*b.Dx(); x < dx; {
+				nx := dx - x
+				if nx > len(c.flushBuf1) {
+					nx = len(c.flushBuf1) &^ 3
 				}
-				for i, rgba := range p[x : x+nx] {
-					c.flushBuf1[4*i+0] = rgba.B
-					c.flushBuf1[4*i+1] = rgba.G
-					c.flushBuf1[4*i+2] = rgba.R
+				for i := 0; i < nx; i += 4 {
+					// X11's order is BGRX, not RGBA.
+					c.flushBuf1[i+0] = p[x+i+2]
+					c.flushBuf1[i+1] = p[x+i+1]
+					c.flushBuf1[i+2] = p[x+i+0]
 				}
 				x += nx
-				if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil {
+				if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
 					if err != os.EOF {
 						log.Println("x11:", err.String())
 					}
@@ -154,7 +155,7 @@ func (c *conn) readSocket() {
 	defer close(c.eventc)
 	for {
 		// X events are always 32 bytes long.
-		if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil {
+		if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil {
 			if err != os.EOF {
 				c.eventc <- gui.ErrEvent{err}
 			}
@@ -177,7 +178,7 @@ func (c *conn) readSocket() {
 			for i := keymapLo; i <= keymapHi; i++ {
 				m := keymap[i]
 				for j := range m {
-					u, err := readU32LE(c.r, c.buf[0:4])
+					u, err := readU32LE(c.r, c.buf[:4])
 					if err != nil {
 						if err != os.EOF {
 							c.eventc <- gui.ErrEvent{err}
@@ -260,14 +261,14 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
 	// Parse the section before the colon.
 	var protocol, host, socket string
 	if display[0] == '/' {
-		socket = display[0:colonIdx]
+		socket = display[:colonIdx]
 	} else {
 		if i := strings.LastIndex(display, "/"); i < 0 {
 			// The default protocol is TCP.
 			protocol = "tcp"
-			host = display[0:colonIdx]
+			host = display[:colonIdx]
 		} else {
-			protocol = display[0:i]
+			protocol = display[:i]
 			host = display[i+1 : colonIdx]
 		}
 	}
@@ -279,7 +280,7 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
 	if i := strings.LastIndex(after, "."); i < 0 {
 		displayStr = after
 	} else {
-		displayStr = after[0:i]
+		displayStr = after[:i]
 	}
 	displayInt, err := strconv.Atoi(displayStr)
 	if err != nil || displayInt < 0 {
@@ -339,7 +340,7 @@ func authenticate(w *bufio.Writer, displayStr string) os.Error {
 
 // readU8 reads a uint8 from r, using b as a scratch buffer.
 func readU8(r io.Reader, b []byte) (uint8, os.Error) {
-	_, err := io.ReadFull(r, b[0:1])
+	_, err := io.ReadFull(r, b[:1])
 	if err != nil {
 		return 0, err
 	}
@@ -348,7 +349,7 @@ func readU8(r io.Reader, b []byte) (uint8, os.Error) {
 
 // readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
 func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
-	_, err := io.ReadFull(r, b[0:2])
+	_, err := io.ReadFull(r, b[:2])
 	if err != nil {
 		return 0, err
 	}
@@ -357,14 +358,14 @@ func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
 
 // readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
 func readU32LE(r io.Reader, b []byte) (uint32, os.Error) {
-	_, err := io.ReadFull(r, b[0:4])
+	_, err := io.ReadFull(r, b[:4])
 	if err != nil {
 		return 0, err
 	}
 	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
 }
 
-// setU32LE sets b[0:4] to be the little-endian representation of u.
+// setU32LE sets b[:4] to be the little-endian representation of u.
 func setU32LE(b []byte, u uint32) {
 	b[0] = byte((u >> 0) & 0xff)
 	b[1] = byte((u >> 8) & 0xff)
@@ -375,7 +376,7 @@ func setU32LE(b []byte, u uint32) {
 // checkPixmapFormats checks that we have an agreeable X pixmap Format.
 func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) {
 	for i := 0; i < n; i++ {
-		_, err = io.ReadFull(r, b[0:8])
+		_, err = io.ReadFull(r, b[:8])
 		if err != nil {
 			return
 		}
@@ -400,7 +401,7 @@ func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err o
 			return
 		}
 		// Ignore 4 bytes of padding.
-		_, err = io.ReadFull(r, b[0:4])
+		_, err = io.ReadFull(r, b[:4])
 		if err != nil {
 			return
 		}
@@ -433,7 +434,7 @@ func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Err
 		}
 		// Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
 		// width and height (pixels), width and height (mm), min and max installed maps.
-		_, err = io.ReadFull(r, b[0:28])
+		_, err = io.ReadFull(r, b[:28])
 		if err != nil {
 			return
 		}
@@ -462,26 +463,26 @@ func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Err
 // handshake performs the protocol handshake with the X server, and ensures
 // that the server provides a compatible Screen, Depth, etc.
 func (c *conn) handshake() os.Error {
-	_, err := io.ReadFull(c.r, c.buf[0:8])
+	_, err := io.ReadFull(c.r, c.buf[:8])
 	if err != nil {
 		return err
 	}
-	// Byte 0:1 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
+	// Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
 	if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
 		return os.NewError("unsupported X version")
 	}
 	// Ignore the release number.
-	_, err = io.ReadFull(c.r, c.buf[0:4])
+	_, err = io.ReadFull(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
 	// Read the resource ID base.
-	resourceIdBase, err := readU32LE(c.r, c.buf[0:4])
+	resourceIdBase, err := readU32LE(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
 	// Read the resource ID mask.
-	resourceIdMask, err := readU32LE(c.r, c.buf[0:4])
+	resourceIdMask, err := readU32LE(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
@@ -489,19 +490,19 @@ func (c *conn) handshake() os.Error {
 		return os.NewError("X resource ID mask is too small")
 	}
 	// Ignore the motion buffer size.
-	_, err = io.ReadFull(c.r, c.buf[0:4])
+	_, err = io.ReadFull(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
 	// Read the vendor length and round it up to a multiple of 4,
 	// for X11 protocol alignment reasons.
-	vendorLen, err := readU16LE(c.r, c.buf[0:2])
+	vendorLen, err := readU16LE(c.r, c.buf[:2])
 	if err != nil {
 		return err
 	}
 	vendorLen = (vendorLen + 3) &^ 3
 	// Read the maximum request length.
-	maxReqLen, err := readU16LE(c.r, c.buf[0:2])
+	maxReqLen, err := readU16LE(c.r, c.buf[:2])
 	if err != nil {
 		return err
 	}
@@ -509,12 +510,12 @@ func (c *conn) handshake() os.Error {
 		return os.NewError("unsupported X maximum request length")
 	}
 	// Read the roots length.
-	rootsLen, err := readU8(c.r, c.buf[0:1])
+	rootsLen, err := readU8(c.r, c.buf[:1])
 	if err != nil {
 		return err
 	}
 	// Read the pixmap formats length.
-	pixmapFormatsLen, err := readU8(c.r, c.buf[0:1])
+	pixmapFormatsLen, err := readU8(c.r, c.buf[:1])
 	if err != nil {
 		return err
 	}
@@ -524,12 +525,12 @@ func (c *conn) handshake() os.Error {
 	if 10+int(vendorLen) > cap(c.buf) {
 		return os.NewError("unsupported X vendor")
 	}
-	_, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)])
+	_, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)])
 	if err != nil {
 		return err
 	}
 	// Check that we have an agreeable pixmap format.
-	agree, err := checkPixmapFormats(c.r, c.buf[0:8], int(pixmapFormatsLen))
+	agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen))
 	if err != nil {
 		return err
 	}
@@ -537,7 +538,7 @@ func (c *conn) handshake() os.Error {
 		return os.NewError("unsupported X pixmap formats")
 	}
 	// Check that we have an agreeable screen.
-	root, visual, err := checkScreens(c.r, c.buf[0:24], int(rootsLen))
+	root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen))
 	if err != nil {
 		return err
 	}
@@ -608,7 +609,7 @@ func NewWindowDisplay(display string) (gui.Window, os.Error) {
 	setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
 	setU32LE(c.buf[76:80], uint32(c.window))
 	// Write the bytes.
-	_, err = c.w.Write(c.buf[0:80])
+	_, err = c.w.Write(c.buf[:80])
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/pkg/exp/norm/normalize.go b/src/pkg/exp/norm/normalize.go
new file mode 100644
index 0000000..e219263
--- /dev/null
+++ b/src/pkg/exp/norm/normalize.go
@@ -0,0 +1,75 @@
+// 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 form contains types and functions for normalizing Unicode strings.
+package norm
+
+// A Form denotes a canonical representation of Unicode code points.
+// The Unicode-defined normalization and equivalence forms are:
+//
+//   NFC   Unicode Normalization Form C
+//   NFD   Unicode Normalization Form D
+//   NFKC  Unicode Normalization Form KC
+//   NFKD  Unicode Normalization Form KD
+//
+// For a Form f, this documentation uses the notation f(x) to mean
+// the bytes or string x converted to the given form.
+// A position n in x is called a boundary if conversion to the form can
+// proceed independently on both sides:
+//   f(x) == append(f(x[0:n]), f(x[n:])...)
+//
+// References: http://unicode.org/reports/tr15/ and
+// http://unicode.org/notes/tn5/.
+type Form int
+
+const (
+	NFC Form = iota
+	NFD
+	NFKC
+	NFKD
+)
+
+// Bytes returns f(b). May return b if f(b) = b.
+func (f Form) Bytes(b []byte) []byte
+
+// String returns f(s).
+func (f Form) String(s string) string
+
+// IsNormal returns true if b == f(b).
+func (f Form) IsNormal(b []byte) bool
+
+// IsNormalString returns true if s == f(s).
+func (f Form) IsNormalString(s string) bool
+
+// Append returns f(append(out, b...)).
+// The buffer out must be empty or equal to f(out).
+func (f Form) Append(out, b []byte) []byte
+
+// AppendString returns f(append(out, []byte(s))).
+// The buffer out must be empty or equal to f(out).
+func (f Form) AppendString(out []byte, s string) []byte
+
+// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpan(b []byte) int
+
+// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpanString(s string) int
+
+// FirstBoundary returns the position i of the first boundary in b.
+// It returns len(b), false if b contains no boundaries.
+func (f Form) FirstBoundary(b []byte) (i int, ok bool)
+
+// FirstBoundaryInString return the position i of the first boundary in s.
+// It returns len(s), false if s contains no boundaries.
+func (f Form) FirstBoundaryInString(s string) (i int, ok bool)
+
+// LastBoundaryIn returns the position i of the last boundary in b.
+// It returns 0, false if b contains no boundary.
+func (f Form) LastBoundary(b []byte) (i int, ok bool)
+
+// LastBoundaryInString returns the position i of the last boundary in s.
+// It returns 0, false if s contains no boundary.
+func (f Form) LastBoundaryInString(s string) (i int, ok bool)
diff --git a/src/pkg/exp/ogle/Makefile b/src/pkg/exp/ogle/Makefile
deleted file mode 100644
index ef65d36..0000000
--- a/src/pkg/exp/ogle/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=exp/ogle
-GOFILES=\
-	abort.go\
-	arch.go\
-	cmd.go\
-	event.go\
-	frame.go\
-	goroutine.go\
-	rruntime.go\
-	rtype.go\
-	rvalue.go\
-	process.go\
-	vars.go\
-
-CLEANFILES+=ogle
-
-include ../../../Make.pkg
-
-main.$O: main.go package
-	$(GC) -I_obj $<
-
-ogle: main.$O
-	$(LD) -L_obj -o $@ $<
diff --git a/src/pkg/exp/ogle/abort.go b/src/pkg/exp/ogle/abort.go
deleted file mode 100644
index 311a7b3..0000000
--- a/src/pkg/exp/ogle/abort.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"os"
-	"runtime"
-)
-
-// An aborter aborts the thread's current computation, usually
-// passing the error to a waiting thread.
-type aborter interface {
-	Abort(err os.Error)
-}
-
-type ogleAborter chan os.Error
-
-func (a ogleAborter) Abort(err os.Error) {
-	a <- err
-	runtime.Goexit()
-}
-
-// try executes a computation; if the computation Aborts, try returns
-// the error passed to abort.
-func try(f func(a aborter)) os.Error {
-	a := make(ogleAborter)
-	go func() {
-		f(a)
-		a <- nil
-	}()
-	err := <-a
-	return err
-}
diff --git a/src/pkg/exp/ogle/arch.go b/src/pkg/exp/ogle/arch.go
deleted file mode 100644
index 52b1c97..0000000
--- a/src/pkg/exp/ogle/arch.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/proc"
-	"math"
-)
-
-type Arch interface {
-	// ToWord converts an array of up to 8 bytes in memory order
-	// to a word.
-	ToWord(data []byte) proc.Word
-	// FromWord converts a word to an array of up to 8 bytes in
-	// memory order.
-	FromWord(v proc.Word, out []byte)
-	// ToFloat32 converts a word to a float.  The order of this
-	// word will be the order returned by ToWord on the memory
-	// representation of a float, and thus may require reversing.
-	ToFloat32(bits uint32) float32
-	// FromFloat32 converts a float to a word.  This should return
-	// a word that can be passed to FromWord to get the memory
-	// representation of a float on this architecture.
-	FromFloat32(f float32) uint32
-	// ToFloat64 is to float64 as ToFloat32 is to float32.
-	ToFloat64(bits uint64) float64
-	// FromFloat64 is to float64 as FromFloat32 is to float32.
-	FromFloat64(f float64) uint64
-
-	// IntSize returns the number of bytes in an 'int'.
-	IntSize() int
-	// PtrSize returns the number of bytes in a 'uintptr'.
-	PtrSize() int
-	// FloatSize returns the number of bytes in a 'float'.
-	FloatSize() int
-	// Align rounds offset up to the appropriate offset for a
-	// basic type with the given width.
-	Align(offset, width int) int
-
-	// G returns the current G pointer.
-	G(regs proc.Regs) proc.Word
-
-	// ClosureSize returns the number of bytes expected by
-	// ParseClosure.
-	ClosureSize() int
-	// ParseClosure takes ClosureSize bytes read from a return PC
-	// in a remote process, determines if the code is a closure,
-	// and returns the frame size of the closure if it is.
-	ParseClosure(data []byte) (frame int, ok bool)
-}
-
-type ArchLSB struct{}
-
-func (ArchLSB) ToWord(data []byte) proc.Word {
-	var v proc.Word
-	for i, b := range data {
-		v |= proc.Word(b) << (uint(i) * 8)
-	}
-	return v
-}
-
-func (ArchLSB) FromWord(v proc.Word, out []byte) {
-	for i := range out {
-		out[i] = byte(v)
-		v >>= 8
-	}
-}
-
-func (ArchLSB) ToFloat32(bits uint32) float32 {
-	// TODO(austin) Do these definitions depend on my current
-	// architecture?
-	return math.Float32frombits(bits)
-}
-
-func (ArchLSB) FromFloat32(f float32) uint32 { return math.Float32bits(f) }
-
-func (ArchLSB) ToFloat64(bits uint64) float64 { return math.Float64frombits(bits) }
-
-func (ArchLSB) FromFloat64(f float64) uint64 { return math.Float64bits(f) }
-
-type ArchAlignedMultiple struct{}
-
-func (ArchAlignedMultiple) Align(offset, width int) int {
-	return ((offset - 1) | (width - 1)) + 1
-}
-
-type amd64 struct {
-	ArchLSB
-	ArchAlignedMultiple
-	gReg int
-}
-
-func (a *amd64) IntSize() int { return 4 }
-
-func (a *amd64) PtrSize() int { return 8 }
-
-func (a *amd64) FloatSize() int { return 4 }
-
-func (a *amd64) G(regs proc.Regs) proc.Word {
-	// See src/pkg/runtime/mkasmh
-	if a.gReg == -1 {
-		ns := regs.Names()
-		for i, n := range ns {
-			if n == "r15" {
-				a.gReg = i
-				break
-			}
-		}
-	}
-
-	return regs.Get(a.gReg)
-}
-
-func (a *amd64) ClosureSize() int { return 8 }
-
-func (a *amd64) ParseClosure(data []byte) (int, bool) {
-	if data[0] == 0x48 && data[1] == 0x81 && data[2] == 0xc4 && data[7] == 0xc3 {
-		return int(a.ToWord(data[3:7]) + 8), true
-	}
-	return 0, false
-}
-
-var Amd64 = &amd64{gReg: -1}
diff --git a/src/pkg/exp/ogle/cmd.go b/src/pkg/exp/ogle/cmd.go
deleted file mode 100644
index ff0d24c..0000000
--- a/src/pkg/exp/ogle/cmd.go
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package ogle is the beginning of a debugger for Go.
-package ogle
-
-import (
-	"bufio"
-	"debug/elf"
-	"debug/proc"
-	"exp/eval"
-	"fmt"
-	"go/scanner"
-	"go/token"
-	"os"
-	"strconv"
-	"strings"
-)
-
-var fset = token.NewFileSet()
-var world *eval.World
-var curProc *Process
-
-func Main() {
-	world = eval.NewWorld()
-	defineFuncs()
-	r := bufio.NewReader(os.Stdin)
-	for {
-		print("; ")
-		line, err := r.ReadSlice('\n')
-		if err != nil {
-			break
-		}
-
-		// Try line as a command
-		cmd, rest := getCmd(line)
-		if cmd != nil {
-			err := cmd.handler(rest)
-			if err != nil {
-				scanner.PrintError(os.Stderr, err)
-			}
-			continue
-		}
-
-		// Try line as code
-		code, err := world.Compile(fset, string(line))
-		if err != nil {
-			scanner.PrintError(os.Stderr, err)
-			continue
-		}
-		v, err := code.Run()
-		if err != nil {
-			fmt.Fprintf(os.Stderr, err.String())
-			continue
-		}
-		if v != nil {
-			println(v.String())
-		}
-	}
-}
-
-// newScanner creates a new scanner that scans that given input bytes.
-func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) {
-	sc := new(scanner.Scanner)
-	ev := new(scanner.ErrorVector)
-	file := fset.AddFile("input", fset.Base(), len(input))
-	sc.Init(file, input, ev, 0)
-	return sc, ev
-}
-
-/*
- * Commands
- */
-
-// A UsageError occurs when a command is called with illegal arguments.
-type UsageError string
-
-func (e UsageError) String() string { return string(e) }
-
-// A cmd represents a single command with a handler.
-type cmd struct {
-	cmd     string
-	handler func([]byte) os.Error
-}
-
-var cmds = []cmd{
-	{"load", cmdLoad},
-	{"bt", cmdBt},
-}
-
-// getCmd attempts to parse an input line as a registered command.  If
-// successful, it returns the command and the bytes remaining after
-// the command, which should be passed to the command.
-func getCmd(line []byte) (*cmd, []byte) {
-	sc, _ := newScanner(line)
-	pos, tok, lit := sc.Scan()
-	if sc.ErrorCount != 0 || tok != token.IDENT {
-		return nil, nil
-	}
-
-	slit := string(lit)
-	for i := range cmds {
-		if cmds[i].cmd == slit {
-			return &cmds[i], line[fset.Position(pos).Offset+len(lit):]
-		}
-	}
-	return nil, nil
-}
-
-// cmdLoad starts or attaches to a process.  Its form is similar to
-// import:
-//
-//  load [sym] "path" [;]
-//
-// sym specifies the name to give to the process.  If not given, the
-// name is derived from the path of the process.  If ".", then the
-// packages from the remote process are defined into the current
-// namespace.  If given, this symbol is defined as a package
-// containing the process' packages.
-//
-// path gives the path of the process to start or attach to.  If it is
-// "pid:<num>", then attach to the given PID.  Otherwise, treat it as
-// a file path and space-separated arguments and start a new process.
-//
-// load always sets the current process to the loaded process.
-func cmdLoad(args []byte) os.Error {
-	ident, path, err := parseLoad(args)
-	if err != nil {
-		return err
-	}
-	if curProc != nil {
-		return UsageError("multiple processes not implemented")
-	}
-	if ident != "." {
-		return UsageError("process identifiers not implemented")
-	}
-
-	// Parse argument and start or attach to process
-	var fname string
-	var tproc proc.Process
-	if len(path) >= 4 && path[0:4] == "pid:" {
-		pid, err := strconv.Atoi(path[4:])
-		if err != nil {
-			return err
-		}
-		fname, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
-		if err != nil {
-			return err
-		}
-		tproc, err = proc.Attach(pid)
-		if err != nil {
-			return err
-		}
-		println("Attached to", pid)
-	} else {
-		parts := strings.Split(path, " ")
-		if len(parts) == 0 {
-			fname = ""
-		} else {
-			fname = parts[0]
-		}
-		tproc, err = proc.StartProcess(fname, parts, &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}})
-		if err != nil {
-			return err
-		}
-		println("Started", path)
-		// TODO(austin) If we fail after this point, kill tproc
-		// before detaching.
-	}
-
-	// Get symbols
-	f, err := os.Open(fname)
-	if err != nil {
-		tproc.Detach()
-		return err
-	}
-	defer f.Close()
-	elf, err := elf.NewFile(f)
-	if err != nil {
-		tproc.Detach()
-		return err
-	}
-	curProc, err = NewProcessElf(tproc, elf)
-	if err != nil {
-		tproc.Detach()
-		return err
-	}
-
-	// Prepare new process
-	curProc.OnGoroutineCreate().AddHandler(EventPrint)
-	curProc.OnGoroutineExit().AddHandler(EventPrint)
-
-	err = curProc.populateWorld(world)
-	if err != nil {
-		tproc.Detach()
-		return err
-	}
-
-	return nil
-}
-
-func parseLoad(args []byte) (ident string, path string, err os.Error) {
-	err = UsageError("Usage: load [sym] \"path\"")
-	sc, ev := newScanner(args)
-
-	var toks [4]token.Token
-	var lits [4]string
-	for i := range toks {
-		_, toks[i], lits[i] = sc.Scan()
-	}
-	if sc.ErrorCount != 0 {
-		err = ev.GetError(scanner.NoMultiples)
-		return
-	}
-
-	i := 0
-	switch toks[i] {
-	case token.PERIOD, token.IDENT:
-		ident = string(lits[i])
-		i++
-	}
-
-	if toks[i] != token.STRING {
-		return
-	}
-	path, uerr := strconv.Unquote(string(lits[i]))
-	if uerr != nil {
-		err = uerr
-		return
-	}
-	i++
-
-	if toks[i] == token.SEMICOLON {
-		i++
-	}
-	if toks[i] != token.EOF {
-		return
-	}
-
-	return ident, path, nil
-}
-
-// cmdBt prints a backtrace for the current goroutine.  It takes no
-// arguments.
-func cmdBt(args []byte) os.Error {
-	err := parseNoArgs(args, "Usage: bt")
-	if err != nil {
-		return err
-	}
-
-	if curProc == nil || curProc.curGoroutine == nil {
-		return NoCurrentGoroutine{}
-	}
-
-	f := curProc.curGoroutine.frame
-	if f == nil {
-		fmt.Println("No frames on stack")
-		return nil
-	}
-
-	for f.Inner() != nil {
-		f = f.Inner()
-	}
-
-	for i := 0; i < 100; i++ {
-		if f == curProc.curGoroutine.frame {
-			fmt.Printf("=> ")
-		} else {
-			fmt.Printf("   ")
-		}
-		fmt.Printf("%8x %v\n", f.pc, f)
-		f, err = f.Outer()
-		if err != nil {
-			return err
-		}
-		if f == nil {
-			return nil
-		}
-	}
-
-	fmt.Println("...")
-	return nil
-}
-
-func parseNoArgs(args []byte, usage string) os.Error {
-	sc, ev := newScanner(args)
-	_, tok, _ := sc.Scan()
-	if sc.ErrorCount != 0 {
-		return ev.GetError(scanner.NoMultiples)
-	}
-	if tok != token.EOF {
-		return UsageError(usage)
-	}
-	return nil
-}
-
-/*
- * Functions
- */
-
-// defineFuncs populates world with the built-in functions.
-func defineFuncs() {
-	t, v := eval.FuncFromNativeTyped(fnOut, fnOutSig)
-	world.DefineConst("Out", t, v)
-	t, v = eval.FuncFromNativeTyped(fnContWait, fnContWaitSig)
-	world.DefineConst("ContWait", t, v)
-	t, v = eval.FuncFromNativeTyped(fnBpSet, fnBpSetSig)
-	world.DefineConst("BpSet", t, v)
-}
-
-// printCurFrame prints the current stack frame, as it would appear in
-// a backtrace.
-func printCurFrame() {
-	if curProc == nil || curProc.curGoroutine == nil {
-		return
-	}
-	f := curProc.curGoroutine.frame
-	if f == nil {
-		return
-	}
-	fmt.Printf("=> %8x %v\n", f.pc, f)
-}
-
-// fnOut moves the current frame to the caller of the current frame.
-func fnOutSig() {}
-func fnOut(t *eval.Thread, args []eval.Value, res []eval.Value) {
-	if curProc == nil {
-		t.Abort(NoCurrentGoroutine{})
-	}
-	err := curProc.Out()
-	if err != nil {
-		t.Abort(err)
-	}
-	// TODO(austin) Only in the command form
-	printCurFrame()
-}
-
-// fnContWait continues the current process and waits for a stopping event.
-func fnContWaitSig() {}
-func fnContWait(t *eval.Thread, args []eval.Value, res []eval.Value) {
-	if curProc == nil {
-		t.Abort(NoCurrentGoroutine{})
-	}
-	err := curProc.ContWait()
-	if err != nil {
-		t.Abort(err)
-	}
-	// TODO(austin) Only in the command form
-	ev := curProc.Event()
-	if ev != nil {
-		fmt.Printf("%v\n", ev)
-	}
-	printCurFrame()
-}
-
-// fnBpSet sets a breakpoint at the entry to the named function.
-func fnBpSetSig(string) {}
-func fnBpSet(t *eval.Thread, args []eval.Value, res []eval.Value) {
-	// TODO(austin) This probably shouldn't take a symbol name.
-	// Perhaps it should take an interface that provides PC's.
-	// Functions and instructions can implement that interface and
-	// we can have something to translate file:line pairs.
-	if curProc == nil {
-		t.Abort(NoCurrentGoroutine{})
-	}
-	name := args[0].(eval.StringValue).Get(t)
-	fn := curProc.syms.LookupFunc(name)
-	if fn == nil {
-		t.Abort(UsageError("no such function " + name))
-	}
-	curProc.OnBreakpoint(proc.Word(fn.Entry)).AddHandler(EventStop)
-}
diff --git a/src/pkg/exp/ogle/event.go b/src/pkg/exp/ogle/event.go
deleted file mode 100644
index d7092de..0000000
--- a/src/pkg/exp/ogle/event.go
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/proc"
-	"fmt"
-	"os"
-)
-
-/*
- * Hooks and events
- */
-
-// An EventHandler is a function that takes an event and returns a
-// response to that event and possibly an error.  If an event handler
-// returns an error, the process stops and no other handlers for that
-// event are executed.
-type EventHandler func(e Event) (EventAction, os.Error)
-
-// An EventAction is an event handler's response to an event.  If all
-// of an event's handlers execute without returning errors, their
-// results are combined as follows: If any handler returned
-// EAContinue, then the process resumes (without returning from
-// WaitStop); otherwise, if any handler returned EAStop, the process
-// remains stopped; otherwise, if all handlers returned EADefault, the
-// process resumes.  A handler may return EARemoveSelf bit-wise or'd
-// with any other action to indicate that the handler should be
-// removed from the hook.
-type EventAction int
-
-const (
-	EARemoveSelf EventAction = 0x100
-	EADefault    EventAction = iota
-	EAStop
-	EAContinue
-)
-
-// A EventHook allows event handlers to be added and removed.
-type EventHook interface {
-	AddHandler(EventHandler)
-	RemoveHandler(EventHandler)
-	NumHandler() int
-	handle(e Event) (EventAction, os.Error)
-	String() string
-}
-
-// EventHook is almost, but not quite, suitable for user-defined
-// events.  If we want user-defined events, make EventHook a struct,
-// special-case adding and removing handlers in breakpoint hooks, and
-// provide a public interface for posting events to hooks.
-
-type Event interface {
-	Process() *Process
-	Goroutine() *Goroutine
-	String() string
-}
-
-type commonHook struct {
-	// Head of handler chain
-	head *handler
-	// Number of non-internal handlers
-	len int
-}
-
-type handler struct {
-	eh EventHandler
-	// True if this handler must be run before user-defined
-	// handlers in order to ensure correctness.
-	internal bool
-	// True if this handler has been removed from the chain.
-	removed bool
-	next    *handler
-}
-
-func (h *commonHook) AddHandler(eh EventHandler) {
-	h.addHandler(eh, false)
-}
-
-func (h *commonHook) addHandler(eh EventHandler, internal bool) {
-	// Ensure uniqueness of handlers
-	h.RemoveHandler(eh)
-
-	if !internal {
-		h.len++
-	}
-	// Add internal handlers to the beginning
-	if internal || h.head == nil {
-		h.head = &handler{eh, internal, false, h.head}
-		return
-	}
-	// Add handler after internal handlers
-	// TODO(austin) This should probably go on the end instead
-	prev := h.head
-	for prev.next != nil && prev.internal {
-		prev = prev.next
-	}
-	prev.next = &handler{eh, internal, false, prev.next}
-}
-
-func (h *commonHook) RemoveHandler(eh EventHandler) {
-	plink := &h.head
-	for l := *plink; l != nil; plink, l = &l.next, l.next {
-		if l.eh == eh {
-			if !l.internal {
-				h.len--
-			}
-			l.removed = true
-			*plink = l.next
-			break
-		}
-	}
-}
-
-func (h *commonHook) NumHandler() int { return h.len }
-
-func (h *commonHook) handle(e Event) (EventAction, os.Error) {
-	action := EADefault
-	plink := &h.head
-	for l := *plink; l != nil; plink, l = &l.next, l.next {
-		if l.removed {
-			continue
-		}
-		a, err := l.eh(e)
-		if a&EARemoveSelf == EARemoveSelf {
-			if !l.internal {
-				h.len--
-			}
-			l.removed = true
-			*plink = l.next
-			a &^= EARemoveSelf
-		}
-		if err != nil {
-			return EAStop, err
-		}
-		if a > action {
-			action = a
-		}
-	}
-	return action, nil
-}
-
-type commonEvent struct {
-	// The process of this event
-	p *Process
-	// The goroutine of this event.
-	t *Goroutine
-}
-
-func (e *commonEvent) Process() *Process { return e.p }
-
-func (e *commonEvent) Goroutine() *Goroutine { return e.t }
-
-/*
- * Standard event handlers
- */
-
-// EventPrint is a standard event handler that prints events as they
-// occur.  It will not cause the process to stop.
-func EventPrint(ev Event) (EventAction, os.Error) {
-	// TODO(austin) Include process name here?
-	fmt.Fprintf(os.Stderr, "*** %v\n", ev.String())
-	return EADefault, nil
-}
-
-// EventStop is a standard event handler that causes the process to stop.
-func EventStop(ev Event) (EventAction, os.Error) {
-	return EAStop, nil
-}
-
-/*
- * Breakpoints
- */
-
-type breakpointHook struct {
-	commonHook
-	p  *Process
-	pc proc.Word
-}
-
-// A Breakpoint event occurs when a process reaches a particular
-// program counter.  When this event is handled, the current goroutine
-// will be the goroutine that reached the program counter.
-type Breakpoint struct {
-	commonEvent
-	osThread proc.Thread
-	pc       proc.Word
-}
-
-func (h *breakpointHook) AddHandler(eh EventHandler) {
-	h.addHandler(eh, false)
-}
-
-func (h *breakpointHook) addHandler(eh EventHandler, internal bool) {
-	// We register breakpoint events lazily to avoid holding
-	// references to breakpoints without handlers.  Be sure to use
-	// the "canonical" breakpoint if there is one.
-	if cur, ok := h.p.breakpointHooks[h.pc]; ok {
-		h = cur
-	}
-	oldhead := h.head
-	h.commonHook.addHandler(eh, internal)
-	if oldhead == nil && h.head != nil {
-		h.p.proc.AddBreakpoint(h.pc)
-		h.p.breakpointHooks[h.pc] = h
-	}
-}
-
-func (h *breakpointHook) RemoveHandler(eh EventHandler) {
-	oldhead := h.head
-	h.commonHook.RemoveHandler(eh)
-	if oldhead != nil && h.head == nil {
-		h.p.proc.RemoveBreakpoint(h.pc)
-		h.p.breakpointHooks[h.pc] = nil, false
-	}
-}
-
-func (h *breakpointHook) String() string {
-	// TODO(austin) Include process name?
-	// TODO(austin) Use line:pc or at least sym+%#x
-	return fmt.Sprintf("breakpoint at %#x", h.pc)
-}
-
-func (b *Breakpoint) PC() proc.Word { return b.pc }
-
-func (b *Breakpoint) String() string {
-	// TODO(austin) Include process name and goroutine
-	// TODO(austin) Use line:pc or at least sym+%#x
-	return fmt.Sprintf("breakpoint at %#x", b.pc)
-}
-
-/*
- * Goroutine create/exit
- */
-
-type goroutineCreateHook struct {
-	commonHook
-}
-
-func (h *goroutineCreateHook) String() string { return "goroutine create" }
-
-// A GoroutineCreate event occurs when a process creates a new
-// goroutine.  When this event is handled, the current goroutine will
-// be the newly created goroutine.
-type GoroutineCreate struct {
-	commonEvent
-	parent *Goroutine
-}
-
-// Parent returns the goroutine that created this goroutine.  May be
-// nil if this event is the creation of the first goroutine.
-func (e *GoroutineCreate) Parent() *Goroutine { return e.parent }
-
-func (e *GoroutineCreate) String() string {
-	// TODO(austin) Include process name
-	if e.parent == nil {
-		return fmt.Sprintf("%v created", e.t)
-	}
-	return fmt.Sprintf("%v created by %v", e.t, e.parent)
-}
-
-type goroutineExitHook struct {
-	commonHook
-}
-
-func (h *goroutineExitHook) String() string { return "goroutine exit" }
-
-// A GoroutineExit event occurs when a Go goroutine exits.
-type GoroutineExit struct {
-	commonEvent
-}
-
-func (e *GoroutineExit) String() string {
-	// TODO(austin) Include process name
-	//return fmt.Sprintf("%v exited", e.t);
-	// For debugging purposes
-	return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base)
-}
diff --git a/src/pkg/exp/ogle/frame.go b/src/pkg/exp/ogle/frame.go
deleted file mode 100644
index 1538362..0000000
--- a/src/pkg/exp/ogle/frame.go
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/gosym"
-	"debug/proc"
-	"fmt"
-	"os"
-)
-
-// A Frame represents a single frame on a remote call stack.
-type Frame struct {
-	// pc is the PC of the next instruction that will execute in
-	// this frame.  For lower frames, this is the instruction
-	// following the CALL instruction.
-	pc, sp, fp proc.Word
-	// The runtime.Stktop of the active stack segment
-	stk remoteStruct
-	// The function this stack frame is in
-	fn *gosym.Func
-	// The path and line of the CALL or current instruction.  Note
-	// that this differs slightly from the meaning of Frame.pc.
-	path string
-	line int
-	// The inner and outer frames of this frame.  outer is filled
-	// in lazily.
-	inner, outer *Frame
-}
-
-// newFrame returns the top-most Frame of the given g's thread.
-func newFrame(g remoteStruct) (*Frame, os.Error) {
-	var f *Frame
-	err := try(func(a aborter) { f = aNewFrame(a, g) })
-	return f, err
-}
-
-func aNewFrame(a aborter, g remoteStruct) *Frame {
-	p := g.r.p
-	var pc, sp proc.Word
-
-	// Is this G alive?
-	switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
-	case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
-		return nil
-	}
-
-	// Find the OS thread for this G
-
-	// TODO(austin) Ideally, we could look at the G's state and
-	// figure out if it's on an OS thread or not.  However, this
-	// is difficult because the state isn't updated atomically
-	// with scheduling changes.
-	for _, t := range p.proc.Threads() {
-		regs, err := t.Regs()
-		if err != nil {
-			// TODO(austin) What to do?
-			continue
-		}
-		thisg := p.G(regs)
-		if thisg == g.addr().base {
-			// Found this G's OS thread
-			pc = regs.PC()
-			sp = regs.SP()
-
-			// If this thread crashed, try to recover it
-			if pc == 0 {
-				pc = p.peekUintptr(a, pc)
-				sp += 8
-			}
-
-			break
-		}
-	}
-
-	if pc == 0 && sp == 0 {
-		// G is not mapped to an OS thread.  Use the
-		// scheduler's stored PC and SP.
-		sched := g.field(p.f.G.Sched).(remoteStruct)
-		pc = proc.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
-		sp = proc.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a))
-	}
-
-	// Get Stktop
-	stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct)
-
-	return prepareFrame(a, pc, sp, stk, nil)
-}
-
-// prepareFrame creates a Frame from the PC and SP within that frame,
-// as well as the active stack segment.  This function takes care of
-// traversing stack breaks and unwinding closures.
-func prepareFrame(a aborter, pc, sp proc.Word, stk remoteStruct, inner *Frame) *Frame {
-	// Based on src/pkg/runtime/amd64/traceback.c:traceback
-	p := stk.r.p
-	top := inner == nil
-
-	// Get function
-	var path string
-	var line int
-	var fn *gosym.Func
-
-	for i := 0; i < 100; i++ {
-		// Traverse segmented stack breaks
-		if p.sys.lessstack != nil && pc == proc.Word(p.sys.lessstack.Value) {
-			// Get stk->gobuf.pc
-			pc = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
-			// Get stk->gobuf.sp
-			sp = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a))
-			// Get stk->stackbase
-			stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct)
-			continue
-		}
-
-		// Get the PC of the call instruction
-		callpc := pc
-		if !top && (p.sys.goexit == nil || pc != proc.Word(p.sys.goexit.Value)) {
-			callpc--
-		}
-
-		// Look up function
-		path, line, fn = p.syms.PCToLine(uint64(callpc))
-		if fn != nil {
-			break
-		}
-
-		// Closure?
-		var buf = make([]byte, p.ClosureSize())
-		if _, err := p.Peek(pc, buf); err != nil {
-			break
-		}
-		spdelta, ok := p.ParseClosure(buf)
-		if ok {
-			sp += proc.Word(spdelta)
-			pc = p.peekUintptr(a, sp-proc.Word(p.PtrSize()))
-		}
-	}
-	if fn == nil {
-		return nil
-	}
-
-	// Compute frame pointer
-	var fp proc.Word
-	if fn.FrameSize < p.PtrSize() {
-		fp = sp + proc.Word(p.PtrSize())
-	} else {
-		fp = sp + proc.Word(fn.FrameSize)
-	}
-	// TODO(austin) To really figure out if we're in the prologue,
-	// we need to disassemble the function and look for the call
-	// to morestack.  For now, just special case the entry point.
-	//
-	// TODO(austin) What if we're in the call to morestack in the
-	// prologue?  Then top == false.
-	if top && pc == proc.Word(fn.Entry) {
-		// We're in the function prologue, before SP
-		// has been adjusted for the frame.
-		fp -= proc.Word(fn.FrameSize - p.PtrSize())
-	}
-
-	return &Frame{pc, sp, fp, stk, fn, path, line, inner, nil}
-}
-
-// Outer returns the Frame that called this Frame, or nil if this is
-// the outermost frame.
-func (f *Frame) Outer() (*Frame, os.Error) {
-	var fr *Frame
-	err := try(func(a aborter) { fr = f.aOuter(a) })
-	return fr, err
-}
-
-func (f *Frame) aOuter(a aborter) *Frame {
-	// Is there a cached outer frame
-	if f.outer != nil {
-		return f.outer
-	}
-
-	p := f.stk.r.p
-
-	sp := f.fp
-	if f.fn == p.sys.newproc && f.fn == p.sys.deferproc {
-		// TODO(rsc) The compiler inserts two push/pop's
-		// around calls to go and defer.  Russ says this
-		// should get fixed in the compiler, but we account
-		// for it for now.
-		sp += proc.Word(2 * p.PtrSize())
-	}
-
-	pc := p.peekUintptr(a, f.fp-proc.Word(p.PtrSize()))
-	if pc < 0x1000 {
-		return nil
-	}
-
-	// TODO(austin) Register this frame for shoot-down.
-
-	f.outer = prepareFrame(a, pc, sp, f.stk, f)
-	return f.outer
-}
-
-// Inner returns the Frame called by this Frame, or nil if this is the
-// innermost frame.
-func (f *Frame) Inner() *Frame { return f.inner }
-
-func (f *Frame) String() string {
-	res := f.fn.Name
-	if f.pc > proc.Word(f.fn.Value) {
-		res += fmt.Sprintf("+%#x", f.pc-proc.Word(f.fn.Entry))
-	}
-	return res + fmt.Sprintf(" %s:%d", f.path, f.line)
-}
diff --git a/src/pkg/exp/ogle/goroutine.go b/src/pkg/exp/ogle/goroutine.go
deleted file mode 100644
index 5104ec6..0000000
--- a/src/pkg/exp/ogle/goroutine.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/proc"
-	"exp/eval"
-	"fmt"
-	"os"
-)
-
-// A Goroutine represents a goroutine in a remote process.
-type Goroutine struct {
-	g     remoteStruct
-	frame *Frame
-	dead  bool
-}
-
-func (t *Goroutine) String() string {
-	if t.dead {
-		return "<dead thread>"
-	}
-	// TODO(austin) Give threads friendly ID's, possibly including
-	// the name of the entry function.
-	return fmt.Sprintf("thread %#x", t.g.addr().base)
-}
-
-// isG0 returns true if this thread if the internal idle thread
-func (t *Goroutine) isG0() bool { return t.g.addr().base == t.g.r.p.sys.g0.addr().base }
-
-func (t *Goroutine) resetFrame() (err os.Error) {
-	// TODO(austin) Reuse any live part of the current frame stack
-	// so existing references to Frame's keep working.
-	t.frame, err = newFrame(t.g)
-	return
-}
-
-// Out selects the caller frame of the current frame.
-func (t *Goroutine) Out() os.Error {
-	f, err := t.frame.Outer()
-	if f != nil {
-		t.frame = f
-	}
-	return err
-}
-
-// In selects the frame called by the current frame.
-func (t *Goroutine) In() os.Error {
-	f := t.frame.Inner()
-	if f != nil {
-		t.frame = f
-	}
-	return nil
-}
-
-func readylockedBP(ev Event) (EventAction, os.Error) {
-	b := ev.(*Breakpoint)
-	p := b.Process()
-
-	// The new g is the only argument to this function, so the
-	// stack will have the return address, then the G*.
-	regs, err := b.osThread.Regs()
-	if err != nil {
-		return EAStop, err
-	}
-	sp := regs.SP()
-	addr := sp + proc.Word(p.PtrSize())
-	arg := remotePtr{remote{addr, p}, p.runtime.G}
-	var gp eval.Value
-	err = try(func(a aborter) { gp = arg.aGet(a) })
-	if err != nil {
-		return EAStop, err
-	}
-	if gp == nil {
-		return EAStop, UnknownGoroutine{b.osThread, 0}
-	}
-	gs := gp.(remoteStruct)
-	g := &Goroutine{gs, nil, false}
-	p.goroutines[gs.addr().base] = g
-
-	// Enqueue goroutine creation event
-	parent := b.Goroutine()
-	if parent.isG0() {
-		parent = nil
-	}
-	p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent})
-
-	// If we don't have any thread selected, select this one
-	if p.curGoroutine == nil {
-		p.curGoroutine = g
-	}
-
-	return EADefault, nil
-}
-
-func goexitBP(ev Event) (EventAction, os.Error) {
-	b := ev.(*Breakpoint)
-	p := b.Process()
-
-	g := b.Goroutine()
-	g.dead = true
-
-	addr := g.g.addr().base
-	p.goroutines[addr] = nil, false
-
-	// Enqueue thread exit event
-	p.postEvent(&GoroutineExit{commonEvent{p, g}})
-
-	// If we just exited our selected goroutine, selected another
-	if p.curGoroutine == g {
-		p.selectSomeGoroutine()
-	}
-
-	return EADefault, nil
-}
diff --git a/src/pkg/exp/ogle/main.go b/src/pkg/exp/ogle/main.go
deleted file mode 100644
index 1999ecc..0000000
--- a/src/pkg/exp/ogle/main.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "exp/ogle"
-
-func main() { ogle.Main() }
diff --git a/src/pkg/exp/ogle/process.go b/src/pkg/exp/ogle/process.go
deleted file mode 100644
index 7c803b3..0000000
--- a/src/pkg/exp/ogle/process.go
+++ /dev/null
@@ -1,521 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/elf"
-	"debug/gosym"
-	"debug/proc"
-	"exp/eval"
-	"fmt"
-	"log"
-	"os"
-	"reflect"
-)
-
-// A FormatError indicates a failure to process information in or
-// about a remote process, such as unexpected or missing information
-// in the object file or runtime structures.
-type FormatError string
-
-func (e FormatError) String() string { return string(e) }
-
-// An UnknownArchitecture occurs when trying to load an object file
-// that indicates an architecture not supported by the debugger.
-type UnknownArchitecture elf.Machine
-
-func (e UnknownArchitecture) String() string {
-	return "unknown architecture: " + elf.Machine(e).String()
-}
-
-// A ProcessNotStopped error occurs when attempting to read or write
-// memory or registers of a process that is not stopped.
-type ProcessNotStopped struct{}
-
-func (e ProcessNotStopped) String() string { return "process not stopped" }
-
-// An UnknownGoroutine error is an internal error representing an
-// unrecognized G structure pointer.
-type UnknownGoroutine struct {
-	OSThread  proc.Thread
-	Goroutine proc.Word
-}
-
-func (e UnknownGoroutine) String() string {
-	return fmt.Sprintf("internal error: unknown goroutine (G %#x)", e.Goroutine)
-}
-
-// A NoCurrentGoroutine error occurs when no goroutine is currently
-// selected in a process (or when there are no goroutines in a
-// process).
-type NoCurrentGoroutine struct{}
-
-func (e NoCurrentGoroutine) String() string { return "no current goroutine" }
-
-// A Process represents a remote attached process.
-type Process struct {
-	Arch
-	proc proc.Process
-
-	// The symbol table of this process
-	syms *gosym.Table
-
-	// A possibly-stopped OS thread, or nil
-	threadCache proc.Thread
-
-	// Types parsed from the remote process
-	types map[proc.Word]*remoteType
-
-	// Types and values from the remote runtime package
-	runtime runtimeValues
-
-	// Runtime field indexes
-	f runtimeIndexes
-
-	// Globals from the sys package (or from no package)
-	sys struct {
-		lessstack, goexit, newproc, deferproc, newprocreadylocked *gosym.Func
-		allg                                                      remotePtr
-		g0                                                        remoteStruct
-	}
-
-	// Event queue
-	posted  []Event
-	pending []Event
-	event   Event
-
-	// Event hooks
-	breakpointHooks     map[proc.Word]*breakpointHook
-	goroutineCreateHook *goroutineCreateHook
-	goroutineExitHook   *goroutineExitHook
-
-	// Current goroutine, or nil if there are no goroutines
-	curGoroutine *Goroutine
-
-	// Goroutines by the address of their G structure
-	goroutines map[proc.Word]*Goroutine
-}
-
-/*
- * Process creation
- */
-
-// NewProcess constructs a new remote process around a traced
-// process, an architecture, and a symbol table.
-func NewProcess(tproc proc.Process, arch Arch, syms *gosym.Table) (*Process, os.Error) {
-	p := &Process{
-		Arch:                arch,
-		proc:                tproc,
-		syms:                syms,
-		types:               make(map[proc.Word]*remoteType),
-		breakpointHooks:     make(map[proc.Word]*breakpointHook),
-		goroutineCreateHook: new(goroutineCreateHook),
-		goroutineExitHook:   new(goroutineExitHook),
-		goroutines:          make(map[proc.Word]*Goroutine),
-	}
-
-	// Fill in remote runtime
-	p.bootstrap()
-
-	switch {
-	case p.sys.allg.addr().base == 0:
-		return nil, FormatError("failed to find runtime symbol 'allg'")
-	case p.sys.g0.addr().base == 0:
-		return nil, FormatError("failed to find runtime symbol 'g0'")
-	case p.sys.newprocreadylocked == nil:
-		return nil, FormatError("failed to find runtime symbol 'newprocreadylocked'")
-	case p.sys.goexit == nil:
-		return nil, FormatError("failed to find runtime symbol 'sys.goexit'")
-	}
-
-	// Get current goroutines
-	p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false}
-	err := try(func(a aborter) {
-		g := p.sys.allg.aGet(a)
-		for g != nil {
-			gs := g.(remoteStruct)
-			fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base)
-			p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false}
-			g = gs.field(p.f.G.Alllink).(remotePtr).aGet(a)
-		}
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	// Create internal breakpoints to catch new and exited goroutines
-	p.OnBreakpoint(proc.Word(p.sys.newprocreadylocked.Entry)).(*breakpointHook).addHandler(readylockedBP, true)
-	p.OnBreakpoint(proc.Word(p.sys.goexit.Entry)).(*breakpointHook).addHandler(goexitBP, true)
-
-	// Select current frames
-	for _, g := range p.goroutines {
-		g.resetFrame()
-	}
-
-	p.selectSomeGoroutine()
-
-	return p, nil
-}
-
-func elfGoSyms(f *elf.File) (*gosym.Table, os.Error) {
-	text := f.Section(".text")
-	symtab := f.Section(".gosymtab")
-	pclntab := f.Section(".gopclntab")
-	if text == nil || symtab == nil || pclntab == nil {
-		return nil, nil
-	}
-
-	symdat, err := symtab.Data()
-	if err != nil {
-		return nil, err
-	}
-	pclndat, err := pclntab.Data()
-	if err != nil {
-		return nil, err
-	}
-
-	pcln := gosym.NewLineTable(pclndat, text.Addr)
-	tab, err := gosym.NewTable(symdat, pcln)
-	if err != nil {
-		return nil, err
-	}
-
-	return tab, nil
-}
-
-// NewProcessElf constructs a new remote process around a traced
-// process and the process' ELF object.
-func NewProcessElf(tproc proc.Process, f *elf.File) (*Process, os.Error) {
-	syms, err := elfGoSyms(f)
-	if err != nil {
-		return nil, err
-	}
-	if syms == nil {
-		return nil, FormatError("Failed to find symbol table")
-	}
-	var arch Arch
-	switch f.Machine {
-	case elf.EM_X86_64:
-		arch = Amd64
-	default:
-		return nil, UnknownArchitecture(f.Machine)
-	}
-	return NewProcess(tproc, arch, syms)
-}
-
-// bootstrap constructs the runtime structure of a remote process.
-func (p *Process) bootstrap() {
-	// Manually construct runtime types
-	p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch)
-	p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch)
-	p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch)
-
-	p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch)
-	p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch)
-	p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch)
-	p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch)
-	p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch)
-	p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch)
-	p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch)
-	p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch)
-
-	p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch)
-	p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch)
-	p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch)
-
-	// Get addresses of type.*runtime.XType for discrimination.
-	rtv := reflect.Indirect(reflect.ValueOf(&p.runtime))
-	rtvt := rtv.Type()
-	for i := 0; i < rtv.NumField(); i++ {
-		n := rtvt.Field(i).Name
-		if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' {
-			continue
-		}
-		sym := p.syms.LookupSym("type.*runtime." + n[1:])
-		if sym == nil {
-			continue
-		}
-		rtv.Field(i).SetUint(sym.Value)
-	}
-
-	// Get runtime field indexes
-	fillRuntimeIndexes(&p.runtime, &p.f)
-
-	// Fill G status
-	p.runtime.runtimeGStatus = rt1GStatus
-
-	// Get globals
-	p.sys.lessstack = p.syms.LookupFunc("sys.lessstack")
-	p.sys.goexit = p.syms.LookupFunc("goexit")
-	p.sys.newproc = p.syms.LookupFunc("sys.newproc")
-	p.sys.deferproc = p.syms.LookupFunc("sys.deferproc")
-	p.sys.newprocreadylocked = p.syms.LookupFunc("newprocreadylocked")
-	if allg := p.syms.LookupSym("allg"); allg != nil {
-		p.sys.allg = remotePtr{remote{proc.Word(allg.Value), p}, p.runtime.G}
-	}
-	if g0 := p.syms.LookupSym("g0"); g0 != nil {
-		p.sys.g0 = p.runtime.G.mk(remote{proc.Word(g0.Value), p}).(remoteStruct)
-	}
-}
-
-func (p *Process) selectSomeGoroutine() {
-	// Once we have friendly goroutine ID's, there might be a more
-	// reasonable behavior for this.
-	p.curGoroutine = nil
-	for _, g := range p.goroutines {
-		if !g.isG0() && g.frame != nil {
-			p.curGoroutine = g
-			return
-		}
-	}
-}
-
-/*
- * Process memory
- */
-
-func (p *Process) someStoppedOSThread() proc.Thread {
-	if p.threadCache != nil {
-		if _, err := p.threadCache.Stopped(); err == nil {
-			return p.threadCache
-		}
-	}
-
-	for _, t := range p.proc.Threads() {
-		if _, err := t.Stopped(); err == nil {
-			p.threadCache = t
-			return t
-		}
-	}
-	return nil
-}
-
-func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) {
-	thr := p.someStoppedOSThread()
-	if thr == nil {
-		return 0, ProcessNotStopped{}
-	}
-	return thr.Peek(addr, out)
-}
-
-func (p *Process) Poke(addr proc.Word, b []byte) (int, os.Error) {
-	thr := p.someStoppedOSThread()
-	if thr == nil {
-		return 0, ProcessNotStopped{}
-	}
-	return thr.Poke(addr, b)
-}
-
-func (p *Process) peekUintptr(a aborter, addr proc.Word) proc.Word {
-	return proc.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a))
-}
-
-/*
- * Events
- */
-
-// OnBreakpoint returns the hook that is run when the program reaches
-// the given program counter.
-func (p *Process) OnBreakpoint(pc proc.Word) EventHook {
-	if bp, ok := p.breakpointHooks[pc]; ok {
-		return bp
-	}
-	// The breakpoint will register itself when a handler is added
-	return &breakpointHook{commonHook{nil, 0}, p, pc}
-}
-
-// OnGoroutineCreate returns the hook that is run when a goroutine is created.
-func (p *Process) OnGoroutineCreate() EventHook {
-	return p.goroutineCreateHook
-}
-
-// OnGoroutineExit returns the hook that is run when a goroutine exits.
-func (p *Process) OnGoroutineExit() EventHook { return p.goroutineExitHook }
-
-// osThreadToGoroutine looks up the goroutine running on an OS thread.
-func (p *Process) osThreadToGoroutine(t proc.Thread) (*Goroutine, os.Error) {
-	regs, err := t.Regs()
-	if err != nil {
-		return nil, err
-	}
-	g := p.G(regs)
-	gt, ok := p.goroutines[g]
-	if !ok {
-		return nil, UnknownGoroutine{t, g}
-	}
-	return gt, nil
-}
-
-// causesToEvents translates the stop causes of the underlying process
-// into an event queue.
-func (p *Process) causesToEvents() ([]Event, os.Error) {
-	// Count causes we're interested in
-	nev := 0
-	for _, t := range p.proc.Threads() {
-		if c, err := t.Stopped(); err == nil {
-			switch c := c.(type) {
-			case proc.Breakpoint:
-				nev++
-			case proc.Signal:
-				// TODO(austin)
-				//nev++;
-			}
-		}
-	}
-
-	// Translate causes to events
-	events := make([]Event, nev)
-	i := 0
-	for _, t := range p.proc.Threads() {
-		if c, err := t.Stopped(); err == nil {
-			switch c := c.(type) {
-			case proc.Breakpoint:
-				gt, err := p.osThreadToGoroutine(t)
-				if err != nil {
-					return nil, err
-				}
-				events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)}
-				i++
-			case proc.Signal:
-				// TODO(austin)
-			}
-		}
-	}
-
-	return events, nil
-}
-
-// postEvent appends an event to the posted queue.  These events will
-// be processed before any currently pending events.
-func (p *Process) postEvent(ev Event) {
-	p.posted = append(p.posted, ev)
-}
-
-// processEvents processes events in the event queue until no events
-// remain, a handler returns EAStop, or a handler returns an error.
-// It returns either EAStop or EAContinue and possibly an error.
-func (p *Process) processEvents() (EventAction, os.Error) {
-	var ev Event
-	for len(p.posted) > 0 {
-		ev, p.posted = p.posted[0], p.posted[1:]
-		action, err := p.processEvent(ev)
-		if action == EAStop {
-			return action, err
-		}
-	}
-
-	for len(p.pending) > 0 {
-		ev, p.pending = p.pending[0], p.pending[1:]
-		action, err := p.processEvent(ev)
-		if action == EAStop {
-			return action, err
-		}
-	}
-
-	return EAContinue, nil
-}
-
-// processEvent processes a single event, without manipulating the
-// event queues.  It returns either EAStop or EAContinue and possibly
-// an error.
-func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
-	p.event = ev
-
-	var action EventAction
-	var err os.Error
-	switch ev := p.event.(type) {
-	case *Breakpoint:
-		hook, ok := p.breakpointHooks[ev.pc]
-		if !ok {
-			break
-		}
-		p.curGoroutine = ev.Goroutine()
-		action, err = hook.handle(ev)
-
-	case *GoroutineCreate:
-		p.curGoroutine = ev.Goroutine()
-		action, err = p.goroutineCreateHook.handle(ev)
-
-	case *GoroutineExit:
-		action, err = p.goroutineExitHook.handle(ev)
-
-	default:
-		log.Panicf("Unknown event type %T in queue", p.event)
-	}
-
-	if err != nil {
-		return EAStop, err
-	} else if action == EAStop {
-		return EAStop, nil
-	}
-	return EAContinue, nil
-}
-
-// Event returns the last event that caused the process to stop.  This
-// may return nil if the process has never been stopped by an event.
-//
-// TODO(austin) Return nil if the user calls p.Stop()?
-func (p *Process) Event() Event { return p.event }
-
-/*
- * Process control
- */
-
-// TODO(austin) Cont, WaitStop, and Stop.  Need to figure out how
-// event handling works with these.  Originally I did it only in
-// WaitStop, but if you Cont and there are pending events, then you
-// have to not actually continue and wait until a WaitStop to process
-// them, even if the event handlers will tell you to continue.  We
-// could handle them in both Cont and WaitStop to avoid this problem,
-// but it's still weird if an event happens after the Cont and before
-// the WaitStop that the handlers say to continue from.  Or we could
-// handle them on a separate thread.  Then obviously you get weird
-// asynchronous things, like prints while the user it typing a command,
-// but that's not necessarily a bad thing.
-
-// ContWait resumes process execution and waits for an event to occur
-// that stops the process.
-func (p *Process) ContWait() os.Error {
-	for {
-		a, err := p.processEvents()
-		if err != nil {
-			return err
-		} else if a == EAStop {
-			break
-		}
-		err = p.proc.Continue()
-		if err != nil {
-			return err
-		}
-		err = p.proc.WaitStop()
-		if err != nil {
-			return err
-		}
-		for _, g := range p.goroutines {
-			g.resetFrame()
-		}
-		p.pending, err = p.causesToEvents()
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// Out selects the caller frame of the current frame.
-func (p *Process) Out() os.Error {
-	if p.curGoroutine == nil {
-		return NoCurrentGoroutine{}
-	}
-	return p.curGoroutine.Out()
-}
-
-// In selects the frame called by the current frame.
-func (p *Process) In() os.Error {
-	if p.curGoroutine == nil {
-		return NoCurrentGoroutine{}
-	}
-	return p.curGoroutine.In()
-}
diff --git a/src/pkg/exp/ogle/rruntime.go b/src/pkg/exp/ogle/rruntime.go
deleted file mode 100644
index 950418b..0000000
--- a/src/pkg/exp/ogle/rruntime.go
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/proc"
-	"exp/eval"
-	"reflect"
-)
-
-// This file contains remote runtime definitions.  Using reflection,
-// we convert all of these to interpreter types and layout their
-// remote representations using the architecture rules.
-//
-// We could get most of these definitions from our own runtime
-// package; however, some of them differ in convenient ways, some of
-// them are not defined or exported by the runtime, and having our own
-// definitions makes it easy to support multiple remote runtime
-// versions.  This may turn out to be overkill.
-//
-// All of these structures are prefixed with rt1 to indicate the
-// runtime version and to mark them as types used only as templates
-// for remote types.
-
-/*
- * Runtime data headers
- *
- * See $GOROOT/src/pkg/runtime/runtime.h
- */
-
-type rt1String struct {
-	str uintptr
-	len int
-}
-
-type rt1Slice struct {
-	array uintptr
-	len   int
-	cap   int
-}
-
-type rt1Eface struct {
-	typ uintptr
-	ptr uintptr
-}
-
-/*
- * Runtime type structures
- *
- * See $GOROOT/src/pkg/runtime/type.h and $GOROOT/src/pkg/runtime/type.go
- */
-
-type rt1UncommonType struct {
-	name    *string
-	pkgPath *string
-	//methods []method;
-}
-
-type rt1CommonType struct {
-	size                   uintptr
-	hash                   uint32
-	alg, align, fieldAlign uint8
-	string                 *string
-	uncommonType           *rt1UncommonType
-}
-
-type rt1Type struct {
-	// While Type is technically an Eface, treating the
-	// discriminator as an opaque pointer and taking advantage of
-	// the commonType prologue on all Type's makes type parsing
-	// much simpler.
-	typ uintptr
-	ptr *rt1CommonType
-}
-
-type rt1StructField struct {
-	name    *string
-	pkgPath *string
-	typ     *rt1Type
-	tag     *string
-	offset  uintptr
-}
-
-type rt1StructType struct {
-	rt1CommonType
-	fields []rt1StructField
-}
-
-type rt1PtrType struct {
-	rt1CommonType
-	elem *rt1Type
-}
-
-type rt1SliceType struct {
-	rt1CommonType
-	elem *rt1Type
-}
-
-type rt1ArrayType struct {
-	rt1CommonType
-	elem *rt1Type
-	len  uintptr
-}
-
-/*
- * Runtime scheduler structures
- *
- * See $GOROOT/src/pkg/runtime/runtime.h
- */
-
-// Fields beginning with _ are only for padding
-
-type rt1Stktop struct {
-	stackguard uintptr
-	stackbase  *rt1Stktop
-	gobuf      rt1Gobuf
-	_args      uint32
-	_fp        uintptr
-}
-
-type rt1Gobuf struct {
-	sp uintptr
-	pc uintptr
-	g  *rt1G
-	r0 uintptr
-}
-
-type rt1G struct {
-	_stackguard uintptr
-	stackbase   *rt1Stktop
-	_defer      uintptr
-	sched       rt1Gobuf
-	_stack0     uintptr
-	_entry      uintptr
-	alllink     *rt1G
-	_param      uintptr
-	status      int16
-	// Incomplete
-}
-
-var rt1GStatus = runtimeGStatus{
-	Gidle:     0,
-	Grunnable: 1,
-	Grunning:  2,
-	Gsyscall:  3,
-	Gwaiting:  4,
-	Gmoribund: 5,
-	Gdead:     6,
-}
-
-// runtimeIndexes stores the indexes of fields in the runtime
-// structures.  It is filled in using reflection, so the name of the
-// fields must match the names of the remoteType's in runtimeValues
-// exactly and the names of the index fields must be the capitalized
-// version of the names of the fields in the runtime structures above.
-type runtimeIndexes struct {
-	String struct {
-		Str, Len int
-	}
-	Slice struct {
-		Array, Len, Cap int
-	}
-	Eface struct {
-		Typ, Ptr int
-	}
-
-	UncommonType struct {
-		Name, PkgPath int
-	}
-	CommonType struct {
-		Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
-	}
-	Type struct {
-		Typ, Ptr int
-	}
-	StructField struct {
-		Name, PkgPath, Typ, Tag, Offset int
-	}
-	StructType struct {
-		Fields int
-	}
-	PtrType struct {
-		Elem int
-	}
-	SliceType struct {
-		Elem int
-	}
-	ArrayType struct {
-		Elem, Len int
-	}
-
-	Stktop struct {
-		Stackguard, Stackbase, Gobuf int
-	}
-	Gobuf struct {
-		Sp, Pc, G int
-	}
-	G struct {
-		Stackbase, Sched, Status, Alllink int
-	}
-}
-
-// Values of G status codes
-type runtimeGStatus struct {
-	Gidle, Grunnable, Grunning, Gsyscall, Gwaiting, Gmoribund, Gdead int64
-}
-
-// runtimeValues stores the types and values that correspond to those
-// in the remote runtime package.
-type runtimeValues struct {
-	// Runtime data headers
-	String, Slice, Eface *remoteType
-	// Runtime type structures
-	Type, CommonType, UncommonType, StructField, StructType, PtrType,
-	ArrayType, SliceType *remoteType
-	// Runtime scheduler structures
-	Stktop, Gobuf, G *remoteType
-	// Addresses of *runtime.XType types.  These are the
-	// discriminators on the runtime.Type interface.  We use local
-	// reflection to fill these in from the remote symbol table,
-	// so the names must match the runtime names.
-	PBoolType,
-	PUint8Type, PUint16Type, PUint32Type, PUint64Type, PUintType, PUintptrType,
-	PInt8Type, PInt16Type, PInt32Type, PInt64Type, PIntType,
-	PFloat32Type, PFloat64Type, PFloatType,
-	PArrayType, PStringType, PStructType, PPtrType, PFuncType,
-	PInterfaceType, PSliceType, PMapType, PChanType,
-	PDotDotDotType, PUnsafePointerType proc.Word
-	// G status values
-	runtimeGStatus
-}
-
-// fillRuntimeIndexes fills a runtimeIndexes structure will the field
-// indexes gathered from the remoteTypes recorded in a runtimeValues
-// structure.
-func fillRuntimeIndexes(runtime *runtimeValues, out *runtimeIndexes) {
-	outv := reflect.Indirect(reflect.ValueOf(out))
-	outt := outv.Type()
-	runtimev := reflect.Indirect(reflect.ValueOf(runtime))
-
-	// out contains fields corresponding to each runtime type
-	for i := 0; i < outt.NumField(); i++ {
-		// Find the interpreter type for this runtime type
-		name := outt.Field(i).Name
-		et := runtimev.FieldByName(name).Interface().(*remoteType).Type.(*eval.StructType)
-
-		// Get the field indexes of the interpreter struct type
-		indexes := make(map[string]int, len(et.Elems))
-		for j, f := range et.Elems {
-			if f.Anonymous {
-				continue
-			}
-			name := f.Name
-			if name[0] >= 'a' && name[0] <= 'z' {
-				name = string(name[0]+'A'-'a') + name[1:]
-			}
-			indexes[name] = j
-		}
-
-		// Fill this field of out
-		outStructv := outv.Field(i)
-		outStructt := outStructv.Type()
-		for j := 0; j < outStructt.NumField(); j++ {
-			f := outStructv.Field(j)
-			name := outStructt.Field(j).Name
-			f.SetInt(int64(indexes[name]))
-		}
-	}
-}
diff --git a/src/pkg/exp/ogle/rtype.go b/src/pkg/exp/ogle/rtype.go
deleted file mode 100644
index b3c3557..0000000
--- a/src/pkg/exp/ogle/rtype.go
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/proc"
-	"exp/eval"
-	"fmt"
-	"log"
-)
-
-const debugParseRemoteType = false
-
-// A remoteType is the local representation of a type in a remote process.
-type remoteType struct {
-	eval.Type
-	// The size of values of this type in bytes.
-	size int
-	// The field alignment of this type.  Only used for
-	// manually-constructed types.
-	fieldAlign int
-	// The maker function to turn a remote address of a value of
-	// this type into an interpreter Value.
-	mk maker
-}
-
-var manualTypes = make(map[Arch]map[eval.Type]*remoteType)
-
-// newManualType constructs a remote type from an interpreter Type
-// using the size and alignment properties of the given architecture.
-// Most types are parsed directly out of the remote process, but to do
-// so we need to layout the structures that describe those types ourselves.
-func newManualType(t eval.Type, arch Arch) *remoteType {
-	if nt, ok := t.(*eval.NamedType); ok {
-		t = nt.Def
-	}
-
-	// Get the type map for this architecture
-	typeMap := manualTypes[arch]
-	if typeMap == nil {
-		typeMap = make(map[eval.Type]*remoteType)
-		manualTypes[arch] = typeMap
-
-		// Construct basic types for this architecture
-		basicType := func(t eval.Type, mk maker, size int, fieldAlign int) {
-			t = t.(*eval.NamedType).Def
-			if fieldAlign == 0 {
-				fieldAlign = size
-			}
-			typeMap[t] = &remoteType{t, size, fieldAlign, mk}
-		}
-		basicType(eval.Uint8Type, mkUint8, 1, 0)
-		basicType(eval.Uint32Type, mkUint32, 4, 0)
-		basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0)
-		basicType(eval.Int16Type, mkInt16, 2, 0)
-		basicType(eval.Int32Type, mkInt32, 4, 0)
-		basicType(eval.IntType, mkInt, arch.IntSize(), 0)
-		basicType(eval.StringType, mkString, arch.PtrSize()+arch.IntSize(), arch.PtrSize())
-	}
-
-	if rt, ok := typeMap[t]; ok {
-		return rt
-	}
-
-	var rt *remoteType
-	switch t := t.(type) {
-	case *eval.PtrType:
-		var elem *remoteType
-		mk := func(r remote) eval.Value { return remotePtr{r, elem} }
-		rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk}
-		// Construct the element type after registering the
-		// type to break cycles.
-		typeMap[eval.Type(t)] = rt
-		elem = newManualType(t.Elem, arch)
-
-	case *eval.ArrayType:
-		elem := newManualType(t.Elem, arch)
-		mk := func(r remote) eval.Value { return remoteArray{r, t.Len, elem} }
-		rt = &remoteType{t, elem.size * int(t.Len), elem.fieldAlign, mk}
-
-	case *eval.SliceType:
-		elem := newManualType(t.Elem, arch)
-		mk := func(r remote) eval.Value { return remoteSlice{r, elem} }
-		rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk}
-
-	case *eval.StructType:
-		layout := make([]remoteStructField, len(t.Elems))
-		offset := 0
-		fieldAlign := 0
-		for i, f := range t.Elems {
-			elem := newManualType(f.Type, arch)
-			if fieldAlign == 0 {
-				fieldAlign = elem.fieldAlign
-			}
-			offset = arch.Align(offset, elem.fieldAlign)
-			layout[i].offset = offset
-			layout[i].fieldType = elem
-			offset += elem.size
-		}
-		mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
-		rt = &remoteType{t, offset, fieldAlign, mk}
-
-	default:
-		log.Panicf("cannot manually construct type %T", t)
-	}
-
-	typeMap[t] = rt
-	return rt
-}
-
-var prtIndent = ""
-
-// parseRemoteType parses a Type structure in a remote process to
-// construct the corresponding interpreter type and remote type.
-func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
-	addr := rs.addr().base
-	p := rs.addr().p
-
-	// We deal with circular types by discovering cycles at
-	// NamedTypes.  If a type cycles back to something other than
-	// a named type, we're guaranteed that there will be a named
-	// type somewhere in that cycle.  Thus, we continue down,
-	// re-parsing types until we reach the named type in the
-	// cycle.  In order to still create one remoteType per remote
-	// type, we insert an empty remoteType in the type map the
-	// first time we encounter the type and re-use that structure
-	// the second time we encounter it.
-
-	rt, ok := p.types[addr]
-	if ok && rt.Type != nil {
-		return rt
-	} else if !ok {
-		rt = &remoteType{}
-		p.types[addr] = rt
-	}
-
-	if debugParseRemoteType {
-		sym := p.syms.SymByAddr(uint64(addr))
-		name := "<unknown>"
-		if sym != nil {
-			name = sym.Name
-		}
-		log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name)
-		prtIndent += " "
-		defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }()
-	}
-
-	// Get Type header
-	itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a))
-	typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct)
-
-	// Is this a named type?
-	var nt *eval.NamedType
-	uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a)
-	if uncommon != nil {
-		name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a)
-		if name != nil {
-			// TODO(austin) Declare type in appropriate remote package
-			nt = eval.NewNamedType(name.(remoteString).aGet(a))
-			rt.Type = nt
-		}
-	}
-
-	// Create type
-	var t eval.Type
-	var mk maker
-	switch itype {
-	case p.runtime.PBoolType:
-		t = eval.BoolType
-		mk = mkBool
-	case p.runtime.PUint8Type:
-		t = eval.Uint8Type
-		mk = mkUint8
-	case p.runtime.PUint16Type:
-		t = eval.Uint16Type
-		mk = mkUint16
-	case p.runtime.PUint32Type:
-		t = eval.Uint32Type
-		mk = mkUint32
-	case p.runtime.PUint64Type:
-		t = eval.Uint64Type
-		mk = mkUint64
-	case p.runtime.PUintType:
-		t = eval.UintType
-		mk = mkUint
-	case p.runtime.PUintptrType:
-		t = eval.UintptrType
-		mk = mkUintptr
-	case p.runtime.PInt8Type:
-		t = eval.Int8Type
-		mk = mkInt8
-	case p.runtime.PInt16Type:
-		t = eval.Int16Type
-		mk = mkInt16
-	case p.runtime.PInt32Type:
-		t = eval.Int32Type
-		mk = mkInt32
-	case p.runtime.PInt64Type:
-		t = eval.Int64Type
-		mk = mkInt64
-	case p.runtime.PIntType:
-		t = eval.IntType
-		mk = mkInt
-	case p.runtime.PFloat32Type:
-		t = eval.Float32Type
-		mk = mkFloat32
-	case p.runtime.PFloat64Type:
-		t = eval.Float64Type
-		mk = mkFloat64
-	case p.runtime.PStringType:
-		t = eval.StringType
-		mk = mkString
-
-	case p.runtime.PArrayType:
-		// Cast to an ArrayType
-		typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct)
-		len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a))
-		elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct))
-		t = eval.NewArrayType(len, elem.Type)
-		mk = func(r remote) eval.Value { return remoteArray{r, len, elem} }
-
-	case p.runtime.PStructType:
-		// Cast to a StructType
-		typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct)
-		fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a)
-
-		fields := make([]eval.StructField, fs.Len)
-		layout := make([]remoteStructField, fs.Len)
-		for i := range fields {
-			f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct)
-			elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct)
-			elem := parseRemoteType(a, elemrs)
-			fields[i].Type = elem.Type
-			name := f.field(p.f.StructField.Name).(remotePtr).aGet(a)
-			if name == nil {
-				fields[i].Anonymous = true
-			} else {
-				fields[i].Name = name.(remoteString).aGet(a)
-			}
-			layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a))
-			layout[i].fieldType = elem
-		}
-
-		t = eval.NewStructType(fields)
-		mk = func(r remote) eval.Value { return remoteStruct{r, layout} }
-
-	case p.runtime.PPtrType:
-		// Cast to a PtrType
-		typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct)
-		elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct))
-		t = eval.NewPtrType(elem.Type)
-		mk = func(r remote) eval.Value { return remotePtr{r, elem} }
-
-	case p.runtime.PSliceType:
-		// Cast to a SliceType
-		typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct)
-		elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct))
-		t = eval.NewSliceType(elem.Type)
-		mk = func(r remote) eval.Value { return remoteSlice{r, elem} }
-
-	case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType:
-		// TODO(austin)
-		t = eval.UintptrType
-		mk = mkUintptr
-
-	default:
-		sym := p.syms.SymByAddr(uint64(itype))
-		name := "<unknown symbol>"
-		if sym != nil {
-			name = sym.Name
-		}
-		err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name)
-		a.Abort(FormatError(err))
-	}
-
-	// Fill in the remote type
-	if nt != nil {
-		nt.Complete(t)
-	} else {
-		rt.Type = t
-	}
-	rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a))
-	rt.mk = mk
-
-	return rt
-}
diff --git a/src/pkg/exp/ogle/rvalue.go b/src/pkg/exp/ogle/rvalue.go
deleted file mode 100644
index 3d630f9..0000000
--- a/src/pkg/exp/ogle/rvalue.go
+++ /dev/null
@@ -1,515 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/proc"
-	"exp/eval"
-	"fmt"
-)
-
-// A RemoteMismatchError occurs when an operation that requires two
-// identical remote processes is given different process.  For
-// example, this occurs when trying to set a pointer in one process to
-// point to something in another process.
-type RemoteMismatchError string
-
-func (e RemoteMismatchError) String() string { return string(e) }
-
-// A ReadOnlyError occurs when attempting to set or assign to a
-// read-only value.
-type ReadOnlyError string
-
-func (e ReadOnlyError) String() string { return string(e) }
-
-// A maker is a function that converts a remote address into an
-// interpreter Value.
-type maker func(remote) eval.Value
-
-type remoteValue interface {
-	addr() remote
-}
-
-// remote represents an address in a remote process.
-type remote struct {
-	base proc.Word
-	p    *Process
-}
-
-func (v remote) Get(a aborter, size int) uint64 {
-	// TODO(austin) This variable might temporarily be in a
-	// register.  We could trace the assembly back from the
-	// current PC, looking for the beginning of the function or a
-	// call (both of which guarantee that the variable is in
-	// memory), or an instruction that loads the variable into a
-	// register.
-	//
-	// TODO(austin) If this is a local variable, it might not be
-	// live at this PC.  In fact, because the compiler reuses
-	// slots, there might even be a different local variable at
-	// this location right now.  A simple solution to both
-	// problems is to include the range of PC's over which a local
-	// variable is live in the symbol table.
-	//
-	// TODO(austin) We need to prevent the remote garbage
-	// collector from collecting objects out from under us.
-	var arr [8]byte
-	buf := arr[0:size]
-	_, err := v.p.Peek(v.base, buf)
-	if err != nil {
-		a.Abort(err)
-	}
-	return uint64(v.p.ToWord(buf))
-}
-
-func (v remote) Set(a aborter, size int, x uint64) {
-	var arr [8]byte
-	buf := arr[0:size]
-	v.p.FromWord(proc.Word(x), buf)
-	_, err := v.p.Poke(v.base, buf)
-	if err != nil {
-		a.Abort(err)
-	}
-}
-
-func (v remote) plus(x proc.Word) remote { return remote{v.base + x, v.p} }
-
-func tryRVString(f func(a aborter) string) string {
-	var s string
-	err := try(func(a aborter) { s = f(a) })
-	if err != nil {
-		return fmt.Sprintf("<error: %v>", err)
-	}
-	return s
-}
-
-/*
- * Bool
- */
-
-type remoteBool struct {
-	r remote
-}
-
-func (v remoteBool) String() string {
-	return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteBool) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.BoolValue).Get(t))
-}
-
-func (v remoteBool) Get(t *eval.Thread) bool { return v.aGet(t) }
-
-func (v remoteBool) aGet(a aborter) bool { return v.r.Get(a, 1) != 0 }
-
-func (v remoteBool) Set(t *eval.Thread, x bool) {
-	v.aSet(t, x)
-}
-
-func (v remoteBool) aSet(a aborter, x bool) {
-	if x {
-		v.r.Set(a, 1, 1)
-	} else {
-		v.r.Set(a, 1, 0)
-	}
-}
-
-func (v remoteBool) addr() remote { return v.r }
-
-func mkBool(r remote) eval.Value { return remoteBool{r} }
-
-/*
- * Uint
- */
-
-type remoteUint struct {
-	r    remote
-	size int
-}
-
-func (v remoteUint) String() string {
-	return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteUint) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.UintValue).Get(t))
-}
-
-func (v remoteUint) Get(t *eval.Thread) uint64 {
-	return v.aGet(t)
-}
-
-func (v remoteUint) aGet(a aborter) uint64 { return v.r.Get(a, v.size) }
-
-func (v remoteUint) Set(t *eval.Thread, x uint64) {
-	v.aSet(t, x)
-}
-
-func (v remoteUint) aSet(a aborter, x uint64) { v.r.Set(a, v.size, x) }
-
-func (v remoteUint) addr() remote { return v.r }
-
-func mkUint8(r remote) eval.Value { return remoteUint{r, 1} }
-
-func mkUint16(r remote) eval.Value { return remoteUint{r, 2} }
-
-func mkUint32(r remote) eval.Value { return remoteUint{r, 4} }
-
-func mkUint64(r remote) eval.Value { return remoteUint{r, 8} }
-
-func mkUint(r remote) eval.Value { return remoteUint{r, r.p.IntSize()} }
-
-func mkUintptr(r remote) eval.Value { return remoteUint{r, r.p.PtrSize()} }
-
-/*
- * Int
- */
-
-type remoteInt struct {
-	r    remote
-	size int
-}
-
-func (v remoteInt) String() string {
-	return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteInt) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.IntValue).Get(t))
-}
-
-func (v remoteInt) Get(t *eval.Thread) int64 { return v.aGet(t) }
-
-func (v remoteInt) aGet(a aborter) int64 { return int64(v.r.Get(a, v.size)) }
-
-func (v remoteInt) Set(t *eval.Thread, x int64) {
-	v.aSet(t, x)
-}
-
-func (v remoteInt) aSet(a aborter, x int64) { v.r.Set(a, v.size, uint64(x)) }
-
-func (v remoteInt) addr() remote { return v.r }
-
-func mkInt8(r remote) eval.Value { return remoteInt{r, 1} }
-
-func mkInt16(r remote) eval.Value { return remoteInt{r, 2} }
-
-func mkInt32(r remote) eval.Value { return remoteInt{r, 4} }
-
-func mkInt64(r remote) eval.Value { return remoteInt{r, 8} }
-
-func mkInt(r remote) eval.Value { return remoteInt{r, r.p.IntSize()} }
-
-/*
- * Float
- */
-
-type remoteFloat struct {
-	r    remote
-	size int
-}
-
-func (v remoteFloat) String() string {
-	return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.FloatValue).Get(t))
-}
-
-func (v remoteFloat) Get(t *eval.Thread) float64 {
-	return v.aGet(t)
-}
-
-func (v remoteFloat) aGet(a aborter) float64 {
-	bits := v.r.Get(a, v.size)
-	switch v.size {
-	case 4:
-		return float64(v.r.p.ToFloat32(uint32(bits)))
-	case 8:
-		return v.r.p.ToFloat64(bits)
-	}
-	panic("Unexpected float size")
-}
-
-func (v remoteFloat) Set(t *eval.Thread, x float64) {
-	v.aSet(t, x)
-}
-
-func (v remoteFloat) aSet(a aborter, x float64) {
-	var bits uint64
-	switch v.size {
-	case 4:
-		bits = uint64(v.r.p.FromFloat32(float32(x)))
-	case 8:
-		bits = v.r.p.FromFloat64(x)
-	default:
-		panic("Unexpected float size")
-	}
-	v.r.Set(a, v.size, bits)
-}
-
-func (v remoteFloat) addr() remote { return v.r }
-
-func mkFloat32(r remote) eval.Value { return remoteFloat{r, 4} }
-
-func mkFloat64(r remote) eval.Value { return remoteFloat{r, 8} }
-
-func mkFloat(r remote) eval.Value { return remoteFloat{r, r.p.FloatSize()} }
-
-/*
- * String
- */
-
-type remoteString struct {
-	r remote
-}
-
-func (v remoteString) String() string {
-	return tryRVString(func(a aborter) string { return v.aGet(a) })
-}
-
-func (v remoteString) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.StringValue).Get(t))
-}
-
-func (v remoteString) Get(t *eval.Thread) string {
-	return v.aGet(t)
-}
-
-func (v remoteString) aGet(a aborter) string {
-	rs := v.r.p.runtime.String.mk(v.r).(remoteStruct)
-	str := proc.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a))
-	len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a)
-
-	bytes := make([]uint8, len)
-	_, err := v.r.p.Peek(str, bytes)
-	if err != nil {
-		a.Abort(err)
-	}
-	return string(bytes)
-}
-
-func (v remoteString) Set(t *eval.Thread, x string) {
-	v.aSet(t, x)
-}
-
-func (v remoteString) aSet(a aborter, x string) {
-	// TODO(austin) This isn't generally possible without the
-	// ability to allocate remote memory.
-	a.Abort(ReadOnlyError("remote strings cannot be assigned to"))
-}
-
-func mkString(r remote) eval.Value { return remoteString{r} }
-
-/*
- * Array
- */
-
-type remoteArray struct {
-	r        remote
-	len      int64
-	elemType *remoteType
-}
-
-func (v remoteArray) String() string {
-	res := "{"
-	for i := int64(0); i < v.len; i++ {
-		if i > 0 {
-			res += ", "
-		}
-		res += v.elem(i).String()
-	}
-	return res + "}"
-}
-
-func (v remoteArray) Assign(t *eval.Thread, o eval.Value) {
-	// TODO(austin) Could do a bigger memcpy if o is a
-	// remoteArray in the same Process.
-	oa := o.(eval.ArrayValue)
-	for i := int64(0); i < v.len; i++ {
-		v.Elem(t, i).Assign(t, oa.Elem(t, i))
-	}
-}
-
-func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue {
-	return v
-}
-
-func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
-	return v.elem(i)
-}
-
-func (v remoteArray) elem(i int64) eval.Value {
-	return v.elemType.mk(v.r.plus(proc.Word(int64(v.elemType.size) * i)))
-}
-
-func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue {
-	return remoteArray{v.r.plus(proc.Word(int64(v.elemType.size) * i)), len, v.elemType}
-}
-
-/*
- * Struct
- */
-
-type remoteStruct struct {
-	r      remote
-	layout []remoteStructField
-}
-
-type remoteStructField struct {
-	offset    int
-	fieldType *remoteType
-}
-
-func (v remoteStruct) String() string {
-	res := "{"
-	for i := range v.layout {
-		if i > 0 {
-			res += ", "
-		}
-		res += v.field(i).String()
-	}
-	return res + "}"
-}
-
-func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) {
-	// TODO(austin) Could do a bigger memcpy.
-	oa := o.(eval.StructValue)
-	l := len(v.layout)
-	for i := 0; i < l; i++ {
-		v.Field(t, i).Assign(t, oa.Field(t, i))
-	}
-}
-
-func (v remoteStruct) Get(t *eval.Thread) eval.StructValue {
-	return v
-}
-
-func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
-	return v.field(i)
-}
-
-func (v remoteStruct) field(i int) eval.Value {
-	f := &v.layout[i]
-	return f.fieldType.mk(v.r.plus(proc.Word(f.offset)))
-}
-
-func (v remoteStruct) addr() remote { return v.r }
-
-/*
- * Pointer
- */
-
-// TODO(austin) Comparing two remote pointers for equality in the
-// interpreter will crash it because the Value's returned from
-// remotePtr.Get() will be structs.
-
-type remotePtr struct {
-	r        remote
-	elemType *remoteType
-}
-
-func (v remotePtr) String() string {
-	return tryRVString(func(a aborter) string {
-		e := v.aGet(a)
-		if e == nil {
-			return "<nil>"
-		}
-		return "&" + e.String()
-	})
-}
-
-func (v remotePtr) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.PtrValue).Get(t))
-}
-
-func (v remotePtr) Get(t *eval.Thread) eval.Value {
-	return v.aGet(t)
-}
-
-func (v remotePtr) aGet(a aborter) eval.Value {
-	addr := proc.Word(v.r.Get(a, v.r.p.PtrSize()))
-	if addr == 0 {
-		return nil
-	}
-	return v.elemType.mk(remote{addr, v.r.p})
-}
-
-func (v remotePtr) Set(t *eval.Thread, x eval.Value) {
-	v.aSet(t, x)
-}
-
-func (v remotePtr) aSet(a aborter, x eval.Value) {
-	if x == nil {
-		v.r.Set(a, v.r.p.PtrSize(), 0)
-		return
-	}
-	xr, ok := x.(remoteValue)
-	if !ok || v.r.p != xr.addr().p {
-		a.Abort(RemoteMismatchError("remote pointer must point within the same process"))
-	}
-	v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base))
-}
-
-func (v remotePtr) addr() remote { return v.r }
-
-/*
- * Slice
- */
-
-type remoteSlice struct {
-	r        remote
-	elemType *remoteType
-}
-
-func (v remoteSlice) String() string {
-	return tryRVString(func(a aborter) string {
-		b := v.aGet(a).Base
-		if b == nil {
-			return "<nil>"
-		}
-		return b.String()
-	})
-}
-
-func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.SliceValue).Get(t))
-}
-
-func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
-	return v.aGet(t)
-}
-
-func (v remoteSlice) aGet(a aborter) eval.Slice {
-	rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
-	base := proc.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a))
-	nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a)
-	cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a)
-	if base == 0 {
-		return eval.Slice{nil, nel, cap}
-	}
-	return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap}
-}
-
-func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) {
-	v.aSet(t, x)
-}
-
-func (v remoteSlice) aSet(a aborter, x eval.Slice) {
-	rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
-	if x.Base == nil {
-		rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0)
-	} else {
-		ar, ok := x.Base.(remoteArray)
-		if !ok || v.r.p != ar.r.p {
-			a.Abort(RemoteMismatchError("remote slice must point within the same process"))
-		}
-		rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base))
-	}
-	rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len)
-	rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap)
-}
diff --git a/src/pkg/exp/ogle/vars.go b/src/pkg/exp/ogle/vars.go
deleted file mode 100644
index 8a3a147..0000000
--- a/src/pkg/exp/ogle/vars.go
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ogle
-
-import (
-	"debug/gosym"
-	"debug/proc"
-	"exp/eval"
-	"log"
-	"os"
-)
-
-/*
- * Remote frame pointers
- */
-
-// A NotOnStack error occurs when attempting to access a variable in a
-// remote frame where that remote frame is not on the current stack.
-type NotOnStack struct {
-	Fn        *gosym.Func
-	Goroutine *Goroutine
-}
-
-func (e NotOnStack) String() string {
-	return "function " + e.Fn.Name + " not on " + e.Goroutine.String() + "'s stack"
-}
-
-// A remoteFramePtr is an implementation of eval.PtrValue that
-// represents a pointer to a function frame in a remote process.  When
-// accessed, this locates the function on the current goroutine's
-// stack and returns a structure containing the local variables of
-// that function.
-type remoteFramePtr struct {
-	p  *Process
-	fn *gosym.Func
-	rt *remoteType
-}
-
-func (v remoteFramePtr) String() string {
-	// TODO(austin): This could be a really awesome string method
-	return "<remote frame>"
-}
-
-func (v remoteFramePtr) Assign(t *eval.Thread, o eval.Value) {
-	v.Set(t, o.(eval.PtrValue).Get(t))
-}
-
-func (v remoteFramePtr) Get(t *eval.Thread) eval.Value {
-	g := v.p.curGoroutine
-	if g == nil || g.frame == nil {
-		t.Abort(NoCurrentGoroutine{})
-	}
-
-	for f := g.frame; f != nil; f = f.aOuter(t) {
-		if f.fn != v.fn {
-			continue
-		}
-
-		// TODO(austin): Register for shootdown with f
-		return v.rt.mk(remote{f.fp, v.p})
-	}
-
-	t.Abort(NotOnStack{v.fn, g})
-	panic("fail")
-}
-
-func (v remoteFramePtr) Set(t *eval.Thread, x eval.Value) {
-	// Theoretically this could be a static error.  If remote
-	// packages were packages, remote frames could just be defined
-	// as constants.
-	t.Abort(ReadOnlyError("remote frames cannot be assigned to"))
-}
-
-/*
- * Remote packages
- */
-
-// TODO(austin): Remote packages are implemented as structs right now,
-// which has some weird consequences.  You can attempt to assign to a
-// remote package.  It also produces terrible error messages.
-// Ideally, these would actually be packages, but somehow first-class
-// so they could be assigned to other names.
-
-// A remotePackage is an implementation of eval.StructValue that
-// represents a package in a remote process.  It's essentially a
-// regular struct, except it cannot be assigned to.
-type remotePackage struct {
-	defs []eval.Value
-}
-
-func (v remotePackage) String() string { return "<remote package>" }
-
-func (v remotePackage) Assign(t *eval.Thread, o eval.Value) {
-	t.Abort(ReadOnlyError("remote packages cannot be assigned to"))
-}
-
-func (v remotePackage) Get(t *eval.Thread) eval.StructValue {
-	return v
-}
-
-func (v remotePackage) Field(t *eval.Thread, i int) eval.Value {
-	return v.defs[i]
-}
-
-/*
- * Remote variables
- */
-
-// populateWorld defines constants in the given world for each package
-// in this process.  These packages are structs that, in turn, contain
-// fields for each global and function in that package.
-func (p *Process) populateWorld(w *eval.World) os.Error {
-	type def struct {
-		t eval.Type
-		v eval.Value
-	}
-	packages := make(map[string]map[string]def)
-
-	for _, s := range p.syms.Syms {
-		if s.ReceiverName() != "" {
-			// TODO(austin)
-			continue
-		}
-
-		// Package
-		pkgName := s.PackageName()
-		switch pkgName {
-		case "", "type", "extratype", "string", "go":
-			// "go" is really "go.string"
-			continue
-		}
-		pkg, ok := packages[pkgName]
-		if !ok {
-			pkg = make(map[string]def)
-			packages[pkgName] = pkg
-		}
-
-		// Symbol name
-		name := s.BaseName()
-		if _, ok := pkg[name]; ok {
-			log.Printf("Multiple definitions of symbol %s", s.Name)
-			continue
-		}
-
-		// Symbol type
-		rt, err := p.typeOfSym(&s)
-		if err != nil {
-			return err
-		}
-
-		// Definition
-		switch s.Type {
-		case 'D', 'd', 'B', 'b':
-			// Global variable
-			if rt == nil {
-				continue
-			}
-			pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(s.Value), p})}
-
-		case 'T', 't', 'L', 'l':
-			// Function
-			s := s.Func
-			// TODO(austin): Ideally, this would *also* be
-			// callable.  How does that interact with type
-			// conversion syntax?
-			rt, err := p.makeFrameType(s)
-			if err != nil {
-				return err
-			}
-			pkg[name] = def{eval.NewPtrType(rt.Type), remoteFramePtr{p, s, rt}}
-		}
-	}
-
-	// TODO(austin): Define remote types
-
-	// Define packages
-	for pkgName, defs := range packages {
-		fields := make([]eval.StructField, len(defs))
-		vals := make([]eval.Value, len(defs))
-		i := 0
-		for name, def := range defs {
-			fields[i].Name = name
-			fields[i].Type = def.t
-			vals[i] = def.v
-			i++
-		}
-		pkgType := eval.NewStructType(fields)
-		pkgVal := remotePackage{vals}
-
-		err := w.DefineConst(pkgName, pkgType, pkgVal)
-		if err != nil {
-			log.Printf("while defining package %s: %v", pkgName, err)
-		}
-	}
-
-	return nil
-}
-
-// typeOfSym returns the type associated with a symbol.  If the symbol
-// has no type, returns nil.
-func (p *Process) typeOfSym(s *gosym.Sym) (*remoteType, os.Error) {
-	if s.GoType == 0 {
-		return nil, nil
-	}
-	addr := proc.Word(s.GoType)
-	var rt *remoteType
-	err := try(func(a aborter) { rt = parseRemoteType(a, p.runtime.Type.mk(remote{addr, p}).(remoteStruct)) })
-	if err != nil {
-		return nil, err
-	}
-	return rt, nil
-}
-
-// makeFrameType constructs a struct type for the frame of a function.
-// The offsets in this struct type are such that the struct can be
-// instantiated at this function's frame pointer.
-func (p *Process) makeFrameType(s *gosym.Func) (*remoteType, os.Error) {
-	n := len(s.Params) + len(s.Locals)
-	fields := make([]eval.StructField, n)
-	layout := make([]remoteStructField, n)
-	i := 0
-
-	// TODO(austin): There can be multiple locals/parameters with
-	// the same name.  We probably need liveness information to do
-	// anything about this.  Once we have that, perhaps we give
-	// such fields interface{} type?  Or perhaps we disambiguate
-	// the names with numbers.  Disambiguation is annoying for
-	// things like "i", where there's an obvious right answer.
-
-	for _, param := range s.Params {
-		rt, err := p.typeOfSym(param)
-		if err != nil {
-			return nil, err
-		}
-		if rt == nil {
-			//fmt.Printf(" (no type)\n");
-			continue
-		}
-		// TODO(austin): Why do local variables carry their
-		// package name?
-		fields[i].Name = param.BaseName()
-		fields[i].Type = rt.Type
-		// Parameters have positive offsets from FP
-		layout[i].offset = int(param.Value)
-		layout[i].fieldType = rt
-		i++
-	}
-
-	for _, local := range s.Locals {
-		rt, err := p.typeOfSym(local)
-		if err != nil {
-			return nil, err
-		}
-		if rt == nil {
-			continue
-		}
-		fields[i].Name = local.BaseName()
-		fields[i].Type = rt.Type
-		// Locals have negative offsets from FP - PtrSize
-		layout[i].offset = -int(local.Value) - p.PtrSize()
-		layout[i].fieldType = rt
-		i++
-	}
-
-	fields = fields[0:i]
-	layout = layout[0:i]
-	t := eval.NewStructType(fields)
-	mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
-	return &remoteType{t, 0, 0, mk}, nil
-}
diff --git a/src/pkg/exp/regexp/Makefile b/src/pkg/exp/regexp/Makefile
new file mode 100644
index 0000000..fc90df3
--- /dev/null
+++ b/src/pkg/exp/regexp/Makefile
@@ -0,0 +1,12 @@
+# 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.
+
+include ../../../Make.inc
+
+TARG=exp/regexp
+GOFILES=\
+	exec.go\
+	regexp.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/exp/regexp/all_test.go b/src/pkg/exp/regexp/all_test.go
new file mode 100644
index 0000000..77f32ca
--- /dev/null
+++ b/src/pkg/exp/regexp/all_test.go
@@ -0,0 +1,429 @@
+// 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 regexp
+
+import (
+	"os"
+	"strings"
+	"testing"
+)
+
+var good_re = []string{
+	``,
+	`.`,
+	`^.$`,
+	`a`,
+	`a*`,
+	`a+`,
+	`a?`,
+	`a|b`,
+	`a*|b*`,
+	`(a*|b)(c*|d)`,
+	`[a-z]`,
+	`[a-abc-c\-\]\[]`,
+	`[a-z]+`,
+	`[abc]`,
+	`[^1234]`,
+	`[^\n]`,
+	`\!\\`,
+}
+
+/*
+type stringError struct {
+	re  string
+	err os.Error
+}
+
+var bad_re = []stringError{
+	{`*`, ErrBareClosure},
+	{`+`, ErrBareClosure},
+	{`?`, ErrBareClosure},
+	{`(abc`, ErrUnmatchedLpar},
+	{`abc)`, ErrUnmatchedRpar},
+	{`x[a-z`, ErrUnmatchedLbkt},
+	{`abc]`, ErrUnmatchedRbkt},
+	{`[z-a]`, ErrBadRange},
+	{`abc\`, ErrExtraneousBackslash},
+	{`a**`, ErrBadClosure},
+	{`a*+`, ErrBadClosure},
+	{`a??`, ErrBadClosure},
+	{`\x`, ErrBadBackslash},
+}
+*/
+
+func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
+	re, err := Compile(expr)
+	if err != error {
+		t.Error("compiling `", expr, "`; unexpected error: ", err.String())
+	}
+	return re
+}
+
+func TestGoodCompile(t *testing.T) {
+	for i := 0; i < len(good_re); i++ {
+		compileTest(t, good_re[i], nil)
+	}
+}
+
+/*
+func TestBadCompile(t *testing.T) {
+	for i := 0; i < len(bad_re); i++ {
+		compileTest(t, bad_re[i].re, bad_re[i].err)
+	}
+}
+*/
+
+func matchTest(t *testing.T, test *FindTest) {
+	re := compileTest(t, test.pat, nil)
+	if re == nil {
+		return
+	}
+	m := re.MatchString(test.text)
+	if m != (len(test.matches) > 0) {
+		t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+	}
+	// now try bytes
+	m = re.Match([]byte(test.text))
+	if m != (len(test.matches) > 0) {
+		t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+	}
+}
+
+func TestMatch(t *testing.T) {
+	for _, test := range findTests {
+		matchTest(t, &test)
+	}
+}
+
+func matchFunctionTest(t *testing.T, test *FindTest) {
+	m, err := MatchString(test.pat, test.text)
+	if err == nil {
+		return
+	}
+	if m != (len(test.matches) > 0) {
+		t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+	}
+}
+
+func TestMatchFunction(t *testing.T) {
+	for _, test := range findTests {
+		matchFunctionTest(t, &test)
+	}
+}
+
+type ReplaceTest struct {
+	pattern, replacement, input, output string
+}
+
+var replaceTests = []ReplaceTest{
+	// Test empty input and/or replacement, with pattern that matches the empty string.
+	{"", "", "", ""},
+	{"", "x", "", "x"},
+	{"", "", "abc", "abc"},
+	{"", "x", "abc", "xaxbxcx"},
+
+	// Test empty input and/or replacement, with pattern that does not match the empty string.
+	{"b", "", "", ""},
+	{"b", "x", "", ""},
+	{"b", "", "abc", "ac"},
+	{"b", "x", "abc", "axc"},
+	{"y", "", "", ""},
+	{"y", "x", "", ""},
+	{"y", "", "abc", "abc"},
+	{"y", "x", "abc", "abc"},
+
+	// Multibyte characters -- verify that we don't try to match in the middle
+	// of a character.
+	{"[a-c]*", "x", "\u65e5", "x\u65e5x"},
+	{"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
+
+	// Start and end of a string.
+	{"^[a-c]*", "x", "abcdabc", "xdabc"},
+	{"[a-c]*$", "x", "abcdabc", "abcdx"},
+	{"^[a-c]*$", "x", "abcdabc", "abcdabc"},
+	{"^[a-c]*", "x", "abc", "x"},
+	{"[a-c]*$", "x", "abc", "x"},
+	{"^[a-c]*$", "x", "abc", "x"},
+	{"^[a-c]*", "x", "dabce", "xdabce"},
+	{"[a-c]*$", "x", "dabce", "dabcex"},
+	{"^[a-c]*$", "x", "dabce", "dabce"},
+	{"^[a-c]*", "x", "", "x"},
+	{"[a-c]*$", "x", "", "x"},
+	{"^[a-c]*$", "x", "", "x"},
+
+	{"^[a-c]+", "x", "abcdabc", "xdabc"},
+	{"[a-c]+$", "x", "abcdabc", "abcdx"},
+	{"^[a-c]+$", "x", "abcdabc", "abcdabc"},
+	{"^[a-c]+", "x", "abc", "x"},
+	{"[a-c]+$", "x", "abc", "x"},
+	{"^[a-c]+$", "x", "abc", "x"},
+	{"^[a-c]+", "x", "dabce", "dabce"},
+	{"[a-c]+$", "x", "dabce", "dabce"},
+	{"^[a-c]+$", "x", "dabce", "dabce"},
+	{"^[a-c]+", "x", "", ""},
+	{"[a-c]+$", "x", "", ""},
+	{"^[a-c]+$", "x", "", ""},
+
+	// Other cases.
+	{"abc", "def", "abcdefg", "defdefg"},
+	{"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
+	{"abc", "", "abcdabc", "d"},
+	{"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
+	{"abc", "d", "", ""},
+	{"abc", "d", "abc", "d"},
+	{".+", "x", "abc", "x"},
+	{"[a-c]*", "x", "def", "xdxexfx"},
+	{"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
+	{"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+}
+
+type ReplaceFuncTest struct {
+	pattern       string
+	replacement   func(string) string
+	input, output string
+}
+
+var replaceFuncTests = []ReplaceFuncTest{
+	{"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
+	{"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
+	{"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
+}
+
+func TestReplaceAll(t *testing.T) {
+	for _, tc := range replaceTests {
+		re, err := Compile(tc.pattern)
+		if err != nil {
+			t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+			continue
+		}
+		actual := re.ReplaceAllString(tc.input, tc.replacement)
+		if actual != tc.output {
+			t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+				tc.pattern, tc.input, tc.replacement, actual, tc.output)
+		}
+		// now try bytes
+		actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
+		if actual != tc.output {
+			t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+				tc.pattern, tc.input, tc.replacement, actual, tc.output)
+		}
+	}
+}
+
+func TestReplaceAllFunc(t *testing.T) {
+	for _, tc := range replaceFuncTests {
+		re, err := Compile(tc.pattern)
+		if err != nil {
+			t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+			continue
+		}
+		actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
+		if actual != tc.output {
+			t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+				tc.pattern, tc.input, tc.replacement, actual, tc.output)
+		}
+		// now try bytes
+		actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
+		if actual != tc.output {
+			t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+				tc.pattern, tc.input, tc.replacement, actual, tc.output)
+		}
+	}
+}
+
+type MetaTest struct {
+	pattern, output, literal string
+	isLiteral                bool
+}
+
+var metaTests = []MetaTest{
+	{``, ``, ``, true},
+	{`foo`, `foo`, `foo`, true},
+	{`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
+	{`foo.\$`, `foo\.\\\$`, `foo`, false},     // has escaped operators and real operators
+	{`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false},
+}
+
+func TestQuoteMeta(t *testing.T) {
+	for _, tc := range metaTests {
+		// Verify that QuoteMeta returns the expected string.
+		quoted := QuoteMeta(tc.pattern)
+		if quoted != tc.output {
+			t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
+				tc.pattern, quoted, tc.output)
+			continue
+		}
+
+		// Verify that the quoted string is in fact treated as expected
+		// by Compile -- i.e. that it matches the original, unquoted string.
+		if tc.pattern != "" {
+			re, err := Compile(quoted)
+			if err != nil {
+				t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
+				continue
+			}
+			src := "abc" + tc.pattern + "def"
+			repl := "xyz"
+			replaced := re.ReplaceAllString(src, repl)
+			expected := "abcxyzdef"
+			if replaced != expected {
+				t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
+					tc.pattern, src, repl, replaced, expected)
+			}
+		}
+	}
+}
+
+func TestLiteralPrefix(t *testing.T) {
+	for _, tc := range metaTests {
+		// Literal method needs to scan the pattern.
+		re := MustCompile(tc.pattern)
+		str, complete := re.LiteralPrefix()
+		if complete != tc.isLiteral {
+			t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
+		}
+		if str != tc.literal {
+			t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
+		}
+	}
+}
+
+type numSubexpCase struct {
+	input    string
+	expected int
+}
+
+var numSubexpCases = []numSubexpCase{
+	{``, 0},
+	{`.*`, 0},
+	{`abba`, 0},
+	{`ab(b)a`, 1},
+	{`ab(.*)a`, 1},
+	{`(.*)ab(.*)a`, 2},
+	{`(.*)(ab)(.*)a`, 3},
+	{`(.*)((a)b)(.*)a`, 4},
+	{`(.*)(\(ab)(.*)a`, 3},
+	{`(.*)(\(a\)b)(.*)a`, 3},
+}
+
+func TestNumSubexp(t *testing.T) {
+	for _, c := range numSubexpCases {
+		re := MustCompile(c.input)
+		n := re.NumSubexp()
+		if n != c.expected {
+			t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
+		}
+	}
+}
+
+func BenchmarkLiteral(b *testing.B) {
+	x := strings.Repeat("x", 50) + "y"
+	b.StopTimer()
+	re := MustCompile("y")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if !re.MatchString(x) {
+			println("no match!")
+			break
+		}
+	}
+}
+
+func BenchmarkNotLiteral(b *testing.B) {
+	x := strings.Repeat("x", 50) + "y"
+	b.StopTimer()
+	re := MustCompile(".y")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if !re.MatchString(x) {
+			println("no match!")
+			break
+		}
+	}
+}
+
+func BenchmarkMatchClass(b *testing.B) {
+	b.StopTimer()
+	x := strings.Repeat("xxxx", 20) + "w"
+	re := MustCompile("[abcdw]")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if !re.MatchString(x) {
+			println("no match!")
+			break
+		}
+	}
+}
+
+func BenchmarkMatchClass_InRange(b *testing.B) {
+	b.StopTimer()
+	// 'b' is between 'a' and 'c', so the charclass
+	// range checking is no help here.
+	x := strings.Repeat("bbbb", 20) + "c"
+	re := MustCompile("[ac]")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if !re.MatchString(x) {
+			println("no match!")
+			break
+		}
+	}
+}
+
+func BenchmarkReplaceAll(b *testing.B) {
+	x := "abcdefghijklmnopqrstuvwxyz"
+	b.StopTimer()
+	re := MustCompile("[cjrw]")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.ReplaceAllString(x, "")
+	}
+}
+
+func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcdefghijklmnopqrstuvwxyz")
+	re := MustCompile("^zbc(d|e)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcdefghijklmnopqrstuvwxyz")
+	for i := 0; i < 15; i++ {
+		x = append(x, x...)
+	}
+	re := MustCompile("^zbc(d|e)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkAnchoredShortMatch(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcdefghijklmnopqrstuvwxyz")
+	re := MustCompile("^.bc(d|e)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkAnchoredLongMatch(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcdefghijklmnopqrstuvwxyz")
+	for i := 0; i < 15; i++ {
+		x = append(x, x...)
+	}
+	re := MustCompile("^.bc(d|e)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
diff --git a/src/pkg/exp/regexp/exec.go b/src/pkg/exp/regexp/exec.go
new file mode 100644
index 0000000..0670bb9
--- /dev/null
+++ b/src/pkg/exp/regexp/exec.go
@@ -0,0 +1,295 @@
+package regexp
+
+import "exp/regexp/syntax"
+
+// A queue is a 'sparse array' holding pending threads of execution.
+// See http://research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html
+type queue struct {
+	sparse []uint32
+	dense  []entry
+}
+
+// A entry is an entry on a queue.
+// It holds both the instruction pc and the actual thread.
+// Some queue entries are just place holders so that the machine
+// knows it has considered that pc.  Such entries have t == nil.
+type entry struct {
+	pc uint32
+	t  *thread
+}
+
+// A thread is the state of a single path through the machine:
+// an instruction and a corresponding capture array.
+// See http://swtch.com/~rsc/regexp/regexp2.html
+type thread struct {
+	inst *syntax.Inst
+	cap  []int
+}
+
+// A machine holds all the state during an NFA simulation for p.
+type machine struct {
+	re       *Regexp      // corresponding Regexp
+	p        *syntax.Prog // compiled program
+	q0, q1   queue        // two queues for runq, nextq
+	pool     []*thread    // pool of available threads
+	matched  bool         // whether a match was found
+	matchcap []int        // capture information for the match
+}
+
+// progMachine returns a new machine running the prog p.
+func progMachine(p *syntax.Prog) *machine {
+	m := &machine{p: p}
+	n := len(m.p.Inst)
+	m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
+	m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
+	ncap := p.NumCap
+	if ncap < 2 {
+		ncap = 2
+	}
+	m.matchcap = make([]int, ncap)
+	return m
+}
+
+// alloc allocates a new thread with the given instruction.
+// It uses the free pool if possible.
+func (m *machine) alloc(i *syntax.Inst) *thread {
+	var t *thread
+	if n := len(m.pool); n > 0 {
+		t = m.pool[n-1]
+		m.pool = m.pool[:n-1]
+	} else {
+		t = new(thread)
+		t.cap = make([]int, cap(m.matchcap))
+	}
+	t.cap = t.cap[:len(m.matchcap)]
+	t.inst = i
+	return t
+}
+
+// free returns t to the free pool.
+func (m *machine) free(t *thread) {
+	m.pool = append(m.pool, t)
+}
+
+// match runs the machine over the input starting at pos.
+// It reports whether a match was found.
+// If so, m.matchcap holds the submatch information.
+func (m *machine) match(i input, pos int) bool {
+	startCond := m.re.cond
+	if startCond == ^syntax.EmptyOp(0) { // impossible
+		return false
+	}
+	m.matched = false
+	for i := range m.matchcap {
+		m.matchcap[i] = -1
+	}
+	runq, nextq := &m.q0, &m.q1
+	rune, rune1 := endOfText, endOfText
+	width, width1 := 0, 0
+	rune, width = i.step(pos)
+	if rune != endOfText {
+		rune1, width1 = i.step(pos + width)
+	}
+	// TODO: Let caller specify the initial flag setting.
+	// For now assume pos == 0 is beginning of text and
+	// pos != 0 is not even beginning of line.
+	// TODO: Word boundary.
+	var flag syntax.EmptyOp
+	if pos == 0 {
+		flag = syntax.EmptyBeginText | syntax.EmptyBeginLine
+	}
+
+	// Update flag using lookahead rune.
+	if rune1 == '\n' {
+		flag |= syntax.EmptyEndLine
+	}
+	if rune1 == endOfText {
+		flag |= syntax.EmptyEndText
+	}
+
+	for {
+		if len(runq.dense) == 0 {
+			if startCond&syntax.EmptyBeginText != 0 && pos != 0 {
+				// Anchored match, past beginning of text.
+				break
+			}
+			if m.matched {
+				// Have match; finished exploring alternatives.
+				break
+			}
+			if len(m.re.prefix) > 0 && rune1 != m.re.prefixRune && i.canCheckPrefix() {
+				// Match requires literal prefix; fast search for it.
+				advance := i.index(m.re, pos)
+				if advance < 0 {
+					break
+				}
+				pos += advance
+				rune, width = i.step(pos)
+				rune1, width1 = i.step(pos + width)
+			}
+		}
+		if !m.matched {
+			if len(m.matchcap) > 0 {
+				m.matchcap[0] = pos
+			}
+			m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag)
+		}
+		// TODO: word boundary
+		flag = 0
+		if rune == '\n' {
+			flag |= syntax.EmptyBeginLine
+		}
+		if rune1 == '\n' {
+			flag |= syntax.EmptyEndLine
+		}
+		if rune1 == endOfText {
+			flag |= syntax.EmptyEndText
+		}
+		m.step(runq, nextq, pos, pos+width, rune, flag)
+		if width == 0 {
+			break
+		}
+		pos += width
+		rune, width = rune1, width1
+		if rune != endOfText {
+			rune1, width1 = i.step(pos + width)
+		}
+		runq, nextq = nextq, runq
+	}
+	m.clear(nextq)
+	return m.matched
+}
+
+// clear frees all threads on the thread queue.
+func (m *machine) clear(q *queue) {
+	for _, d := range q.dense {
+		if d.t != nil {
+			m.free(d.t)
+		}
+	}
+	q.dense = q.dense[:0]
+}
+
+// step executes one step of the machine, running each of the threads
+// on runq and appending new threads to nextq.
+// The step processes the rune c (which may be endOfText),
+// which starts at position pos and ends at nextPos.
+// nextCond gives the setting for the empty-width flags after c.
+func (m *machine) step(runq, nextq *queue, pos, nextPos, c int, nextCond syntax.EmptyOp) {
+	for j := 0; j < len(runq.dense); j++ {
+		d := &runq.dense[j]
+		t := d.t
+		if t == nil {
+			continue
+		}
+		/*
+			 * If we support leftmost-longest matching:
+				if longest && matched && match[0] < t.cap[0] {
+					m.free(t)
+					continue
+				}
+		*/
+
+		i := t.inst
+		switch i.Op {
+		default:
+			panic("bad inst")
+
+		case syntax.InstMatch:
+			if len(t.cap) > 0 {
+				t.cap[1] = pos
+				copy(m.matchcap, t.cap)
+			}
+			m.matched = true
+			for _, d := range runq.dense[j+1:] {
+				if d.t != nil {
+					m.free(d.t)
+				}
+			}
+			runq.dense = runq.dense[:0]
+
+		case syntax.InstRune:
+			if i.MatchRune(c) {
+				m.add(nextq, i.Out, nextPos, t.cap, nextCond)
+			}
+		}
+		m.free(t)
+	}
+	runq.dense = runq.dense[:0]
+}
+
+// add adds an entry to q for pc, unless the q already has such an entry.
+// It also recursively adds an entry for all instructions reachable from pc by following
+// empty-width conditions satisfied by cond.  pos gives the current position
+// in the input.
+func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp) {
+	if pc == 0 {
+		return
+	}
+	if j := q.sparse[pc]; j < uint32(len(q.dense)) && q.dense[j].pc == pc {
+		return
+	}
+
+	j := len(q.dense)
+	q.dense = q.dense[:j+1]
+	d := &q.dense[j]
+	d.t = nil
+	d.pc = pc
+	q.sparse[pc] = uint32(j)
+
+	i := &m.p.Inst[pc]
+	switch i.Op {
+	default:
+		panic("unhandled")
+	case syntax.InstFail:
+		// nothing
+	case syntax.InstAlt, syntax.InstAltMatch:
+		m.add(q, i.Out, pos, cap, cond)
+		m.add(q, i.Arg, pos, cap, cond)
+	case syntax.InstEmptyWidth:
+		if syntax.EmptyOp(i.Arg)&^cond == 0 {
+			m.add(q, i.Out, pos, cap, cond)
+		}
+	case syntax.InstNop:
+		m.add(q, i.Out, pos, cap, cond)
+	case syntax.InstCapture:
+		if int(i.Arg) < len(cap) {
+			opos := cap[i.Arg]
+			cap[i.Arg] = pos
+			m.add(q, i.Out, pos, cap, cond)
+			cap[i.Arg] = opos
+		} else {
+			m.add(q, i.Out, pos, cap, cond)
+		}
+	case syntax.InstMatch, syntax.InstRune:
+		t := m.alloc(i)
+		if len(t.cap) > 0 {
+			copy(t.cap, cap)
+		}
+		d.t = t
+	}
+}
+
+// empty is a non-nil 0-element slice,
+// so doExecute can avoid an allocation
+// when 0 captures are requested from a successful match.
+var empty = make([]int, 0)
+
+// doExecute finds the leftmost match in the input and returns
+// the position of its subexpressions.
+func (re *Regexp) doExecute(i input, pos int, ncap int) []int {
+	m := re.get()
+	m.matchcap = m.matchcap[:ncap]
+	if !m.match(i, pos) {
+		re.put(m)
+		return nil
+	}
+	if ncap == 0 {
+		re.put(m)
+		return empty // empty but not nil
+	}
+	cap := make([]int, ncap)
+	copy(cap, m.matchcap)
+	re.put(m)
+	return cap
+}
diff --git a/src/pkg/exp/regexp/find_test.go b/src/pkg/exp/regexp/find_test.go
new file mode 100644
index 0000000..dddc348
--- /dev/null
+++ b/src/pkg/exp/regexp/find_test.go
@@ -0,0 +1,472 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+// For each pattern/text pair, what is the expected output of each function?
+// We can derive the textual results from the indexed results, the non-submatch
+// results from the submatched results, the single results from the 'all' results,
+// and the byte results from the string results. Therefore the table includes
+// only the FindAllStringSubmatchIndex result.
+type FindTest struct {
+	pat     string
+	text    string
+	matches [][]int
+}
+
+func (t FindTest) String() string {
+	return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
+}
+
+var findTests = []FindTest{
+	{``, ``, build(1, 0, 0)},
+	{`^abcdefg`, "abcdefg", build(1, 0, 7)},
+	{`a+`, "baaab", build(1, 1, 4)},
+	{"abcd..", "abcdef", build(1, 0, 6)},
+	{`a`, "a", build(1, 0, 1)},
+	{`x`, "y", nil},
+	{`b`, "abc", build(1, 1, 2)},
+	{`.`, "a", build(1, 0, 1)},
+	{`.*`, "abcdef", build(1, 0, 6)},
+	{`^`, "abcde", build(1, 0, 0)},
+	{`$`, "abcde", build(1, 5, 5)},
+	{`^abcd$`, "abcd", build(1, 0, 4)},
+	{`^bcd'`, "abcdef", nil},
+	{`^abcd$`, "abcde", nil},
+	{`a+`, "baaab", build(1, 1, 4)},
+	{`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
+	{`[a-z]+`, "abcd", build(1, 0, 4)},
+	{`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
+	{`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
+	{`[^\n]+`, "abcd\n", build(1, 0, 4)},
+	{`[日本語]+`, "日本語日本語", build(1, 0, 18)},
+	{`日本語+`, "日本語", build(1, 0, 9)},
+	{`日本語+`, "日本語語語語", build(1, 0, 18)},
+	{`()`, "", build(1, 0, 0, 0, 0)},
+	{`(a)`, "a", build(1, 0, 1, 0, 1)},
+	{`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
+	{`(.*)`, "", build(1, 0, 0, 0, 0)},
+	{`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
+	{`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
+	{`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
+	{`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
+	{`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
+	{`\a\f\n\r\t\v`, "\a\f\n\r\t\v", build(1, 0, 6)},
+	{`[\a\f\n\r\t\v]+`, "\a\f\n\r\t\v", build(1, 0, 6)},
+
+	{`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
+	{`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
+	{`[.]`, ".", build(1, 0, 1)},
+	{`/$`, "/abc/", build(1, 4, 5)},
+	{`/$`, "/abc", nil},
+
+	// multiple matches
+	{`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
+	{`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
+	{`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
+	{`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
+	{`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
+
+	// fixed bugs
+	{`ab$`, "cab", build(1, 1, 3)},
+	{`axxb$`, "axxcb", nil},
+	{`data`, "daXY data", build(1, 5, 9)},
+	{`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
+	{`zx+`, "zzx", build(1, 1, 3)},
+
+	// can backslash-escape any punctuation
+	{`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
+		`!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+	{`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
+		`!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+	{"\\`", "`", build(1, 0, 1)},
+	{"[\\`]+", "`", build(1, 0, 1)},
+
+	// long set of matches (longer than startSize)
+	{
+		".",
+		"qwertyuiopasdfghjklzxcvbnm1234567890",
+		build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
+			10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
+			20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
+			30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
+	},
+}
+
+// build is a helper to construct a [][]int by extracting n sequences from x.
+// This represents n matches with len(x)/n submatches each.
+func build(n int, x ...int) [][]int {
+	ret := make([][]int, n)
+	runLength := len(x) / n
+	j := 0
+	for i := range ret {
+		ret[i] = make([]int, runLength)
+		copy(ret[i], x[j:])
+		j += runLength
+		if j > len(x) {
+			panic("invalid build entry")
+		}
+	}
+	return ret
+}
+
+// First the simple cases.
+
+func TestFind(t *testing.T) {
+	for _, test := range findTests {
+		re := MustCompile(test.pat)
+		if re.String() != test.pat {
+			t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat)
+		}
+		result := re.Find([]byte(test.text))
+		switch {
+		case len(test.matches) == 0 && len(result) == 0:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Errorf("expected match; got none: %s", test)
+		case test.matches != nil && result != nil:
+			expect := test.text[test.matches[0][0]:test.matches[0][1]]
+			if expect != string(result) {
+				t.Errorf("expected %q got %q: %s", expect, result, test)
+			}
+		}
+	}
+}
+
+func TestFindString(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindString(test.text)
+		switch {
+		case len(test.matches) == 0 && len(result) == 0:
+			// ok
+		case test.matches == nil && result != "":
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == "":
+			// Tricky because an empty result has two meanings: no match or empty match.
+			if test.matches[0][0] != test.matches[0][1] {
+				t.Errorf("expected match; got none: %s", test)
+			}
+		case test.matches != nil && result != "":
+			expect := test.text[test.matches[0][0]:test.matches[0][1]]
+			if expect != result {
+				t.Errorf("expected %q got %q: %s", expect, result, test)
+			}
+		}
+	}
+}
+
+func testFindIndex(test *FindTest, result []int, t *testing.T) {
+	switch {
+	case len(test.matches) == 0 && len(result) == 0:
+		// ok
+	case test.matches == nil && result != nil:
+		t.Errorf("expected no match; got one: %s", test)
+	case test.matches != nil && result == nil:
+		t.Errorf("expected match; got none: %s", test)
+	case test.matches != nil && result != nil:
+		expect := test.matches[0]
+		if expect[0] != result[0] || expect[1] != result[1] {
+			t.Errorf("expected %v got %v: %s", expect, result, test)
+		}
+	}
+}
+
+func TestFindIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
+	}
+}
+
+func TestFindStringIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
+	}
+}
+
+func TestFindReaderIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t)
+	}
+}
+
+// Now come the simple All cases.
+
+func TestFindAll(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
+		switch {
+		case test.matches == nil && result == nil:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Fatalf("expected match; got none: %s", test)
+		case test.matches != nil && result != nil:
+			if len(test.matches) != len(result) {
+				t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+				continue
+			}
+			for k, e := range test.matches {
+				expect := test.text[e[0]:e[1]]
+				if expect != string(result[k]) {
+					t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
+				}
+			}
+		}
+	}
+}
+
+func TestFindAllString(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindAllString(test.text, -1)
+		switch {
+		case test.matches == nil && result == nil:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Errorf("expected match; got none: %s", test)
+		case test.matches != nil && result != nil:
+			if len(test.matches) != len(result) {
+				t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+				continue
+			}
+			for k, e := range test.matches {
+				expect := test.text[e[0]:e[1]]
+				if expect != result[k] {
+					t.Errorf("expected %q got %q: %s", expect, result, test)
+				}
+			}
+		}
+	}
+}
+
+func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
+	switch {
+	case test.matches == nil && result == nil:
+		// ok
+	case test.matches == nil && result != nil:
+		t.Errorf("expected no match; got one: %s", test)
+	case test.matches != nil && result == nil:
+		t.Errorf("expected match; got none: %s", test)
+	case test.matches != nil && result != nil:
+		if len(test.matches) != len(result) {
+			t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+			return
+		}
+		for k, e := range test.matches {
+			if e[0] != result[k][0] || e[1] != result[k][1] {
+				t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
+			}
+		}
+	}
+}
+
+func TestFindAllIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
+	}
+}
+
+func TestFindAllStringIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
+	}
+}
+
+// Now come the Submatch cases.
+
+func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
+	if len(submatches) != len(result)*2 {
+		t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+		return
+	}
+	for k := 0; k < len(submatches); k += 2 {
+		if submatches[k] == -1 {
+			if result[k/2] != nil {
+				t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+			}
+			continue
+		}
+		expect := test.text[submatches[k]:submatches[k+1]]
+		if expect != string(result[k/2]) {
+			t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+			return
+		}
+	}
+}
+
+func TestFindSubmatch(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
+		switch {
+		case test.matches == nil && result == nil:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Errorf("expected match; got none: %s", test)
+		case test.matches != nil && result != nil:
+			testSubmatchBytes(&test, 0, test.matches[0], result, t)
+		}
+	}
+}
+
+func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
+	if len(submatches) != len(result)*2 {
+		t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+		return
+	}
+	for k := 0; k < len(submatches); k += 2 {
+		if submatches[k] == -1 {
+			if result[k/2] != "" {
+				t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+			}
+			continue
+		}
+		expect := test.text[submatches[k]:submatches[k+1]]
+		if expect != result[k/2] {
+			t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+			return
+		}
+	}
+}
+
+func TestFindStringSubmatch(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindStringSubmatch(test.text)
+		switch {
+		case test.matches == nil && result == nil:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Errorf("expected match; got none: %s", test)
+		case test.matches != nil && result != nil:
+			testSubmatchString(&test, 0, test.matches[0], result, t)
+		}
+	}
+}
+
+func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
+	if len(expect) != len(result) {
+		t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
+		return
+	}
+	for k, e := range expect {
+		if e != result[k] {
+			t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
+		}
+	}
+}
+
+func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
+	switch {
+	case test.matches == nil && result == nil:
+		// ok
+	case test.matches == nil && result != nil:
+		t.Errorf("expected no match; got one: %s", test)
+	case test.matches != nil && result == nil:
+		t.Errorf("expected match; got none: %s", test)
+	case test.matches != nil && result != nil:
+		testSubmatchIndices(test, 0, test.matches[0], result, t)
+	}
+}
+
+func TestFindSubmatchIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
+	}
+}
+
+func TestFindStringSubmatchIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+	}
+}
+
+func TestFindReaderSubmatchIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t)
+	}
+}
+
+// Now come the monster AllSubmatch cases.
+
+func TestFindAllSubmatch(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
+		switch {
+		case test.matches == nil && result == nil:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Errorf("expected match; got none: %s", test)
+		case len(test.matches) != len(result):
+			t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+		case test.matches != nil && result != nil:
+			for k, match := range test.matches {
+				testSubmatchBytes(&test, k, match, result[k], t)
+			}
+		}
+	}
+}
+
+func TestFindAllStringSubmatch(t *testing.T) {
+	for _, test := range findTests {
+		result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
+		switch {
+		case test.matches == nil && result == nil:
+			// ok
+		case test.matches == nil && result != nil:
+			t.Errorf("expected no match; got one: %s", test)
+		case test.matches != nil && result == nil:
+			t.Errorf("expected match; got none: %s", test)
+		case len(test.matches) != len(result):
+			t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+		case test.matches != nil && result != nil:
+			for k, match := range test.matches {
+				testSubmatchString(&test, k, match, result[k], t)
+			}
+		}
+	}
+}
+
+func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
+	switch {
+	case test.matches == nil && result == nil:
+		// ok
+	case test.matches == nil && result != nil:
+		t.Errorf("expected no match; got one: %s", test)
+	case test.matches != nil && result == nil:
+		t.Errorf("expected match; got none: %s", test)
+	case len(test.matches) != len(result):
+		t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+	case test.matches != nil && result != nil:
+		for k, match := range test.matches {
+			testSubmatchIndices(test, k, match, result[k], t)
+		}
+	}
+}
+
+func TestFindAllSubmatchIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
+	}
+}
+
+func TestFindAllStringSubmatchIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+	}
+}
diff --git a/src/pkg/exp/regexp/regexp.go b/src/pkg/exp/regexp/regexp.go
new file mode 100644
index 0000000..1b75900
--- /dev/null
+++ b/src/pkg/exp/regexp/regexp.go
@@ -0,0 +1,795 @@
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package regexp implements a simple regular expression library.
+//
+// The syntax of the regular expressions accepted is the same
+// general syntax used by Perl, Python, and other languages.
+// More precisely, it is the syntax accepted by RE2 and described at
+// http://code.google.com/p/re2/wiki/Syntax, except for \C.
+//
+// All characters are UTF-8-encoded code points.
+//
+// There are 16 methods of Regexp that match a regular expression and identify
+// the matched text.  Their names are matched by this regular expression:
+//
+//	Find(All)?(String)?(Submatch)?(Index)?
+//
+// If 'All' is present, the routine matches successive non-overlapping
+// matches of the entire expression.  Empty matches abutting a preceding
+// match are ignored.  The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine.  These routines take
+// an extra integer argument, n; if n >= 0, the function returns at most n
+// matches/submatches.
+//
+// If 'String' is present, the argument is a string; otherwise it is a slice
+// of bytes; return values are adjusted as appropriate.
+//
+// If 'Submatch' is present, the return value is a slice identifying the
+// successive submatches of the expression.  Submatches are matches of
+// parenthesized subexpressions within the regular expression, numbered from
+// left to right in order of opening parenthesis.  Submatch 0 is the match of
+// the entire expression, submatch 1 the match of the first parenthesized
+// subexpression, and so on.
+//
+// If 'Index' is present, matches and submatches are identified by byte index
+// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
+// the nth submatch.  The pair for n==0 identifies the match of the entire
+// expression.  If 'Index' is not present, the match is identified by the
+// text of the match/submatch.  If an index is negative, it means that
+// subexpression did not match any string in the input.
+//
+// There is also a subset of the methods that can be applied to text read
+// from a RuneReader:
+//
+//	MatchReader, FindReaderIndex, FindReaderSubmatchIndex
+//
+// This set may grow.  Note that regular expression matches may need to
+// examine text beyond the text returned by a match, so the methods that
+// match text from a RuneReader may read arbitrarily far into the input
+// before returning.
+//
+// (There are a few other methods that do not match this pattern.)
+//
+package regexp
+
+import (
+	"bytes"
+	"exp/regexp/syntax"
+	"io"
+	"os"
+	"strings"
+	"sync"
+	"utf8"
+)
+
+var debug = false
+
+// Error is the local type for a parsing error.
+type Error string
+
+func (e Error) String() string {
+	return string(e)
+}
+
+// Regexp is the representation of a compiled regular expression.
+// The public interface is entirely through methods.
+// A Regexp is safe for concurrent use by multiple goroutines.
+type Regexp struct {
+	// read-only after Compile
+	expr           string         // as passed to Compile
+	prog           *syntax.Prog   // compiled program
+	prefix         string         // required prefix in unanchored matches
+	prefixBytes    []byte         // prefix, as a []byte
+	prefixComplete bool           // prefix is the entire regexp
+	prefixRune     int            // first rune in prefix
+	cond           syntax.EmptyOp // empty-width conditions required at start of match
+
+	// cache of machines for running regexp
+	mu      sync.Mutex
+	machine []*machine
+}
+
+// String returns the source text used to compile the regular expression.
+func (re *Regexp) String() string {
+	return re.expr
+}
+
+// Compile parses a regular expression and returns, if successful, a Regexp
+// object that can be used to match against text.
+func Compile(expr string) (*Regexp, os.Error) {
+	re, err := syntax.Parse(expr, syntax.Perl)
+	if err != nil {
+		return nil, err
+	}
+	prog, err := syntax.Compile(re)
+	if err != nil {
+		return nil, err
+	}
+	regexp := &Regexp{
+		expr: expr,
+		prog: prog,
+	}
+	regexp.prefix, regexp.prefixComplete = prog.Prefix()
+	if regexp.prefix != "" {
+		// TODO(rsc): Remove this allocation by adding
+		// IndexString to package bytes.
+		regexp.prefixBytes = []byte(regexp.prefix)
+		regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix)
+	}
+	regexp.cond = prog.StartCond()
+	return regexp, nil
+}
+
+// get returns a machine to use for matching re.
+// It uses the re's machine cache if possible, to avoid
+// unnecessary allocation.
+func (re *Regexp) get() *machine {
+	re.mu.Lock()
+	if n := len(re.machine); n > 0 {
+		z := re.machine[n-1]
+		re.machine = re.machine[:n-1]
+		re.mu.Unlock()
+		return z
+	}
+	re.mu.Unlock()
+	z := progMachine(re.prog)
+	z.re = re
+	return z
+}
+
+// put returns a machine to the re's machine cache.
+// There is no attempt to limit the size of the cache, so it will
+// grow to the maximum number of simultaneous matches
+// run using re.  (The cache empties when re gets garbage collected.)
+func (re *Regexp) put(z *machine) {
+	re.mu.Lock()
+	re.machine = append(re.machine, z)
+	re.mu.Unlock()
+}
+
+// MustCompile is like Compile but panics if the expression cannot be parsed.
+// It simplifies safe initialization of global variables holding compiled regular
+// expressions.
+func MustCompile(str string) *Regexp {
+	regexp, error := Compile(str)
+	if error != nil {
+		panic(`regexp: compiling "` + str + `": ` + error.String())
+	}
+	return regexp
+}
+
+// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
+func (re *Regexp) NumSubexp() int {
+	// NumCap/2 because captures count ( and ) separately.
+	// -1 because NumCap counts $0 but NumSubexp does not.
+	return re.prog.NumCap/2 - 1
+}
+
+const endOfText = -1
+
+// input abstracts different representations of the input text. It provides
+// one-character lookahead.
+type input interface {
+	step(pos int) (rune int, width int) // advance one rune
+	canCheckPrefix() bool               // can we look ahead without losing info?
+	hasPrefix(re *Regexp) bool
+	index(re *Regexp, pos int) int
+}
+
+// inputString scans a string.
+type inputString struct {
+	str string
+}
+
+func newInputString(str string) *inputString {
+	return &inputString{str: str}
+}
+
+func (i *inputString) step(pos int) (int, int) {
+	if pos < len(i.str) {
+		return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
+	}
+	return endOfText, 0
+}
+
+func (i *inputString) canCheckPrefix() bool {
+	return true
+}
+
+func (i *inputString) hasPrefix(re *Regexp) bool {
+	return strings.HasPrefix(i.str, re.prefix)
+}
+
+func (i *inputString) index(re *Regexp, pos int) int {
+	return strings.Index(i.str[pos:], re.prefix)
+}
+
+// inputBytes scans a byte slice.
+type inputBytes struct {
+	str []byte
+}
+
+func newInputBytes(str []byte) *inputBytes {
+	return &inputBytes{str: str}
+}
+
+func (i *inputBytes) step(pos int) (int, int) {
+	if pos < len(i.str) {
+		return utf8.DecodeRune(i.str[pos:len(i.str)])
+	}
+	return endOfText, 0
+}
+
+func (i *inputBytes) canCheckPrefix() bool {
+	return true
+}
+
+func (i *inputBytes) hasPrefix(re *Regexp) bool {
+	return bytes.HasPrefix(i.str, re.prefixBytes)
+}
+
+func (i *inputBytes) index(re *Regexp, pos int) int {
+	return bytes.Index(i.str[pos:], re.prefixBytes)
+}
+
+// inputReader scans a RuneReader.
+type inputReader struct {
+	r     io.RuneReader
+	atEOT bool
+	pos   int
+}
+
+func newInputReader(r io.RuneReader) *inputReader {
+	return &inputReader{r: r}
+}
+
+func (i *inputReader) step(pos int) (int, int) {
+	if !i.atEOT && pos != i.pos {
+		return endOfText, 0
+
+	}
+	r, w, err := i.r.ReadRune()
+	if err != nil {
+		i.atEOT = true
+		return endOfText, 0
+	}
+	i.pos += w
+	return r, w
+}
+
+func (i *inputReader) canCheckPrefix() bool {
+	return false
+}
+
+func (i *inputReader) hasPrefix(re *Regexp) bool {
+	return false
+}
+
+func (i *inputReader) index(re *Regexp, pos int) int {
+	return -1
+}
+
+// LiteralPrefix returns a literal string that must begin any match
+// of the regular expression re.  It returns the boolean true if the
+// literal string comprises the entire regular expression.
+func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
+	return re.prefix, re.prefixComplete
+}
+
+// MatchReader returns whether the Regexp matches the text read by the
+// RuneReader.  The return value is a boolean: true for match, false for no
+// match.
+func (re *Regexp) MatchReader(r io.RuneReader) bool {
+	return re.doExecute(newInputReader(r), 0, 0) != nil
+}
+
+// MatchString returns whether the Regexp matches the string s.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) MatchString(s string) bool {
+	return re.doExecute(newInputString(s), 0, 0) != nil
+}
+
+// Match returns whether the Regexp matches the byte slice b.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) Match(b []byte) bool {
+	return re.doExecute(newInputBytes(b), 0, 0) != nil
+}
+
+// MatchReader checks whether a textual regular expression matches the text
+// read by the RuneReader.  More complicated queries need to use Compile and
+// the full Regexp interface.
+func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error) {
+	re, err := Compile(pattern)
+	if err != nil {
+		return false, err
+	}
+	return re.MatchReader(r), nil
+}
+
+// MatchString checks whether a textual regular expression
+// matches a string.  More complicated queries need
+// to use Compile and the full Regexp interface.
+func MatchString(pattern string, s string) (matched bool, error os.Error) {
+	re, err := Compile(pattern)
+	if err != nil {
+		return false, err
+	}
+	return re.MatchString(s), nil
+}
+
+// Match checks whether a textual regular expression
+// matches a byte slice.  More complicated queries need
+// to use Compile and the full Regexp interface.
+func Match(pattern string, b []byte) (matched bool, error os.Error) {
+	re, err := Compile(pattern)
+	if err != nil {
+		return false, err
+	}
+	return re.Match(b), nil
+}
+
+// ReplaceAllString returns a copy of src in which all matches for the Regexp
+// have been replaced by repl.  No support is provided for expressions
+// (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllString(src, repl string) string {
+	return re.ReplaceAllStringFunc(src, func(string) string { return repl })
+}
+
+// ReplaceAllStringFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched string).  No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
+	lastMatchEnd := 0 // end position of the most recent match
+	searchPos := 0    // position where we next look for a match
+	buf := new(bytes.Buffer)
+	for searchPos <= len(src) {
+		a := re.doExecute(newInputString(src), searchPos, 2)
+		if len(a) == 0 {
+			break // no more matches
+		}
+
+		// Copy the unmatched characters before this match.
+		io.WriteString(buf, src[lastMatchEnd:a[0]])
+
+		// Now insert a copy of the replacement string, but not for a
+		// match of the empty string immediately after another match.
+		// (Otherwise, we get double replacement for patterns that
+		// match both empty and nonempty strings.)
+		if a[1] > lastMatchEnd || a[0] == 0 {
+			io.WriteString(buf, repl(src[a[0]:a[1]]))
+		}
+		lastMatchEnd = a[1]
+
+		// Advance past this match; always advance at least one character.
+		_, width := utf8.DecodeRuneInString(src[searchPos:])
+		if searchPos+width > a[1] {
+			searchPos += width
+		} else if searchPos+1 > a[1] {
+			// This clause is only needed at the end of the input
+			// string.  In that case, DecodeRuneInString returns width=0.
+			searchPos++
+		} else {
+			searchPos = a[1]
+		}
+	}
+
+	// Copy the unmatched characters after the last match.
+	io.WriteString(buf, src[lastMatchEnd:])
+
+	return buf.String()
+}
+
+// ReplaceAll returns a copy of src in which all matches for the Regexp
+// have been replaced by repl.  No support is provided for expressions
+// (e.g. \1 or $1) in the replacement text.
+func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
+	return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
+}
+
+// ReplaceAllFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched []byte).  No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
+	lastMatchEnd := 0 // end position of the most recent match
+	searchPos := 0    // position where we next look for a match
+	buf := new(bytes.Buffer)
+	for searchPos <= len(src) {
+		a := re.doExecute(newInputBytes(src), searchPos, 2)
+		if len(a) == 0 {
+			break // no more matches
+		}
+
+		// Copy the unmatched characters before this match.
+		buf.Write(src[lastMatchEnd:a[0]])
+
+		// Now insert a copy of the replacement string, but not for a
+		// match of the empty string immediately after another match.
+		// (Otherwise, we get double replacement for patterns that
+		// match both empty and nonempty strings.)
+		if a[1] > lastMatchEnd || a[0] == 0 {
+			buf.Write(repl(src[a[0]:a[1]]))
+		}
+		lastMatchEnd = a[1]
+
+		// Advance past this match; always advance at least one character.
+		_, width := utf8.DecodeRune(src[searchPos:])
+		if searchPos+width > a[1] {
+			searchPos += width
+		} else if searchPos+1 > a[1] {
+			// This clause is only needed at the end of the input
+			// string.  In that case, DecodeRuneInString returns width=0.
+			searchPos++
+		} else {
+			searchPos = a[1]
+		}
+	}
+
+	// Copy the unmatched characters after the last match.
+	buf.Write(src[lastMatchEnd:])
+
+	return buf.Bytes()
+}
+
+var specialBytes = []byte(`\.+*?()|[]{}^$`)
+
+func special(b byte) bool {
+	return bytes.IndexByte(specialBytes, b) >= 0
+}
+
+// QuoteMeta returns a string that quotes all regular expression metacharacters
+// inside the argument text; the returned string is a regular expression matching
+// the literal text.  For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+func QuoteMeta(s string) string {
+	b := make([]byte, 2*len(s))
+
+	// A byte loop is correct because all metacharacters are ASCII.
+	j := 0
+	for i := 0; i < len(s); i++ {
+		if special(s[i]) {
+			b[j] = '\\'
+			j++
+		}
+		b[j] = s[i]
+		j++
+	}
+	return string(b[0:j])
+}
+
+// Find matches in slice b if b is non-nil, otherwise find matches in string s.
+func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
+	var end int
+	if b == nil {
+		end = len(s)
+	} else {
+		end = len(b)
+	}
+
+	for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
+		var in input
+		if b == nil {
+			in = newInputString(s)
+		} else {
+			in = newInputBytes(b)
+		}
+		matches := re.doExecute(in, pos, re.prog.NumCap)
+		if len(matches) == 0 {
+			break
+		}
+
+		accept := true
+		if matches[1] == pos {
+			// We've found an empty match.
+			if matches[0] == prevMatchEnd {
+				// We don't allow an empty match right
+				// after a previous match, so ignore it.
+				accept = false
+			}
+			var width int
+			// TODO: use step()
+			if b == nil {
+				_, width = utf8.DecodeRuneInString(s[pos:end])
+			} else {
+				_, width = utf8.DecodeRune(b[pos:end])
+			}
+			if width > 0 {
+				pos += width
+			} else {
+				pos = end + 1
+			}
+		} else {
+			pos = matches[1]
+		}
+		prevMatchEnd = matches[1]
+
+		if accept {
+			deliver(matches)
+			i++
+		}
+	}
+}
+
+// Find returns a slice holding the text of the leftmost match in b of the regular expression.
+// A return value of nil indicates no match.
+func (re *Regexp) Find(b []byte) []byte {
+	a := re.doExecute(newInputBytes(b), 0, 2)
+	if a == nil {
+		return nil
+	}
+	return b[a[0]:a[1]]
+}
+
+// FindIndex returns a two-element slice of integers defining the location of
+// the leftmost match in b of the regular expression.  The match itself is at
+// b[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindIndex(b []byte) (loc []int) {
+	a := re.doExecute(newInputBytes(b), 0, 2)
+	if a == nil {
+		return nil
+	}
+	return a[0:2]
+}
+
+// FindString returns a string holding the text of the leftmost match in s of the regular
+// expression.  If there is no match, the return value is an empty string,
+// but it will also be empty if the regular expression successfully matches
+// an empty string.  Use FindStringIndex or FindStringSubmatch if it is
+// necessary to distinguish these cases.
+func (re *Regexp) FindString(s string) string {
+	a := re.doExecute(newInputString(s), 0, 2)
+	if a == nil {
+		return ""
+	}
+	return s[a[0]:a[1]]
+}
+
+// FindStringIndex returns a two-element slice of integers defining the
+// location of the leftmost match in s of the regular expression.  The match
+// itself is at s[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringIndex(s string) []int {
+	a := re.doExecute(newInputString(s), 0, 2)
+	if a == nil {
+		return nil
+	}
+	return a[0:2]
+}
+
+// FindReaderIndex returns a two-element slice of integers defining the
+// location of the leftmost match of the regular expression in text read from
+// the RuneReader.  The match itself is at s[loc[0]:loc[1]].  A return
+// value of nil indicates no match.
+func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
+	a := re.doExecute(newInputReader(r), 0, 2)
+	if a == nil {
+		return nil
+	}
+	return a[0:2]
+}
+
+// FindSubmatch returns a slice of slices holding the text of the leftmost
+// match of the regular expression in b and the matches, if any, of its
+// subexpressions, as defined by the 'Submatch' descriptions in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatch(b []byte) [][]byte {
+	a := re.doExecute(newInputBytes(b), 0, re.prog.NumCap)
+	if a == nil {
+		return nil
+	}
+	ret := make([][]byte, len(a)/2)
+	for i := range ret {
+		if a[2*i] >= 0 {
+			ret[i] = b[a[2*i]:a[2*i+1]]
+		}
+	}
+	return ret
+}
+
+// FindSubmatchIndex returns a slice holding the index pairs identifying the
+// leftmost match of the regular expression in b and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatchIndex(b []byte) []int {
+	return re.doExecute(newInputBytes(b), 0, re.prog.NumCap)
+}
+
+// FindStringSubmatch returns a slice of strings holding the text of the
+// leftmost match of the regular expression in s and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatch(s string) []string {
+	a := re.doExecute(newInputString(s), 0, re.prog.NumCap)
+	if a == nil {
+		return nil
+	}
+	ret := make([]string, len(a)/2)
+	for i := range ret {
+		if a[2*i] >= 0 {
+			ret[i] = s[a[2*i]:a[2*i+1]]
+		}
+	}
+	return ret
+}
+
+// FindStringSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression in s and the
+// matches, if any, of its subexpressions, as defined by the 'Submatch' and
+// 'Index' descriptions in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatchIndex(s string) []int {
+	return re.doExecute(newInputString(s), 0, re.prog.NumCap)
+}
+
+// FindReaderSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression of text read by
+// the RuneReader, and the matches, if any, of its subexpressions, as defined
+// by the 'Submatch' and 'Index' descriptions in the package comment.  A
+// return value of nil indicates no match.
+func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
+	return re.doExecute(newInputReader(r), 0, re.prog.NumCap)
+}
+
+const startSize = 10 // The size at which to start a slice in the 'All' routines.
+
+// FindAll is the 'All' version of Find; it returns a slice of all successive
+// matches of the expression, as defined by the 'All' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAll(b []byte, n int) [][]byte {
+	if n < 0 {
+		n = len(b) + 1
+	}
+	result := make([][]byte, 0, startSize)
+	re.allMatches("", b, n, func(match []int) {
+		result = append(result, b[match[0]:match[1]])
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
+	if n < 0 {
+		n = len(b) + 1
+	}
+	result := make([][]int, 0, startSize)
+	re.allMatches("", b, n, func(match []int) {
+		result = append(result, match[0:2])
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllString is the 'All' version of FindString; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllString(s string, n int) []string {
+	if n < 0 {
+		n = len(s) + 1
+	}
+	result := make([]string, 0, startSize)
+	re.allMatches(s, nil, n, func(match []int) {
+		result = append(result, s[match[0]:match[1]])
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
+// slice of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
+	if n < 0 {
+		n = len(s) + 1
+	}
+	result := make([][]int, 0, startSize)
+	re.allMatches(s, nil, n, func(match []int) {
+		result = append(result, match[0:2])
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
+// of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
+	if n < 0 {
+		n = len(b) + 1
+	}
+	result := make([][][]byte, 0, startSize)
+	re.allMatches("", b, n, func(match []int) {
+		slice := make([][]byte, len(match)/2)
+		for j := range slice {
+			if match[2*j] >= 0 {
+				slice[j] = b[match[2*j]:match[2*j+1]]
+			}
+		}
+		result = append(result, slice)
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
+// a slice of all successive matches of the expression, as defined by the
+// 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
+	if n < 0 {
+		n = len(b) + 1
+	}
+	result := make([][]int, 0, startSize)
+	re.allMatches("", b, n, func(match []int) {
+		result = append(result, match)
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
+// returns a slice of all successive matches of the expression, as defined by
+// the 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
+	if n < 0 {
+		n = len(s) + 1
+	}
+	result := make([][]string, 0, startSize)
+	re.allMatches(s, nil, n, func(match []int) {
+		slice := make([]string, len(match)/2)
+		for j := range slice {
+			if match[2*j] >= 0 {
+				slice[j] = s[match[2*j]:match[2*j+1]]
+			}
+		}
+		result = append(result, slice)
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
+
+// FindAllStringSubmatchIndex is the 'All' version of
+// FindStringSubmatchIndex; it returns a slice of all successive matches of
+// the expression, as defined by the 'All' description in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
+	if n < 0 {
+		n = len(s) + 1
+	}
+	result := make([][]int, 0, startSize)
+	re.allMatches(s, nil, n, func(match []int) {
+		result = append(result, match)
+	})
+	if len(result) == 0 {
+		return nil
+	}
+	return result
+}
diff --git a/src/pkg/exp/regexp/syntax/compile.go b/src/pkg/exp/regexp/syntax/compile.go
index ec9556f..5ea2425 100644
--- a/src/pkg/exp/regexp/syntax/compile.go
+++ b/src/pkg/exp/regexp/syntax/compile.go
@@ -86,6 +86,7 @@ func Compile(re *Regexp) (*Prog, os.Error) {
 
 func (c *compiler) init() {
 	c.p = new(Prog)
+	c.p.NumCap = 2 // implicit ( and ) for whole match $0
 	c.inst(InstFail)
 }
 
@@ -185,6 +186,10 @@ func (c *compiler) cap(arg uint32) frag {
 	f := c.inst(InstCapture)
 	f.out = patchList(f.i << 1)
 	c.p.Inst[f.i].Arg = arg
+
+	if c.p.NumCap < int(arg)+1 {
+		c.p.NumCap = int(arg) + 1
+	}
 	return f
 }
 
diff --git a/src/pkg/exp/regexp/syntax/parse.go b/src/pkg/exp/regexp/syntax/parse.go
index b6c91f7..4eed182 100644
--- a/src/pkg/exp/regexp/syntax/parse.go
+++ b/src/pkg/exp/regexp/syntax/parse.go
@@ -1760,7 +1760,6 @@ func (ra ranges) Swap(i, j int) {
 	p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1]
 }
 
-
 func checkUTF8(s string) os.Error {
 	for s != "" {
 		rune, size := utf8.DecodeRuneInString(s)
diff --git a/src/pkg/exp/regexp/syntax/prog.go b/src/pkg/exp/regexp/syntax/prog.go
index 6eeb3da..bf85b72 100644
--- a/src/pkg/exp/regexp/syntax/prog.go
+++ b/src/pkg/exp/regexp/syntax/prog.go
@@ -10,8 +10,9 @@ import (
 
 // A Prog is a compiled regular expression program.
 type Prog struct {
-	Inst  []Inst
-	Start int // index of start instruction
+	Inst   []Inst
+	Start  int // index of start instruction
+	NumCap int // number of InstCapture insts in re
 }
 
 // An InstOp is an instruction opcode.
@@ -54,6 +55,61 @@ func (p *Prog) String() string {
 	return b.String()
 }
 
+// skipNop follows any no-op or capturing instructions
+// and returns the resulting pc.
+func (p *Prog) skipNop(pc uint32) *Inst {
+	i := &p.Inst[pc]
+	for i.Op == InstNop || i.Op == InstCapture {
+		pc = i.Out
+		i = &p.Inst[pc]
+	}
+	return i
+}
+
+// Prefix returns a literal string that all matches for the
+// regexp must start with.  Complete is true if the prefix
+// is the entire match.
+func (p *Prog) Prefix() (prefix string, complete bool) {
+	i := p.skipNop(uint32(p.Start))
+
+	// Avoid allocation of buffer if prefix is empty.
+	if i.Op != InstRune || len(i.Rune) != 1 {
+		return "", i.Op == InstMatch
+	}
+
+	// Have prefix; gather characters.
+	var buf bytes.Buffer
+	for i.Op == InstRune && len(i.Rune) == 1 {
+		buf.WriteRune(i.Rune[0])
+		i = p.skipNop(i.Out)
+	}
+	return buf.String(), i.Op == InstMatch
+}
+
+// StartCond returns the leading empty-width conditions that must
+// be true in any match.  It returns ^EmptyOp(0) if no matches are possible.
+func (p *Prog) StartCond() EmptyOp {
+	var flag EmptyOp
+	pc := uint32(p.Start)
+	i := &p.Inst[pc]
+Loop:
+	for {
+		switch i.Op {
+		case InstEmptyWidth:
+			flag |= EmptyOp(i.Arg)
+		case InstFail:
+			return ^EmptyOp(0)
+		case InstCapture, InstNop:
+			// skip
+		default:
+			break Loop
+		}
+		pc = i.Out
+		i = &p.Inst[pc]
+	}
+	return flag
+}
+
 // MatchRune returns true if the instruction matches (and consumes) r.
 // It should only be called when i.Op == InstRune.
 func (i *Inst) MatchRune(r int) bool {
@@ -123,7 +179,6 @@ func (i *Inst) MatchEmptyWidth(before int, after int) bool {
 	panic("unknown empty width arg")
 }
 
-
 func (i *Inst) String() string {
 	var b bytes.Buffer
 	dumpInst(&b, i)
diff --git a/src/pkg/exp/template/Makefile b/src/pkg/exp/template/Makefile
index 8550b0d..988791f 100644
--- a/src/pkg/exp/template/Makefile
+++ b/src/pkg/exp/template/Makefile
@@ -8,6 +8,7 @@ TARG=exp/template
 GOFILES=\
 	exec.go\
 	funcs.go\
+	helper.go\
 	lex.go\
 	parse.go\
 	set.go\
diff --git a/src/pkg/exp/template/doc.go b/src/pkg/exp/template/doc.go
new file mode 100644
index 0000000..c374ace
--- /dev/null
+++ b/src/pkg/exp/template/doc.go
@@ -0,0 +1,296 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package template implements data-driven templates for generating textual output
+such as HTML.
+
+Templates are executed by applying them to a data structure. Annotations in the
+template refer to elements of the data structure (typically a field of a struct
+or a key in a map) to control execution and derive values to be displayed.
+Execution of the template walks the structure and sets the cursor, represented
+by a period '.' and called "dot", to the value at the current location in the
+structure as execution proceeds.
+
+The input text for a template is UTF-8-encoded text in any format.
+"Actions"--data evaluations or control structures--are delimited by
+"{{" and "}}"; all text outside actions is copied to the output unchanged.
+Actions may not span newlines.
+
+Once constructed, templates and template sets can be executed safely in
+parallel.
+
+Actions
+
+Here is the list of actions. "Arguments" and "pipelines" are evaluations of
+data, defined in detail below.
+
+*/
+//	{{/* a comment */}}
+//		A comment; discarded. Comments do not nest.
+/*
+
+	{{pipeline}}
+		The default textual representation of the value of the pipeline
+		is copied to the output.
+
+	{{if pipeline}} T1 {{end}}
+		If the value of the pipeline is empty, no output is generated;
+		otherwise, T1 is executed.  The empty values are false, 0, any
+		nil pointer or interface value, and any array, slice, map, or
+		string of length zero.
+		Dot is unaffected.
+
+	{{if pipeline}} T1 {{else}} T0 {{end}}
+		If the value of the pipeline is empty, T0 is executed;
+		otherwise, T1 is executed.  Dot is unaffected.
+
+	{{range pipeline}} T1 {{end}}
+		The value of the pipeline must be an array, slice, or map. If
+		the value of the pipeline has length zero, nothing is output;
+		otherwise, dot is set to the successive elements of the array,
+		slice, or map and T1 is executed.
+
+	{{range pipeline}} T1 {{else}} T0 {{end}}
+		The value of the pipeline must be an array, slice, or map. If
+		the value of the pipeline has length zero, dot is unaffected and
+		T0 is executed; otherwise, dot is set to the successive elements
+		of the array, slice, or map and T1 is executed.
+
+	{{template "name"}}
+		The template with the specified name is executed with nil data.
+
+	{{template "name" pipeline}}
+		The template with the specified name is executed with dot set
+		to the value of the pipeline.
+
+	{{with pipeline}} T1 {{end}}
+		If the value of the pipeline is empty, no output is generated;
+		otherwise, dot is set to the value of the pipeline and T1 is
+		executed.
+
+	{{with pipeline}} T1 {{else}} T0 {{end}}
+		If the value of the pipeline is empty, dot is unaffected and T0
+		is executed; otherwise, dot is set to the value of the pipeline
+		and T1 is executed.
+
+Arguments
+
+An argument is a simple value, denoted by one of the following.
+
+	- A boolean, string, character, integer, floating-point, imaginary
+	  or complex constant in Go syntax. These behave like Go's untyped
+	  constants, although raw strings may not span newlines.
+	- The character '.' (period):
+		.
+	  The result is the value of dot.
+	- A variable name, which is a (possibly empty) alphanumeric string
+	  preceded by a dollar sign, such as
+		$piOver2
+	  or
+		$
+	  The result is the value of the variable.
+	  Variables are described below.
+	- The name of a field of the data, which must be a struct, preceded
+	  by a period, such as
+		.Field
+	  The result is the value of the field. Field invocations may be
+	  chained:
+	    .Field1.Field2
+	  Fields can also be evaluated on variables, including chaining:
+	    $x.Field1.Field2
+	- The name of a niladic method of the data, preceded by a period,
+	  such as
+		.Method
+	  The result is the value of invoking the method with dot as the
+	  receiver, dot.Method(). Such a method must have one return value (of
+	  any type) or two return values, the second of which is an os.Error.
+	  If it has two and the returned error is non-nil, execution terminates
+	  and an error is returned to the caller as the value of Execute.
+	  Method invocations may be chained and combined with fields
+	  to any depth:
+	    .Field1.Method1.Field2.Method2
+	  Methods can also be evaluated on variables, including chaining:
+	    $x.Method1.Field
+	- The name of a niladic function, such as
+		fun
+	  The result is the value of invoking the function, fun(). The return
+	  types and values behave as in methods. Functions and function
+	  names are described below.
+
+Arguments may evaluate to any type; if they are pointers the implementation
+automatically indirects to the base type when required.
+
+A pipeline is a possibly chained sequence of "commands". A command is a simple
+value (argument) or a function or method call, possibly with multiple arguments:
+
+	Argument
+		The result is the value of evaluating the argument.
+	.Method [Argument...]
+		The method can be alone or the last element of a chain but,
+		unlike methods in the middle of a chain, it can take arguments.
+		The result is the value of calling the method with the
+		arguments:
+			dot.Method(Argument1, etc.)
+	functionName [Argument...]
+		The result is the value of calling the function associated
+		with the name:
+			function(Argument1, etc.)
+		Functions and function names are described below.
+
+Pipelines
+
+A pipeline may be "chained" by separating a sequence of commands with pipeline
+characters '|'. In a chained pipeline, the result of the each command is
+passed as the last argument of the following command. The output of the final
+command in the pipeline is the value of the pipeline.
+
+The output of a command will be either one value or two values, the second of
+which has type os.Error. If that second value is present and evaluates to
+non-nil, execution terminates and the error is returned to the caller of
+Execute.
+
+Variables
+
+A pipeline inside an action may initialize a variable to capture the result.
+The initialization has syntax
+
+	$variable := pipeline
+
+where $variable is the name of the variable. An action that declares a
+variable produces no output.
+
+If a "range" action initializes a variable, the variable is set to the
+successive elements of the iteration.  Also, a "range" may declare two
+variables, separated by a comma:
+
+	$index, $element := pipeline
+
+in which case $index and $element are set to the successive values of the
+array/slice index or map key and element, respectively.  Note that if there is
+only one variable, it is assigned the element; this is opposite to the
+convention in Go range clauses.
+
+A variable's scope extends to the "end" action of the control structure ("if",
+"with", or "range") in which it is declared, or to the end of the template if
+there is no such control structure.  A template invocation does not inherit
+variables from the point of its invocation.
+
+When execution begins, $ is set to the data argument passed to Execute, that is,
+to the starting value of dot.
+
+Examples
+
+Here are some example one-line templates demonstrating pipelines and variables.
+All produce the quoted word "output":
+
+	{{"\"output\""}}
+		A string constant.
+	{{`"output"`}}
+		A raw string constant.
+	{{printf "%q" "output"}}
+		A function call.
+	{{"output" | printf "%q"}}
+		A function call whose final argument comes from the previous
+		command.
+	{{"put" | printf "%s%s" "out" | printf "%q"}}
+		A more elaborate call.
+	{{"output" | printf "%s" | printf "%q"}}
+		A longer chain.
+	{{with "output"}}{{printf "%q" .}}{{end}}
+		A with action using dot.
+	{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
+		A with action that creates and uses a variable.
+	{{with $x := "output"}}{{printf "%q" $x}}{{end}}
+		A with action that uses the variable in another action.
+	{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
+		The same, but pipelined.
+
+Functions
+
+During execution functions are found in three function maps: first in the
+template, then in the "template set" (described below), and finally in the
+global function map. By default, no functions are defined in the template or
+the set but the Funcs methods can be used to add them.
+
+Predefined global functions are named as follows.
+
+	and
+		Returns the boolean AND of its arguments by returning the
+		first empty argument or the last argument, that is,
+		"and x y" behaves as "if x then y else x". All the
+		arguments are evaluated.
+	html
+		Returns the escaped HTML equivalent of the textual
+		representation of its arguments.
+	index
+		Returns the result of indexing its first argument by the
+		following arguments. Thus "index x 1 2 3" is, in Go syntax,
+		x[1][2][3]. Each indexed item must be a map, slice, or array.
+	js
+		Returns the escaped JavaScript equivalent of the textual
+		representation of its arguments.
+	not
+		Returns the boolean negation of its single argument.
+	or
+		Returns the boolean OR of its arguments by returning the
+		first non-empty argument or the last argument, that is,
+		"or x y" behaves as "if x then x else y". All the
+		arguments are evaluated.
+	print
+		An alias for fmt.Sprint
+	printf
+		An alias for fmt.Sprintf
+	println
+		An alias for fmt.Sprintln
+
+The boolean functions take any zero value to be false and a non-zero value to
+be true.
+
+Template sets
+
+Each template is named by a string specified when it is created.  A template may
+use a template invocation to instantiate another template directly or by its
+name; see the explanation of the template action above. The name is looked up
+in the template set associated with the template.
+
+If no template invocation actions occur in the template, the issue of template
+sets can be ignored.  If it does contain invocations, though, the template
+containing the invocations must be part of a template set in which to look up
+the names.
+
+There are two ways to construct template sets.
+
+The first is to use a Set's Parse method to create a set of named templates from
+a single input defining multiple templates.  The syntax of the definitions is to
+surround each template declaration with a define and end action.
+
+The define action names the template being created by providing a string
+constant. Here is a simple example of input to Set.Parse:
+
+	`{{define "T1"}} definition of template T1 {{end}}
+	{{define "T2"}} definition of template T2 {{end}}
+	{{define "T3"}} {{template "T1"}} {{template "T2"}} {{end}}`
+
+This defines two templates, T1 and T2, and a third T3 that invokes the other two
+when it is executed.
+
+The second way to build a template set is to use Set's Add method to add a
+parsed template to a set.  A template may be bound at most one set.  If it's
+necessary to have a template in multiple sets, the template definition must be
+parsed multiple times to create distinct *Template values.
+
+Set.Parse may be called multiple times on different inputs to construct the set.
+Two sets may therefore be constructed with a common base set of templates plus,
+through a second Parse call each, specializations for some elements.
+
+A template may be executed directly or through Set.Execute, which executes a
+named template from the set.  To invoke our example above, we might write,
+
+	err := set.Execute(os.Stdout, "T3", "no data needed")
+	if err != nil {
+		log.Fatalf("execution failed: %s", err)
+	}
+*/
+package template
diff --git a/src/pkg/exp/template/exec.go b/src/pkg/exp/template/exec.go
index fb0a9e6..40a947d 100644
--- a/src/pkg/exp/template/exec.go
+++ b/src/pkg/exp/template/exec.go
@@ -10,8 +10,6 @@ import (
 	"os"
 	"reflect"
 	"strings"
-	"unicode"
-	"utf8"
 )
 
 // state represents the state of an execution. It's not part of the
@@ -20,10 +18,49 @@ import (
 type state struct {
 	tmpl *Template
 	wr   io.Writer
-	set  *Set
-	line int // line number for errors
+	line int        // line number for errors
+	vars []variable // push-down stack of variable values.
 }
 
+// variable holds the dynamic value of a variable such as $, $x etc.
+type variable struct {
+	name  string
+	value reflect.Value
+}
+
+// push pushes a new variable on the stack.
+func (s *state) push(name string, value reflect.Value) {
+	s.vars = append(s.vars, variable{name, value})
+}
+
+// mark returns the length of the variable stack.
+func (s *state) mark() int {
+	return len(s.vars)
+}
+
+// pop pops the variable stack up to the mark.
+func (s *state) pop(mark int) {
+	s.vars = s.vars[0:mark]
+}
+
+// setVar overwrites the top-nth variable on the stack. Used by range iterations.
+func (s *state) setVar(n int, value reflect.Value) {
+	s.vars[len(s.vars)-n].value = value
+}
+
+// varValue returns the value of the named variable.
+func (s *state) varValue(name string) reflect.Value {
+	for i := s.mark() - 1; i >= 0; i-- {
+		if s.vars[i].name == name {
+			return s.vars[i].value
+		}
+	}
+	s.errorf("undefined variable: %s", name)
+	return zero
+}
+
+var zero reflect.Value
+
 // errorf formats the error and terminates processing.
 func (s *state) errorf(format string, args ...interface{}) {
 	format = fmt.Sprintf("template: %s:%d: %s", s.tmpl.name, s.line, format)
@@ -37,55 +74,54 @@ func (s *state) error(err os.Error) {
 
 // Execute applies a parsed template to the specified data object,
 // writing the output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) os.Error {
-	return t.ExecuteInSet(wr, data, nil)
-}
-
-// ExecuteInSet applies a parsed template to the specified data object,
-// writing the output to wr. Nested template invocations will be resolved
-// from the specified set.
-func (t *Template) ExecuteInSet(wr io.Writer, data interface{}, set *Set) (err os.Error) {
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
 	defer t.recover(&err)
+	value := reflect.ValueOf(data)
 	state := &state{
 		tmpl: t,
 		wr:   wr,
-		set:  set,
 		line: 1,
+		vars: []variable{{"$", value}},
 	}
 	if t.root == nil {
 		state.errorf("must be parsed before execution")
 	}
-	state.walk(reflect.ValueOf(data), t.root)
+	state.walk(value, t.root)
 	return
 }
 
 // Walk functions step through the major pieces of the template structure,
 // generating output as they go.
-func (s *state) walk(data reflect.Value, n node) {
+func (s *state) walk(dot reflect.Value, n node) {
 	switch n := n.(type) {
 	case *actionNode:
 		s.line = n.line
-		s.printValue(n, s.evalPipeline(data, n.pipeline))
-	case *listNode:
-		for _, node := range n.nodes {
-			s.walk(data, node)
+		// Do not pop variables so they persist until next end.
+		// Also, if the action declares variables, don't print the result.
+		val := s.evalPipeline(dot, n.pipe)
+		if len(n.pipe.decl) == 0 {
+			s.printValue(n, val)
 		}
 	case *ifNode:
 		s.line = n.line
-		s.walkIfOrWith(nodeIf, data, n.pipeline, n.list, n.elseList)
+		s.walkIfOrWith(nodeIf, dot, n.pipe, n.list, n.elseList)
+	case *listNode:
+		for _, node := range n.nodes {
+			s.walk(dot, node)
+		}
 	case *rangeNode:
 		s.line = n.line
-		s.walkRange(data, n)
+		s.walkRange(dot, n)
+	case *templateNode:
+		s.line = n.line
+		s.walkTemplate(dot, n)
 	case *textNode:
 		if _, err := s.wr.Write(n.text); err != nil {
 			s.error(err)
 		}
-	case *templateNode:
-		s.line = n.line
-		s.walkTemplate(data, n)
 	case *withNode:
 		s.line = n.line
-		s.walkIfOrWith(nodeWith, data, n.pipeline, n.list, n.elseList)
+		s.walkIfOrWith(nodeWith, dot, n.pipe, n.list, n.elseList)
 	default:
 		s.errorf("unknown node: %s", n)
 	}
@@ -93,19 +129,21 @@ func (s *state) walk(data reflect.Value, n node) {
 
 // walkIfOrWith walks an 'if' or 'with' node. The two control structures
 // are identical in behavior except that 'with' sets dot.
-func (s *state) walkIfOrWith(typ nodeType, data reflect.Value, pipe []*commandNode, list, elseList *listNode) {
-	val := s.evalPipeline(data, pipe)
+func (s *state) walkIfOrWith(typ nodeType, dot reflect.Value, pipe *pipeNode, list, elseList *listNode) {
+	defer s.pop(s.mark())
+	val := s.evalPipeline(dot, pipe)
 	truth, ok := isTrue(val)
 	if !ok {
 		s.errorf("if/with can't use value of type %T", val.Interface())
 	}
 	if truth {
 		if typ == nodeWith {
-			data = val
+			s.walk(val, list)
+		} else {
+			s.walk(dot, list)
 		}
-		s.walk(data, list)
 	} else if elseList != nil {
-		s.walk(data, elseList)
+		s.walk(dot, elseList)
 	}
 }
 
@@ -117,31 +155,44 @@ func isTrue(val reflect.Value) (truth, ok bool) {
 		truth = val.Len() > 0
 	case reflect.Bool:
 		truth = val.Bool()
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		truth = val.Int() != 0
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		truth = val.Uint() != 0
-	case reflect.Float32, reflect.Float64:
-		truth = val.Float() != 0
 	case reflect.Complex64, reflect.Complex128:
 		truth = val.Complex() != 0
 	case reflect.Chan, reflect.Func, reflect.Ptr:
 		truth = !val.IsNil()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		truth = val.Int() != 0
+	case reflect.Float32, reflect.Float64:
+		truth = val.Float() != 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		truth = val.Uint() != 0
 	default:
 		return
 	}
 	return truth, true
 }
 
-func (s *state) walkRange(data reflect.Value, r *rangeNode) {
-	val := s.evalPipeline(data, r.pipeline)
+func (s *state) walkRange(dot reflect.Value, r *rangeNode) {
+	defer s.pop(s.mark())
+	val, _ := indirect(s.evalPipeline(dot, r.pipe))
+	// mark top of stack before any variables in the body are pushed.
+	mark := s.mark()
 	switch val.Kind() {
 	case reflect.Array, reflect.Slice:
 		if val.Len() == 0 {
 			break
 		}
 		for i := 0; i < val.Len(); i++ {
-			s.walk(val.Index(i), r.list)
+			elem := val.Index(i)
+			// Set top var (lexically the second if there are two) to the element.
+			if len(r.pipe.decl) > 0 {
+				s.setVar(1, elem)
+			}
+			// Set next var (lexically the first if there are two) to the index.
+			if len(r.pipe.decl) > 1 {
+				s.setVar(2, reflect.ValueOf(i))
+			}
+			s.walk(elem, r.list)
+			s.pop(mark)
 		}
 		return
 	case reflect.Map:
@@ -149,166 +200,222 @@ func (s *state) walkRange(data reflect.Value, r *rangeNode) {
 			break
 		}
 		for _, key := range val.MapKeys() {
-			s.walk(val.MapIndex(key), r.list)
+			elem := val.MapIndex(key)
+			// Set top var (lexically the second if there are two) to the element.
+			if len(r.pipe.decl) > 0 {
+				s.setVar(1, elem)
+			}
+			// Set next var (lexically the first if there are two) to the key.
+			if len(r.pipe.decl) > 1 {
+				s.setVar(2, key)
+			}
+			s.walk(elem, r.list)
+			s.pop(mark)
 		}
 		return
 	default:
 		s.errorf("range can't iterate over value of type %T", val.Interface())
 	}
 	if r.elseList != nil {
-		s.walk(data, r.elseList)
+		s.walk(dot, r.elseList)
 	}
 }
 
-func (s *state) walkTemplate(data reflect.Value, t *templateNode) {
-	name := s.evalArg(data, reflect.TypeOf("string"), t.name).String()
-	if s.set == nil {
-		s.errorf("no set defined in which to invoke template named %q", name)
+func (s *state) walkTemplate(dot reflect.Value, t *templateNode) {
+	set := s.tmpl.set
+	if set == nil {
+		s.errorf("no set defined in which to invoke template named %q", t.name)
 	}
-	tmpl := s.set.tmpl[name]
+	tmpl := set.tmpl[t.name]
 	if tmpl == nil {
-		s.errorf("template %q not in set", name)
+		s.errorf("template %q not in set", t.name)
 	}
-	data = s.evalPipeline(data, t.pipeline)
+	// Variables declared by the pipeline persist.
+	dot = s.evalPipeline(dot, t.pipe)
 	newState := *s
 	newState.tmpl = tmpl
-	newState.walk(data, tmpl.root)
+	// No dynamic scoping: template invocations inherit no variables.
+	newState.vars = []variable{{"$", dot}}
+	newState.walk(dot, tmpl.root)
 }
 
 // Eval functions evaluate pipelines, commands, and their elements and extract
 // values from the data structure by examining fields, calling methods, and so on.
 // The printing of those values happens only through walk functions.
 
-func (s *state) evalPipeline(data reflect.Value, pipe []*commandNode) reflect.Value {
-	value := reflect.Value{}
-	for _, cmd := range pipe {
-		value = s.evalCommand(data, cmd, value) // previous value is this one's final arg.
+// evalPipeline returns the value acquired by evaluating a pipeline. If the
+// pipeline has a variable declaration, the variable will be pushed on the
+// stack. Callers should therefore pop the stack after they are finished
+// executing commands depending on the pipeline value.
+func (s *state) evalPipeline(dot reflect.Value, pipe *pipeNode) (value reflect.Value) {
+	if pipe == nil {
+		return
+	}
+	for _, cmd := range pipe.cmds {
+		value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
 		// If the object has type interface{}, dig down one level to the thing inside.
 		if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
 			value = reflect.ValueOf(value.Interface()) // lovely!
 		}
 	}
+	for _, variable := range pipe.decl {
+		s.push(variable.ident[0], value)
+	}
 	return value
 }
 
-func (s *state) evalCommand(data reflect.Value, cmd *commandNode, final reflect.Value) reflect.Value {
+func (s *state) notAFunction(args []node, final reflect.Value) {
+	if len(args) > 1 || final.IsValid() {
+		s.errorf("can't give argument to non-function %s", args[0])
+	}
+}
+
+func (s *state) evalCommand(dot reflect.Value, cmd *commandNode, final reflect.Value) reflect.Value {
 	firstWord := cmd.args[0]
 	switch n := firstWord.(type) {
 	case *fieldNode:
-		return s.evalFieldNode(data, n, cmd.args, final)
+		return s.evalFieldNode(dot, n, cmd.args, final)
 	case *identifierNode:
-		return s.evalFieldOrCall(data, n.ident, cmd.args, final)
-	}
-	if len(cmd.args) > 1 || final.IsValid() {
-		s.errorf("can't give argument to non-function %s", cmd.args[0])
+		// Must be a function.
+		return s.evalFunction(dot, n.ident, cmd.args, final)
+	case *variableNode:
+		return s.evalVariableNode(dot, n, cmd.args, final)
 	}
-	switch word := cmd.args[0].(type) {
-	case *dotNode:
-		return data
+	s.notAFunction(cmd.args, final)
+	switch word := firstWord.(type) {
 	case *boolNode:
 		return reflect.ValueOf(word.true)
+	case *dotNode:
+		return dot
 	case *numberNode:
-		// These are ideal constants but we don't know the type
-		// and we have no context.  (If it was a method argument,
-		// we'd know what we need.) The syntax guides us to some extent.
-		switch {
-		case word.isComplex:
-			return reflect.ValueOf(word.complex128) // incontrovertible.
-		case word.isFloat && strings.IndexAny(word.text, ".eE") >= 0:
-			return reflect.ValueOf(word.float64)
-		case word.isInt:
-			return reflect.ValueOf(word.int64)
-		case word.isUint:
-			return reflect.ValueOf(word.uint64)
-		}
+		return s.idealConstant(word)
 	case *stringNode:
 		return reflect.ValueOf(word.text)
 	}
-	s.errorf("can't handle command %q", firstWord)
+	s.errorf("can't evaluate command %q", firstWord)
 	panic("not reached")
 }
 
-func (s *state) evalFieldNode(data reflect.Value, field *fieldNode, args []node, final reflect.Value) reflect.Value {
-	// Up to the last entry, it must be a field.
-	n := len(field.ident)
-	for i := 0; i < n-1; i++ {
-		data = s.evalField(data, field.ident[i])
+// idealConstant is called to return the value of a number in a context where
+// we don't know the type. In that case, the syntax of the number tells us
+// its type, and we use Go rules to resolve.  Note there is no such thing as
+// a uint ideal constant in this situation - the value must be of int type.
+func (s *state) idealConstant(constant *numberNode) reflect.Value {
+	// These are ideal constants but we don't know the type
+	// and we have no context.  (If it was a method argument,
+	// we'd know what we need.) The syntax guides us to some extent.
+	switch {
+	case constant.isComplex:
+		return reflect.ValueOf(constant.complex128) // incontrovertible.
+	case constant.isFloat && strings.IndexAny(constant.text, ".eE") >= 0:
+		return reflect.ValueOf(constant.float64)
+	case constant.isInt:
+		n := int(constant.int64)
+		if int64(n) != constant.int64 {
+			s.errorf("%s overflows int", constant.text)
+		}
+		return reflect.ValueOf(n)
+	case constant.isUint:
+		s.errorf("%s overflows int", constant.text)
 	}
-	// Now it can be a field or method and if a method, gets arguments.
-	return s.evalFieldOrCall(data, field.ident[n-1], args, final)
+	return zero
 }
 
-// Is this an exported - upper case - name?
-func isExported(name string) bool {
-	rune, _ := utf8.DecodeRuneInString(name)
-	return unicode.IsUpper(rune)
+func (s *state) evalFieldNode(dot reflect.Value, field *fieldNode, args []node, final reflect.Value) reflect.Value {
+	return s.evalFieldChain(dot, dot, field.ident, args, final)
 }
 
-func (s *state) evalField(data reflect.Value, fieldName string) reflect.Value {
-	var isNil bool
-	if data, isNil = indirect(data); isNil {
-		s.errorf("%s is nil pointer", fieldName)
-	}
-	switch data.Kind() {
-	case reflect.Struct:
-		// Is it a field?
-		field := data.FieldByName(fieldName)
-		// TODO: look higher up the tree if we can't find it here. Also unexported fields
-		// might succeed higher up, as map keys.
-		if field.IsValid() && isExported(fieldName) { // valid and exported
-			return field
-		}
-		s.errorf("%s has no exported field %q", data.Type(), fieldName)
-	default:
-		s.errorf("can't evaluate field %s of type %s", fieldName, data.Type())
+func (s *state) evalVariableNode(dot reflect.Value, v *variableNode, args []node, final reflect.Value) reflect.Value {
+	// $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
+	value := s.varValue(v.ident[0])
+	if len(v.ident) == 1 {
+		return value
 	}
-	panic("not reached")
+	return s.evalFieldChain(dot, value, v.ident[1:], args, final)
 }
 
-func (s *state) evalFieldOrCall(data reflect.Value, fieldName string, args []node, final reflect.Value) reflect.Value {
-	// Is it a function?
-	if function, ok := findFunction(fieldName, s.tmpl, s.set); ok {
-		return s.evalCall(data, function, fieldName, false, args, final)
-	}
-	ptr := data
-	for data.Kind() == reflect.Ptr && !data.IsNil() {
-		ptr, data = data, reflect.Indirect(data)
+// evalFieldChain evaluates .X.Y.Z possibly followed by arguments.
+// dot is the environment in which to evaluate arguments, while
+// receiver is the value being walked along the chain.
+func (s *state) evalFieldChain(dot, receiver reflect.Value, ident []string, args []node, final reflect.Value) reflect.Value {
+	n := len(ident)
+	for i := 0; i < n-1; i++ {
+		receiver = s.evalField(dot, ident[i], nil, zero, receiver)
 	}
-	// Is it a method? We use the pointer because it has value methods too.
-	if method, ok := methodByName(ptr.Type(), fieldName); ok {
-		return s.evalCall(ptr, method.Func, fieldName, true, args, final)
+	// Now if it's a method, it gets the arguments.
+	return s.evalField(dot, ident[n-1], args, final, receiver)
+}
+
+func (s *state) evalFunction(dot reflect.Value, name string, args []node, final reflect.Value) reflect.Value {
+	function, ok := findFunction(name, s.tmpl, s.tmpl.set)
+	if !ok {
+		s.errorf("%q is not a defined function", name)
 	}
-	if len(args) > 1 || final.IsValid() {
-		s.errorf("%s is not a method but has arguments", fieldName)
+	return s.evalCall(dot, function, name, args, final)
+}
+
+// evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
+// The 'final' argument represents the return value from the preceding
+// value of the pipeline, if any.
+func (s *state) evalField(dot reflect.Value, fieldName string, args []node, final, receiver reflect.Value) reflect.Value {
+	if !receiver.IsValid() {
+		return zero
+	}
+	typ := receiver.Type()
+	receiver, _ = indirect(receiver)
+	// Need to get to a value of type *T to guarantee we see all
+	// methods of T and *T.
+	ptr := receiver
+	if ptr.CanAddr() {
+		ptr = ptr.Addr()
+	}
+	if method, ok := methodByName(ptr, fieldName); ok {
+		return s.evalCall(dot, method, fieldName, args, final)
+	}
+	// It's not a method; is it a field of a struct?
+	receiver, isNil := indirect(receiver)
+	if receiver.Kind() == reflect.Struct {
+		tField, ok := receiver.Type().FieldByName(fieldName)
+		if ok {
+			field := receiver.FieldByIndex(tField.Index)
+			if len(args) > 1 || final.IsValid() {
+				s.errorf("%s is not a method but has arguments", fieldName)
+			}
+			if tField.PkgPath == "" { // field is exported
+				return field
+			}
+		}
 	}
-	switch data.Kind() {
-	case reflect.Struct:
-		return s.evalField(data, fieldName)
-	default:
-		s.errorf("can't handle evaluation of field %s of type %s", fieldName, data.Type())
+	if isNil {
+		s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
 	}
+	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
 	panic("not reached")
 }
 
 // TODO: delete when reflect's own MethodByName is released.
-func methodByName(typ reflect.Type, name string) (reflect.Method, bool) {
+func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) {
+	typ := receiver.Type()
 	for i := 0; i < typ.NumMethod(); i++ {
 		if typ.Method(i).Name == name {
-			return typ.Method(i), true
+			return receiver.Method(i), true // This value includes the receiver.
 		}
 	}
-	return reflect.Method{}, false
+	return zero, false
 }
 
 var (
 	osErrorType = reflect.TypeOf(new(os.Error)).Elem()
 )
 
-func (s *state) evalCall(v, fun reflect.Value, name string, isMethod bool, args []node, final reflect.Value) reflect.Value {
-	typ := fun.Type()
-	if !isMethod && len(args) > 0 { // Args will be nil if it's a niladic call in an argument list
-		args = args[1:] // first arg is name of function; not used in call.
+// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
+// it looks just like a function call.  The arg list, if non-nil, includes (in the manner of the shell), arg[0]
+// as the function itself.
+func (s *state) evalCall(dot, fun reflect.Value, name string, args []node, final reflect.Value) reflect.Value {
+	if args != nil {
+		args = args[1:] // Zeroth arg is function name/node; not passed to function.
 	}
+	typ := fun.Type()
 	numIn := len(args)
 	if final.IsValid() {
 		numIn++
@@ -327,60 +434,67 @@ func (s *state) evalCall(v, fun reflect.Value, name string, isMethod bool, args
 	}
 	// Build the arg list.
 	argv := make([]reflect.Value, numIn)
-	// First arg is the receiver.
+	// Args must be evaluated. Fixed args first.
 	i := 0
-	if isMethod {
-		argv[0] = v
-		i++
-	}
-	// Others must be evaluated. Fixed args first.
 	for ; i < numFixed; i++ {
-		argv[i] = s.evalArg(v, typ.In(i), args[i])
+		argv[i] = s.evalArg(dot, typ.In(i), args[i])
 	}
-	// And now the ... args.
+	// Now the ... args.
 	if typ.IsVariadic() {
 		argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice.
 		for ; i < len(args); i++ {
-			argv[i] = s.evalArg(v, argType, args[i])
+			argv[i] = s.evalArg(dot, argType, args[i])
 		}
 	}
 	// Add final value if necessary.
 	if final.IsValid() {
-		argv[len(args)] = final
+		argv[i] = final
 	}
 	result := fun.Call(argv)
 	// If we have an os.Error that is not nil, stop execution and return that error to the caller.
 	if len(result) == 2 && !result[1].IsNil() {
-		s.error(result[1].Interface().(os.Error))
+		s.errorf("error calling %s: %s", name, result[1].Interface().(os.Error))
 	}
 	return result[0]
 }
 
-func (s *state) evalArg(data reflect.Value, typ reflect.Type, n node) reflect.Value {
-	if field, ok := n.(*fieldNode); ok {
-		value := s.evalFieldNode(data, field, []node{n}, reflect.Value{})
-		if !value.Type().AssignableTo(typ) {
-			s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
-		}
-		return value
+// validateType guarantees that the value is valid and assignable to the type.
+func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
+	if !value.IsValid() {
+		s.errorf("invalid value; expected %s", typ)
+	}
+	if !value.Type().AssignableTo(typ) {
+		s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
+	}
+	return value
+}
+
+func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n node) reflect.Value {
+	switch arg := n.(type) {
+	case *dotNode:
+		return s.validateType(dot, typ)
+	case *fieldNode:
+		return s.validateType(s.evalFieldNode(dot, arg, []node{n}, zero), typ)
+	case *variableNode:
+		return s.validateType(s.evalVariableNode(dot, arg, nil, zero), typ)
 	}
 	switch typ.Kind() {
 	case reflect.Bool:
 		return s.evalBool(typ, n)
-	case reflect.String:
-		return s.evalString(typ, n)
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return s.evalInteger(typ, n)
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		return s.evalUnsignedInteger(typ, n)
-	case reflect.Float32, reflect.Float64:
-		return s.evalFloat(typ, n)
 	case reflect.Complex64, reflect.Complex128:
 		return s.evalComplex(typ, n)
+	case reflect.Float32, reflect.Float64:
+		return s.evalFloat(typ, n)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return s.evalInteger(typ, n)
 	case reflect.Interface:
 		if typ.NumMethod() == 0 {
-			return s.evalEmptyInterface(data, typ, n)
+			return s.evalEmptyInterface(dot, n)
 		}
+	case reflect.String:
+		return s.evalString(typ, n)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return s.evalUnsignedInteger(typ, n)
 	}
 	s.errorf("can't handle %s for arg of type %s", n, typ)
 	panic("not reached")
@@ -446,43 +560,38 @@ func (s *state) evalComplex(typ reflect.Type, n node) reflect.Value {
 	panic("not reached")
 }
 
-func (s *state) evalEmptyInterface(data reflect.Value, typ reflect.Type, n node) reflect.Value {
+func (s *state) evalEmptyInterface(dot reflect.Value, n node) reflect.Value {
 	switch n := n.(type) {
 	case *boolNode:
 		return reflect.ValueOf(n.true)
 	case *dotNode:
-		return data
+		return dot
 	case *fieldNode:
-		return s.evalFieldNode(data, n, nil, reflect.Value{})
+		return s.evalFieldNode(dot, n, nil, zero)
 	case *identifierNode:
-		return s.evalFieldOrCall(data, n.ident, nil, reflect.Value{})
+		return s.evalFunction(dot, n.ident, nil, zero)
 	case *numberNode:
-		if n.isComplex {
-			return reflect.ValueOf(n.complex128)
-		}
-		if n.isInt {
-			return reflect.ValueOf(n.int64)
-		}
-		if n.isUint {
-			return reflect.ValueOf(n.uint64)
-		}
-		if n.isFloat {
-			return reflect.ValueOf(n.float64)
-		}
+		return s.idealConstant(n)
 	case *stringNode:
 		return reflect.ValueOf(n.text)
+	case *variableNode:
+		return s.evalVariableNode(dot, n, nil, zero)
 	}
 	s.errorf("can't handle assignment of %s to empty interface argument", n)
 	panic("not reached")
 }
 
 // indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
+// We indirect through pointers and empty interfaces (only) because
+// non-empty interfaces have methods we might need.
 func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
-	for v.Kind() == reflect.Ptr {
+	for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
 		if v.IsNil() {
 			return v, true
 		}
-		v = v.Elem()
+		if v.Kind() == reflect.Ptr || v.NumMethod() == 0 {
+			v = v.Elem()
+		}
 	}
 	return v, false
 }
diff --git a/src/pkg/exp/template/exec_test.go b/src/pkg/exp/template/exec_test.go
index 86b958e..d9b8afb 100644
--- a/src/pkg/exp/template/exec_test.go
+++ b/src/pkg/exp/template/exec_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"fmt"
 	"os"
+	"reflect"
 	"sort"
 	"strings"
 	"testing"
@@ -16,6 +17,7 @@ import (
 // T has lots of interesting pieces to use to test execution.
 type T struct {
 	// Basics
+	True        bool
 	I           int
 	U16         uint16
 	X           string
@@ -42,9 +44,16 @@ type T struct {
 	PI  *int
 	PSI *[]int
 	NIL *int
+	// Template to test evaluation of templates.
+	Tmpl *Template
+}
+
+type U struct {
+	V string
 }
 
 var tVal = &T{
+	True:   true,
 	I:      17,
 	U16:    16,
 	X:      "x",
@@ -60,9 +69,10 @@ var tVal = &T{
 	Empty1: 3,
 	Empty2: "empty2",
 	Empty3: []int{7, 8},
-	Empty4: &U{"v"},
+	Empty4: &U{"UinEmpty"},
 	PI:     newInt(23),
 	PSI:    newIntSlice(21, 22, 23),
+	Tmpl:   Must(New("x").Parse("test template")), // "x" is the value of .X
 }
 
 // Helpers for creation.
@@ -81,7 +91,7 @@ func newIntSlice(n ...int) *[]int {
 
 // Simple methods with and without arguments.
 func (t *T) Method0() string {
-	return "resultOfMethod0"
+	return "M0"
 }
 
 func (t *T) Method1(a int) int {
@@ -120,8 +130,20 @@ func (t *T) EPERM(error bool) (bool, os.Error) {
 	return false, nil
 }
 
-type U struct {
-	V string
+// A few methods to test chaining.
+func (t *T) GetU() *U {
+	return t.U
+}
+
+func (u *U) TrueFalse(b bool) string {
+	if b {
+		return "true"
+	}
+	return ""
+}
+
+func typeOf(arg interface{}) string {
+	return fmt.Sprintf("%T", arg)
 }
 
 type execTest struct {
@@ -132,11 +154,27 @@ type execTest struct {
 	ok     bool
 }
 
+// bigInt and bigUint are hex string representing numbers either side
+// of the max int boundary.
+// We do it this way so the test doesn't depend on ints being 32 bits.
+var (
+	bigInt  = fmt.Sprintf("0x%x", int(1<<uint(reflect.TypeOf(0).Bits()-1)-1))
+	bigUint = fmt.Sprintf("0x%x", uint(1<<uint(reflect.TypeOf(0).Bits()-1)))
+)
+
 var execTests = []execTest{
 	// Trivial cases.
 	{"empty", "", "", nil, true},
 	{"text", "some text", "some text", nil, true},
 
+	// Ideal constants.
+	{"ideal int", "{{typeOf 3}}", "int", 0, true},
+	{"ideal float", "{{typeOf 1.0}}", "float64", 0, true},
+	{"ideal exp float", "{{typeOf 1e1}}", "float64", 0, true},
+	{"ideal complex", "{{typeOf 1i}}", "complex128", 0, true},
+	{"ideal int", "{{typeOf " + bigInt + "}}", "int", 0, true},
+	{"ideal too big", "{{typeOf " + bigUint + "}}", "", 0, false},
+
 	// Fields of structs.
 	{".X", "-{{.X}}-", "-x-", tVal, true},
 	{".U.V", "-{{.U.V}}-", "-v-", tVal, true},
@@ -155,28 +193,46 @@ var execTests = []execTest{
 		b string
 	}{7, "seven"}, true},
 
+	// Variables.
+	{"$ int", "{{$}}", "123", 123, true},
+	{"$.I", "{{$.I}}", "17", tVal, true},
+	{"$.U.V", "{{$.U.V}}", "v", tVal, true},
+	{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
+
 	// Pointers.
 	{"*int", "{{.PI}}", "23", tVal, true},
 	{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
 	{"*[]int[1]", "{{index .PSI 1}}", "22", tVal, true},
 	{"NIL", "{{.NIL}}", "<nil>", tVal, true},
 
-	// Emtpy interfaces holding values.
+	// Empty interfaces holding values.
 	{"empty nil", "{{.Empty0}}", "<no value>", tVal, true},
 	{"empty with int", "{{.Empty1}}", "3", tVal, true},
 	{"empty with string", "{{.Empty2}}", "empty2", tVal, true},
 	{"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
-	{"empty with struct", "{{.Empty4}}", "{v}", tVal, true},
+	{"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
+	{"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
 
 	// Method calls.
-	{".Method0", "-{{.Method0}}-", "-resultOfMethod0-", tVal, true},
+	{".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
 	{".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
 	{".Method1(.I)", "-{{.Method1 .I}}-", "-17-", tVal, true},
 	{".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
 	{".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
+	{".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
+	{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
+	{"method on chained var",
+		"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
+		"true", tVal, true},
+	{"chained method",
+		"{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
+		"true", tVal, true},
+	{"chained method on variable",
+		"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
+		"true", tVal, true},
 
 	// Pipelines.
-	{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 resultOfMethod0-", tVal, true},
+	{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
 
 	// If.
 	{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
@@ -193,17 +249,23 @@ var execTests = []execTest{
 	{"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
 	{"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
 	{"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+	{"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
+	{"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
 
-	// Printf.
-	{"printf", `{{printf "hello, printf"}}`, "hello, printf", tVal, true},
+	// Print etc.
+	{"print", `{{print "hello, print"}}`, "hello, print", tVal, true},
+	{"print", `{{print 1 2 3}}`, "1 2 3", tVal, true},
+	{"println", `{{println 1 2 3}}`, "1 2 3\n", tVal, true},
 	{"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
 	{"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
 	{"printf complex", `{{printf "%g" 1+7i}}`, "(1+7i)", tVal, true},
 	{"printf string", `{{printf "%s" "hello"}}`, "hello", tVal, true},
-	{"printf function", `{{printf "%#q" gopher}}`, "`gopher`", tVal, true},
+	{"printf function", `{{printf "%#q" zeroArgs}}`, "`zeroArgs`", tVal, true},
 	{"printf field", `{{printf "%s" .U.V}}`, "v", tVal, true},
-	{"printf method", `{{printf "%s" .Method0}}`, "resultOfMethod0", tVal, true},
-	{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) resultOfMethod0", tVal, true},
+	{"printf method", `{{printf "%s" .Method0}}`, "M0", tVal, true},
+	{"printf dot", `{{with .I}}{{printf "%d" .}}{{end}}`, "17", tVal, true},
+	{"printf var", `{{with $x := .I}}{{printf "%d" $x}}{{end}}`, "17", tVal, true},
+	{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
 
 	// HTML.
 	{"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
@@ -216,8 +278,8 @@ var execTests = []execTest{
 
 	// Booleans
 	{"not", "{{not true}} {{not false}}", "false true", nil, true},
-	{"and", "{{and 0 0}} {{and 1 0}} {{and 0 1}} {{and 1 1}}", "false false false true", nil, true},
-	{"or", "{{or 0 0}} {{or 1 0}} {{or 0 1}} {{or 1 1}}", "false true true true", nil, true},
+	{"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
+	{"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
 	{"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
 	{"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
 
@@ -247,7 +309,10 @@ var execTests = []execTest{
 	{"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
 	{"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
 	{"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
-	{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "v", tVal, true},
+	{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "UinEmpty", tVal, true},
+	{"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
+	{"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
+	{"with variable and action", "{{with $x := $}}{{$y := $.U.V}}{{$y}}{{end}}", "v", tVal, true},
 
 	// Range.
 	{"range []int", "{{range .SI}}-{{.}}-{{end}}", "-3--4--5-", tVal, true},
@@ -261,28 +326,46 @@ var execTests = []execTest{
 	{"range map else", "{{range .MSI | .MSort}}-{{.}}-{{else}}EMPTY{{end}}", "-one--three--two-", tVal, true},
 	{"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
 	{"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
+	{"range $x SI", "{{range $x := .SI}}<{{$x}}>{{end}}", "<3><4><5>", tVal, true},
+	{"range $x $y SI", "{{range $x, $y := .SI}}<{{$x}}={{$y}}>{{end}}", "<0=3><1=4><2=5>", tVal, true},
+	{"range $x MSIone", "{{range $x := .MSIone}}<{{$x}}>{{end}}", "<1>", tVal, true},
+	{"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
+	{"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
+	{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
+
+	// Cute examples.
+	{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
+	{"or as if false", `{{or .SIEmpty "slice is empty"}}`, "slice is empty", tVal, true},
 
 	// Error handling.
 	{"error method, error", "{{.EPERM true}}", "", tVal, false},
 	{"error method, no error", "{{.EPERM false}}", "false", tVal, true},
+
+	// Fixed bugs.
+	// Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
+	{"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
 }
 
-func gopher() string {
-	return "gopher"
+func zeroArgs() string {
+	return "zeroArgs"
+}
+
+func oneArg(a string) string {
+	return "oneArg=" + a
 }
 
 func testExecute(execTests []execTest, set *Set, t *testing.T) {
 	b := new(bytes.Buffer)
-	funcs := FuncMap{"gopher": gopher}
+	funcs := FuncMap{"zeroArgs": zeroArgs, "oneArg": oneArg, "typeOf": typeOf}
 	for _, test := range execTests {
 		tmpl := New(test.name).Funcs(funcs)
-		err := tmpl.Parse(test.input)
+		_, err := tmpl.ParseInSet(test.input, set)
 		if err != nil {
 			t.Errorf("%s: parse error: %s", test.name, err)
 			continue
 		}
 		b.Reset()
-		err = tmpl.ExecuteInSet(b, test.data, set)
+		err = tmpl.Execute(b, test.data)
 		switch {
 		case !test.ok && err == nil:
 			t.Errorf("%s: expected error; got none", test.name)
@@ -311,7 +394,7 @@ func TestExecute(t *testing.T) {
 func TestExecuteError(t *testing.T) {
 	b := new(bytes.Buffer)
 	tmpl := New("error")
-	err := tmpl.Parse("{{.EPERM true}}")
+	_, err := tmpl.Parse("{{.EPERM true}}")
 	if err != nil {
 		t.Fatalf("parse error: %s", err)
 	}
@@ -319,6 +402,9 @@ func TestExecuteError(t *testing.T) {
 	if err == nil {
 		t.Errorf("expected error; got none")
 	} else if !strings.Contains(err.String(), os.EPERM.String()) {
+		if *debug {
+			fmt.Printf("test execute error: %s\n", err)
+		}
 		t.Errorf("expected os.EPERM; got %s", err)
 	}
 }
@@ -332,6 +418,7 @@ func TestJSEscaping(t *testing.T) {
 		{`Go "jump" \`, `Go \"jump\" \\`},
 		{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
 		{"unprintable \uFDFF", `unprintable \uFDFF`},
+		{`<html>`, `\x3Chtml\x3E`},
 	}
 	for _, tc := range testCases {
 		s := JSEscapeString(tc.in)
@@ -340,3 +427,84 @@ func TestJSEscaping(t *testing.T) {
 		}
 	}
 }
+
+// A nice example: walk a binary tree.
+
+type Tree struct {
+	Val         int
+	Left, Right *Tree
+}
+
+const treeTemplate = `
+	{{define "tree"}}
+	[
+		{{.Val}}
+		{{with .Left}}
+			{{template "tree" .}}
+		{{end}}
+		{{with .Right}}
+			{{template "tree" .}}
+		{{end}}
+	]
+	{{end}}
+`
+
+func TestTree(t *testing.T) {
+	var tree = &Tree{
+		1,
+		&Tree{
+			2, &Tree{
+				3,
+				&Tree{
+					4, nil, nil,
+				},
+				nil,
+			},
+			&Tree{
+				5,
+				&Tree{
+					6, nil, nil,
+				},
+				nil,
+			},
+		},
+		&Tree{
+			7,
+			&Tree{
+				8,
+				&Tree{
+					9, nil, nil,
+				},
+				nil,
+			},
+			&Tree{
+				10,
+				&Tree{
+					11, nil, nil,
+				},
+				nil,
+			},
+		},
+	}
+	set := new(Set)
+	_, err := set.Parse(treeTemplate)
+	if err != nil {
+		t.Fatal("parse error:", err)
+	}
+	var b bytes.Buffer
+	err = set.Execute(&b, "tree", tree)
+	if err != nil {
+		t.Fatal("exec error:", err)
+	}
+	stripSpace := func(r int) int {
+		if r == '\t' || r == '\n' {
+			return -1
+		}
+		return r
+	}
+	result := strings.Map(stripSpace, b.String())
+	const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
+	if result != expect {
+		t.Errorf("expected %q got %q", expect, result)
+	}
+}
diff --git a/src/pkg/exp/template/funcs.go b/src/pkg/exp/template/funcs.go
index 66be40f..58b2baf 100644
--- a/src/pkg/exp/template/funcs.go
+++ b/src/pkg/exp/template/funcs.go
@@ -17,17 +17,20 @@ import (
 
 // FuncMap is the type of the map defining the mapping from names to functions.
 // Each function must have either a single return value, or two return values of
-// which the second has type os.Error.
+// which the second has type os.Error. If the second argument evaluates to non-nil
+// during execution, execution terminates and Execute returns an error.
 type FuncMap map[string]interface{}
 
 var funcs = map[string]reflect.Value{
-	"and":    reflect.ValueOf(and),
-	"html":   reflect.ValueOf(HTMLEscaper),
-	"index":  reflect.ValueOf(index),
-	"js":     reflect.ValueOf(JSEscaper),
-	"not":    reflect.ValueOf(not),
-	"or":     reflect.ValueOf(or),
-	"printf": reflect.ValueOf(fmt.Sprintf),
+	"and":     reflect.ValueOf(and),
+	"html":    reflect.ValueOf(HTMLEscaper),
+	"index":   reflect.ValueOf(index),
+	"js":      reflect.ValueOf(JSEscaper),
+	"not":     reflect.ValueOf(not),
+	"or":      reflect.ValueOf(or),
+	"print":   reflect.ValueOf(fmt.Sprint),
+	"printf":  reflect.ValueOf(fmt.Sprintf),
+	"println": reflect.ValueOf(fmt.Sprintln),
 }
 
 // addFuncs adds to values the functions in funcs, converting them to reflect.Values.
@@ -119,22 +122,39 @@ func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
 
 // Boolean logic.
 
-// and returns the Boolean AND of its arguments.
-func and(arg0 interface{}, args ...interface{}) (truth bool) {
-	truth, _ = isTrue(reflect.ValueOf(arg0))
-	for i := 0; truth && i < len(args); i++ {
-		truth, _ = isTrue(reflect.ValueOf(args[i]))
+func truth(a interface{}) bool {
+	t, _ := isTrue(reflect.ValueOf(a))
+	return t
+}
+
+// and computes the Boolean AND of its arguments, returning
+// the first false argument it encounters, or the last argument.
+func and(arg0 interface{}, args ...interface{}) interface{} {
+	if !truth(arg0) {
+		return arg0
+	}
+	for i := range args {
+		arg0 = args[i]
+		if !truth(arg0) {
+			break
+		}
 	}
-	return
+	return arg0
 }
 
-// or returns the Boolean OR of its arguments.
-func or(arg0 interface{}, args ...interface{}) (truth bool) {
-	truth, _ = isTrue(reflect.ValueOf(arg0))
-	for i := 0; !truth && i < len(args); i++ {
-		truth, _ = isTrue(reflect.ValueOf(args[i]))
+// or computes the Boolean OR of its arguments, returning
+// the first true argument it encounters, or the last argument.
+func or(arg0 interface{}, args ...interface{}) interface{} {
+	if truth(arg0) {
+		return arg0
 	}
-	return
+	for i := range args {
+		arg0 = args[i]
+		if truth(arg0) {
+			break
+		}
+	}
+	return arg0
 }
 
 // not returns the Boolean negation of its argument.
@@ -213,23 +233,24 @@ var (
 	jsBackslash = []byte(`\\`)
 	jsApos      = []byte(`\'`)
 	jsQuot      = []byte(`\"`)
+	jsLt        = []byte(`\x3C`)
+	jsGt        = []byte(`\x3E`)
 )
 
-
 // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
 func JSEscape(w io.Writer, b []byte) {
 	last := 0
 	for i := 0; i < len(b); i++ {
 		c := b[i]
 
-		if ' ' <= c && c < utf8.RuneSelf && c != '\\' && c != '"' && c != '\'' {
+		if !jsIsSpecial(int(c)) {
 			// fast path: nothing to do
 			continue
 		}
 		w.Write(b[last:i])
 
 		if c < utf8.RuneSelf {
-			// Quotes and slashes get quoted.
+			// Quotes, slashes and angle brackets get quoted.
 			// Control characters get written as \u00XX.
 			switch c {
 			case '\\':
@@ -238,6 +259,10 @@ func JSEscape(w io.Writer, b []byte) {
 				w.Write(jsApos)
 			case '"':
 				w.Write(jsQuot)
+			case '<':
+				w.Write(jsLt)
+			case '>':
+				w.Write(jsGt)
 			default:
 				w.Write(jsLowUni)
 				t, b := c>>4, c&0x0f
@@ -273,7 +298,7 @@ func JSEscapeString(s string) string {
 
 func jsIsSpecial(rune int) bool {
 	switch rune {
-	case '\\', '\'', '"':
+	case '\\', '\'', '"', '<', '>':
 		return true
 	}
 	return rune < ' ' || utf8.RuneSelf <= rune
diff --git a/src/pkg/exp/template/helper.go b/src/pkg/exp/template/helper.go
new file mode 100644
index 0000000..4187897
--- /dev/null
+++ b/src/pkg/exp/template/helper.go
@@ -0,0 +1,234 @@
+// 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.
+
+// Helper functions to make constructing templates and sets easier.
+
+package template
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+)
+
+// Functions and methods to parse a single template.
+
+// Must is a helper that wraps a call to a function returning (*Template, os.Error)
+// and panics if the error is non-nil. It is intended for use in variable initializations
+// such as
+//	var t = template.Must(template.Parse("text"))
+func Must(t *Template, err os.Error) *Template {
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+// ParseFile creates a new Template and parses the template definition from
+// the named file.  The template name is the base name of the file.
+func ParseFile(filename string) (*Template, os.Error) {
+	t := New(filepath.Base(filename))
+	return t.ParseFile(filename)
+}
+
+// parseFileInSet creates a new Template and parses the template
+// definition from the named file. The template name is the base name
+// of the file. It also adds the template to the set. Function bindings are
+// checked against those in the set.
+func parseFileInSet(filename string, set *Set) (*Template, os.Error) {
+	t := New(filepath.Base(filename))
+	return t.parseFileInSet(filename, set)
+}
+
+// ParseFile reads the template definition from a file and parses it to
+// construct an internal representation of the template for execution.
+func (t *Template) ParseFile(filename string) (*Template, os.Error) {
+	b, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return t, err
+	}
+	return t.Parse(string(b))
+}
+
+// parseFileInSet is the same as ParseFile except that function bindings
+// are checked against those in the set and the template is added
+// to the set.
+func (t *Template) parseFileInSet(filename string, set *Set) (*Template, os.Error) {
+	b, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return t, err
+	}
+	return t.ParseInSet(string(b), set)
+}
+
+// Functions and methods to parse a set.
+
+// SetMust is a helper that wraps a call to a function returning (*Set, os.Error)
+// and panics if the error is non-nil. It is intended for use in variable initializations
+// such as
+//	var s = template.SetMust(template.ParseSetFile("file"))
+func SetMust(s *Set, err os.Error) *Set {
+	if err != nil {
+		panic(err)
+	}
+	return s
+}
+
+// ParseFile parses the named files into a set of named templates.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func (s *Set) ParseFile(filenames ...string) (*Set, os.Error) {
+	for _, filename := range filenames {
+		b, err := ioutil.ReadFile(filename)
+		if err != nil {
+			return s, err
+		}
+		_, err = s.Parse(string(b))
+		if err != nil {
+			return s, err
+		}
+	}
+	return s, nil
+}
+
+// ParseSetFile creates a new Set and parses the set definition from the
+// named files. Each file must be individually parseable.
+func ParseSetFile(filenames ...string) (*Set, os.Error) {
+	s := new(Set)
+	for _, filename := range filenames {
+		b, err := ioutil.ReadFile(filename)
+		if err != nil {
+			return s, err
+		}
+		_, err = s.Parse(string(b))
+		if err != nil {
+			return s, err
+		}
+	}
+	return s, nil
+}
+
+// ParseFiles parses the set definition from the files identified by the
+// pattern.  The pattern is processed by filepath.Glob and must match at
+// least one file.
+func (s *Set) ParseFiles(pattern string) (*Set, os.Error) {
+	filenames, err := filepath.Glob(pattern)
+	if err != nil {
+		return s, err
+	}
+	if len(filenames) == 0 {
+		return s, fmt.Errorf("pattern matches no files: %#q", pattern)
+	}
+	return s.ParseFile(filenames...)
+}
+
+// ParseSetFiles creates a new Set and parses the set definition from the
+// files identified by the pattern. The pattern is processed by filepath.Glob
+// and must match at least one file.
+func ParseSetFiles(pattern string) (*Set, os.Error) {
+	set, err := new(Set).ParseFiles(pattern)
+	if err != nil {
+		return set, err
+	}
+	return set, nil
+}
+
+// Functions and methods to parse stand-alone template files into a set.
+
+// ParseTemplateFile parses the named template files and adds
+// them to the set. Each template will named the base name of
+// its file.
+// Unlike with ParseFile, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFile is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func (s *Set) ParseTemplateFile(filenames ...string) (*Set, os.Error) {
+	for _, filename := range filenames {
+		_, err := parseFileInSet(filename, s)
+		if err != nil {
+			return s, err
+		}
+	}
+	return s, nil
+}
+
+// ParseTemplateFiles parses the template files matched by the
+// patern and adds them to the set. Each template will named
+// the base name of its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func (s *Set) ParseTemplateFiles(pattern string) (*Set, os.Error) {
+	filenames, err := filepath.Glob(pattern)
+	if err != nil {
+		return s, err
+	}
+	for _, filename := range filenames {
+		_, err := parseFileInSet(filename, s)
+		if err != nil {
+			return s, err
+		}
+	}
+	return s, nil
+}
+
+// ParseTemplateFile creates a set by parsing the named files,
+// each of which defines a single template. Each template will
+// named the base name of its file.
+// Unlike with ParseFile, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFile is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateFile(filenames ...string) (*Set, os.Error) {
+	set := new(Set)
+	for _, filename := range filenames {
+		t, err := ParseFile(filename)
+		if err != nil {
+			return set, err
+		}
+		if err := set.add(t); err != nil {
+			return set, err
+		}
+	}
+	return set, nil
+}
+
+// ParseTemplateFiles creates a set by parsing the files matched
+// by the pattern, each of which defines a single template. Each
+// template will named the base name of its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateFiles(pattern string) (*Set, os.Error) {
+	set := new(Set)
+	filenames, err := filepath.Glob(pattern)
+	if err != nil {
+		return set, err
+	}
+	for _, filename := range filenames {
+		t, err := ParseFile(filename)
+		if err != nil {
+			return set, err
+		}
+		if err := set.add(t); err != nil {
+			return set, err
+		}
+	}
+	return set, nil
+}
diff --git a/src/pkg/exp/template/lex.go b/src/pkg/exp/template/lex.go
index d781529..97f4e9d 100644
--- a/src/pkg/exp/template/lex.go
+++ b/src/pkg/exp/template/lex.go
@@ -35,9 +35,12 @@ func (i item) String() string {
 type itemType int
 
 const (
-	itemError   itemType = iota // error occurred; value is text of error
-	itemBool                    // boolean constant
-	itemComplex                 // complex constant (1+2i); imaginary is just a number
+	itemError        itemType = iota // error occurred; value is text of error
+	itemBool                         // boolean constant
+	itemChar                         // printable ASCII character; grab bag for comma etc.
+	itemCharConstant                 // character constant
+	itemComplex                      // complex constant (1+2i); imaginary is just a number
+	itemColonEquals                  // colon-equals (':=') introducing a declaration
 	itemEOF
 	itemField      // alphanumeric identifier, starting with '.', possibly chained ('.x.y')
 	itemIdentifier // alphanumeric identifier
@@ -48,6 +51,7 @@ const (
 	itemRightDelim // right action delimiter
 	itemString     // quoted string (includes quotes)
 	itemText       // plain text
+	itemVariable   // variable starting with '$', such as '$' or  '$1' or '$hello'.
 	// Keywords appear after all the rest.
 	itemKeyword  // used only to delimit the keywords
 	itemDot      // the cursor, spelled '.'.
@@ -62,18 +66,22 @@ const (
 
 // Make the types prettyprint.
 var itemName = map[itemType]string{
-	itemError:      "error",
-	itemBool:       "bool",
-	itemComplex:    "complex",
-	itemEOF:        "EOF",
-	itemField:      "field",
-	itemIdentifier: "identifier",
-	itemLeftDelim:  "left delim",
-	itemNumber:     "number",
-	itemPipe:       "pipe",
-	itemRawString:  "raw string",
-	itemRightDelim: "right delim",
-	itemString:     "string",
+	itemError:        "error",
+	itemBool:         "bool",
+	itemChar:         "char",
+	itemCharConstant: "charconst",
+	itemComplex:      "complex",
+	itemColonEquals:  ":=",
+	itemEOF:          "EOF",
+	itemField:        "field",
+	itemIdentifier:   "identifier",
+	itemLeftDelim:    "left delim",
+	itemNumber:       "number",
+	itemPipe:         "pipe",
+	itemRawString:    "raw string",
+	itemRightDelim:   "right delim",
+	itemString:       "string",
+	itemVariable:     "variable",
 	// keywords
 	itemDot:      ".",
 	itemDefine:   "define",
@@ -279,12 +287,21 @@ func lexInsideAction(l *lexer) stateFn {
 			return l.errorf("unclosed action")
 		case isSpace(r):
 			l.ignore()
+		case r == ':':
+			if l.next() != '=' {
+				return l.errorf("expected :=")
+			}
+			l.emit(itemColonEquals)
 		case r == '|':
 			l.emit(itemPipe)
 		case r == '"':
 			return lexQuote
 		case r == '`':
 			return lexRawQuote
+		case r == '$':
+			return lexIdentifier
+		case r == '\'':
+			return lexChar
 		case r == '.':
 			// special look-ahead for ".field" so we don't break l.backup().
 			if l.pos < len(l.input) {
@@ -300,6 +317,9 @@ func lexInsideAction(l *lexer) stateFn {
 		case isAlphaNumeric(r):
 			l.backup()
 			return lexIdentifier
+		case r <= unicode.MaxASCII && unicode.IsPrint(r):
+			l.emit(itemChar)
+			return lexInsideAction
 		default:
 			return l.errorf("unrecognized character in action: %#U", r)
 		}
@@ -314,7 +334,7 @@ Loop:
 		switch r := l.next(); {
 		case isAlphaNumeric(r):
 			// absorb.
-		case r == '.' && l.input[l.start] == '.':
+		case r == '.' && (l.input[l.start] == '.' || l.input[l.start] == '$'):
 			// field chaining; absorb into one token.
 		default:
 			l.backup()
@@ -324,6 +344,8 @@ Loop:
 				l.emit(key[word])
 			case word[0] == '.':
 				l.emit(itemField)
+			case word[0] == '$':
+				l.emit(itemVariable)
 			case word == "true", word == "false":
 				l.emit(itemBool)
 			default:
@@ -335,6 +357,27 @@ Loop:
 	return lexInsideAction
 }
 
+// lexChar scans a character constant. The initial quote is already
+// scanned.  Syntax checking is done by the parse.
+func lexChar(l *lexer) stateFn {
+Loop:
+	for {
+		switch l.next() {
+		case '\\':
+			if r := l.next(); r != eof && r != '\n' {
+				break
+			}
+			fallthrough
+		case eof, '\n':
+			return l.errorf("unterminated character constant")
+		case '\'':
+			break Loop
+		}
+	}
+	l.emit(itemCharConstant)
+	return lexInsideAction
+}
+
 // lexNumber scans a number: decimal, octal, hex, float, or imaginary.  This
 // isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
 // and "089" - but when it's wrong the input is invalid and the parser (via
diff --git a/src/pkg/exp/template/lex_test.go b/src/pkg/exp/template/lex_test.go
index 256ec04..a585a41 100644
--- a/src/pkg/exp/template/lex_test.go
+++ b/src/pkg/exp/template/lex_test.go
@@ -36,6 +36,14 @@ var lexTests = []lexTest{
 		{itemText, "-world"},
 		tEOF,
 	}},
+	{"punctuation", "{{,@%}}", []item{
+		tLeft,
+		{itemChar, ","},
+		{itemChar, "@"},
+		{itemChar, "%"},
+		tRight,
+		tEOF,
+	}},
 	{"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
 	{"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
 	{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
@@ -53,6 +61,18 @@ var lexTests = []lexTest{
 		tRight,
 		tEOF,
 	}},
+	{"characters", `{{'a' '\n' '\'' '\\' '\u00FF' '\xFF' '本'}}`, []item{
+		tLeft,
+		{itemCharConstant, `'a'`},
+		{itemCharConstant, `'\n'`},
+		{itemCharConstant, `'\''`},
+		{itemCharConstant, `'\\'`},
+		{itemCharConstant, `'\u00FF'`},
+		{itemCharConstant, `'\xFF'`},
+		{itemCharConstant, `'本'`},
+		tRight,
+		tEOF,
+	}},
 	{"bools", "{{true false}}", []item{
 		tLeft,
 		{itemBool, "true"},
@@ -85,6 +105,20 @@ var lexTests = []lexTest{
 		tRight,
 		tEOF,
 	}},
+	{"variables", "{{$c := printf $ $hello $23 $ $var.Field .Method}}", []item{
+		tLeft,
+		{itemVariable, "$c"},
+		{itemColonEquals, ":="},
+		{itemIdentifier, "printf"},
+		{itemVariable, "$"},
+		{itemVariable, "$hello"},
+		{itemVariable, "$23"},
+		{itemVariable, "$"},
+		{itemVariable, "$var.Field"},
+		{itemField, ".Method"},
+		tRight,
+		tEOF,
+	}},
 	{"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
 		{itemText, "intro "},
 		tLeft,
@@ -101,11 +135,29 @@ var lexTests = []lexTest{
 		{itemText, " outro"},
 		tEOF,
 	}},
+	{"declaration", "{{$v := 3}}", []item{
+		tLeft,
+		{itemVariable, "$v"},
+		{itemColonEquals, ":="},
+		{itemNumber, "3"},
+		tRight,
+		tEOF,
+	}},
+	{"2 declarations", "{{$v , $w := 3}}", []item{
+		tLeft,
+		{itemVariable, "$v"},
+		{itemChar, ","},
+		{itemVariable, "$w"},
+		{itemColonEquals, ":="},
+		{itemNumber, "3"},
+		tRight,
+		tEOF,
+	}},
 	// errors
-	{"badchar", "#{{#}}", []item{
+	{"badchar", "#{{\x01}}", []item{
 		{itemText, "#"},
 		tLeft,
-		{itemError, "unrecognized character in action: U+0023 '#'"},
+		{itemError, "unrecognized character in action: U+0001"},
 	}},
 	{"unclosed action", "{{\n}}", []item{
 		tLeft,
@@ -124,6 +176,10 @@ var lexTests = []lexTest{
 		tLeft,
 		{itemError, "unterminated raw quoted string"},
 	}},
+	{"unclosed char constant", "{{'\n}}", []item{
+		tLeft,
+		{itemError, "unterminated character constant"},
+	}},
 	{"bad number", "{{3k}}", []item{
 		tLeft,
 		{itemError, `bad number syntax: "3k"`},
diff --git a/src/pkg/exp/template/parse.go b/src/pkg/exp/template/parse.go
index 8b2d602..8a0b51e 100644
--- a/src/pkg/exp/template/parse.go
+++ b/src/pkg/exp/template/parse.go
@@ -20,36 +20,49 @@ type Template struct {
 	name  string
 	root  *listNode
 	funcs map[string]reflect.Value
+	set   *Set // can be nil.
 	// Parsing only; cleared after parse.
-	set      *Set
-	lex      *lexer
-	token    item // token lookahead for parser
-	havePeek bool
+	parseSet  *Set // for function lookup during parse.
+	lex       *lexer
+	token     [2]item // two-token lookahead for parser.
+	peekCount int
+	vars      []string // variables defined at the moment.
+}
+
+// Name returns the name of the template.
+func (t *Template) Name() string {
+	return t.name
 }
 
 // next returns the next token.
 func (t *Template) next() item {
-	if t.havePeek {
-		t.havePeek = false
+	if t.peekCount > 0 {
+		t.peekCount--
 	} else {
-		t.token = t.lex.nextItem()
+		t.token[0] = t.lex.nextItem()
 	}
-	return t.token
+	return t.token[t.peekCount]
 }
 
 // backup backs the input stream up one token.
 func (t *Template) backup() {
-	t.havePeek = true
+	t.peekCount++
+}
+
+// backup2 backs the input stream up two tokens
+func (t *Template) backup2(t1 item) {
+	t.token[1] = t1
+	t.peekCount = 2
 }
 
 // peek returns but does not consume the next token.
 func (t *Template) peek() item {
-	if t.havePeek {
-		return t.token
+	if t.peekCount > 0 {
+		return t.token[t.peekCount-1]
 	}
-	t.token = t.lex.nextItem()
-	t.havePeek = true
-	return t.token
+	t.peekCount = 1
+	t.token[0] = t.lex.nextItem()
+	return t.token[0]
 }
 
 // A node is an element in the parse tree. The interface is trivial.
@@ -76,9 +89,11 @@ const (
 	nodeIf
 	nodeList
 	nodeNumber
+	nodePipe
 	nodeRange
 	nodeString
 	nodeTemplate
+	nodeVariable
 	nodeWith
 )
 
@@ -122,23 +137,42 @@ func (t *textNode) String() string {
 	return fmt.Sprintf("(text: %q)", t.text)
 }
 
-// actionNode holds an action (something bounded by delimiters).
-type actionNode struct {
+// pipeNode holds a pipeline with optional declaration
+type pipeNode struct {
 	nodeType
-	line     int
-	pipeline []*commandNode
+	line int
+	decl []*variableNode
+	cmds []*commandNode
 }
 
-func newAction(line int, pipeline []*commandNode) *actionNode {
-	return &actionNode{nodeType: nodeAction, line: line, pipeline: pipeline}
+func newPipeline(line int, decl []*variableNode) *pipeNode {
+	return &pipeNode{nodeType: nodePipe, line: line, decl: decl}
+}
+
+func (p *pipeNode) append(command *commandNode) {
+	p.cmds = append(p.cmds, command)
+}
+
+func (p *pipeNode) String() string {
+	if p.decl != nil {
+		return fmt.Sprintf("%v := %v", p.decl, p.cmds)
+	}
+	return fmt.Sprintf("%v", p.cmds)
+}
+
+// actionNode holds an action (something bounded by delimiters).
+type actionNode struct {
+	nodeType
+	line int
+	pipe *pipeNode
 }
 
-func (a *actionNode) append(command *commandNode) {
-	a.pipeline = append(a.pipeline, command)
+func newAction(line int, pipe *pipeNode) *actionNode {
+	return &actionNode{nodeType: nodeAction, line: line, pipe: pipe}
 }
 
 func (a *actionNode) String() string {
-	return fmt.Sprintf("(action: %v)", a.pipeline)
+	return fmt.Sprintf("(action: %v)", a.pipe)
 }
 
 // commandNode holds a command (a pipeline inside an evaluating action).
@@ -173,6 +207,20 @@ func (i *identifierNode) String() string {
 	return fmt.Sprintf("I=%s", i.ident)
 }
 
+// variableNode holds a variable.
+type variableNode struct {
+	nodeType
+	ident []string
+}
+
+func newVariable(ident string) *variableNode {
+	return &variableNode{nodeType: nodeVariable, ident: strings.Split(ident, ".")}
+}
+
+func (v *variableNode) String() string {
+	return fmt.Sprintf("V=%s", v.ident)
+}
+
 // dotNode holds the special identifier '.'. It is represented by a nil pointer.
 type dotNode bool
 
@@ -237,9 +285,25 @@ type numberNode struct {
 	text       string
 }
 
-func newNumber(text string, isComplex bool) (*numberNode, os.Error) {
+func newNumber(text string, typ itemType) (*numberNode, os.Error) {
 	n := &numberNode{nodeType: nodeNumber, text: text}
-	if isComplex {
+	switch typ {
+	case itemCharConstant:
+		rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
+		if err != nil {
+			return nil, err
+		}
+		if tail != "'" {
+			return nil, fmt.Errorf("malformed character constant: %s", text)
+		}
+		n.int64 = int64(rune)
+		n.isInt = true
+		n.uint64 = uint64(rune)
+		n.isUint = true
+		n.float64 = float64(rune) // odd but those are the rules.
+		n.isFloat = true
+		return n, nil
+	case itemComplex:
 		// fmt.Sscan can parse the pair, so let it do the work.
 		if _, err := fmt.Sscan(text, &n.complex128); err != nil {
 			return nil, err
@@ -370,83 +434,85 @@ func (e *elseNode) String() string {
 	return "{{else}}"
 }
 // ifNode represents an {{if}} action and its commands.
-// TODO: what should evaluation look like? is a pipeline enough?
+// TODO: what should evaluation look like? is a pipe enough?
 type ifNode struct {
 	nodeType
 	line     int
-	pipeline []*commandNode
+	pipe     *pipeNode
 	list     *listNode
 	elseList *listNode
 }
 
-func newIf(line int, pipeline []*commandNode, list, elseList *listNode) *ifNode {
-	return &ifNode{nodeType: nodeIf, line: line, pipeline: pipeline, list: list, elseList: elseList}
+func newIf(line int, pipe *pipeNode, list, elseList *listNode) *ifNode {
+	return &ifNode{nodeType: nodeIf, line: line, pipe: pipe, list: list, elseList: elseList}
 }
 
 func (i *ifNode) String() string {
 	if i.elseList != nil {
-		return fmt.Sprintf("({{if %s}} %s {{else}} %s)", i.pipeline, i.list, i.elseList)
+		return fmt.Sprintf("({{if %s}} %s {{else}} %s)", i.pipe, i.list, i.elseList)
 	}
-	return fmt.Sprintf("({{if %s}} %s)", i.pipeline, i.list)
+	return fmt.Sprintf("({{if %s}} %s)", i.pipe, i.list)
 }
 
 // rangeNode represents a {{range}} action and its commands.
 type rangeNode struct {
 	nodeType
 	line     int
-	pipeline []*commandNode
+	pipe     *pipeNode
 	list     *listNode
 	elseList *listNode
 }
 
-func newRange(line int, pipeline []*commandNode, list, elseList *listNode) *rangeNode {
-	return &rangeNode{nodeType: nodeRange, line: line, pipeline: pipeline, list: list, elseList: elseList}
+func newRange(line int, pipe *pipeNode, list, elseList *listNode) *rangeNode {
+	return &rangeNode{nodeType: nodeRange, line: line, pipe: pipe, list: list, elseList: elseList}
 }
 
 func (r *rangeNode) String() string {
 	if r.elseList != nil {
-		return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.pipeline, r.list, r.elseList)
+		return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.pipe, r.list, r.elseList)
 	}
-	return fmt.Sprintf("({{range %s}} %s)", r.pipeline, r.list)
+	return fmt.Sprintf("({{range %s}} %s)", r.pipe, r.list)
 }
 
 // templateNode represents a {{template}} action.
 type templateNode struct {
 	nodeType
-	line     int
-	name     node
-	pipeline []*commandNode
+	line int
+	name string
+	pipe *pipeNode
 }
 
-func newTemplate(line int, name node, pipeline []*commandNode) *templateNode {
-	return &templateNode{nodeType: nodeTemplate, line: line, name: name, pipeline: pipeline}
+func newTemplate(line int, name string, pipe *pipeNode) *templateNode {
+	return &templateNode{nodeType: nodeTemplate, line: line, name: name, pipe: pipe}
 }
 
 func (t *templateNode) String() string {
-	return fmt.Sprintf("{{template %s %s}}", t.name, t.pipeline)
+	if t.pipe == nil {
+		return fmt.Sprintf("{{template %q}}", t.name)
+	}
+	return fmt.Sprintf("{{template %q %s}}", t.name, t.pipe)
 }
 
 // withNode represents a {{with}} action and its commands.
 type withNode struct {
 	nodeType
 	line     int
-	pipeline []*commandNode
+	pipe     *pipeNode
 	list     *listNode
 	elseList *listNode
 }
 
-func newWith(line int, pipeline []*commandNode, list, elseList *listNode) *withNode {
-	return &withNode{nodeType: nodeWith, line: line, pipeline: pipeline, list: list, elseList: elseList}
+func newWith(line int, pipe *pipeNode, list, elseList *listNode) *withNode {
+	return &withNode{nodeType: nodeWith, line: line, pipe: pipe, list: list, elseList: elseList}
 }
 
 func (w *withNode) String() string {
 	if w.elseList != nil {
-		return fmt.Sprintf("({{with %s}} %s {{else}} %s)", w.pipeline, w.list, w.elseList)
+		return fmt.Sprintf("({{with %s}} %s {{else}} %s)", w.pipe, w.list, w.elseList)
 	}
-	return fmt.Sprintf("({{with %s}} %s)", w.pipeline, w.list)
+	return fmt.Sprintf("({{with %s}} %s)", w.pipe, w.list)
 }
 
-
 // Parsing.
 
 // New allocates a new template with the given name.
@@ -457,9 +523,9 @@ func New(name string) *Template {
 	}
 }
 
-// Funcs adds to the template's function map the elements of the
-// argument map.   It panics if a value in the map is not a function
-// with appropriate return type.
+// Funcs adds the elements of the argument map to the template's function
+// map.  It panics if a value in the map is not a function with appropriate
+// return type.
 // The return value is the template, so calls can be chained.
 func (t *Template) Funcs(funcMap FuncMap) *Template {
 	addFuncs(t.funcs, funcMap)
@@ -509,13 +575,16 @@ func (t *Template) recover(errp *os.Error) {
 // startParse starts the template parsing from the lexer.
 func (t *Template) startParse(set *Set, lex *lexer) {
 	t.root = nil
-	t.set = set
 	t.lex = lex
+	t.vars = []string{"$"}
+	t.parseSet = set
 }
 
 // stopParse terminates parsing.
 func (t *Template) stopParse() {
-	t.set, t.lex = nil, nil
+	t.lex = nil
+	t.vars = nil
+	t.parseSet = nil
 }
 
 // atEOF returns true if, possibly after spaces, we're at EOF.
@@ -539,27 +608,40 @@ func (t *Template) atEOF() bool {
 	return false
 }
 
-// Parse parses the template definition string to construct an internal representation
-// of the template for execution.
-func (t *Template) Parse(s string) (err os.Error) {
-	t.startParse(nil, lex(t.name, s))
+// Parse parses the template definition string to construct an internal
+// representation of the template for execution.
+func (t *Template) Parse(s string) (tmpl *Template, err os.Error) {
 	defer t.recover(&err)
+	t.startParse(t.set, lex(t.name, s))
 	t.parse(true)
 	t.stopParse()
-	return
+	return t, nil
 }
 
-// ParseInSet parses the template definition string to construct an internal representation
-// of the template for execution. Function bindings are checked against those in the set.
-func (t *Template) ParseInSet(s string, set *Set) (err os.Error) {
-	t.startParse(set, lex(t.name, s))
+// ParseInSet parses the template definition string to construct an internal
+// representation of the template for execution. It also adds the template
+// to the set.
+// Function bindings are checked against those in the set.
+func (t *Template) ParseInSet(s string, set *Set) (tmpl *Template, err os.Error) {
 	defer t.recover(&err)
+	t.startParse(set, lex(t.name, s))
 	t.parse(true)
 	t.stopParse()
-	return
+	t.addToSet(set)
+	return t, nil
+}
+
+// addToSet adds the template to the set, verifying it's not being double-assigned.
+func (t *Template) addToSet(set *Set) {
+	if set == nil || t.set == set {
+		return
+	}
+	// If double-assigned, Add will panic and we will turn that into an error.
+	set.Add(t)
 }
 
-// parse is the helper for Parse. It triggers an error if we expect EOF but don't reach it.
+// parse is the helper for Parse.
+// It triggers an error if we expect EOF but don't reach it.
 func (t *Template) parse(toEOF bool) (next node) {
 	t.root, next = t.itemList(true)
 	if toEOF && next != nil {
@@ -623,23 +705,51 @@ func (t *Template) action() (n node) {
 		return t.withControl()
 	}
 	t.backup()
+	// Do not pop variables; they persist until "end".
 	return newAction(t.lex.lineNumber(), t.pipeline("command"))
 }
 
 // Pipeline:
 //	field or command
 //	pipeline "|" pipeline
-func (t *Template) pipeline(context string) (pipe []*commandNode) {
+func (t *Template) pipeline(context string) (pipe *pipeNode) {
+	var decl []*variableNode
+	// Are there declarations?
+	for {
+		if v := t.peek(); v.typ == itemVariable {
+			t.next()
+			if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
+				t.next()
+				variable := newVariable(v.val)
+				if len(variable.ident) != 1 {
+					t.errorf("illegal variable in declaration: %s", v.val)
+				}
+				decl = append(decl, variable)
+				t.vars = append(t.vars, v.val)
+				if next.typ == itemChar && next.val == "," {
+					if context == "range" && len(decl) < 2 {
+						continue
+					}
+					t.errorf("too many declarations in %s", context)
+				}
+			} else {
+				t.backup2(v)
+			}
+		}
+		break
+	}
+	pipe = newPipeline(t.lex.lineNumber(), decl)
 	for {
 		switch token := t.next(); token.typ {
 		case itemRightDelim:
-			if len(pipe) == 0 {
+			if len(pipe.cmds) == 0 {
 				t.errorf("missing value for %s", context)
 			}
 			return
-		case itemBool, itemComplex, itemDot, itemField, itemIdentifier, itemNumber, itemRawString, itemString:
+		case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
+			itemVariable, itemNumber, itemRawString, itemString:
 			t.backup()
-			pipe = append(pipe, t.command())
+			pipe.append(t.command())
 		default:
 			t.unexpected(token, context)
 		}
@@ -647,8 +757,9 @@ func (t *Template) pipeline(context string) (pipe []*commandNode) {
 	return
 }
 
-func (t *Template) parseControl(context string) (lineNum int, pipe []*commandNode, list, elseList *listNode) {
+func (t *Template) parseControl(context string) (lineNum int, pipe *pipeNode, list, elseList *listNode) {
 	lineNum = t.lex.lineNumber()
+	defer t.popVars(len(t.vars))
 	pipe = t.pipeline(context)
 	var next node
 	list, next = t.itemList(false)
@@ -688,7 +799,6 @@ func (t *Template) withControl() node {
 	return newWith(t.parseControl("with"))
 }
 
-
 // End:
 //	{{end}}
 // End keyword is past.
@@ -710,28 +820,24 @@ func (t *Template) elseControl() node {
 // Template keyword is past.  The name must be something that can evaluate
 // to a string.
 func (t *Template) templateControl() node {
-	var name node
+	var name string
 	switch token := t.next(); token.typ {
-	case itemIdentifier:
-		if _, ok := findFunction(token.val, t, t.set); !ok {
-			t.errorf("function %q not defined", token.val)
-		}
-		name = newIdentifier(token.val)
-	case itemDot:
-		name = newDot()
-	case itemField:
-		name = newField(token.val)
 	case itemString, itemRawString:
 		s, err := strconv.Unquote(token.val)
 		if err != nil {
 			t.error(err)
 		}
-		name = newString(s)
+		name = s
 	default:
 		t.unexpected(token, "template invocation")
 	}
-	pipeline := t.pipeline("template")
-	return newTemplate(t.lex.lineNumber(), name, pipeline)
+	var pipe *pipeNode
+	if t.next().typ != itemRightDelim {
+		t.backup()
+		// Do not pop variables; they persist until "end".
+		pipe = t.pipeline("template")
+	}
+	return newTemplate(t.lex.lineNumber(), name, pipe)
 }
 
 // command:
@@ -750,18 +856,20 @@ Loop:
 		case itemError:
 			t.errorf("%s", token.val)
 		case itemIdentifier:
-			if _, ok := findFunction(token.val, t, t.set); !ok {
+			if _, ok := findFunction(token.val, t, t.parseSet); !ok {
 				t.errorf("function %q not defined", token.val)
 			}
 			cmd.append(newIdentifier(token.val))
 		case itemDot:
 			cmd.append(newDot())
+		case itemVariable:
+			cmd.append(t.useVar(token.val))
 		case itemField:
 			cmd.append(newField(token.val))
 		case itemBool:
 			cmd.append(newBool(token.val == "true"))
-		case itemComplex, itemNumber:
-			number, err := newNumber(token.val, token.typ == itemComplex)
+		case itemCharConstant, itemComplex, itemNumber:
+			number, err := newNumber(token.val, token.typ)
 			if err != nil {
 				t.error(err)
 			}
@@ -781,3 +889,21 @@ Loop:
 	}
 	return cmd
 }
+
+// popVars trims the variable list to the specified length
+func (t *Template) popVars(n int) {
+	t.vars = t.vars[:n]
+}
+
+// useVar returns a node for a variable reference. It errors if the
+// variable is not defined.
+func (t *Template) useVar(name string) node {
+	v := newVariable(name)
+	for _, varName := range t.vars {
+		if varName == v.ident[0] {
+			return v
+		}
+	}
+	t.errorf("undefined variable %q", v.ident[0])
+	return nil
+}
diff --git a/src/pkg/exp/template/parse_test.go b/src/pkg/exp/template/parse_test.go
index 71580f8..fb8956a 100644
--- a/src/pkg/exp/template/parse_test.go
+++ b/src/pkg/exp/template/parse_test.go
@@ -29,6 +29,8 @@ var numberTests = []numberTest{
 	{"0", true, true, true, false, 0, 0, 0, 0},
 	{"-0", true, true, true, false, 0, 0, 0, 0}, // check that -0 is a uint.
 	{"73", true, true, true, false, 73, 73, 73, 0},
+	{"073", true, true, true, false, 073, 073, 073, 0},
+	{"0x73", true, true, true, false, 0x73, 0x73, 0x73, 0},
 	{"-73", true, false, true, false, -73, 0, -73, 0},
 	{"+73", true, false, true, false, 73, 0, 73, 0},
 	{"100", true, true, true, false, 100, 100, 100, 0},
@@ -39,6 +41,7 @@ var numberTests = []numberTest{
 	{"-1e19", false, false, true, false, 0, 0, -1e19, 0},
 	{"4i", false, false, false, true, 0, 0, 0, 4i},
 	{"-1.2+4.2i", false, false, false, true, 0, 0, 0, -1.2 + 4.2i},
+	{"073i", false, false, false, true, 0, 0, 0, 73i}, // not octal!
 	// complex with 0 imaginary are float (and maybe integer)
 	{"0i", true, true, true, true, 0, 0, 0, 0},
 	{"-1.2+0i", false, false, true, true, 0, 0, -1.2, -1.2},
@@ -48,12 +51,23 @@ var numberTests = []numberTest{
 	{"0123", true, true, true, false, 0123, 0123, 0123, 0},
 	{"-0x0", true, true, true, false, 0, 0, 0, 0},
 	{"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0},
+	// character constants
+	{`'a'`, true, true, true, false, 'a', 'a', 'a', 0},
+	{`'\n'`, true, true, true, false, '\n', '\n', '\n', 0},
+	{`'\\'`, true, true, true, false, '\\', '\\', '\\', 0},
+	{`'\''`, true, true, true, false, '\'', '\'', '\'', 0},
+	{`'\xFF'`, true, true, true, false, 0xFF, 0xFF, 0xFF, 0},
+	{`'パ'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+	{`'\u30d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+	{`'\U000030d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
 	// some broken syntax
 	{text: "+-2"},
 	{text: "0x123."},
 	{text: "1e."},
 	{text: "0xi."},
 	{text: "1+2."},
+	{text: "'x"},
+	{text: "'xx'"},
 }
 
 func TestNumberParse(t *testing.T) {
@@ -61,11 +75,19 @@ func TestNumberParse(t *testing.T) {
 		// If fmt.Sscan thinks it's complex, it's complex.  We can't trust the output
 		// because imaginary comes out as a number.
 		var c complex128
-		_, err := fmt.Sscan(test.text, &c)
-		n, err := newNumber(test.text, err == nil)
+		typ := itemNumber
+		if test.text[0] == '\'' {
+			typ = itemCharConstant
+		} else {
+			_, err := fmt.Sscan(test.text, &c)
+			if err == nil {
+				typ = itemComplex
+			}
+		}
+		n, err := newNumber(test.text, typ)
 		ok := test.isInt || test.isUint || test.isFloat || test.isComplex
 		if ok && err != nil {
-			t.Errorf("unexpected error for %q", test.text)
+			t.Errorf("unexpected error for %q: %s", test.text, err)
 			continue
 		}
 		if !ok && err == nil {
@@ -73,6 +95,9 @@ func TestNumberParse(t *testing.T) {
 			continue
 		}
 		if !ok {
+			if *debug {
+				fmt.Printf("%s\n\t%s\n", test.text, err)
+			}
 			continue
 		}
 		if n.isComplex != test.isComplex {
@@ -146,10 +171,20 @@ var parseTests = []parseTest{
 		`[(action: [(command: [F=[X]])])]`},
 	{"simple command", "{{printf}}", noError,
 		`[(action: [(command: [I=printf])])]`},
+	{"$ invocation", "{{$}}", noError,
+		"[(action: [(command: [V=[$]])])]"},
+	{"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError,
+		"[({{with [V=[$x]] := [(command: [N=3])]}} [(action: [(command: [V=[$x] N=23])])])]"},
+	{"variable with fields", "{{$.I}}", noError,
+		"[(action: [(command: [V=[$ I]])])]"},
 	{"multi-word command", "{{printf `%d` 23}}", noError,
 		"[(action: [(command: [I=printf S=`%d` N=23])])]"},
 	{"pipeline", "{{.X|.Y}}", noError,
 		`[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+	{"pipeline with decl", "{{$x := .X|.Y}}", noError,
+		`[(action: [V=[$x]] := [(command: [F=[X]]) (command: [F=[Y]])])]`},
+	{"declaration", "{{.X|.Y}}", noError,
+		`[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
 	{"simple if", "{{if .X}}hello{{end}}", noError,
 		`[({{if [(command: [F=[X]])]}} [(text: "hello")])]`},
 	{"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
@@ -166,25 +201,36 @@ var parseTests = []parseTest{
 		`[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
 	{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
 		`[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
-	{"constants", "{{range .SI 1 -3.2i true false }}{{end}}", noError,
-		`[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false])]}} [])]`},
-	{"template", "{{template `x` .Y}}", noError,
-		"[{{template S=`x` [(command: [F=[Y]])]}}]"},
+	{"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
+		`[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false N='a'])]}} [])]`},
+	{"template", "{{template `x`}}", noError,
+		`[{{template "x"}}]`},
+	{"template with arg", "{{template `x` .Y}}", noError,
+		`[{{template "x" [(command: [F=[Y]])]}}]`},
 	{"with", "{{with .X}}hello{{end}}", noError,
 		`[({{with [(command: [F=[X]])]}} [(text: "hello")])]`},
 	{"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
 		`[({{with [(command: [F=[X]])]}} [(text: "hello")] {{else}} [(text: "goodbye")])]`},
 	// Errors.
 	{"unclosed action", "hello{{range", hasError, ""},
+	{"unmatched end", "{{end}}", hasError, ""},
 	{"missing end", "hello{{range .x}}", hasError, ""},
 	{"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
 	{"undefined function", "hello{{undefined}}", hasError, ""},
+	{"undefined variable", "{{$x}}", hasError, ""},
+	{"variable undefined after end", "{{with $x := 4}}{{end}}{{$x}}", hasError, ""},
+	{"variable undefined in template", "{{template $v}}", hasError, ""},
+	{"declare with field", "{{with $x.Y := 4}}{{end}}", hasError, ""},
+	{"template with field ref", "{{template .X}}", hasError, ""},
+	{"template with var", "{{template $v}}", hasError, ""},
+	{"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
+	{"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
+	{"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
 }
 
 func TestParse(t *testing.T) {
 	for _, test := range parseTests {
-		tmpl := New(test.name)
-		err := tmpl.Parse(test.input)
+		tmpl, err := New(test.name).Parse(test.input)
 		switch {
 		case err == nil && !test.ok:
 			t.Errorf("%q: expected error; got none", test.name)
diff --git a/src/pkg/exp/template/set.go b/src/pkg/exp/template/set.go
index 492e270..a685e99 100644
--- a/src/pkg/exp/template/set.go
+++ b/src/pkg/exp/template/set.go
@@ -14,57 +14,71 @@ import (
 )
 
 // Set holds a set of related templates that can refer to one another by name.
+// The zero value represents an empty set.
 // A template may be a member of multiple sets.
 type Set struct {
 	tmpl  map[string]*Template
 	funcs map[string]reflect.Value
 }
 
-// NewSet allocates a new, empty template set.
-func NewSet() *Set {
-	return &Set{
-		tmpl:  make(map[string]*Template),
-		funcs: make(map[string]reflect.Value),
+func (s *Set) init() {
+	if s.tmpl == nil {
+		s.tmpl = make(map[string]*Template)
+		s.funcs = make(map[string]reflect.Value)
 	}
 }
 
-// Funcs adds to the set's function map the elements of the
-// argument map.   It panics if a value in the map is not a function
-// with appropriate return type.
+// Funcs adds the elements of the argument map to the set's function map.  It
+// panics if a value in the map is not a function with appropriate return
+// type.
 // The return value is the set, so calls can be chained.
 func (s *Set) Funcs(funcMap FuncMap) *Set {
+	s.init()
 	addFuncs(s.funcs, funcMap)
 	return s
 }
 
-// Add adds the argument templates to the set. It panics if the call
-// attempts to reuse a name defined in the template.
+// Add adds the argument templates to the set. It panics if two templates
+// with the same name are added or if a template is already a member of
+// a set.
 // The return value is the set, so calls can be chained.
 func (s *Set) Add(templates ...*Template) *Set {
 	for _, t := range templates {
-		if _, ok := s.tmpl[t.name]; ok {
-			panic(fmt.Errorf("template: %q already defined in set", t.name))
+		if err := s.add(t); err != nil {
+			panic(err)
 		}
-		s.tmpl[t.name] = t
 	}
 	return s
 }
 
+// add adds the argument template to the set.
+func (s *Set) add(t *Template) os.Error {
+	s.init()
+	if t.set != nil {
+		return fmt.Errorf("template: %q already in a set", t.name)
+	}
+	if _, ok := s.tmpl[t.name]; ok {
+		return fmt.Errorf("template: %q already defined in set", t.name)
+	}
+	s.tmpl[t.name] = t
+	t.set = s
+	return nil
+}
+
 // Template returns the template with the given name in the set,
 // or nil if there is no such template.
 func (s *Set) Template(name string) *Template {
 	return s.tmpl[name]
 }
 
-// Execute looks for the named template in the set and then applies that
-// template to the specified data object, writing the output to wr.  Nested
-// template invocations will be resolved from the set.
-func (s *Set) Execute(name string, wr io.Writer, data interface{}) os.Error {
+// Execute applies the named template to the specified data object, writing
+// the output to wr.
+func (s *Set) Execute(wr io.Writer, name string, data interface{}) os.Error {
 	tmpl := s.tmpl[name]
 	if tmpl == nil {
 		return fmt.Errorf("template: no template %q in set", name)
 	}
-	return tmpl.ExecuteInSet(wr, data, s)
+	return tmpl.Execute(wr, data)
 }
 
 // recover is the handler that turns panics into returns from the top
@@ -81,8 +95,13 @@ func (s *Set) recover(errp *os.Error) {
 	return
 }
 
-// Parse parses the file into a set of named templates.
-func (s *Set) Parse(text string) (err os.Error) {
+// Parse parses a string into a set of named templates.  Parse may be called
+// multiple times for a given set, adding the templates defined in the string
+// to the set.  If a template is redefined, the element in the set is
+// overwritten with the new definition.
+func (s *Set) Parse(text string) (set *Set, err os.Error) {
+	set = s
+	s.init()
 	defer s.recover(&err)
 	lex := lex("set", text)
 	const context = "define clause"
@@ -109,7 +128,8 @@ func (s *Set) Parse(text string) (err os.Error) {
 			t.errorf("unexpected %s in %s", end, context)
 		}
 		t.stopParse()
+		t.addToSet(s)
 		s.tmpl[t.name] = t
 	}
-	return nil
+	return s, nil
 }
diff --git a/src/pkg/exp/template/set_test.go b/src/pkg/exp/template/set_test.go
index c0115ec..4f2d76e 100644
--- a/src/pkg/exp/template/set_test.go
+++ b/src/pkg/exp/template/set_test.go
@@ -38,8 +38,7 @@ var setParseTests = []setParseTest{
 
 func TestSetParse(t *testing.T) {
 	for _, test := range setParseTests {
-		set := NewSet()
-		err := set.Parse(test.input)
+		set, err := new(Set).Parse(test.input)
 		switch {
 		case err == nil && !test.ok:
 			t.Errorf("%q: expected error; got none", test.name)
@@ -54,6 +53,9 @@ func TestSetParse(t *testing.T) {
 			}
 			continue
 		}
+		if set == nil {
+			continue
+		}
 		if len(set.tmpl) != len(test.names) {
 			t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(set.tmpl))
 			continue
@@ -72,30 +74,158 @@ func TestSetParse(t *testing.T) {
 	}
 }
 
-
 var setExecTests = []execTest{
 	{"empty", "", "", nil, true},
 	{"text", "some text", "some text", nil, true},
-	{"invoke text", `{{template "text" .SI}}`, "TEXT", tVal, true},
+	{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
+	{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
 	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
 	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
 	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
 	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
+	{"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
+
+	// User-defined function: test argument evaluator.
+	{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
+	{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
 }
 
-const setText = `
-	{{define "text"}}TEXT{{end}}
+// These strings are also in testdata/*.
+const setText1 = `
+	{{define "x"}}TEXT{{end}}
 	{{define "dotV"}}{{.V}}{{end}}
+`
+
+const setText2 = `
 	{{define "dot"}}{{.}}{{end}}
 	{{define "nested"}}{{template "dot" .}}{{end}}
 `
 
 func TestSetExecute(t *testing.T) {
 	// Declare a set with a couple of templates first.
-	set := NewSet()
-	err := set.Parse(setText)
+	set, err := new(Set).Parse(setText1)
 	if err != nil {
 		t.Fatalf("error parsing set: %s", err)
 	}
+	_, err = set.Parse(setText2)
+	if err != nil {
+		t.Fatalf("error parsing set: %s", err)
+	}
+	testExecute(setExecTests, set, t)
+}
+
+func TestSetParseFile(t *testing.T) {
+	set, err := new(Set).ParseFile("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	_, err = set.ParseFile("testdata/file1.tmpl", "testdata/file2.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
 	testExecute(setExecTests, set, t)
 }
+
+func TestParseSetFile(t *testing.T) {
+	set, err := ParseSetFile("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	set, err = ParseSetFile("testdata/file1.tmpl", "testdata/file2.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(setExecTests, set, t)
+}
+
+func TestSetParseFiles(t *testing.T) {
+	set, err := new(Set).ParseFiles("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	_, err = set.ParseFiles("[x")
+	if err == nil {
+		t.Error("expected error for bad pattern; got none")
+	}
+	_, err = set.ParseFiles("testdata/file*.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(setExecTests, set, t)
+}
+
+func TestParseSetFiles(t *testing.T) {
+	set, err := ParseSetFiles("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	set, err = ParseSetFiles("[x")
+	if err == nil {
+		t.Error("expected error for bad pattern; got none")
+	}
+	set, err = ParseSetFiles("testdata/file*.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(setExecTests, set, t)
+}
+
+var templateFileExecTests = []execTest{
+	{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\ntemplate2\n", 0, true},
+}
+
+func TestSetParseTemplateFile(t *testing.T) {
+	set, err := ParseTemplateFile("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	_, err = set.ParseTemplateFile("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateFile(t *testing.T) {
+	set, err := ParseTemplateFile("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	set, err = ParseTemplateFile("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(templateFileExecTests, set, t)
+}
+
+func TestSetParseTemplateFiles(t *testing.T) {
+	set, err := ParseTemplateFiles("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	_, err = set.ParseTemplateFiles("[x")
+	if err == nil {
+		t.Error("expected error for bad pattern; got none")
+	}
+	_, err = set.ParseTemplateFiles("testdata/tmpl*.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateFiles(t *testing.T) {
+	set, err := ParseTemplateFiles("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	set, err = ParseTemplateFiles("[x")
+	if err == nil {
+		t.Error("expected error for bad pattern; got none")
+	}
+	set, err = ParseTemplateFiles("testdata/tmpl*.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(templateFileExecTests, set, t)
+}
diff --git a/src/pkg/exp/template/testdata/file1.tmpl b/src/pkg/exp/template/testdata/file1.tmpl
new file mode 100644
index 0000000..febf9d9
--- /dev/null
+++ b/src/pkg/exp/template/testdata/file1.tmpl
@@ -0,0 +1,2 @@
+{{define "x"}}TEXT{{end}}
+{{define "dotV"}}{{.V}}{{end}}
diff --git a/src/pkg/exp/template/testdata/file2.tmpl b/src/pkg/exp/template/testdata/file2.tmpl
new file mode 100644
index 0000000..39bf6fb
--- /dev/null
+++ b/src/pkg/exp/template/testdata/file2.tmpl
@@ -0,0 +1,2 @@
+{{define "dot"}}{{.}}{{end}}
+{{define "nested"}}{{template "dot" .}}{{end}}
diff --git a/src/pkg/exp/template/testdata/tmpl1.tmpl b/src/pkg/exp/template/testdata/tmpl1.tmpl
new file mode 100644
index 0000000..3d15b81
--- /dev/null
+++ b/src/pkg/exp/template/testdata/tmpl1.tmpl
@@ -0,0 +1 @@
+template1
diff --git a/src/pkg/exp/template/testdata/tmpl2.tmpl b/src/pkg/exp/template/testdata/tmpl2.tmpl
new file mode 100644
index 0000000..a374d2f
--- /dev/null
+++ b/src/pkg/exp/template/testdata/tmpl2.tmpl
@@ -0,0 +1 @@
+template2
diff --git a/src/pkg/exp/wingui/winapi.go b/src/pkg/exp/wingui/winapi.go
index fb0d610..fdf9d9e 100644
--- a/src/pkg/exp/wingui/winapi.go
+++ b/src/pkg/exp/wingui/winapi.go
@@ -9,7 +9,7 @@ import (
 	"unsafe"
 )
 
-func loadDll(fname string) uint32 {
+func loadDll(fname string) syscall.Handle {
 	h, e := syscall.LoadLibrary(fname)
 	if e != 0 {
 		abortf("LoadLibrary(%s) failed with err=%d.\n", fname, e)
@@ -17,7 +17,7 @@ func loadDll(fname string) uint32 {
 	return h
 }
 
-func getSysProcAddr(m uint32, pname string) uintptr {
+func getSysProcAddr(m syscall.Handle, pname string) uintptr {
 	p, e := syscall.GetProcAddress(m, pname)
 	if e != 0 {
 		abortf("GetProcAddress(%s) failed with err=%d.\n", pname, e)
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index 7123d4b..7b733fa 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/expvar/expvar.go
@@ -189,7 +189,6 @@ func (f Func) String() string {
 	return string(v)
 }
 
-
 // All published variables.
 var vars map[string]Var = make(map[string]Var)
 var mutex sync.Mutex
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index f9b852c..01bbc37 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -66,6 +66,9 @@ import (
 	"strconv"
 )
 
+// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
+var ErrHelp = os.NewError("flag: help requested")
+
 // -- Bool Value
 type boolValue bool
 
@@ -568,12 +571,18 @@ func Var(value Value, name string, usage string) {
 func (f *FlagSet) failf(format string, a ...interface{}) os.Error {
 	err := fmt.Errorf(format, a...)
 	fmt.Fprintln(os.Stderr, err)
+	f.usage()
+	return err
+}
+
+// usage calls the Usage method for the flag set, or the usage function if
+// the flag set is commandLine.
+func (f *FlagSet) usage() {
 	if f == commandLine {
 		Usage()
 	} else {
 		f.Usage()
 	}
-	return err
 }
 
 // parseOne parses one flag. It returns whether a flag was seen.
@@ -613,6 +622,10 @@ func (f *FlagSet) parseOne() (bool, os.Error) {
 	m := f.formal
 	flag, alreadythere := m[name] // BUG
 	if !alreadythere {
+		if name == "help" || name == "h" { // special case for nice help message.
+			f.usage()
+			return false, ErrHelp
+		}
 		return false, f.failf("flag provided but not defined: -%s", name)
 	}
 	if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
@@ -645,6 +658,7 @@ func (f *FlagSet) parseOne() (bool, os.Error) {
 // Parse parses flag definitions from the argument list, which should not
 // include the command name.  Must be called after all flags in the FlagSet
 // are defined and before flags are accessed by the program.
+// The return value will be ErrHelp if -help was set but not defined.
 func (f *FlagSet) Parse(arguments []string) os.Error {
 	f.args = arguments
 	for {
diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go
index fbd7069..63d0a9f 100644
--- a/src/pkg/flag/flag_test.go
+++ b/src/pkg/flag/flag_test.go
@@ -210,3 +210,46 @@ func TestChangingArgs(t *testing.T) {
 		t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
 	}
 }
+
+// Test that -help invokes the usage message and returns ErrHelp.
+func TestHelp(t *testing.T) {
+	var helpCalled = false
+	fs := NewFlagSet("help test", ContinueOnError)
+	fs.Usage = func() { helpCalled = true }
+	var flag bool
+	fs.BoolVar(&flag, "flag", false, "regular flag")
+	// Regular flag invocation should work
+	err := fs.Parse([]string{"-flag=true"})
+	if err != nil {
+		t.Fatal("expected no error; got ", err)
+	}
+	if !flag {
+		t.Error("flag was not set by -flag")
+	}
+	if helpCalled {
+		t.Error("help called for regular flag")
+		helpCalled = false // reset for next test
+	}
+	// Help flag should work as expected.
+	err = fs.Parse([]string{"-help"})
+	if err == nil {
+		t.Fatal("error expected")
+	}
+	if err != ErrHelp {
+		t.Fatal("expected ErrHelp; got ", err)
+	}
+	if !helpCalled {
+		t.Fatal("help was not called")
+	}
+	// If we define a help flag, that should override.
+	var help bool
+	fs.BoolVar(&help, "help", false, "help flag")
+	helpCalled = false
+	err = fs.Parse([]string{"-help"})
+	if err != nil {
+		t.Fatal("expected no error for defined -help; got ", err)
+	}
+	if helpCalled {
+		t.Fatal("help was called; should not have been for defined help flag")
+	}
+}
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 9a80245..d13d09c 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -43,7 +43,6 @@ func TestFmtInterface(t *testing.T) {
 	}
 }
 
-
 const b32 uint32 = 1<<32 - 1
 const b64 uint64 = 1<<64 - 1
 
@@ -181,6 +180,8 @@ var fmttests = []struct {
 	{"%+d", 0, "+0"},
 	{"% d", 0, " 0"},
 	{"% d", 12345, " 12345"},
+	{"%.0d", 0, ""},
+	{"%.d", 0, ""},
 
 	// unicode format
 	{"%U", 0x1, "U+0001"},
@@ -634,7 +635,6 @@ func TestBlankln(t *testing.T) {
 	}
 }
 
-
 // Check Formatter with Sprint, Sprintln, Sprintf
 func TestFormatterPrintln(t *testing.T) {
 	f := F(1)
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index bec55f7..24b15a2 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -166,6 +166,11 @@ func (f *fmt) fmt_boolean(v bool) {
 // integer; interprets prec but not wid.  Once formatted, result is sent to pad()
 // and then flags are cleared.
 func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
+	// precision of 0 and value of 0 means "print nothing"
+	if f.precPresent && f.prec == 0 && a == 0 {
+		return
+	}
+
 	var buf []byte = f.intbuf[0:]
 	negative := signedness == signed && a < 0
 	if negative {
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 5c083e5..7387349 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -53,7 +53,7 @@ type Formatter interface {
 	Format(f State, c int)
 }
 
-// Stringer is implemented by any value that has a String method(),
+// Stringer is implemented by any value that has a String method,
 // which defines the ``native'' format for that value.
 // The String method is used to print values passed as an operand
 // to a %s or %v format or to an unformatted printer such as Print.
@@ -61,7 +61,7 @@ type Stringer interface {
 	String() string
 }
 
-// GoStringer is implemented by any value that has a GoString() method,
+// GoStringer is implemented by any value that has a GoString method,
 // which defines the Go syntax for that value.
 // The GoString method is used to print values passed as an operand
 // to a %#v format.
@@ -253,7 +253,6 @@ func Sprintln(a ...interface{}) string {
 	return s
 }
 
-
 // Get the i'th arg of the struct value.
 // If the arg itself is an interface, return a value for
 // the thing inside the interface, not the interface itself.
@@ -929,6 +928,10 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 				}
 			} else {
 				p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+				if !p.fmt.precPresent {
+					p.fmt.prec = 0
+					p.fmt.precPresent = true
+				}
 			}
 		}
 		if i >= end {
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index d93a8c1..259451d 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -271,14 +271,12 @@ func notSpace(r int) bool {
 	return !unicode.IsSpace(r)
 }
 
-
 // skipSpace provides Scan() methods the ability to skip space and newline characters 
 // in keeping with the current scanning mode set by format strings and Scan()/Scanln().
 func (s *ss) SkipSpace() {
 	s.skipSpace(false)
 }
 
-
 // readRune is a structure to enable reading UTF-8 encoded code points
 // from an io.Reader.  It is used if the Reader given to the scanner does
 // not already implement io.RuneReader.
@@ -337,7 +335,6 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
 	return
 }
 
-
 var ssFree = newCache(func() interface{} { return new(ss) })
 
 // Allocate a new ss struct or grab a cached one.
@@ -411,7 +408,6 @@ func (s *ss) skipSpace(stopAtNewline bool) {
 	}
 }
 
-
 // token returns the next space-delimited string from the input.  It
 // skips white space.  For Scanln, it stops at newlines.  For Scan,
 // newlines are treated as spaces.
@@ -554,9 +550,11 @@ func (s *ss) getBase(verb int) (base int, digits string) {
 
 // scanNumber returns the numerical string with specified digits starting here.
 func (s *ss) scanNumber(digits string, haveDigits bool) string {
-	s.notEOF()
-	if !haveDigits && !s.accept(digits) {
-		s.errorString("expected integer")
+	if !haveDigits {
+		s.notEOF()
+		if !s.accept(digits) {
+			s.errorString("expected integer")
+		}
 	}
 	for s.accept(digits) {
 	}
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 98b3b54..3f06e57 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -298,6 +298,8 @@ var scanfTests = []ScanfTest{
 	// Fixed bugs
 	{"%d\n", "27\n", &intVal, 27},  // ok
 	{"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
+	{"%v", "0", &intVal, 0},        // was: "EOF"; 0 was taken as base prefix and not counted.
+	{"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted.
 }
 
 var overflowTests = []ScanTest{
diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go
index b1c7d4a..22bd5ee 100644
--- a/src/pkg/go/ast/ast.go
+++ b/src/pkg/go/ast/ast.go
@@ -13,7 +13,6 @@ import (
 	"utf8"
 )
 
-
 // ----------------------------------------------------------------------------
 // Interfaces
 //
@@ -31,35 +30,30 @@ import (
 // That position information is needed to properly position comments
 // when printing the construct.
 
-
 // All node types implement the Node interface.
 type Node interface {
 	Pos() token.Pos // position of first character belonging to the node
 	End() token.Pos // position of first character immediately after the node
 }
 
-
 // All expression nodes implement the Expr interface.
 type Expr interface {
 	Node
 	exprNode()
 }
 
-
 // All statement nodes implement the Stmt interface.
 type Stmt interface {
 	Node
 	stmtNode()
 }
 
-
 // All declaration nodes implement the Decl interface.
 type Decl interface {
 	Node
 	declNode()
 }
 
-
 // ----------------------------------------------------------------------------
 // Comments
 
@@ -69,11 +63,9 @@ type Comment struct {
 	Text  string    // comment text (excluding '\n' for //-style comments)
 }
 
-
 func (c *Comment) Pos() token.Pos { return c.Slash }
 func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) }
 
-
 // A CommentGroup represents a sequence of comments
 // with no other tokens and no empty lines between.
 //
@@ -81,11 +73,9 @@ type CommentGroup struct {
 	List []*Comment // len(List) > 0
 }
 
-
 func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
 func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
 
-
 // ----------------------------------------------------------------------------
 // Expressions and types
 
@@ -101,7 +91,6 @@ type Field struct {
 	Comment *CommentGroup // line comments; or nil
 }
 
-
 func (f *Field) Pos() token.Pos {
 	if len(f.Names) > 0 {
 		return f.Names[0].Pos()
@@ -109,7 +98,6 @@ func (f *Field) Pos() token.Pos {
 	return f.Type.Pos()
 }
 
-
 func (f *Field) End() token.Pos {
 	if f.Tag != nil {
 		return f.Tag.End()
@@ -117,7 +105,6 @@ func (f *Field) End() token.Pos {
 	return f.Type.End()
 }
 
-
 // A FieldList represents a list of Fields, enclosed by parentheses or braces.
 type FieldList struct {
 	Opening token.Pos // position of opening parenthesis/brace, if any
@@ -125,7 +112,6 @@ type FieldList struct {
 	Closing token.Pos // position of closing parenthesis/brace, if any
 }
 
-
 func (f *FieldList) Pos() token.Pos {
 	if f.Opening.IsValid() {
 		return f.Opening
@@ -138,7 +124,6 @@ func (f *FieldList) Pos() token.Pos {
 	return token.NoPos
 }
 
-
 func (f *FieldList) End() token.Pos {
 	if f.Closing.IsValid() {
 		return f.Closing + 1
@@ -151,7 +136,6 @@ func (f *FieldList) End() token.Pos {
 	return token.NoPos
 }
 
-
 // NumFields returns the number of (named and anonymous fields) in a FieldList.
 func (f *FieldList) NumFields() int {
 	n := 0
@@ -167,7 +151,6 @@ func (f *FieldList) NumFields() int {
 	return n
 }
 
-
 // An expression is represented by a tree consisting of one
 // or more of the following concrete expression nodes.
 //
@@ -298,7 +281,6 @@ type (
 	}
 )
 
-
 // The direction of a channel type is indicated by one
 // of the following constants.
 //
@@ -309,7 +291,6 @@ const (
 	RECV
 )
 
-
 // A type is represented by a tree consisting of one
 // or more of the following type-specific expression
 // nodes.
@@ -360,7 +341,6 @@ type (
 	}
 )
 
-
 // Pos and End implementations for expression/type nodes.
 //
 func (x *BadExpr) Pos() token.Pos  { return x.From }
@@ -391,7 +371,6 @@ func (x *InterfaceType) Pos() token.Pos  { return x.Interface }
 func (x *MapType) Pos() token.Pos        { return x.Map }
 func (x *ChanType) Pos() token.Pos       { return x.Begin }
 
-
 func (x *BadExpr) End() token.Pos { return x.To }
 func (x *Ident) End() token.Pos   { return token.Pos(int(x.NamePos) + len(x.Name)) }
 func (x *Ellipsis) End() token.Pos {
@@ -430,7 +409,6 @@ func (x *InterfaceType) End() token.Pos { return x.Methods.End() }
 func (x *MapType) End() token.Pos       { return x.Value.End() }
 func (x *ChanType) End() token.Pos      { return x.Value.End() }
 
-
 // exprNode() ensures that only expression/type nodes can be
 // assigned to an ExprNode.
 //
@@ -458,7 +436,6 @@ func (x *InterfaceType) exprNode() {}
 func (x *MapType) exprNode()       {}
 func (x *ChanType) exprNode()      {}
 
-
 // ----------------------------------------------------------------------------
 // Convenience functions for Idents
 
@@ -469,7 +446,6 @@ var noPos token.Pos
 //
 func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
 
-
 // IsExported returns whether name is an exported Go symbol
 // (i.e., whether it begins with an uppercase letter).
 //
@@ -478,13 +454,11 @@ func IsExported(name string) bool {
 	return unicode.IsUpper(ch)
 }
 
-
 // IsExported returns whether id is an exported Go symbol
 // (i.e., whether it begins with an uppercase letter).
 //
 func (id *Ident) IsExported() bool { return IsExported(id.Name) }
 
-
 func (id *Ident) String() string {
 	if id != nil {
 		return id.Name
@@ -492,7 +466,6 @@ func (id *Ident) String() string {
 	return "<nil>"
 }
 
-
 // ----------------------------------------------------------------------------
 // Statements
 
@@ -660,7 +633,6 @@ type (
 	}
 )
 
-
 // Pos and End implementations for statement nodes.
 //
 func (s *BadStmt) Pos() token.Pos        { return s.From }
@@ -685,7 +657,6 @@ func (s *SelectStmt) Pos() token.Pos     { return s.Select }
 func (s *ForStmt) Pos() token.Pos        { return s.For }
 func (s *RangeStmt) Pos() token.Pos      { return s.For }
 
-
 func (s *BadStmt) End() token.Pos  { return s.To }
 func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
 func (s *EmptyStmt) End() token.Pos {
@@ -737,7 +708,6 @@ func (s *SelectStmt) End() token.Pos { return s.Body.End() }
 func (s *ForStmt) End() token.Pos    { return s.Body.End() }
 func (s *RangeStmt) End() token.Pos  { return s.Body.End() }
 
-
 // stmtNode() ensures that only statement nodes can be
 // assigned to a StmtNode.
 //
@@ -763,7 +733,6 @@ func (s *SelectStmt) stmtNode()     {}
 func (s *ForStmt) stmtNode()        {}
 func (s *RangeStmt) stmtNode()      {}
 
-
 // ----------------------------------------------------------------------------
 // Declarations
 
@@ -805,7 +774,6 @@ type (
 	}
 )
 
-
 // Pos and End implementations for spec nodes.
 //
 func (s *ImportSpec) Pos() token.Pos {
@@ -817,7 +785,6 @@ func (s *ImportSpec) Pos() token.Pos {
 func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
 func (s *TypeSpec) Pos() token.Pos  { return s.Name.Pos() }
 
-
 func (s *ImportSpec) End() token.Pos { return s.Path.End() }
 func (s *ValueSpec) End() token.Pos {
 	if n := len(s.Values); n > 0 {
@@ -830,7 +797,6 @@ func (s *ValueSpec) End() token.Pos {
 }
 func (s *TypeSpec) End() token.Pos { return s.Type.End() }
 
-
 // specNode() ensures that only spec nodes can be
 // assigned to a Spec.
 //
@@ -838,7 +804,6 @@ func (s *ImportSpec) specNode() {}
 func (s *ValueSpec) specNode()  {}
 func (s *TypeSpec) specNode()   {}
 
-
 // A declaration is represented by one of the following declaration nodes.
 //
 type (
@@ -880,14 +845,12 @@ type (
 	}
 )
 
-
 // Pos and End implementations for declaration nodes.
 //
 func (d *BadDecl) Pos() token.Pos  { return d.From }
 func (d *GenDecl) Pos() token.Pos  { return d.TokPos }
 func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
 
-
 func (d *BadDecl) End() token.Pos { return d.To }
 func (d *GenDecl) End() token.Pos {
 	if d.Rparen.IsValid() {
@@ -902,7 +865,6 @@ func (d *FuncDecl) End() token.Pos {
 	return d.Type.End()
 }
 
-
 // declNode() ensures that only declaration nodes can be
 // assigned to a DeclNode.
 //
@@ -910,7 +872,6 @@ func (d *BadDecl) declNode()  {}
 func (d *GenDecl) declNode()  {}
 func (d *FuncDecl) declNode() {}
 
-
 // ----------------------------------------------------------------------------
 // Files and packages
 
@@ -931,7 +892,6 @@ type File struct {
 	Comments   []*CommentGroup // list of all comments in the source file
 }
 
-
 func (f *File) Pos() token.Pos { return f.Package }
 func (f *File) End() token.Pos {
 	if n := len(f.Decls); n > 0 {
@@ -940,7 +900,6 @@ func (f *File) End() token.Pos {
 	return f.Name.End()
 }
 
-
 // A Package node represents a set of source files
 // collectively building a Go package.
 //
@@ -951,6 +910,5 @@ type Package struct {
 	Files   map[string]*File   // Go source files by filename
 }
 
-
 func (p *Package) Pos() token.Pos { return token.NoPos }
 func (p *Package) End() token.Pos { return token.NoPos }
diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go
index 0907fd5..2673343 100644
--- a/src/pkg/go/ast/filter.go
+++ b/src/pkg/go/ast/filter.go
@@ -20,7 +20,6 @@ func identListExports(list []*Ident) []*Ident {
 	return list[0:j]
 }
 
-
 // fieldName assumes that x is the type of an anonymous field and
 // returns the corresponding field name. If x is not an acceptable
 // anonymous field, the result is nil.
@@ -39,7 +38,6 @@ func fieldName(x Expr) *Ident {
 	return nil
 }
 
-
 func fieldListExports(fields *FieldList) (removedFields bool) {
 	if fields == nil {
 		return
@@ -78,7 +76,6 @@ func fieldListExports(fields *FieldList) (removedFields bool) {
 	return
 }
 
-
 func paramListExports(fields *FieldList) {
 	if fields == nil {
 		return
@@ -88,7 +85,6 @@ func paramListExports(fields *FieldList) {
 	}
 }
 
-
 func typeExports(typ Expr) {
 	switch t := typ.(type) {
 	case *ArrayType:
@@ -112,7 +108,6 @@ func typeExports(typ Expr) {
 	}
 }
 
-
 func specExports(spec Spec) bool {
 	switch s := spec.(type) {
 	case *ValueSpec:
@@ -130,7 +125,6 @@ func specExports(spec Spec) bool {
 	return false
 }
 
-
 func specListExports(list []Spec) []Spec {
 	j := 0
 	for _, s := range list {
@@ -142,7 +136,6 @@ func specListExports(list []Spec) []Spec {
 	return list[0:j]
 }
 
-
 func declExports(decl Decl) bool {
 	switch d := decl.(type) {
 	case *GenDecl:
@@ -155,7 +148,6 @@ func declExports(decl Decl) bool {
 	return false
 }
 
-
 // FileExports trims the AST for a Go source file in place such that only
 // exported nodes remain: all top-level identifiers which are not exported
 // and their associated information (such as type, initial value, or function
@@ -178,7 +170,6 @@ func FileExports(src *File) bool {
 	return j > 0
 }
 
-
 // PackageExports trims the AST for a Go package in place such that only
 // exported nodes remain. The pkg.Files list is not changed, so that file
 // names and top-level package comments don't get lost.
@@ -196,7 +187,6 @@ func PackageExports(pkg *Package) bool {
 	return hasExports
 }
 
-
 // ----------------------------------------------------------------------------
 // General filtering
 
@@ -213,7 +203,6 @@ func filterIdentList(list []*Ident, f Filter) []*Ident {
 	return list[0:j]
 }
 
-
 func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
 	if fields == nil {
 		return false
@@ -246,7 +235,6 @@ func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
 	return
 }
 
-
 func filterSpec(spec Spec, f Filter) bool {
 	switch s := spec.(type) {
 	case *ValueSpec:
@@ -272,7 +260,6 @@ func filterSpec(spec Spec, f Filter) bool {
 	return false
 }
 
-
 func filterSpecList(list []Spec, f Filter) []Spec {
 	j := 0
 	for _, s := range list {
@@ -284,7 +271,6 @@ func filterSpecList(list []Spec, f Filter) []Spec {
 	return list[0:j]
 }
 
-
 // FilterDecl trims the AST for a Go declaration in place by removing
 // all names (including struct field and interface method names, but
 // not from parameter lists) that don't pass through the filter f.
@@ -303,7 +289,6 @@ func FilterDecl(decl Decl, f Filter) bool {
 	return false
 }
 
-
 // FilterFile trims the AST for a Go file in place by removing all
 // names from top-level declarations (including struct field and
 // interface method names, but not from parameter lists) that don't
@@ -326,7 +311,6 @@ func FilterFile(src *File, f Filter) bool {
 	return j > 0
 }
 
-
 // FilterPackage trims the AST for a Go package in place by removing all
 // names from top-level declarations (including struct field and
 // interface method names, but not from parameter lists) that don't
@@ -348,7 +332,6 @@ func FilterPackage(pkg *Package, f Filter) bool {
 	return hasDecls
 }
 
-
 // ----------------------------------------------------------------------------
 // Merging of package files
 
@@ -368,7 +351,6 @@ const (
 //
 var separator = &Comment{noPos, "//"}
 
-
 // MergePackageFiles creates a file AST by merging the ASTs of the
 // files belonging to a package. The mode flags control merging behavior.
 //
diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go
index 81e1da1..62a3048 100644
--- a/src/pkg/go/ast/print.go
+++ b/src/pkg/go/ast/print.go
@@ -14,11 +14,9 @@ import (
 	"reflect"
 )
 
-
 // A FieldFilter may be provided to Fprint to control the output.
 type FieldFilter func(name string, value reflect.Value) bool
 
-
 // NotNilFilter returns true for field values that are not nil;
 // it returns false otherwise.
 func NotNilFilter(_ string, v reflect.Value) bool {
@@ -29,7 +27,6 @@ func NotNilFilter(_ string, v reflect.Value) bool {
 	return true
 }
 
-
 // Fprint prints the (sub-)tree starting at AST node x to w.
 // If fset != nil, position information is interpreted relative
 // to that file set. Otherwise positions are printed as integer
@@ -68,14 +65,12 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
 	return
 }
 
-
 // Print prints x to standard output, skipping nil fields.
 // Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
 func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
 	return Fprint(os.Stdout, fset, x, NotNilFilter)
 }
 
-
 type printer struct {
 	output  io.Writer
 	fset    *token.FileSet
@@ -87,7 +82,6 @@ type printer struct {
 	line    int                 // current line number
 }
 
-
 var indent = []byte(".  ")
 
 func (p *printer) Write(data []byte) (n int, err os.Error) {
@@ -120,14 +114,12 @@ func (p *printer) Write(data []byte) (n int, err os.Error) {
 	return
 }
 
-
 // localError wraps locally caught os.Errors so we can distinguish
 // them from genuine panics which we don't want to return as errors.
 type localError struct {
 	err os.Error
 }
 
-
 // printf is a convenience wrapper that takes care of print errors.
 func (p *printer) printf(format string, args ...interface{}) {
 	n, err := fmt.Fprintf(p, format, args...)
@@ -137,7 +129,6 @@ func (p *printer) printf(format string, args ...interface{}) {
 	}
 }
 
-
 // Implementation note: Print is written for AST nodes but could be
 // used to print arbitrary data structures; such a version should
 // probably be in a different package.
diff --git a/src/pkg/go/ast/print_test.go b/src/pkg/go/ast/print_test.go
index 30b396f..f4e8f7a 100644
--- a/src/pkg/go/ast/print_test.go
+++ b/src/pkg/go/ast/print_test.go
@@ -10,7 +10,6 @@ import (
 	"testing"
 )
 
-
 var tests = []struct {
 	x interface{} // x is printed as s
 	s string
@@ -49,7 +48,6 @@ var tests = []struct {
 		3  }`},
 }
 
-
 // Split s into lines, trim whitespace from all lines, and return
 // the concatenated non-empty lines.
 func trim(s string) string {
@@ -65,7 +63,6 @@ func trim(s string) string {
 	return strings.Join(lines[0:i], "\n")
 }
 
-
 func TestPrint(t *testing.T) {
 	var buf bytes.Buffer
 	for _, test := range tests {
diff --git a/src/pkg/go/ast/resolve.go b/src/pkg/go/ast/resolve.go
index ecd2e8a..3927a79 100644
--- a/src/pkg/go/ast/resolve.go
+++ b/src/pkg/go/ast/resolve.go
@@ -14,23 +14,19 @@ import (
 	"strconv"
 )
 
-
 type pkgBuilder struct {
 	scanner.ErrorVector
 	fset *token.FileSet
 }
 
-
 func (p *pkgBuilder) error(pos token.Pos, msg string) {
 	p.Error(p.fset.Position(pos), msg)
 }
 
-
 func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) {
 	p.error(pos, fmt.Sprintf(format, args...))
 }
 
-
 func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
 	alt := scope.Insert(obj)
 	if alt == nil && altScope != nil {
@@ -46,7 +42,6 @@ func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
 	}
 }
 
-
 func resolve(scope *Scope, ident *Ident) bool {
 	for ; scope != nil; scope = scope.Outer {
 		if obj := scope.Lookup(ident.Name); obj != nil {
@@ -57,7 +52,6 @@ func resolve(scope *Scope, ident *Ident) bool {
 	return false
 }
 
-
 // An Importer resolves import paths to package Objects.
 // The imports map records the packages already imported,
 // indexed by package id (canonical import path).
@@ -69,7 +63,6 @@ func resolve(scope *Scope, ident *Ident) bool {
 // return pkg.
 type Importer func(imports map[string]*Object, path string) (pkg *Object, err os.Error)
 
-
 // NewPackage creates a new Package node from a set of File nodes. It resolves
 // unresolved identifiers across files and updates each file's Unresolved list
 // accordingly. If a non-nil importer and universe scope are provided, they are
diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go
index b966f78..92e3669 100644
--- a/src/pkg/go/ast/scope.go
+++ b/src/pkg/go/ast/scope.go
@@ -12,7 +12,6 @@ import (
 	"go/token"
 )
 
-
 // A Scope maintains the set of named language entities declared
 // in the scope and a link to the immediately surrounding (outer)
 // scope.
@@ -22,14 +21,12 @@ type Scope struct {
 	Objects map[string]*Object
 }
 
-
 // NewScope creates a new scope nested in the outer scope.
 func NewScope(outer *Scope) *Scope {
 	const n = 4 // initial scope capacity
 	return &Scope{outer, make(map[string]*Object, n)}
 }
 
-
 // Lookup returns the object with the given name if it is
 // found in scope s, otherwise it returns nil. Outer scopes
 // are ignored.
@@ -38,7 +35,6 @@ func (s *Scope) Lookup(name string) *Object {
 	return s.Objects[name]
 }
 
-
 // Insert attempts to insert a named object obj into the scope s.
 // If the scope already contains an object alt with the same name,
 // Insert leaves the scope unchanged and returns alt. Otherwise
@@ -51,7 +47,6 @@ func (s *Scope) Insert(obj *Object) (alt *Object) {
 	return
 }
 
-
 // Debugging support
 func (s *Scope) String() string {
 	var buf bytes.Buffer
@@ -66,7 +61,6 @@ func (s *Scope) String() string {
 	return buf.String()
 }
 
-
 // ----------------------------------------------------------------------------
 // Objects
 
@@ -91,13 +85,11 @@ type Object struct {
 	Type interface{} // place holder for type information; may be nil
 }
 
-
 // NewObj creates a new object of a given kind and name.
 func NewObj(kind ObjKind, name string) *Object {
 	return &Object{Kind: kind, Name: name}
 }
 
-
 // Pos computes the source position of the declaration of an object name.
 // The result may be an invalid position if it cannot be computed
 // (obj.Decl may be nil or not correct).
@@ -137,7 +129,6 @@ func (obj *Object) Pos() token.Pos {
 	return token.NoPos
 }
 
-
 // ObKind describes what an object represents.
 type ObjKind int
 
@@ -152,7 +143,6 @@ const (
 	Lbl                // label
 )
 
-
 var objKindStrings = [...]string{
 	Bad: "bad",
 	Pkg: "package",
@@ -163,5 +153,4 @@ var objKindStrings = [...]string{
 	Lbl: "label",
 }
 
-
 func (kind ObjKind) String() string { return objKindStrings[kind] }
diff --git a/src/pkg/go/ast/walk.go b/src/pkg/go/ast/walk.go
index 95c4b3a..181cfd1 100644
--- a/src/pkg/go/ast/walk.go
+++ b/src/pkg/go/ast/walk.go
@@ -13,7 +13,6 @@ type Visitor interface {
 	Visit(node Node) (w Visitor)
 }
 
-
 // Helper functions for common node lists. They may be empty.
 
 func walkIdentList(v Visitor, list []*Ident) {
@@ -22,28 +21,24 @@ func walkIdentList(v Visitor, list []*Ident) {
 	}
 }
 
-
 func walkExprList(v Visitor, list []Expr) {
 	for _, x := range list {
 		Walk(v, x)
 	}
 }
 
-
 func walkStmtList(v Visitor, list []Stmt) {
 	for _, x := range list {
 		Walk(v, x)
 	}
 }
 
-
 func walkDeclList(v Visitor, list []Decl) {
 	for _, x := range list {
 		Walk(v, x)
 	}
 }
 
-
 // TODO(gri): Investigate if providing a closure to Walk leads to
 //            simpler use (and may help eliminate Inspect in turn).
 
@@ -369,7 +364,6 @@ func Walk(v Visitor, node Node) {
 	v.Visit(nil)
 }
 
-
 type inspector func(Node) bool
 
 func (f inspector) Visit(node Node) Visitor {
@@ -379,7 +373,6 @@ func (f inspector) Visit(node Node) Visitor {
 	return nil
 }
 
-
 // Inspect traverses an AST in depth-first order: It starts by calling
 // f(node); node must not be nil. If f returns true, Inspect invokes f
 // for all the non-nil children of node, recursively.
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index d83a666..97f92bf 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -61,7 +61,9 @@ func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
 	if len(info.CgoFiles) > 0 {
 		cgoFiles := b.abss(info.CgoFiles...)
 		s.addInput(cgoFiles...)
-		outGo, outObj := b.cgo(cgoFiles)
+		cgoCFiles := b.abss(info.CFiles...)
+		s.addInput(cgoCFiles...)
+		outGo, outObj := b.cgo(cgoFiles, cgoCFiles)
 		gofiles = append(gofiles, outGo...)
 		ofiles = append(ofiles, outObj...)
 		s.addIntermediate(outGo...)
@@ -182,7 +184,7 @@ func (s *Script) Clean() (err os.Error) {
 	return
 }
 
-// Clean removes the Script's Intermediate and Output files.
+// Nuke removes the Script's Intermediate and Output files.
 // It tries to remove every file and returns the first error it encounters.
 func (s *Script) Nuke() (err os.Error) {
 	// Reverse order so that directories get removed after the files they contain.
@@ -213,6 +215,14 @@ func (c *Cmd) String() string {
 
 // Run executes the Cmd.
 func (c *Cmd) Run() os.Error {
+	if c.Args[0] == "mkdir" {
+		for _, p := range c.Output {
+			if err := os.MkdirAll(p, 0777); err != nil {
+				return fmt.Errorf("command %q: %v", c, err)
+			}
+		}
+		return nil
+	}
 	out := new(bytes.Buffer)
 	cmd := exec.Command(c.Args[0], c.Args[1:]...)
 	cmd.Dir = c.Dir
@@ -362,7 +372,7 @@ func (b *build) gccArgs(args ...string) []string {
 
 var cgoRe = regexp.MustCompile(`[/\\:]`)
 
-func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
+func (b *build) cgo(cgofiles, cgocfiles []string) (outGo, outObj []string) {
 	// cgo
 	// TODO(adg): CGOPKGPATH
 	// TODO(adg): CGO_FLAGS
@@ -405,6 +415,12 @@ func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
 			b.script.addIntermediate(ofile)
 		}
 	}
+	for _, cfile := range cgocfiles {
+		ofile := b.obj + cgoRe.ReplaceAllString(cfile[:len(cfile)-1], "_") + "o"
+		b.gccCompile(ofile, cfile)
+		linkobj = append(linkobj, ofile)
+		outObj = append(outObj, ofile)
+	}
 	dynObj := b.obj + "_cgo_.o"
 	b.gccLink(dynObj, linkobj...)
 	b.script.addIntermediate(dynObj)
diff --git a/src/pkg/go/build/cgotest/cgotest.c b/src/pkg/go/build/cgotest/cgotest.c
new file mode 100644
index 0000000..b13acb2
--- /dev/null
+++ b/src/pkg/go/build/cgotest/cgotest.c
@@ -0,0 +1,9 @@
+// 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.
+
+int
+Add(int x, int y, int *sum)
+{
+	sum = x+y;
+}
diff --git a/src/pkg/go/build/cgotest/cgotest.go b/src/pkg/go/build/cgotest/cgotest.go
index 32b9318..93bbf06 100644
--- a/src/pkg/go/build/cgotest/cgotest.go
+++ b/src/pkg/go/build/cgotest/cgotest.go
@@ -7,6 +7,13 @@ package cgotest
 /*
 char* greeting = "hello, world";
 */
+// #include "cgotest.h"
 import "C"
+import "unsafe"
 
 var Greeting = C.GoString(C.greeting)
+
+func DoAdd(x, y int) (sum int) {
+	C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum)))
+	return
+}
diff --git a/src/pkg/go/build/cgotest/cgotest.h b/src/pkg/go/build/cgotest/cgotest.h
new file mode 100644
index 0000000..9c73643
--- /dev/null
+++ b/src/pkg/go/build/cgotest/cgotest.h
@@ -0,0 +1,5 @@
+// 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.
+
+extern int Add(int, int, int *);
diff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
index ea588ab..7c120d0 100644
--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -10,10 +10,9 @@ import (
 	"os"
 	"path/filepath"
 	"runtime"
-	"strings"
 )
 
-// Path is a validated list of Trees derived from $GOPATH at init.
+// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
 var Path []*Tree
 
 // Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
@@ -79,7 +78,10 @@ func (t *Tree) HasPkg(pkg string) bool {
 	// TODO(adg): check object version is consistent
 }
 
-var ErrNotFound = os.NewError("package could not be found locally")
+var (
+	ErrNotFound     = os.NewError("go/build: package could not be found locally")
+	ErrTreeNotFound = os.NewError("go/build: no valid GOROOT or GOPATH could be found")
+)
 
 // FindTree takes an import or filesystem path and returns the
 // tree where the package source should be and the package import path.
@@ -93,7 +95,7 @@ func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
 		}
 		for _, t := range Path {
 			tpath := t.SrcDir() + string(filepath.Separator)
-			if !strings.HasPrefix(path, tpath) {
+			if !filepath.HasPrefix(path, tpath) {
 				continue
 			}
 			tree = t
@@ -111,14 +113,22 @@ func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
 			return
 		}
 	}
-	err = ErrNotFound
+	if tree == nil {
+		err = ErrTreeNotFound
+	} else {
+		err = ErrNotFound
+	}
 	return
 }
 
 // isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
+// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
 func isLocalPath(s string) bool {
 	const sep = string(filepath.Separator)
-	return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
+	return s == "." || s == ".." ||
+		filepath.HasPrefix(s, sep) ||
+		filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
+		filepath.VolumeName(s) != ""
 }
 
 var (
@@ -133,12 +143,13 @@ var (
 // set up Path: parse and validate GOROOT and GOPATH variables
 func init() {
 	root := runtime.GOROOT()
-	p, err := newTree(root)
+	t, err := newTree(root)
 	if err != nil {
-		log.Fatalf("Invalid GOROOT %q: %v", root, err)
+		log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+	} else {
+		t.Goroot = true
+		Path = []*Tree{t}
 	}
-	p.Goroot = true
-	Path = []*Tree{p}
 
 	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
 		if p == "" {
@@ -146,7 +157,7 @@ func init() {
 		}
 		t, err := newTree(p)
 		if err != nil {
-			log.Printf("Invalid GOPATH %q: %v", p, err)
+			log.Printf("go/build: invalid GOPATH %q: %v", p, err)
 			continue
 		}
 		Path = append(Path, t)
@@ -160,7 +171,7 @@ func init() {
 	}
 
 	// use GOROOT if no valid GOPATH specified
-	if defaultTree == nil {
+	if defaultTree == nil && len(Path) > 0 {
 		defaultTree = Path[0]
 	}
 }
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index 85640af..2a24b14 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -14,10 +14,8 @@ import (
 	"template" // for htmlEscape
 )
 
-
 func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
 
-
 func stripTrailingWhitespace(s string) string {
 	i := len(s)
 	for i > 0 && isWhitespace(s[i-1]) {
@@ -26,7 +24,6 @@ func stripTrailingWhitespace(s string) string {
 	return s[0:i]
 }
 
-
 // CommentText returns the text of comment,
 // with the comment markers - //, /*, and */ - removed.
 func CommentText(comment *ast.CommentGroup) string {
@@ -85,7 +82,6 @@ func CommentText(comment *ast.CommentGroup) string {
 	return strings.Join(lines, "\n")
 }
 
-
 // Split bytes into lines.
 func split(text []byte) [][]byte {
 	// count lines
@@ -119,7 +115,6 @@ func split(text []byte) [][]byte {
 	return out
 }
 
-
 var (
 	ldquo = []byte("“")
 	rdquo = []byte("”")
@@ -148,7 +143,6 @@ func commentEscape(w io.Writer, s []byte, nice bool) {
 	template.HTMLEscape(w, s[last:])
 }
 
-
 const (
 	// Regexp for Go identifiers
 	identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
@@ -176,7 +170,6 @@ var (
 	html_endpre = []byte("</pre>\n")
 )
 
-
 // Emphasize and escape a line of text for HTML. URLs are converted into links;
 // if the URL also appears in the words map, the link is taken from the map (if
 // the corresponding map value is the empty string, the URL is not converted
@@ -235,7 +228,6 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
 	commentEscape(w, line, nice)
 }
 
-
 func indentLen(s []byte) int {
 	i := 0
 	for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
@@ -244,10 +236,8 @@ func indentLen(s []byte) int {
 	return i
 }
 
-
 func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') }
 
-
 func commonPrefix(a, b []byte) []byte {
 	i := 0
 	for i < len(a) && i < len(b) && a[i] == b[i] {
@@ -256,7 +246,6 @@ func commonPrefix(a, b []byte) []byte {
 	return a[0:i]
 }
 
-
 func unindent(block [][]byte) {
 	if len(block) == 0 {
 		return
@@ -279,7 +268,6 @@ func unindent(block [][]byte) {
 	}
 }
 
-
 // Convert comment text to formatted HTML.
 // The comment was prepared by DocReader,
 // so it is known not to have leading, trailing blank lines
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
index b26cd2b..c7fed97 100644
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -12,7 +12,6 @@ import (
 	"sort"
 )
 
-
 // ----------------------------------------------------------------------------
 
 type typeDoc struct {
@@ -25,7 +24,6 @@ type typeDoc struct {
 	methods   map[string]*ast.FuncDecl
 }
 
-
 // docReader accumulates documentation for a single package.
 // It modifies the AST: Comments (declaration documentation)
 // that have been collected by the DocReader are set to nil
@@ -42,14 +40,12 @@ type docReader struct {
 	bugs    []*ast.CommentGroup
 }
 
-
 func (doc *docReader) init(pkgName string) {
 	doc.pkgName = pkgName
 	doc.types = make(map[string]*typeDoc)
 	doc.funcs = make(map[string]*ast.FuncDecl)
 }
 
-
 func (doc *docReader) addDoc(comments *ast.CommentGroup) {
 	if doc.doc == nil {
 		// common case: just one package comment
@@ -71,7 +67,6 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
 	doc.doc = &ast.CommentGroup{list}
 }
 
-
 func (doc *docReader) addType(decl *ast.GenDecl) {
 	spec := decl.Specs[0].(*ast.TypeSpec)
 	typ := doc.lookupTypeDoc(spec.Name.Name)
@@ -84,7 +79,6 @@ func (doc *docReader) addType(decl *ast.GenDecl) {
 	}
 }
 
-
 func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
 	if name == "" {
 		return nil // no type docs for anonymous types
@@ -98,7 +92,6 @@ func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
 	return tdoc
 }
 
-
 func baseTypeName(typ ast.Expr) string {
 	switch t := typ.(type) {
 	case *ast.Ident:
@@ -113,7 +106,6 @@ func baseTypeName(typ ast.Expr) string {
 	return ""
 }
 
-
 func (doc *docReader) addValue(decl *ast.GenDecl) {
 	// determine if decl should be associated with a type
 	// Heuristic: For each typed entry, determine the type name, if any.
@@ -165,7 +157,6 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
 	*values = append(*values, decl)
 }
 
-
 // Helper function to set the table entry for function f. Makes sure that
 // at least one f with associated documentation is stored in table, if there
 // are multiple f's with the same name.
@@ -183,7 +174,6 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
 	table[name] = f
 }
 
-
 func (doc *docReader) addFunc(fun *ast.FuncDecl) {
 	name := fun.Name.Name
 
@@ -238,7 +228,6 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
 	setFunc(doc.funcs, fun)
 }
 
-
 func (doc *docReader) addDecl(decl ast.Decl) {
 	switch d := decl.(type) {
 	case *ast.GenDecl:
@@ -271,7 +260,6 @@ func (doc *docReader) addDecl(decl ast.Decl) {
 	}
 }
 
-
 func copyCommentList(list []*ast.Comment) []*ast.Comment {
 	return append([]*ast.Comment(nil), list...)
 }
@@ -281,7 +269,6 @@ var (
 	bug_content = regexp.MustCompile("[^ \n\r\t]+")                    // at least one non-whitespace char
 )
 
-
 // addFile adds the AST for a source file to the docReader.
 // Adding the same AST multiple times is a no-op.
 //
@@ -313,7 +300,6 @@ func (doc *docReader) addFile(src *ast.File) {
 	src.Comments = nil // consumed unassociated comments - remove from ast.File node
 }
 
-
 func NewFileDoc(file *ast.File) *PackageDoc {
 	var r docReader
 	r.init(file.Name.Name)
@@ -321,7 +307,6 @@ func NewFileDoc(file *ast.File) *PackageDoc {
 	return r.newDoc("", nil)
 }
 
-
 func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
 	var r docReader
 	r.init(pkg.Name)
@@ -335,7 +320,6 @@ func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
 	return r.newDoc(importpath, filenames)
 }
 
-
 // ----------------------------------------------------------------------------
 // Conversion to external representation
 
@@ -353,7 +337,6 @@ type sortValueDoc []*ValueDoc
 func (p sortValueDoc) Len() int      { return len(p) }
 func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
 
-
 func declName(d *ast.GenDecl) string {
 	if len(d.Specs) != 1 {
 		return ""
@@ -369,7 +352,6 @@ func declName(d *ast.GenDecl) string {
 	return ""
 }
 
-
 func (p sortValueDoc) Less(i, j int) bool {
 	// sort by name
 	// pull blocks (name = "") up to top
@@ -380,7 +362,6 @@ func (p sortValueDoc) Less(i, j int) bool {
 	return p[i].order < p[j].order
 }
 
-
 func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
 	d := make([]*ValueDoc, len(list)) // big enough in any case
 	n := 0
@@ -396,7 +377,6 @@ func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
 	return d
 }
 
-
 // FuncDoc is the documentation for a func declaration,
 // either a top-level function or a method function.
 //
@@ -413,7 +393,6 @@ func (p sortFuncDoc) Len() int           { return len(p) }
 func (p sortFuncDoc) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
 
-
 func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
 	d := make([]*FuncDoc, len(m))
 	i := 0
@@ -433,7 +412,6 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
 	return d
 }
 
-
 // TypeDoc is the documentation for a declared type.
 // Consts and Vars are sorted lists of constants and variables of (mostly) that type.
 // Factories is a sorted list of factory functions that return that type.
@@ -463,7 +441,6 @@ func (p sortTypeDoc) Less(i, j int) bool {
 	return p[i].order < p[j].order
 }
 
-
 // NOTE(rsc): This would appear not to be correct for type ( )
 // blocks, but the doc extractor above has split them into
 // individual declarations.
@@ -520,7 +497,6 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
 	return d
 }
 
-
 func makeBugDocs(list []*ast.CommentGroup) []string {
 	d := make([]string, len(list))
 	for i, g := range list {
@@ -529,7 +505,6 @@ func makeBugDocs(list []*ast.CommentGroup) []string {
 	return d
 }
 
-
 // PackageDoc is the documentation for an entire package.
 //
 type PackageDoc struct {
@@ -544,7 +519,6 @@ type PackageDoc struct {
 	Bugs        []string
 }
 
-
 // newDoc returns the accumulated documentation for the package.
 //
 func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
@@ -565,13 +539,11 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
 	return p
 }
 
-
 // ----------------------------------------------------------------------------
 // Filtering by name
 
 type Filter func(string) bool
 
-
 func matchFields(fields *ast.FieldList, f Filter) bool {
 	if fields != nil {
 		for _, field := range fields.List {
@@ -585,7 +557,6 @@ func matchFields(fields *ast.FieldList, f Filter) bool {
 	return false
 }
 
-
 func matchDecl(d *ast.GenDecl, f Filter) bool {
 	for _, d := range d.Specs {
 		switch v := d.(type) {
@@ -614,7 +585,6 @@ func matchDecl(d *ast.GenDecl, f Filter) bool {
 	return false
 }
 
-
 func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
 	w := 0
 	for _, vd := range a {
@@ -626,7 +596,6 @@ func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
 	return a[0:w]
 }
 
-
 func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
 	w := 0
 	for _, fd := range a {
@@ -638,7 +607,6 @@ func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
 	return a[0:w]
 }
 
-
 func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
 	w := 0
 	for _, td := range a {
@@ -661,7 +629,6 @@ func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
 	return a[0:w]
 }
 
-
 // Filter eliminates documentation for names that don't pass through the filter f.
 // TODO: Recognize "Type.Method" as a name.
 //
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index 1764c38..4f980fc 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -17,7 +17,6 @@ import (
 	"path/filepath"
 )
 
-
 // If src != nil, readSource converts src to a []byte if possible;
 // otherwise it returns an error. If src == nil, readSource returns
 // the result of reading the file specified by filename.
@@ -49,13 +48,14 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
 	return ioutil.ReadFile(filename)
 }
 
-
-func (p *parser) parseEOF() os.Error {
-	p.expect(token.EOF)
-	return p.GetError(scanner.Sorted)
+func (p *parser) errors() os.Error {
+	mode := scanner.Sorted
+	if p.mode&SpuriousErrors == 0 {
+		mode = scanner.NoMultiples
+	}
+	return p.GetError(mode)
 }
 
-
 // ParseExpr parses a Go expression and returns the corresponding
 // AST node. The fset, filename, and src arguments have the same interpretation
 // as for ParseFile. If there is an error, the result expression
@@ -73,9 +73,10 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
 	if p.tok == token.SEMICOLON {
 		p.next() // consume automatically inserted semicolon, if any
 	}
-	return x, p.parseEOF()
-}
+	p.expect(token.EOF)
 
+	return x, p.errors()
+}
 
 // ParseStmtList parses a list of Go statements and returns the list
 // of corresponding AST nodes. The fset, filename, and src arguments have the same
@@ -90,9 +91,11 @@ func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast
 
 	var p parser
 	p.init(fset, filename, data, 0)
-	return p.parseStmtList(), p.parseEOF()
-}
+	list := p.parseStmtList()
+	p.expect(token.EOF)
 
+	return list, p.errors()
+}
 
 // ParseDeclList parses a list of Go declarations and returns the list
 // of corresponding AST nodes. The fset, filename, and src arguments have the same
@@ -107,9 +110,11 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
 
 	var p parser
 	p.init(fset, filename, data, 0)
-	return p.parseDeclList(), p.parseEOF()
-}
+	list := p.parseDeclList()
+	p.expect(token.EOF)
 
+	return list, p.errors()
+}
 
 // ParseFile parses the source code of a single Go source file and returns
 // the corresponding ast.File node. The source code may be provided via
@@ -139,9 +144,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint)
 
 	var p parser
 	p.init(fset, filename, data, mode)
-	return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
-}
+	file := p.parseFile() // parseFile reads to EOF
 
+	return file, p.errors()
+}
 
 // ParseFiles calls ParseFile for each file in the filenames list and returns
 // a map of package name -> package AST with all the packages found. The mode
@@ -171,7 +177,6 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
 	return
 }
 
-
 // ParseDir calls ParseFile for the files in the directory specified by path and
 // returns a map of package name -> package AST with all the packages found. If
 // filter != nil, only the files with os.FileInfo entries passing through the filter
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index 586ee3a..618a150 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -16,7 +16,6 @@ import (
 	"go/token"
 )
 
-
 // The mode parameter to the Parse* functions is a set of flags (or 0).
 // They control the amount of source code parsed and other optional
 // parser functionality.
@@ -27,9 +26,9 @@ const (
 	ParseComments                      // parse comments and add them to AST
 	Trace                              // print a trace of parsed productions
 	DeclarationErrors                  // report declaration errors
+	SpuriousErrors                     // report all (not just the first) errors per line
 )
 
-
 // The parser structure holds the parser's internal state.
 type parser struct {
 	file *token.File
@@ -66,7 +65,6 @@ type parser struct {
 	targetStack [][]*ast.Ident // stack of unresolved labels
 }
 
-
 // scannerMode returns the scanner mode bits given the parser's mode bits.
 func scannerMode(mode uint) uint {
 	var m uint = scanner.InsertSemis
@@ -76,7 +74,6 @@ func scannerMode(mode uint) uint {
 	return m
 }
 
-
 func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
 	p.file = fset.AddFile(filename, fset.Base(), len(src))
 	p.scanner.Init(p.file, src, p, scannerMode(mode))
@@ -95,7 +92,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
 	p.openLabelScope()
 }
 
-
 // ----------------------------------------------------------------------------
 // Scoping support
 
@@ -103,18 +99,15 @@ func (p *parser) openScope() {
 	p.topScope = ast.NewScope(p.topScope)
 }
 
-
 func (p *parser) closeScope() {
 	p.topScope = p.topScope.Outer
 }
 
-
 func (p *parser) openLabelScope() {
 	p.labelScope = ast.NewScope(p.labelScope)
 	p.targetStack = append(p.targetStack, nil)
 }
 
-
 func (p *parser) closeLabelScope() {
 	// resolve labels
 	n := len(p.targetStack) - 1
@@ -130,7 +123,6 @@ func (p *parser) closeLabelScope() {
 	p.labelScope = p.labelScope.Outer
 }
 
-
 func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
 	for _, ident := range idents {
 		assert(ident.Obj == nil, "identifier already declared or resolved")
@@ -152,7 +144,6 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK
 	}
 }
 
-
 func (p *parser) shortVarDecl(idents []*ast.Ident) {
 	// Go spec: A short variable declaration may redeclare variables
 	// provided they were originally declared in the same block with
@@ -178,13 +169,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
 	}
 }
 
-
 // The unresolved object is a sentinel to mark identifiers that have been added
 // to the list of unresolved identifiers. The sentinel is only used for verifying
 // internal consistency.
 var unresolved = new(ast.Object)
 
-
 func (p *parser) resolve(x ast.Expr) {
 	// nothing to do if x is not an identifier or the blank identifier
 	ident, _ := x.(*ast.Ident)
@@ -210,7 +199,6 @@ func (p *parser) resolve(x ast.Expr) {
 	p.unresolved = append(p.unresolved, ident)
 }
 
-
 // ----------------------------------------------------------------------------
 // Parsing support
 
@@ -228,21 +216,18 @@ func (p *parser) printTrace(a ...interface{}) {
 	fmt.Println(a...)
 }
 
-
 func trace(p *parser, msg string) *parser {
 	p.printTrace(msg, "(")
 	p.indent++
 	return p
 }
 
-
 // Usage pattern: defer un(trace(p, "..."));
 func un(p *parser) {
 	p.indent--
 	p.printTrace(")")
 }
 
-
 // Advance to the next token.
 func (p *parser) next0() {
 	// Because of one-token look-ahead, print the previous token
@@ -284,7 +269,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
 	return
 }
 
-
 // Consume a group of adjacent comments, add it to the parser's
 // comments list, and return it together with the line at which
 // the last comment in the group ends. An empty line or non-comment
@@ -306,7 +290,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
 	return
 }
 
-
 // Advance to the next non-comment token. In the process, collect
 // any comment groups encountered, and remember the last lead and
 // and line comments.
@@ -357,12 +340,10 @@ func (p *parser) next() {
 	}
 }
 
-
 func (p *parser) error(pos token.Pos, msg string) {
 	p.Error(p.file.Position(pos), msg)
 }
 
-
 func (p *parser) errorExpected(pos token.Pos, msg string) {
 	msg = "expected " + msg
 	if pos == p.pos {
@@ -380,7 +361,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
 	p.error(pos, msg)
 }
 
-
 func (p *parser) expect(tok token.Token) token.Pos {
 	pos := p.pos
 	if p.tok != tok {
@@ -390,21 +370,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
 	return pos
 }
 
-
 func (p *parser) expectSemi() {
 	if p.tok != token.RPAREN && p.tok != token.RBRACE {
 		p.expect(token.SEMICOLON)
 	}
 }
 
-
 func assert(cond bool, msg string) {
 	if !cond {
 		panic("go/parser internal error: " + msg)
 	}
 }
 
-
 // ----------------------------------------------------------------------------
 // Identifiers
 
@@ -420,7 +397,6 @@ func (p *parser) parseIdent() *ast.Ident {
 	return &ast.Ident{pos, name, nil}
 }
 
-
 func (p *parser) parseIdentList() (list []*ast.Ident) {
 	if p.trace {
 		defer un(trace(p, "IdentList"))
@@ -435,7 +411,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Common productions
 
@@ -454,7 +429,6 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseLhsList() []ast.Expr {
 	list := p.parseExprList(true)
 	switch p.tok {
@@ -478,12 +452,10 @@ func (p *parser) parseLhsList() []ast.Expr {
 	return list
 }
 
-
 func (p *parser) parseRhsList() []ast.Expr {
 	return p.parseExprList(false)
 }
 
-
 // ----------------------------------------------------------------------------
 // Types
 
@@ -504,7 +476,6 @@ func (p *parser) parseType() ast.Expr {
 	return typ
 }
 
-
 // If the result is an identifier, it is not resolved.
 func (p *parser) parseTypeName() ast.Expr {
 	if p.trace {
@@ -525,7 +496,6 @@ func (p *parser) parseTypeName() ast.Expr {
 	return ident
 }
 
-
 func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "ArrayType"))
@@ -545,7 +515,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
 	return &ast.ArrayType{lbrack, len, elt}
 }
 
-
 func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
 	idents := make([]*ast.Ident, len(list))
 	for i, x := range list {
@@ -560,7 +529,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
 	return idents
 }
 
-
 func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "FieldDecl"))
@@ -602,7 +570,6 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 	return field
 }
 
-
 func (p *parser) parseStructType() *ast.StructType {
 	if p.trace {
 		defer un(trace(p, "StructType"))
@@ -624,7 +591,6 @@ func (p *parser) parseStructType() *ast.StructType {
 	return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
 }
 
-
 func (p *parser) parsePointerType() *ast.StarExpr {
 	if p.trace {
 		defer un(trace(p, "PointerType"))
@@ -636,7 +602,6 @@ func (p *parser) parsePointerType() *ast.StarExpr {
 	return &ast.StarExpr{star, base}
 }
 
-
 func (p *parser) tryVarType(isParam bool) ast.Expr {
 	if isParam && p.tok == token.ELLIPSIS {
 		pos := p.pos
@@ -654,7 +619,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
 	return p.tryIdentOrType(false)
 }
 
-
 func (p *parser) parseVarType(isParam bool) ast.Expr {
 	typ := p.tryVarType(isParam)
 	if typ == nil {
@@ -666,7 +630,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
 	return typ
 }
 
-
 func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "VarList"))
@@ -694,7 +657,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
 	if p.trace {
 		defer un(trace(p, "ParameterList"))
@@ -739,7 +701,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 	return
 }
 
-
 func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Parameters"))
@@ -755,7 +716,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
 	return &ast.FieldList{lparen, params, rparen}
 }
 
-
 func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Result"))
@@ -775,7 +735,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
 	return nil
 }
 
-
 func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
 	if p.trace {
 		defer un(trace(p, "Signature"))
@@ -787,7 +746,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis
 	return
 }
 
-
 func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 	if p.trace {
 		defer un(trace(p, "FuncType"))
@@ -800,7 +758,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 	return &ast.FuncType{pos, params, results}, scope
 }
 
-
 func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "MethodSpec"))
@@ -829,7 +786,6 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
 	return spec
 }
 
-
 func (p *parser) parseInterfaceType() *ast.InterfaceType {
 	if p.trace {
 		defer un(trace(p, "InterfaceType"))
@@ -848,7 +804,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
 	return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
 }
 
-
 func (p *parser) parseMapType() *ast.MapType {
 	if p.trace {
 		defer un(trace(p, "MapType"))
@@ -863,7 +818,6 @@ func (p *parser) parseMapType() *ast.MapType {
 	return &ast.MapType{pos, key, value}
 }
 
-
 func (p *parser) parseChanType() *ast.ChanType {
 	if p.trace {
 		defer un(trace(p, "ChanType"))
@@ -887,7 +841,6 @@ func (p *parser) parseChanType() *ast.ChanType {
 	return &ast.ChanType{pos, dir, value}
 }
 
-
 // If the result is an identifier, it is not resolved.
 func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
 	switch p.tok {
@@ -920,7 +873,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
 	return nil
 }
 
-
 func (p *parser) tryType() ast.Expr {
 	typ := p.tryIdentOrType(false)
 	if typ != nil {
@@ -929,7 +881,6 @@ func (p *parser) tryType() ast.Expr {
 	return typ
 }
 
-
 // ----------------------------------------------------------------------------
 // Blocks
 
@@ -945,7 +896,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
 	return
 }
 
-
 func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
 	if p.trace {
 		defer un(trace(p, "Body"))
@@ -962,7 +912,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
 	return &ast.BlockStmt{lbrace, list, rbrace}
 }
 
-
 func (p *parser) parseBlockStmt() *ast.BlockStmt {
 	if p.trace {
 		defer un(trace(p, "BlockStmt"))
@@ -977,7 +926,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
 	return &ast.BlockStmt{lbrace, list, rbrace}
 }
 
-
 // ----------------------------------------------------------------------------
 // Expressions
 
@@ -999,7 +947,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
 	return &ast.FuncLit{typ, body}
 }
 
-
 // parseOperand may return an expression or a raw type (incl. array
 // types of the form [...]T. Callers must verify the result.
 // If lhs is set and the result is an identifier, it is not resolved.
@@ -1049,7 +996,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
 	return &ast.BadExpr{pos, p.pos}
 }
 
-
 func (p *parser) parseSelector(x ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Selector"))
@@ -1060,7 +1006,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
 	return &ast.SelectorExpr{x, sel}
 }
 
-
 func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "TypeAssertion"))
@@ -1079,7 +1024,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
 	return &ast.TypeAssertExpr{x, typ}
 }
 
-
 func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "IndexOrSlice"))
@@ -1108,7 +1052,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 	return &ast.IndexExpr{x, lbrack, low, rbrack}
 }
 
-
 func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	if p.trace {
 		defer un(trace(p, "CallOrConversion"))
@@ -1135,7 +1078,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
 }
 
-
 func (p *parser) parseElement(keyOk bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Element"))
@@ -1158,7 +1100,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
 	return x
 }
 
-
 func (p *parser) parseElementList() (list []ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "ElementList"))
@@ -1175,7 +1116,6 @@ func (p *parser) parseElementList() (list []ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "LiteralValue"))
@@ -1192,7 +1132,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
 	return &ast.CompositeLit{typ, lbrace, elts, rbrace}
 }
 
-
 // checkExpr checks that x is an expression (and not a type).
 func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	switch t := unparen(x).(type) {
@@ -1229,7 +1168,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // isTypeName returns true iff x is a (qualified) TypeName.
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
@@ -1244,7 +1182,6 @@ func isTypeName(x ast.Expr) bool {
 	return true
 }
 
-
 // isLiteralType returns true iff x is a legal composite literal type.
 func isLiteralType(x ast.Expr) bool {
 	switch t := x.(type) {
@@ -1262,7 +1199,6 @@ func isLiteralType(x ast.Expr) bool {
 	return true
 }
 
-
 // If x is of the form *T, deref returns T, otherwise it returns x.
 func deref(x ast.Expr) ast.Expr {
 	if p, isPtr := x.(*ast.StarExpr); isPtr {
@@ -1271,7 +1207,6 @@ func deref(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
 func unparen(x ast.Expr) ast.Expr {
 	if p, isParen := x.(*ast.ParenExpr); isParen {
@@ -1280,7 +1215,6 @@ func unparen(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // checkExprOrType checks that x is an expression or a type
 // (and not a raw type such as [...]T).
 //
@@ -1305,7 +1239,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
 	if p.trace {
@@ -1360,7 +1293,6 @@ L:
 	return x
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 	if p.trace {
@@ -1398,7 +1330,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 	return p.parsePrimaryExpr(lhs)
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	if p.trace {
@@ -1422,7 +1353,6 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	return x
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 // TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
 //            should reject when a type/raw type is obviously not allowed
@@ -1434,12 +1364,10 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
 	return p.parseBinaryExpr(lhs, token.LowestPrec+1)
 }
 
-
 func (p *parser) parseRhs() ast.Expr {
 	return p.parseExpr(false)
 }
 
-
 // ----------------------------------------------------------------------------
 // Statements
 
@@ -1481,7 +1409,13 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 			p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
 			return stmt
 		}
-		p.error(x[0].Pos(), "illegal label declaration")
+		// The label declaration typically starts at x[0].Pos(), but the label
+		// declaration may be erroneous due to a token after that position (and
+		// before the ':'). If SpuriousErrors is not set, the (only) error re-
+		// ported for the line is the illegal label error instead of the token
+		// before the ':' that caused the problem. Thus, use the (latest) colon
+		// position for error reporting.
+		p.error(colon, "illegal label declaration")
 		return &ast.BadStmt{x[0].Pos(), colon + 1}
 
 	case token.ARROW:
@@ -1502,7 +1436,6 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 	return &ast.ExprStmt{x[0]}
 }
 
-
 func (p *parser) parseCallExpr() *ast.CallExpr {
 	x := p.parseRhs()
 	if call, isCall := x.(*ast.CallExpr); isCall {
@@ -1512,7 +1445,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
 	return nil
 }
 
-
 func (p *parser) parseGoStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "GoStmt"))
@@ -1528,7 +1460,6 @@ func (p *parser) parseGoStmt() ast.Stmt {
 	return &ast.GoStmt{pos, call}
 }
 
-
 func (p *parser) parseDeferStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "DeferStmt"))
@@ -1544,7 +1475,6 @@ func (p *parser) parseDeferStmt() ast.Stmt {
 	return &ast.DeferStmt{pos, call}
 }
 
-
 func (p *parser) parseReturnStmt() *ast.ReturnStmt {
 	if p.trace {
 		defer un(trace(p, "ReturnStmt"))
@@ -1561,7 +1491,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
 	return &ast.ReturnStmt{pos, x}
 }
 
-
 func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
 	if p.trace {
 		defer un(trace(p, "BranchStmt"))
@@ -1580,7 +1509,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
 	return &ast.BranchStmt{pos, tok, label}
 }
 
-
 func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
 	if s == nil {
 		return nil
@@ -1592,7 +1520,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
 	return &ast.BadExpr{s.Pos(), s.End()}
 }
 
-
 func (p *parser) parseIfStmt() *ast.IfStmt {
 	if p.trace {
 		defer un(trace(p, "IfStmt"))
@@ -1635,7 +1562,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
 	return &ast.IfStmt{pos, s, x, body, else_}
 }
 
-
 func (p *parser) parseTypeList() (list []ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "TypeList"))
@@ -1650,7 +1576,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
 	if p.trace {
 		defer un(trace(p, "CaseClause"))
@@ -1677,7 +1602,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
 	return &ast.CaseClause{pos, list, colon, body}
 }
 
-
 func isExprSwitch(s ast.Stmt) bool {
 	if s == nil {
 		return true
@@ -1691,7 +1615,6 @@ func isExprSwitch(s ast.Stmt) bool {
 	return false
 }
 
-
 func (p *parser) parseSwitchStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "SwitchStmt"))
@@ -1737,7 +1660,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
 	return &ast.TypeSwitchStmt{pos, s1, s2, body}
 }
 
-
 func (p *parser) parseCommClause() *ast.CommClause {
 	if p.trace {
 		defer un(trace(p, "CommClause"))
@@ -1799,7 +1721,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
 	return &ast.CommClause{pos, comm, colon, body}
 }
 
-
 func (p *parser) parseSelectStmt() *ast.SelectStmt {
 	if p.trace {
 		defer un(trace(p, "SelectStmt"))
@@ -1818,7 +1739,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
 	return &ast.SelectStmt{pos, body}
 }
 
-
 func (p *parser) parseForStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "ForStmt"))
@@ -1888,7 +1808,6 @@ func (p *parser) parseForStmt() ast.Stmt {
 	return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
 }
 
-
 func (p *parser) parseStmt() (s ast.Stmt) {
 	if p.trace {
 		defer un(trace(p, "Statement"))
@@ -1945,13 +1864,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Declarations
 
 type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
 
-
 func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "ImportSpec"))
@@ -1982,7 +1899,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	return spec
 }
 
-
 func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "ConstSpec"))
@@ -2007,7 +1923,6 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
 	return spec
 }
 
-
 func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "TypeSpec"))
@@ -2029,7 +1944,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	return spec
 }
 
-
 func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "VarSpec"))
@@ -2054,7 +1968,6 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	return spec
 }
 
-
 func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
 	if p.trace {
 		defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2079,7 +1992,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
 	return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
 }
 
-
 func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Receiver"))
@@ -2107,7 +2019,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
 	return par
 }
 
-
 func (p *parser) parseFuncDecl() *ast.FuncDecl {
 	if p.trace {
 		defer un(trace(p, "FunctionDecl"))
@@ -2148,7 +2059,6 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
 	return decl
 }
 
-
 func (p *parser) parseDecl() ast.Decl {
 	if p.trace {
 		defer un(trace(p, "Declaration"))
@@ -2179,7 +2089,6 @@ func (p *parser) parseDecl() ast.Decl {
 	return p.parseGenDecl(p.tok, f)
 }
 
-
 func (p *parser) parseDeclList() (list []ast.Decl) {
 	if p.trace {
 		defer un(trace(p, "DeclList"))
@@ -2192,7 +2101,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Source files
 
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 5b52f51..8269db8 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -10,7 +10,6 @@ import (
 	"testing"
 )
 
-
 var fset = token.NewFileSet()
 
 var illegalInputs = []interface{}{
@@ -24,7 +23,6 @@ var illegalInputs = []interface{}{
 	`package p; const c; /* should have constant value */`,
 }
 
-
 func TestParseIllegalInputs(t *testing.T) {
 	for _, src := range illegalInputs {
 		_, err := ParseFile(fset, "", src, 0)
@@ -34,7 +32,6 @@ func TestParseIllegalInputs(t *testing.T) {
 	}
 }
 
-
 var validPrograms = []interface{}{
 	"package p\n",
 	`package p;`,
@@ -56,7 +53,6 @@ var validPrograms = []interface{}{
 	`package p; func f() { switch ; {} };`,
 }
 
-
 func TestParseValidPrograms(t *testing.T) {
 	for _, src := range validPrograms {
 		_, err := ParseFile(fset, "", src, 0)
@@ -66,13 +62,11 @@ func TestParseValidPrograms(t *testing.T) {
 	}
 }
 
-
 var validFiles = []string{
 	"parser.go",
 	"parser_test.go",
 }
 
-
 func TestParse3(t *testing.T) {
 	for _, filename := range validFiles {
 		_, err := ParseFile(fset, filename, nil, DeclarationErrors)
@@ -82,7 +76,6 @@ func TestParse3(t *testing.T) {
 	}
 }
 
-
 func nameFilter(filename string) bool {
 	switch filename {
 	case "parser.go":
@@ -94,10 +87,8 @@ func nameFilter(filename string) bool {
 	return true
 }
 
-
 func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
 
-
 func TestParse4(t *testing.T) {
 	path := "."
 	pkgs, err := ParseDir(fset, path, dirFilter, 0)
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index f2b79d8..9cd975e 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -14,7 +14,6 @@ import (
 	"go/token"
 )
 
-
 // Other formatting issues:
 // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
 //   when the comment spans multiple lines; if such a comment is just two lines, formatting is
@@ -23,7 +22,6 @@ import (
 // - should use blank instead of tab to separate one-line function bodies from
 //   the function header unless there is a group of consecutive one-liners
 
-
 // ----------------------------------------------------------------------------
 // Common AST nodes.
 
@@ -56,7 +54,6 @@ func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin
 	return
 }
 
-
 // setComment sets g as the next comment if g != nil and if node comments
 // are enabled - this mode is used when printing source code fragments such
 // as exports only. It assumes that there are no other pending comments to
@@ -78,7 +75,6 @@ func (p *printer) setComment(g *ast.CommentGroup) {
 	p.cindex = 0
 }
 
-
 type exprListMode uint
 
 const (
@@ -90,7 +86,6 @@ const (
 	periodSep                           // elements are separated by periods
 )
 
-
 // Sets multiLine to true if the identifier list spans multiple lines.
 // If indent is set, a multi-line identifier list is indented after the
 // first linebreak encountered.
@@ -107,7 +102,6 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
 	p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
 }
 
-
 // Print a list of expressions. If the list spans multiple
 // source lines, the original line breaks are respected between
 // expressions. Sets multiLine to true if the list spans multiple
@@ -271,7 +265,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
 	}
 }
 
-
 // Sets multiLine to true if the the parameter list spans multiple lines.
 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
 	p.print(fields.Opening, token.LPAREN)
@@ -302,7 +295,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
 	p.print(fields.Closing, token.RPAREN)
 }
 
-
 // Sets multiLine to true if the signature spans multiple lines.
 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
 	p.parameters(params, multiLine)
@@ -318,7 +310,6 @@ func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
 	}
 }
 
-
 func identListSize(list []*ast.Ident, maxSize int) (size int) {
 	for i, x := range list {
 		if i > 0 {
@@ -332,7 +323,6 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) {
 	return
 }
 
-
 func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
 	if len(list) != 1 {
 		return false // allow only one field
@@ -351,18 +341,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
 	return namesSize+typeSize <= maxSize
 }
 
-
 func (p *printer) setLineComment(text string) {
 	p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
 }
 
-
 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
-	p.nesting++
-	defer func() {
-		p.nesting--
-	}()
-
 	lbrace := fields.Opening
 	list := fields.List
 	rbrace := fields.Closing
@@ -475,7 +458,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
 	p.print(unindent, formfeed, rbrace, token.RBRACE)
 }
 
-
 // ----------------------------------------------------------------------------
 // Expressions
 
@@ -534,7 +516,6 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
 	return
 }
 
-
 func cutoff(e *ast.BinaryExpr, depth int) int {
 	has4, has5, maxProblem := walkBinary(e)
 	if maxProblem > 0 {
@@ -552,7 +533,6 @@ func cutoff(e *ast.BinaryExpr, depth int) int {
 	return 4
 }
 
-
 func diffPrec(expr ast.Expr, prec int) int {
 	x, ok := expr.(*ast.BinaryExpr)
 	if !ok || prec != x.Op.Precedence() {
@@ -561,7 +541,6 @@ func diffPrec(expr ast.Expr, prec int) int {
 	return 0
 }
 
-
 func reduceDepth(depth int) int {
 	depth--
 	if depth < 1 {
@@ -570,7 +549,6 @@ func reduceDepth(depth int) int {
 	return depth
 }
 
-
 // Format the binary expression: decide the cutoff and then format.
 // Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
 // (Algorithm suggestion by Russ Cox.)
@@ -648,13 +626,11 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
 	}
 }
 
-
 func isBinary(expr ast.Expr) bool {
 	_, ok := expr.(*ast.BinaryExpr)
 	return ok
 }
 
-
 // If the expression contains one or more selector expressions, splits it into
 // two expressions at the rightmost period. Writes entire expr to suffix when
 // selector isn't found. Rewrites AST nodes for calls, index expressions and
@@ -694,7 +670,6 @@ func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
 	return
 }
 
-
 // Convert an expression into an expression list split at the periods of
 // selector expressions.
 func selectorExprList(expr ast.Expr) (list []ast.Expr) {
@@ -713,7 +688,6 @@ func selectorExprList(expr ast.Expr) (list []ast.Expr) {
 	return
 }
 
-
 // Sets multiLine to true if the expression spans multiple lines.
 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
 	p.print(expr.Pos())
@@ -900,19 +874,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
 	return
 }
 
-
 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
 	p.expr1(x, token.LowestPrec, depth, multiLine)
 }
 
-
 // Sets multiLine to true if the expression spans multiple lines.
 func (p *printer) expr(x ast.Expr, multiLine *bool) {
 	const depth = 1
 	p.expr1(x, token.LowestPrec, depth, multiLine)
 }
 
-
 // ----------------------------------------------------------------------------
 // Statements
 
@@ -937,7 +908,6 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
 	}
 }
 
-
 // block prints an *ast.BlockStmt; it always spans at least two lines.
 func (p *printer) block(s *ast.BlockStmt, indent int) {
 	p.print(s.Pos(), token.LBRACE)
@@ -946,7 +916,6 @@ func (p *printer) block(s *ast.BlockStmt, indent int) {
 	p.print(s.Rbrace, token.RBRACE)
 }
 
-
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.Ident:
@@ -957,7 +926,6 @@ func isTypeName(x ast.Expr) bool {
 	return false
 }
 
-
 func stripParens(x ast.Expr) ast.Expr {
 	if px, strip := x.(*ast.ParenExpr); strip {
 		// parentheses must not be stripped if there are any
@@ -984,7 +952,6 @@ func stripParens(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
 	p.print(blank)
 	needsBlank := false
@@ -1019,7 +986,6 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
 	}
 }
 
-
 // Sets multiLine to true if the statements spans multiple lines.
 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
 	p.print(stmt.Pos())
@@ -1193,7 +1159,6 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Declarations
 
@@ -1262,7 +1227,6 @@ func keepTypeColumn(specs []ast.Spec) []bool {
 	return m
 }
 
-
 func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
 	p.setComment(s.Doc)
 	p.identList(s.Names, doIndent, multiLine) // always present
@@ -1287,7 +1251,6 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine
 	}
 }
 
-
 // The parameter n is the number of specs in the group. If doIndent is set,
 // multi-line identifier lists in the spec are indented when the first
 // linebreak is encountered.
@@ -1336,7 +1299,6 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
 	}
 }
 
-
 // Sets multiLine to true if the declaration spans multiple lines.
 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
 	p.setComment(d.Doc)
@@ -1380,7 +1342,6 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
 	}
 }
 
-
 // nodeSize determines the size of n in chars after formatting.
 // The result is <= maxSize if the node fits on one line with at
 // most maxSize chars and the formatted output doesn't contain
@@ -1418,7 +1379,6 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
 	return
 }
 
-
 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
 	pos1 := b.Pos()
 	pos2 := b.Rbrace
@@ -1442,18 +1402,12 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
 	return headerSize+bodySize <= maxSize
 }
 
-
 // Sets multiLine to true if the function body spans multiple lines.
 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
 	if b == nil {
 		return
 	}
 
-	p.nesting++
-	defer func() {
-		p.nesting--
-	}()
-
 	if p.isOneLineFunc(b, headerSize) {
 		sep := vtab
 		if isLit {
@@ -1479,7 +1433,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
 	*multiLine = true
 }
 
-
 // distance returns the column difference between from and to if both
 // are on the same line; if they are on different lines (or unknown)
 // the result is infinity.
@@ -1491,7 +1444,6 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int {
 	return infinity
 }
 
-
 // Sets multiLine to true if the declaration spans multiple lines.
 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
 	p.setComment(d.Doc)
@@ -1505,7 +1457,6 @@ func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
 	p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
 }
 
-
 // Sets multiLine to true if the declaration spans multiple lines.
 func (p *printer) decl(decl ast.Decl, multiLine *bool) {
 	switch d := decl.(type) {
@@ -1520,7 +1471,6 @@ func (p *printer) decl(decl ast.Decl, multiLine *bool) {
 	}
 }
 
-
 // ----------------------------------------------------------------------------
 // Files
 
@@ -1535,7 +1485,6 @@ func declToken(decl ast.Decl) (tok token.Token) {
 	return
 }
 
-
 func (p *printer) file(src *ast.File) {
 	p.setComment(src.Doc)
 	p.print(src.Pos(), token.PACKAGE, blank)
diff --git a/src/pkg/go/printer/performance_test.go b/src/pkg/go/printer/performance_test.go
index 31de0b7..84fb280 100644
--- a/src/pkg/go/printer/performance_test.go
+++ b/src/pkg/go/printer/performance_test.go
@@ -17,17 +17,14 @@ import (
 	"testing"
 )
 
-
 var testfile *ast.File
 
-
 func testprint(out io.Writer, file *ast.File) {
 	if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
 		log.Fatalf("print error: %s", err)
 	}
 }
 
-
 // cannot initialize in init because (printer) Fprint launches goroutines.
 func initialize() {
 	const filename = "testdata/parser.go"
@@ -51,7 +48,6 @@ func initialize() {
 	testfile = file
 }
 
-
 func BenchmarkPrint(b *testing.B) {
 	if testfile == nil {
 		initialize()
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 40b15dd..871fefa 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -17,7 +17,6 @@ import (
 	"tabwriter"
 )
 
-
 const debug = false // enable for debugging
 
 
@@ -33,7 +32,6 @@ const (
 	unindent = whiteSpace('<')
 )
 
-
 var (
 	esc       = []byte{tabwriter.Escape}
 	htab      = []byte{'\t'}
@@ -42,16 +40,13 @@ var (
 	formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
 )
 
-
 // Special positions
 var noPos token.Position // use noPos when a position is needed but not known
 var infinity = 1 << 30
 
-
 // Use ignoreMultiLine if the multiLine information is not important.
 var ignoreMultiLine = new(bool)
 
-
 // A pmode value represents the current printer mode.
 type pmode int
 
@@ -60,7 +55,6 @@ const (
 	noExtraLinebreak
 )
 
-
 type printer struct {
 	// Configuration (does not change after initialization)
 	output io.Writer
@@ -69,7 +63,6 @@ type printer struct {
 	errors chan os.Error
 
 	// Current state
-	nesting int         // nesting level (0: top-level (package scope), >0: functions/decls.)
 	written int         // number of bytes written
 	indent  int         // current indentation
 	mode    pmode       // current printer mode
@@ -98,7 +91,6 @@ type printer struct {
 	nodeSizes map[ast.Node]int
 }
 
-
 func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
 	p.output = output
 	p.Config = *cfg
@@ -108,7 +100,6 @@ func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS
 	p.nodeSizes = nodeSizes
 }
 
-
 func (p *printer) internalError(msg ...interface{}) {
 	if debug {
 		fmt.Print(p.pos.String() + ": ")
@@ -117,7 +108,6 @@ func (p *printer) internalError(msg ...interface{}) {
 	}
 }
 
-
 // escape escapes string s by bracketing it with tabwriter.Escape.
 // Escaped strings pass through tabwriter unchanged. (Note that
 // valid Go programs cannot contain tabwriter.Escape bytes since
@@ -131,26 +121,20 @@ func (p *printer) escape(s string) string {
 	return p.litbuf.String()
 }
 
-
 // nlines returns the adjusted number of linebreaks given the desired number
-// of breaks n such that min <= result <= max where max depends on the current
-// nesting level.
+// of breaks n such that min <= result <= max.
 //
 func (p *printer) nlines(n, min int) int {
-	if n < min {
+	const max = 2 // max. number of newlines
+	switch {
+	case n < min:
 		return min
-	}
-	max := 3 // max. number of newlines at the top level (p.nesting == 0)
-	if p.nesting > 0 {
-		max = 2 // max. number of newlines everywhere else
-	}
-	if n > max {
+	case n > max:
 		return max
 	}
 	return n
 }
 
-
 // write0 writes raw (uninterpreted) data to p.output and handles errors.
 // write0 does not indent after newlines, and does not HTML-escape or update p.pos.
 //
@@ -165,7 +149,6 @@ func (p *printer) write0(data []byte) {
 	}
 }
 
-
 // write interprets data and writes it to p.output. It inserts indentation
 // after a line break unless in a tabwriter escape sequence.
 // It updates p.pos as a side-effect.
@@ -220,7 +203,6 @@ func (p *printer) write(data []byte) {
 	p.pos.Column += d
 }
 
-
 func (p *printer) writeNewlines(n int, useFF bool) {
 	if n > 0 {
 		n = p.nlines(n, 0)
@@ -232,7 +214,6 @@ func (p *printer) writeNewlines(n int, useFF bool) {
 	}
 }
 
-
 // writeItem writes data at position pos. data is the text corresponding to
 // a single lexical token, but may also be comment text. pos is the actual
 // (or at least very accurately estimated) position of the data in the original
@@ -261,7 +242,6 @@ func (p *printer) writeItem(pos token.Position, data string) {
 	p.last = p.pos
 }
 
-
 // writeCommentPrefix writes the whitespace before a comment.
 // If there is any pending whitespace, it consumes as much of
 // it as is likely to help position the comment nicely.
@@ -368,7 +348,6 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
 	}
 }
 
-
 // TODO(gri): It should be possible to convert the code below from using
 //            []byte to string and in the process eliminate some conversions.
 
@@ -398,7 +377,6 @@ func split(text []byte) [][]byte {
 	return lines
 }
 
-
 func isBlank(s []byte) bool {
 	for _, b := range s {
 		if b > ' ' {
@@ -408,7 +386,6 @@ func isBlank(s []byte) bool {
 	return true
 }
 
-
 func commonPrefix(a, b []byte) []byte {
 	i := 0
 	for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
@@ -417,7 +394,6 @@ func commonPrefix(a, b []byte) []byte {
 	return a[0:i]
 }
 
-
 func stripCommonPrefix(lines [][]byte) {
 	if len(lines) < 2 {
 		return // at most one line - nothing to do
@@ -545,7 +521,6 @@ func stripCommonPrefix(lines [][]byte) {
 	}
 }
 
-
 func (p *printer) writeComment(comment *ast.Comment) {
 	text := comment.Text
 
@@ -575,7 +550,6 @@ func (p *printer) writeComment(comment *ast.Comment) {
 	}
 }
 
-
 // writeCommentSuffix writes a line break after a comment if indicated
 // and processes any leftover indentation information. If a line break
 // is needed, the kind of break (newline vs formfeed) depends on the
@@ -613,7 +587,6 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
 	return
 }
 
-
 // intersperseComments consumes all comments that appear before the next token
 // tok and prints it together with the buffered whitespace (i.e., the whitespace
 // that needs to be written before the next token). A heuristic is used to mix
@@ -651,7 +624,6 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
 	return false
 }
 
-
 // whiteWhitespace writes the first n whitespace entries.
 func (p *printer) writeWhitespace(n int) {
 	// write entries
@@ -701,7 +673,6 @@ func (p *printer) writeWhitespace(n int) {
 	p.wsbuf = p.wsbuf[0:i]
 }
 
-
 // ----------------------------------------------------------------------------
 // Printing interface
 
@@ -724,7 +695,6 @@ func mayCombine(prev token.Token, next byte) (b bool) {
 	return
 }
 
-
 // print prints a list of "items" (roughly corresponding to syntactic
 // tokens, but also including whitespace and formatting information).
 // It is the only print function that should be called directly from
@@ -812,7 +782,6 @@ func (p *printer) print(args ...interface{}) {
 	}
 }
 
-
 // commentBefore returns true iff the current comment occurs
 // before the next position in the source code.
 //
@@ -820,7 +789,6 @@ func (p *printer) commentBefore(next token.Position) bool {
 	return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
 }
 
-
 // Flush prints any pending comments and whitespace occurring
 // textually before the position of the next token tok. Flush
 // returns true if a pending formfeed character was dropped
@@ -838,7 +806,6 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Trimmer
 
@@ -854,7 +821,6 @@ type trimmer struct {
 	space  bytes.Buffer
 }
 
-
 // trimmer is implemented as a state machine.
 // It can be in one of the following states:
 const (
@@ -863,7 +829,6 @@ const (
 	inText          // inside text
 )
 
-
 // Design note: It is tempting to eliminate extra blanks occurring in
 //              whitespace in this function as it could simplify some
 //              of the blanks logic in the node printing functions.
@@ -941,7 +906,6 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Public interface
 
@@ -952,14 +916,12 @@ const (
 	UseSpaces                  // use spaces instead of tabs for alignment
 )
 
-
 // A Config node controls the output of Fprint.
 type Config struct {
 	Mode     uint // default: 0
 	Tabwidth int  // default: 8
 }
 
-
 // fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
 func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (int, os.Error) {
 	// redirect output through a trimmer to eliminate trailing whitespace
@@ -994,11 +956,9 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
 	go func() {
 		switch n := node.(type) {
 		case ast.Expr:
-			p.nesting = 1
 			p.useNodeComments = true
 			p.expr(n, ignoreMultiLine)
 		case ast.Stmt:
-			p.nesting = 1
 			p.useNodeComments = true
 			// A labeled statement will un-indent to position the
 			// label. Set indent to 1 so we don't get indent "underflow".
@@ -1007,15 +967,12 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
 			}
 			p.stmt(n, false, ignoreMultiLine)
 		case ast.Decl:
-			p.nesting = 1
 			p.useNodeComments = true
 			p.decl(n, ignoreMultiLine)
 		case ast.Spec:
-			p.nesting = 1
 			p.useNodeComments = true
 			p.spec(n, 1, false, ignoreMultiLine)
 		case *ast.File:
-			p.nesting = 0
 			p.comments = n.Comments
 			p.useNodeComments = n.Comments == nil
 			p.file(n)
@@ -1036,7 +993,6 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
 	return p.written, err
 }
 
-
 // Fprint "pretty-prints" an AST node to output and returns the number
 // of bytes written and an error (if any) for a given configuration cfg.
 // Position information is interpreted relative to the file set fset.
@@ -1047,7 +1003,6 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
 	return cfg.fprint(output, fset, node, make(map[ast.Node]int))
 }
 
-
 // Fprint "pretty-prints" an AST node to output.
 // It calls Config.Fprint with default settings.
 //
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index 090f92a..ff2d906 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -16,19 +16,15 @@ import (
 	"time"
 )
 
-
 const (
 	dataDir  = "testdata"
 	tabwidth = 8
 )
 
-
 var update = flag.Bool("update", false, "update golden files")
 
-
 var fset = token.NewFileSet()
 
-
 func lineString(text []byte, i int) string {
 	i0 := i
 	for i < len(text) && text[i] != '\n' {
@@ -37,7 +33,6 @@ func lineString(text []byte, i int) string {
 	return string(text[i0:i])
 }
 
-
 type checkMode uint
 
 const (
@@ -45,7 +40,6 @@ const (
 	rawFormat
 )
 
-
 func runcheck(t *testing.T, source, golden string, mode checkMode) {
 	// parse source
 	prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
@@ -109,7 +103,6 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) {
 	}
 }
 
-
 func check(t *testing.T, source, golden string, mode checkMode) {
 	// start a timer to produce a time-out signal
 	tc := make(chan int)
@@ -135,7 +128,6 @@ func check(t *testing.T, source, golden string, mode checkMode) {
 	}
 }
 
-
 type entry struct {
 	source, golden string
 	mode           checkMode
@@ -154,7 +146,6 @@ var data = []entry{
 	{"slow.input", "slow.golden", 0},
 }
 
-
 func TestFiles(t *testing.T) {
 	for i, e := range data {
 		source := filepath.Join(dataDir, e.source)
@@ -168,7 +159,6 @@ func TestFiles(t *testing.T) {
 	}
 }
 
-
 // TestLineComments, using a simple test case, checks that consequtive line
 // comments are properly terminated with a newline even if the AST position
 // information is incorrect.
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
index b177c35..7b33225 100644
--- a/src/pkg/go/printer/testdata/comments.golden
+++ b/src/pkg/go/printer/testdata/comments.golden
@@ -106,7 +106,6 @@ type S3 struct {
 var x int	// x
 var ()
 
-
 // This comment SHOULD be associated with the next declaration.
 func f0() {
 	const pi = 3.14	// pi
@@ -128,12 +127,10 @@ func f1() {
 	f0()
 }
 
-
 func _() {
 	// this comment should be properly indented
 }
 
-
 func _(x int) int {
 	if x < 0 {	// the tab printed before this comment's // must not affect the remaining lines
 		return -x	// this statement should be properly indented
@@ -144,7 +141,6 @@ func _(x int) int {
 	return x
 }
 
-
 func typeswitch(x interface{}) {
 	switch v := x.(type) {
 	case bool, int, float:
@@ -211,7 +207,6 @@ func _() {
 		aligned line */
 }
 
-
 func _() {
 	/*
 	   freestanding comment
@@ -292,7 +287,6 @@ func _() {
 		aligned line */
 }
 
-
 func _() {
 	/*
 	   freestanding comment
@@ -409,7 +403,6 @@ func _() {
 	*/
 }
 
-
 // Some interesting interspersed comments
 func _( /* this */ x /* is */ /* an */ int) {
 }
@@ -434,7 +427,6 @@ func _() {
 	_ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
 }
 
-
 // Comments immediately adjacent to punctuation (for which the go/printer
 // may only have estimated position information) must remain after the punctuation.
 func _() {
@@ -466,7 +458,6 @@ func _() {
 	}
 }
 
-
 // Line comments with tabs
 func _() {
 	var finput *bufio.Reader	// input file
@@ -479,5 +470,4 @@ func _() {
 	var lflag bool		// -l			- disable line directives
 }
 
-
 /* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/src/pkg/go/printer/testdata/comments.x b/src/pkg/go/printer/testdata/comments.x
index 30a182f..ae77292 100644
--- a/src/pkg/go/printer/testdata/comments.x
+++ b/src/pkg/go/printer/testdata/comments.x
@@ -2,7 +2,6 @@
 //
 package main
 
-
 // The SZ struct; it is empty.
 type SZ struct{}
 
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index fac72f6..970533e 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -44,7 +44,6 @@ import _ "os"
 import _ "os"
 import _ "os"
 
-
 import _ "fmt"
 import _ "fmt"
 import _ "fmt"
@@ -116,7 +115,6 @@ import _ "io"
 
 var _ int
 
-
 // printing of constant literals
 const (
 	_	= "foobar"
@@ -158,7 +156,6 @@ const (
 bar`
 )
 
-
 func _() {
 	type _ int
 	type _ *int
@@ -203,7 +200,6 @@ func _() {
 	var _ func() interface{}
 }
 
-
 // don't lose blank lines in grouped declarations
 const (
 	_	int	= 0
@@ -220,7 +216,6 @@ const (
 	_
 )
 
-
 type (
 	_	int
 	_	struct{}
@@ -231,7 +226,6 @@ type (
 	_	map[string]int
 )
 
-
 var (
 	_	int	= 0
 	_	float	= 1
@@ -244,7 +238,6 @@ var (
 	_	bool
 )
 
-
 // don't lose blank lines in this struct
 type _ struct {
 	String	struct {
@@ -293,7 +286,6 @@ type _ struct {
 	}
 }
 
-
 // no tabs for single or ungrouped decls
 func _() {
 	const xxxxxx = 0
@@ -426,7 +418,6 @@ var (
 	filterDelay	delayTime	// actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
 )
 
-
 // formatting of structs
 type _ struct{}
 
@@ -494,14 +485,12 @@ type _ struct {
 	r, s	float	// this line should be indented
 }
 
-
 // difficult cases
 type _ struct {
 	bool		// comment
 	text	[]byte	// comment
 }
 
-
 // formatting of interfaces
 type EI interface{}
 
@@ -527,7 +516,6 @@ type _ interface {	// this comment must not change indentation
 	gggggggggggg(x, y, z int)	// hurray
 }
 
-
 // formatting of variable declarations
 func _() {
 	type day struct {
@@ -545,7 +533,6 @@ func _() {
 	)
 }
 
-
 // formatting of multi-line variable declarations
 var a1, b1, c1 int	// all on one line
 
@@ -558,7 +545,6 @@ var (
 	a4, b4, c4	int	// this line should be indented
 )
 
-
 func _() {
 	var privateKey2 = &Block{Type:	"RSA PRIVATE KEY",
 		Headers:	map[string]string{},
@@ -570,7 +556,6 @@ func _() {
 	}
 }
 
-
 func _() {
 	var Universe = Scope{
 		Names: map[string]*Ident{
@@ -614,7 +599,6 @@ func _() {
 	}
 }
 
-
 // alignment of map composite entries
 var _ = map[int]int{
 	// small key sizes: always align even if size ratios are large
@@ -638,21 +622,18 @@ var _ = map[int]int{
 	abcde:	a,	// align with previous line
 }
 
-
 func _() {
 	var _ = T{
 		a,	// must introduce trailing comma
 	}
 }
 
-
 // formatting of function results
 func _() func()				{}
 func _() func(int)			{ return nil }
 func _() func(int) int			{ return nil }
 func _() func(int) func(int) func()	{ return nil }
 
-
 // formatting of consecutive single-line functions
 func _()	{}
 func _()	{}
@@ -680,7 +661,6 @@ func _() int {
 	return x
 }
 
-
 // making function declarations safe for new semicolon rules
 func _() { /* multi-line func because of comment */
 }
@@ -689,7 +669,6 @@ func _() {
 	/* multi-line func because block is on multiple lines */
 }
 
-
 // ellipsis parameters
 func _(...int)
 func _(...*int)
@@ -711,7 +690,6 @@ func _(x ...func(...int))
 func _(x ...map[string]int)
 func _(x ...chan int)
 
-
 // these parameter lists must remain multi-line since they are multi-line in the source
 func _(bool,
 int) {
diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden
index a5e2fdc..d0cf24a 100644
--- a/src/pkg/go/printer/testdata/expressions.golden
+++ b/src/pkg/go/printer/testdata/expressions.golden
@@ -17,7 +17,6 @@ var (
 	p							*int
 )
 
-
 func _() {
 	// no spaces around simple or parenthesized expressions
 	_ = (a + 0)
@@ -115,7 +114,6 @@ func _() {
 	x < y || z > 42
 }
 
-
 func _() {
 	_ = a + b
 	_ = a + b + c
@@ -187,7 +185,6 @@ func _() {
 	_ = token(matchType + xlength<<lengthShift + xoffset)
 }
 
-
 func f(x int, args ...int) {
 	f(0, args...)
 	f(1, args)
@@ -226,7 +223,6 @@ func f(x int, args ...int) {
 	_ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
 }
 
-
 func _() {
 	_ = T{}
 	_ = struct{}{}
@@ -236,7 +232,6 @@ func _() {
 	_ = map[int]T{}
 }
 
-
 // one-line structs/interfaces in composite literals (up to a threshold)
 func _() {
 	_ = struct{}{}
@@ -246,7 +241,6 @@ func _() {
 	_ = struct{ s struct{ int } }{struct{ int }{0}}
 }
 
-
 func _() {
 	// do not modify literals
 	_ = "tab1	tab2	tab3	end"	// string contains 3 tabs
@@ -261,7 +255,6 @@ func _() {
 they must not be removed`
 }
 
-
 func _() {
 	// smart handling of indentation for multi-line raw strings
 	var _ = ``
@@ -332,7 +325,6 @@ bar`
 	}
 }
 
-
 func _() {
 	// one-line function literals (body is on a single line)
 	_ = func() {}
@@ -361,7 +353,6 @@ func _() {
 	})
 }
 
-
 func _() {
 	_ = [][]int{
 		[]int{1},
@@ -381,7 +372,6 @@ func _() {
 	_ = [][]int{{1}, {1, 2}, {1, 2, 3}}
 }
 
-
 // various multi-line expressions
 func _() {
 	// do not add extra indentation to multi-line string lists
@@ -397,25 +387,21 @@ func _() {
 	}
 }
 
-
 const _ = F1 +
 	`string = "%s";` +
 	`ptr = *;` +
 	`datafmt.T2 = s ["-" p "-"];`
 
-
 const _ = `datafmt "datafmt";` +
 	`default = "%v";` +
 	`array = *;` +
 	`datafmt.T3 = s  {" " a a / ","};`
 
-
 const _ = `datafmt "datafmt";` +
 	`default = "%v";` +
 	`array = *;` +
 	`datafmt.T3 = s  {" " a a / ","};`
 
-
 func _() {
 	_ = F1 +
 		`string = "%s";` +
@@ -434,7 +420,6 @@ func _() {
 		`datafmt.T3 = s  {" " a a / ","};`
 }
 
-
 func _() {
 	// respect source lines in multi-line expressions
 	_ = a +
@@ -448,7 +433,6 @@ func _() {
 	_ = "170141183460469231731687303715884105727"	// prime
 }
 
-
 // Alignment after overlong lines
 const (
 	_	= "991"
@@ -459,7 +443,6 @@ const (
 	_	= "170141183460469231731687303715884105727"	// prime
 )
 
-
 // Correct placement of operators and comments in multi-line expressions
 func _() {
 	_ = a +	// comment
@@ -471,7 +454,6 @@ func _() {
 	_ = "ba0408" + "7265717569726564"	// field 71, encoding 2, string "required"
 }
 
-
 // Correct placement of terminating comma/closing parentheses in multi-line calls.
 func _() {
 	f(1,
@@ -497,7 +479,6 @@ func _() {
 	)
 }
 
-
 // Align comments in multi-line lists of single-line expressions.
 var txpix = [NCOL]draw.Color{
 	draw.Yellow,		// yellow
@@ -512,7 +493,6 @@ var txpix = [NCOL]draw.Color{
 	draw.Color(0xBB005DFF),	/* maroon */
 }
 
-
 func same(t, u *Time) bool {
 	// respect source lines in multi-line expressions
 	return t.Year == u.Year &&
@@ -526,7 +506,6 @@ func same(t, u *Time) bool {
 		t.Zone == u.Zone
 }
 
-
 func (p *parser) charClass() {
 	// respect source lines in multi-line expressions
 	if cc.negate && len(cc.ranges) == 2 &&
@@ -536,7 +515,6 @@ func (p *parser) charClass() {
 	}
 }
 
-
 func addState(s []state, inst instr, match []int) {
 	// handle comments correctly in multi-line expressions
 	for i := 0; i < l; i++ {
@@ -639,7 +617,6 @@ func _() {
 		c
 }
 
-
 // Don't introduce extra newlines in strangely formatted expression lists.
 func f() {
 	// os.Open parameters should remain on two lines
diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw
index 308d9ed..d7819a3 100644
--- a/src/pkg/go/printer/testdata/expressions.raw
+++ b/src/pkg/go/printer/testdata/expressions.raw
@@ -17,7 +17,6 @@ var (
 	p	*int
 )
 
-
 func _() {
 	// no spaces around simple or parenthesized expressions
 	_ = (a + 0)
@@ -115,7 +114,6 @@ func _() {
 	x < y || z > 42
 }
 
-
 func _() {
 	_ = a + b
 	_ = a + b + c
@@ -187,7 +185,6 @@ func _() {
 	_ = token(matchType + xlength<<lengthShift + xoffset)
 }
 
-
 func f(x int, args ...int) {
 	f(0, args...)
 	f(1, args)
@@ -226,7 +223,6 @@ func f(x int, args ...int) {
 	_ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
 }
 
-
 func _() {
 	_ = T{}
 	_ = struct{}{}
@@ -236,7 +232,6 @@ func _() {
 	_ = map[int]T{}
 }
 
-
 // one-line structs/interfaces in composite literals (up to a threshold)
 func _() {
 	_ = struct{}{}
@@ -246,7 +241,6 @@ func _() {
 	_ = struct{ s struct{ int } }{struct{ int }{0}}
 }
 
-
 func _() {
 	// do not modify literals
 	_ = "tab1	tab2	tab3	end"	// string contains 3 tabs
@@ -261,7 +255,6 @@ func _() {
 they must not be removed`
 }
 
-
 func _() {
 	// smart handling of indentation for multi-line raw strings
 	var _ = ``
@@ -332,7 +325,6 @@ bar`
 	}
 }
 
-
 func _() {
 	// one-line function literals (body is on a single line)
 	_ = func() {}
@@ -361,7 +353,6 @@ func _() {
 	})
 }
 
-
 func _() {
 	_ = [][]int{
 		[]int{1},
@@ -381,7 +372,6 @@ func _() {
 	_ = [][]int{{1}, {1, 2}, {1, 2, 3}}
 }
 
-
 // various multi-line expressions
 func _() {
 	// do not add extra indentation to multi-line string lists
@@ -397,25 +387,21 @@ func _() {
 	}
 }
 
-
 const _ = F1 +
 	`string = "%s";` +
 	`ptr = *;` +
 	`datafmt.T2 = s ["-" p "-"];`
 
-
 const _ = `datafmt "datafmt";` +
 	`default = "%v";` +
 	`array = *;` +
 	`datafmt.T3 = s  {" " a a / ","};`
 
-
 const _ = `datafmt "datafmt";` +
 	`default = "%v";` +
 	`array = *;` +
 	`datafmt.T3 = s  {" " a a / ","};`
 
-
 func _() {
 	_ = F1 +
 		`string = "%s";` +
@@ -434,7 +420,6 @@ func _() {
 		`datafmt.T3 = s  {" " a a / ","};`
 }
 
-
 func _() {
 	// respect source lines in multi-line expressions
 	_ = a +
@@ -448,7 +433,6 @@ func _() {
 	_ = "170141183460469231731687303715884105727"	// prime
 }
 
-
 // Alignment after overlong lines
 const (
 	_	= "991"
@@ -459,7 +443,6 @@ const (
 	_	= "170141183460469231731687303715884105727"		// prime
 )
 
-
 // Correct placement of operators and comments in multi-line expressions
 func _() {
 	_ = a +	// comment
@@ -471,7 +454,6 @@ func _() {
 	_ = "ba0408" + "7265717569726564"	// field 71, encoding 2, string "required"
 }
 
-
 // Correct placement of terminating comma/closing parentheses in multi-line calls.
 func _() {
 	f(1,
@@ -497,7 +479,6 @@ func _() {
 	)
 }
 
-
 // Align comments in multi-line lists of single-line expressions.
 var txpix = [NCOL]draw.Color{
 	draw.Yellow,	// yellow
@@ -512,7 +493,6 @@ var txpix = [NCOL]draw.Color{
 	draw.Color(0xBB005DFF),	/* maroon */
 }
 
-
 func same(t, u *Time) bool {
 	// respect source lines in multi-line expressions
 	return t.Year == u.Year &&
@@ -526,7 +506,6 @@ func same(t, u *Time) bool {
 		t.Zone == u.Zone
 }
 
-
 func (p *parser) charClass() {
 	// respect source lines in multi-line expressions
 	if cc.negate && len(cc.ranges) == 2 &&
@@ -536,7 +515,6 @@ func (p *parser) charClass() {
 	}
 }
 
-
 func addState(s []state, inst instr, match []int) {
 	// handle comments correctly in multi-line expressions
 	for i := 0; i < l; i++ {
@@ -639,7 +617,6 @@ func _() {
 		c
 }
 
-
 // Don't introduce extra newlines in strangely formatted expression lists.
 func f() {
 	// os.Open parameters should remain on two lines
diff --git a/src/pkg/go/printer/testdata/parser.go b/src/pkg/go/printer/testdata/parser.go
index 5c57e41..2d27af4 100644
--- a/src/pkg/go/printer/testdata/parser.go
+++ b/src/pkg/go/printer/testdata/parser.go
@@ -16,7 +16,6 @@ import (
 	"go/token"
 )
 
-
 // The mode parameter to the Parse* functions is a set of flags (or 0).
 // They control the amount of source code parsed and other optional
 // parser functionality.
@@ -29,7 +28,6 @@ const (
 	DeclarationErrors                  // report declaration errors
 )
 
-
 // The parser structure holds the parser's internal state.
 type parser struct {
 	file *token.File
@@ -66,7 +64,6 @@ type parser struct {
 	targetStack [][]*ast.Ident // stack of unresolved labels
 }
 
-
 // scannerMode returns the scanner mode bits given the parser's mode bits.
 func scannerMode(mode uint) uint {
 	var m uint = scanner.InsertSemis
@@ -76,7 +73,6 @@ func scannerMode(mode uint) uint {
 	return m
 }
 
-
 func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
 	p.file = fset.AddFile(filename, fset.Base(), len(src))
 	p.scanner.Init(p.file, src, p, scannerMode(mode))
@@ -95,7 +91,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
 	p.openLabelScope()
 }
 
-
 // ----------------------------------------------------------------------------
 // Scoping support
 
@@ -103,18 +98,15 @@ func (p *parser) openScope() {
 	p.topScope = ast.NewScope(p.topScope)
 }
 
-
 func (p *parser) closeScope() {
 	p.topScope = p.topScope.Outer
 }
 
-
 func (p *parser) openLabelScope() {
 	p.labelScope = ast.NewScope(p.labelScope)
 	p.targetStack = append(p.targetStack, nil)
 }
 
-
 func (p *parser) closeLabelScope() {
 	// resolve labels
 	n := len(p.targetStack) - 1
@@ -130,7 +122,6 @@ func (p *parser) closeLabelScope() {
 	p.labelScope = p.labelScope.Outer
 }
 
-
 func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
 	for _, ident := range idents {
 		assert(ident.Obj == nil, "identifier already declared or resolved")
@@ -151,7 +142,6 @@ func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, i
 	}
 }
 
-
 func (p *parser) shortVarDecl(idents []*ast.Ident) {
 	// Go spec: A short variable declaration may redeclare variables
 	// provided they were originally declared in the same block with
@@ -177,13 +167,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
 	}
 }
 
-
 // The unresolved object is a sentinel to mark identifiers that have been added
 // to the list of unresolved identifiers. The sentinel is only used for verifying
 // internal consistency.
 var unresolved = new(ast.Object)
 
-
 func (p *parser) resolve(x ast.Expr) {
 	// nothing to do if x is not an identifier or the blank identifier
 	ident, _ := x.(*ast.Ident)
@@ -209,7 +197,6 @@ func (p *parser) resolve(x ast.Expr) {
 	p.unresolved = append(p.unresolved, ident)
 }
 
-
 // ----------------------------------------------------------------------------
 // Parsing support
 
@@ -227,21 +214,18 @@ func (p *parser) printTrace(a ...interface{}) {
 	fmt.Println(a...)
 }
 
-
 func trace(p *parser, msg string) *parser {
 	p.printTrace(msg, "(")
 	p.indent++
 	return p
 }
 
-
 // Usage pattern: defer un(trace(p, "..."));
 func un(p *parser) {
 	p.indent--
 	p.printTrace(")")
 }
 
-
 // Advance to the next token.
 func (p *parser) next0() {
 	// Because of one-token look-ahead, print the previous token
@@ -283,7 +267,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
 	return
 }
 
-
 // Consume a group of adjacent comments, add it to the parser's
 // comments list, and return it together with the line at which
 // the last comment in the group ends. An empty line or non-comment
@@ -305,7 +288,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
 	return
 }
 
-
 // Advance to the next non-comment token. In the process, collect
 // any comment groups encountered, and remember the last lead and
 // and line comments.
@@ -356,12 +338,10 @@ func (p *parser) next() {
 	}
 }
 
-
 func (p *parser) error(pos token.Pos, msg string) {
 	p.Error(p.file.Position(pos), msg)
 }
 
-
 func (p *parser) errorExpected(pos token.Pos, msg string) {
 	msg = "expected " + msg
 	if pos == p.pos {
@@ -379,7 +359,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
 	p.error(pos, msg)
 }
 
-
 func (p *parser) expect(tok token.Token) token.Pos {
 	pos := p.pos
 	if p.tok != tok {
@@ -389,21 +368,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
 	return pos
 }
 
-
 func (p *parser) expectSemi() {
 	if p.tok != token.RPAREN && p.tok != token.RBRACE {
 		p.expect(token.SEMICOLON)
 	}
 }
 
-
 func assert(cond bool, msg string) {
 	if !cond {
 		panic("go/parser internal error: " + msg)
 	}
 }
 
-
 // ----------------------------------------------------------------------------
 // Identifiers
 
@@ -419,7 +395,6 @@ func (p *parser) parseIdent() *ast.Ident {
 	return &ast.Ident{pos, name, nil}
 }
 
-
 func (p *parser) parseIdentList() (list []*ast.Ident) {
 	if p.trace {
 		defer un(trace(p, "IdentList"))
@@ -434,7 +409,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Common productions
 
@@ -453,7 +427,6 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseLhsList() []ast.Expr {
 	list := p.parseExprList(true)
 	switch p.tok {
@@ -477,12 +450,10 @@ func (p *parser) parseLhsList() []ast.Expr {
 	return list
 }
 
-
 func (p *parser) parseRhsList() []ast.Expr {
 	return p.parseExprList(false)
 }
 
-
 // ----------------------------------------------------------------------------
 // Types
 
@@ -503,7 +474,6 @@ func (p *parser) parseType() ast.Expr {
 	return typ
 }
 
-
 // If the result is an identifier, it is not resolved.
 func (p *parser) parseTypeName() ast.Expr {
 	if p.trace {
@@ -524,7 +494,6 @@ func (p *parser) parseTypeName() ast.Expr {
 	return ident
 }
 
-
 func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "ArrayType"))
@@ -544,7 +513,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
 	return &ast.ArrayType{lbrack, len, elt}
 }
 
-
 func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
 	idents := make([]*ast.Ident, len(list))
 	for i, x := range list {
@@ -559,7 +527,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
 	return idents
 }
 
-
 func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "FieldDecl"))
@@ -601,7 +568,6 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 	return field
 }
 
-
 func (p *parser) parseStructType() *ast.StructType {
 	if p.trace {
 		defer un(trace(p, "StructType"))
@@ -623,7 +589,6 @@ func (p *parser) parseStructType() *ast.StructType {
 	return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
 }
 
-
 func (p *parser) parsePointerType() *ast.StarExpr {
 	if p.trace {
 		defer un(trace(p, "PointerType"))
@@ -635,7 +600,6 @@ func (p *parser) parsePointerType() *ast.StarExpr {
 	return &ast.StarExpr{star, base}
 }
 
-
 func (p *parser) tryVarType(isParam bool) ast.Expr {
 	if isParam && p.tok == token.ELLIPSIS {
 		pos := p.pos
@@ -653,7 +617,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
 	return p.tryIdentOrType(false)
 }
 
-
 func (p *parser) parseVarType(isParam bool) ast.Expr {
 	typ := p.tryVarType(isParam)
 	if typ == nil {
@@ -665,7 +628,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
 	return typ
 }
 
-
 func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "VarList"))
@@ -693,7 +655,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
 	if p.trace {
 		defer un(trace(p, "ParameterList"))
@@ -738,7 +699,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 	return
 }
 
-
 func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Parameters"))
@@ -754,7 +714,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
 	return &ast.FieldList{lparen, params, rparen}
 }
 
-
 func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Result"))
@@ -774,7 +733,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
 	return nil
 }
 
-
 func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
 	if p.trace {
 		defer un(trace(p, "Signature"))
@@ -786,7 +744,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis
 	return
 }
 
-
 func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 	if p.trace {
 		defer un(trace(p, "FuncType"))
@@ -799,7 +756,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 	return &ast.FuncType{pos, params, results}, scope
 }
 
-
 func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "MethodSpec"))
@@ -827,7 +783,6 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
 	return spec
 }
 
-
 func (p *parser) parseInterfaceType() *ast.InterfaceType {
 	if p.trace {
 		defer un(trace(p, "InterfaceType"))
@@ -846,7 +801,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
 	return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
 }
 
-
 func (p *parser) parseMapType() *ast.MapType {
 	if p.trace {
 		defer un(trace(p, "MapType"))
@@ -861,7 +815,6 @@ func (p *parser) parseMapType() *ast.MapType {
 	return &ast.MapType{pos, key, value}
 }
 
-
 func (p *parser) parseChanType() *ast.ChanType {
 	if p.trace {
 		defer un(trace(p, "ChanType"))
@@ -885,7 +838,6 @@ func (p *parser) parseChanType() *ast.ChanType {
 	return &ast.ChanType{pos, dir, value}
 }
 
-
 // If the result is an identifier, it is not resolved.
 func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
 	switch p.tok {
@@ -918,7 +870,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
 	return nil
 }
 
-
 func (p *parser) tryType() ast.Expr {
 	typ := p.tryIdentOrType(false)
 	if typ != nil {
@@ -927,7 +878,6 @@ func (p *parser) tryType() ast.Expr {
 	return typ
 }
 
-
 // ----------------------------------------------------------------------------
 // Blocks
 
@@ -943,7 +893,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
 	return
 }
 
-
 func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
 	if p.trace {
 		defer un(trace(p, "Body"))
@@ -960,7 +909,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
 	return &ast.BlockStmt{lbrace, list, rbrace}
 }
 
-
 func (p *parser) parseBlockStmt() *ast.BlockStmt {
 	if p.trace {
 		defer un(trace(p, "BlockStmt"))
@@ -975,7 +923,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
 	return &ast.BlockStmt{lbrace, list, rbrace}
 }
 
-
 // ----------------------------------------------------------------------------
 // Expressions
 
@@ -997,7 +944,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
 	return &ast.FuncLit{typ, body}
 }
 
-
 // parseOperand may return an expression or a raw type (incl. array
 // types of the form [...]T. Callers must verify the result.
 // If lhs is set and the result is an identifier, it is not resolved.
@@ -1047,7 +993,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
 	return &ast.BadExpr{pos, p.pos}
 }
 
-
 func (p *parser) parseSelector(x ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Selector"))
@@ -1058,7 +1003,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
 	return &ast.SelectorExpr{x, sel}
 }
 
-
 func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "TypeAssertion"))
@@ -1077,7 +1021,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
 	return &ast.TypeAssertExpr{x, typ}
 }
 
-
 func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "IndexOrSlice"))
@@ -1106,7 +1049,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 	return &ast.IndexExpr{x, lbrack, low, rbrack}
 }
 
-
 func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	if p.trace {
 		defer un(trace(p, "CallOrConversion"))
@@ -1133,7 +1075,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
 }
 
-
 func (p *parser) parseElement(keyOk bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Element"))
@@ -1156,7 +1097,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
 	return x
 }
 
-
 func (p *parser) parseElementList() (list []ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "ElementList"))
@@ -1173,7 +1113,6 @@ func (p *parser) parseElementList() (list []ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "LiteralValue"))
@@ -1190,7 +1129,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
 	return &ast.CompositeLit{typ, lbrace, elts, rbrace}
 }
 
-
 // checkExpr checks that x is an expression (and not a type).
 func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	switch t := unparen(x).(type) {
@@ -1227,7 +1165,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // isTypeName returns true iff x is a (qualified) TypeName.
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
@@ -1242,7 +1179,6 @@ func isTypeName(x ast.Expr) bool {
 	return true
 }
 
-
 // isLiteralType returns true iff x is a legal composite literal type.
 func isLiteralType(x ast.Expr) bool {
 	switch t := x.(type) {
@@ -1260,7 +1196,6 @@ func isLiteralType(x ast.Expr) bool {
 	return true
 }
 
-
 // If x is of the form *T, deref returns T, otherwise it returns x.
 func deref(x ast.Expr) ast.Expr {
 	if p, isPtr := x.(*ast.StarExpr); isPtr {
@@ -1269,7 +1204,6 @@ func deref(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
 func unparen(x ast.Expr) ast.Expr {
 	if p, isParen := x.(*ast.ParenExpr); isParen {
@@ -1278,7 +1212,6 @@ func unparen(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // checkExprOrType checks that x is an expression or a type
 // (and not a raw type such as [...]T).
 //
@@ -1303,7 +1236,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
 	if p.trace {
@@ -1358,7 +1290,6 @@ L:
 	return x
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 	if p.trace {
@@ -1396,7 +1327,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 	return p.parsePrimaryExpr(lhs)
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	if p.trace {
@@ -1420,7 +1350,6 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	return x
 }
 
-
 // If lhs is set and the result is an identifier, it is not resolved.
 // TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
 //            should reject when a type/raw type is obviously not allowed
@@ -1432,12 +1361,10 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
 	return p.parseBinaryExpr(lhs, token.LowestPrec+1)
 }
 
-
 func (p *parser) parseRhs() ast.Expr {
 	return p.parseExpr(false)
 }
 
-
 // ----------------------------------------------------------------------------
 // Statements
 
@@ -1500,7 +1427,6 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 	return &ast.ExprStmt{x[0]}
 }
 
-
 func (p *parser) parseCallExpr() *ast.CallExpr {
 	x := p.parseRhs()
 	if call, isCall := x.(*ast.CallExpr); isCall {
@@ -1510,7 +1436,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
 	return nil
 }
 
-
 func (p *parser) parseGoStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "GoStmt"))
@@ -1526,7 +1451,6 @@ func (p *parser) parseGoStmt() ast.Stmt {
 	return &ast.GoStmt{pos, call}
 }
 
-
 func (p *parser) parseDeferStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "DeferStmt"))
@@ -1542,7 +1466,6 @@ func (p *parser) parseDeferStmt() ast.Stmt {
 	return &ast.DeferStmt{pos, call}
 }
 
-
 func (p *parser) parseReturnStmt() *ast.ReturnStmt {
 	if p.trace {
 		defer un(trace(p, "ReturnStmt"))
@@ -1559,7 +1482,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
 	return &ast.ReturnStmt{pos, x}
 }
 
-
 func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
 	if p.trace {
 		defer un(trace(p, "BranchStmt"))
@@ -1578,7 +1500,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
 	return &ast.BranchStmt{pos, tok, label}
 }
 
-
 func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
 	if s == nil {
 		return nil
@@ -1590,7 +1511,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
 	return &ast.BadExpr{s.Pos(), s.End()}
 }
 
-
 func (p *parser) parseIfStmt() *ast.IfStmt {
 	if p.trace {
 		defer un(trace(p, "IfStmt"))
@@ -1633,7 +1553,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
 	return &ast.IfStmt{pos, s, x, body, else_}
 }
 
-
 func (p *parser) parseTypeList() (list []ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "TypeList"))
@@ -1648,7 +1567,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
 	return
 }
 
-
 func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
 	if p.trace {
 		defer un(trace(p, "CaseClause"))
@@ -1675,7 +1593,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
 	return &ast.CaseClause{pos, list, colon, body}
 }
 
-
 func isExprSwitch(s ast.Stmt) bool {
 	if s == nil {
 		return true
@@ -1689,7 +1606,6 @@ func isExprSwitch(s ast.Stmt) bool {
 	return false
 }
 
-
 func (p *parser) parseSwitchStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "SwitchStmt"))
@@ -1735,7 +1651,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
 	return &ast.TypeSwitchStmt{pos, s1, s2, body}
 }
 
-
 func (p *parser) parseCommClause() *ast.CommClause {
 	if p.trace {
 		defer un(trace(p, "CommClause"))
@@ -1801,7 +1716,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
 	return &ast.CommClause{pos, comm, colon, body}
 }
 
-
 func (p *parser) parseSelectStmt() *ast.SelectStmt {
 	if p.trace {
 		defer un(trace(p, "SelectStmt"))
@@ -1820,7 +1734,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
 	return &ast.SelectStmt{pos, body}
 }
 
-
 func (p *parser) parseForStmt() ast.Stmt {
 	if p.trace {
 		defer un(trace(p, "ForStmt"))
@@ -1890,7 +1803,6 @@ func (p *parser) parseForStmt() ast.Stmt {
 	return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
 }
 
-
 func (p *parser) parseStmt() (s ast.Stmt) {
 	if p.trace {
 		defer un(trace(p, "Statement"))
@@ -1947,13 +1859,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Declarations
 
 type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
 
-
 func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "ImportSpec"))
@@ -1984,7 +1894,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	return spec
 }
 
-
 func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "ConstSpec"))
@@ -2009,7 +1918,6 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
 	return spec
 }
 
-
 func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "TypeSpec"))
@@ -2031,7 +1939,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	return spec
 }
 
-
 func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	if p.trace {
 		defer un(trace(p, "VarSpec"))
@@ -2056,7 +1963,6 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	return spec
 }
 
-
 func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
 	if p.trace {
 		defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2081,7 +1987,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
 	return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
 }
 
-
 func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
 	if p.trace {
 		defer un(trace(p, "Receiver"))
@@ -2109,7 +2014,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
 	return par
 }
 
-
 func (p *parser) parseFuncDecl() *ast.FuncDecl {
 	if p.trace {
 		defer un(trace(p, "FunctionDecl"))
@@ -2150,7 +2054,6 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
 	return decl
 }
 
-
 func (p *parser) parseDecl() ast.Decl {
 	if p.trace {
 		defer un(trace(p, "Declaration"))
@@ -2181,7 +2084,6 @@ func (p *parser) parseDecl() ast.Decl {
 	return p.parseGenDecl(p.tok, f)
 }
 
-
 func (p *parser) parseDeclList() (list []ast.Decl) {
 	if p.trace {
 		defer un(trace(p, "DeclList"))
@@ -2194,7 +2096,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Source files
 
diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden
index 0e48404..a6d8510 100644
--- a/src/pkg/go/printer/testdata/statements.golden
+++ b/src/pkg/go/printer/testdata/statements.golden
@@ -30,7 +30,6 @@ func _() {
 	}
 }
 
-
 // Formatting of switch-statement headers.
 func _() {
 	switch {
@@ -56,7 +55,6 @@ func _() {
 	}
 }
 
-
 // Formatting of switch statement bodies.
 func _() {
 	switch {
@@ -110,7 +108,6 @@ func _() {
 	}
 }
 
-
 // Formatting of selected select statements.
 func _() {
 	select {}
@@ -125,7 +122,6 @@ func _() {
 	}
 }
 
-
 // Formatting of for-statement headers.
 func _() {
 	for {
@@ -164,7 +160,6 @@ func _() {
 	}	// no parens printed
 }
 
-
 // Don't remove mandatory parentheses around composite literals in control clauses.
 func _() {
 	// strip parentheses - no composite literals or composite literals don't start with a type name
@@ -258,7 +253,6 @@ func _() {
 	}
 }
 
-
 // Extra empty lines inside functions. Do respect source code line
 // breaks between statement boundaries but print at most one empty
 // line at a time.
@@ -291,19 +285,16 @@ func _() {
 	}
 }
 
-
 // Formatting around labels.
 func _() {
 L:
 }
 
-
 func _() {
 	// this comment should be indented
 L:	// no semicolon needed
 }
 
-
 func _() {
 	switch 0 {
 	case 0:
@@ -317,7 +308,6 @@ func _() {
 	}
 }
 
-
 func _() {
 	f()
 L1:
@@ -327,26 +317,22 @@ L2:
 L3:
 }
 
-
 func _() {
 	// this comment should be indented
 L:
 }
 
-
 func _() {
 L:
 	_ = 0
 }
 
-
 func _() {
 	// this comment should be indented
 L:
 	_ = 0
 }
 
-
 func _() {
 	for {
 	L1:
@@ -356,7 +342,6 @@ func _() {
 	}
 }
 
-
 func _() {
 	// this comment should be indented
 	for {
@@ -367,7 +352,6 @@ func _() {
 	}
 }
 
-
 func _() {
 	if true {
 		_ = 0
@@ -385,7 +369,6 @@ L:
 	_ = 0
 }
 
-
 func _() {
 	for {
 		goto L
@@ -395,7 +378,6 @@ L:
 	MoreCode()
 }
 
-
 func _() {
 	for {
 		goto L
@@ -408,7 +390,6 @@ L:	// A comment on the same line as the label, followed by a single empty line.
 	MoreCode()
 }
 
-
 func _() {
 	for {
 		goto L
@@ -419,7 +400,6 @@ L:
 	MoreCode()
 }
 
-
 func _() {
 	for {
 		goto AVeryLongLabelThatShouldNotAffectFormatting
diff --git a/src/pkg/go/scanner/errors.go b/src/pkg/go/scanner/errors.go
index 47e35a7..f8e9ffa 100644
--- a/src/pkg/go/scanner/errors.go
+++ b/src/pkg/go/scanner/errors.go
@@ -13,7 +13,6 @@ import (
 	"sort"
 )
 
-
 // An implementation of an ErrorHandler may be provided to the Scanner.
 // If a syntax error is encountered and a handler was installed, Error
 // is called with a position and an error message. The position points
@@ -23,7 +22,6 @@ type ErrorHandler interface {
 	Error(pos token.Position, msg string)
 }
 
-
 // ErrorVector implements the ErrorHandler interface. It maintains a list
 // of errors which can be retrieved with GetErrorList and GetError. The
 // zero value for an ErrorVector is an empty ErrorVector ready to use.
@@ -37,15 +35,12 @@ type ErrorVector struct {
 	errors vector.Vector
 }
 
-
 // Reset resets an ErrorVector to no errors.
 func (h *ErrorVector) Reset() { h.errors.Resize(0, 0) }
 
-
 // ErrorCount returns the number of errors collected.
 func (h *ErrorVector) ErrorCount() int { return h.errors.Len() }
 
-
 // Within ErrorVector, an error is represented by an Error node. The
 // position Pos, if valid, points to the beginning of the offending
 // token, and the error condition is described by Msg.
@@ -55,7 +50,6 @@ type Error struct {
 	Msg string
 }
 
-
 func (e *Error) String() string {
 	if e.Pos.Filename != "" || e.Pos.IsValid() {
 		// don't print "<unknown position>"
@@ -65,16 +59,13 @@ func (e *Error) String() string {
 	return e.Msg
 }
 
-
 // An ErrorList is a (possibly sorted) list of Errors.
 type ErrorList []*Error
 
-
 // ErrorList implements the sort Interface.
 func (p ErrorList) Len() int      { return len(p) }
 func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
 
-
 func (p ErrorList) Less(i, j int) bool {
 	e := &p[i].Pos
 	f := &p[j].Pos
@@ -95,7 +86,6 @@ func (p ErrorList) Less(i, j int) bool {
 	return false
 }
 
-
 func (p ErrorList) String() string {
 	switch len(p) {
 	case 0:
@@ -106,7 +96,6 @@ func (p ErrorList) String() string {
 	return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1)
 }
 
-
 // These constants control the construction of the ErrorList
 // returned by GetErrors.
 //
@@ -116,7 +105,6 @@ const (
 	NoMultiples        // sort error list and leave only the first error per line
 )
 
-
 // GetErrorList returns the list of errors collected by an ErrorVector.
 // The construction of the ErrorList returned is controlled by the mode
 // parameter. If there are no errors, the result is nil.
@@ -151,7 +139,6 @@ func (h *ErrorVector) GetErrorList(mode int) ErrorList {
 	return list
 }
 
-
 // GetError is like GetErrorList, but it returns an os.Error instead
 // so that a nil result can be assigned to an os.Error variable and
 // remains nil.
@@ -164,13 +151,11 @@ func (h *ErrorVector) GetError(mode int) os.Error {
 	return h.GetErrorList(mode)
 }
 
-
 // ErrorVector implements the ErrorHandler interface.
 func (h *ErrorVector) Error(pos token.Position, msg string) {
 	h.errors.Push(&Error{pos, msg})
 }
 
-
 // PrintError is a utility function that prints a list of errors to w,
 // one error per line, if the err parameter is an ErrorList. Otherwise
 // it prints the err string.
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 795f0ac..7f3dd23 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -30,7 +30,6 @@ import (
 	"utf8"
 )
 
-
 // A Scanner holds the scanner's internal state while processing
 // a given text.  It can be allocated as part of another data
 // structure but must be initialized via Init before use.
@@ -54,7 +53,6 @@ type Scanner struct {
 	ErrorCount int // number of errors encountered
 }
 
-
 // Read the next Unicode char into S.ch.
 // S.ch < 0 means end-of-file.
 //
@@ -88,7 +86,6 @@ func (S *Scanner) next() {
 	}
 }
 
-
 // The mode parameter to the Init function is a set of flags (or 0).
 // They control scanner behavior.
 //
@@ -134,7 +131,6 @@ func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint
 	S.next()
 }
 
-
 func (S *Scanner) error(offs int, msg string) {
 	if S.err != nil {
 		S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
@@ -142,7 +138,6 @@ func (S *Scanner) error(offs int, msg string) {
 	S.ErrorCount++
 }
 
-
 var prefix = []byte("//line ")
 
 func (S *Scanner) interpretLineComment(text []byte) {
@@ -163,7 +158,6 @@ func (S *Scanner) interpretLineComment(text []byte) {
 	}
 }
 
-
 func (S *Scanner) scanComment() {
 	// initial '/' already consumed; S.ch == '/' || S.ch == '*'
 	offs := S.offset - 1 // position of initial '/'
@@ -195,7 +189,6 @@ func (S *Scanner) scanComment() {
 	S.error(offs, "comment not terminated")
 }
 
-
 func (S *Scanner) findLineEnd() bool {
 	// initial '/' already consumed
 
@@ -240,17 +233,14 @@ func (S *Scanner) findLineEnd() bool {
 	return false
 }
 
-
 func isLetter(ch int) bool {
 	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
 }
 
-
 func isDigit(ch int) bool {
 	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
 }
 
-
 func (S *Scanner) scanIdentifier() token.Token {
 	offs := S.offset
 	for isLetter(S.ch) || isDigit(S.ch) {
@@ -259,7 +249,6 @@ func (S *Scanner) scanIdentifier() token.Token {
 	return token.Lookup(S.src[offs:S.offset])
 }
 
-
 func digitVal(ch int) int {
 	switch {
 	case '0' <= ch && ch <= '9':
@@ -272,14 +261,12 @@ func digitVal(ch int) int {
 	return 16 // larger than any legal digit val
 }
 
-
 func (S *Scanner) scanMantissa(base int) {
 	for digitVal(S.ch) < base {
 		S.next()
 	}
 }
 
-
 func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
 	// digitVal(S.ch) < 10
 	tok := token.INT
@@ -351,7 +338,6 @@ exit:
 	return tok
 }
 
-
 func (S *Scanner) scanEscape(quote int) {
 	offs := S.offset
 
@@ -396,7 +382,6 @@ func (S *Scanner) scanEscape(quote int) {
 	}
 }
 
-
 func (S *Scanner) scanChar() {
 	// '\'' opening already consumed
 	offs := S.offset - 1
@@ -423,7 +408,6 @@ func (S *Scanner) scanChar() {
 	}
 }
 
-
 func (S *Scanner) scanString() {
 	// '"' opening already consumed
 	offs := S.offset - 1
@@ -443,7 +427,6 @@ func (S *Scanner) scanString() {
 	S.next()
 }
 
-
 func (S *Scanner) scanRawString() {
 	// '`' opening already consumed
 	offs := S.offset - 1
@@ -460,14 +443,12 @@ func (S *Scanner) scanRawString() {
 	S.next()
 }
 
-
 func (S *Scanner) skipWhitespace() {
 	for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
 		S.next()
 	}
 }
 
-
 // Helper functions for scanning multi-byte tokens such as >> += >>= .
 // Different routines recognize different length tok_i based on matches
 // of ch_i. If a token ends in '=', the result is tok1 or tok3
@@ -482,7 +463,6 @@ func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
 	return tok0
 }
 
-
 func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
 	if S.ch == '=' {
 		S.next()
@@ -495,7 +475,6 @@ func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) tok
 	return tok0
 }
 
-
 func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
 	if S.ch == '=' {
 		S.next()
@@ -512,7 +491,6 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
 	return tok0
 }
 
-
 // Scan scans the next token and returns the token position,
 // the token, and the literal string corresponding to the
 // token. The source end is indicated by token.EOF.
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index c096e27..eb9e1cb 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -12,10 +12,8 @@ import (
 	"testing"
 )
 
-
 var fset = token.NewFileSet()
 
-
 const /* class */ (
 	special = iota
 	literal
@@ -23,7 +21,6 @@ const /* class */ (
 	keyword
 )
 
-
 func tokenclass(tok token.Token) int {
 	switch {
 	case tok.IsLiteral():
@@ -36,14 +33,12 @@ func tokenclass(tok token.Token) int {
 	return special
 }
 
-
 type elt struct {
 	tok   token.Token
 	lit   string
 	class int
 }
 
-
 var tokens = [...]elt{
 	// Special tokens
 	{token.COMMENT, "/* a comment */", special},
@@ -178,7 +173,6 @@ var tokens = [...]elt{
 	{token.VAR, "var", keyword},
 }
 
-
 const whitespace = "  \t  \n\n\n" // to separate tokens
 
 type testErrorHandler struct {
@@ -189,7 +183,6 @@ func (h *testErrorHandler) Error(pos token.Position, msg string) {
 	h.t.Errorf("Error() called (msg = %s)", msg)
 }
 
-
 func newlineCount(s string) int {
 	n := 0
 	for i := 0; i < len(s); i++ {
@@ -200,7 +193,6 @@ func newlineCount(s string) int {
 	return n
 }
 
-
 func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
 	pos := fset.Position(p)
 	if pos.Filename != expected.Filename {
@@ -217,7 +209,6 @@ func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
 	}
 }
 
-
 // Verify that calling Scan() provides the correct results.
 func TestScan(t *testing.T) {
 	// make source
@@ -271,7 +262,6 @@ func TestScan(t *testing.T) {
 	}
 }
 
-
 func checkSemi(t *testing.T, line string, mode uint) {
 	var S Scanner
 	file := fset.AddFile("TestSemis", fset.Base(), len(line))
@@ -305,7 +295,6 @@ func checkSemi(t *testing.T, line string, mode uint) {
 	}
 }
 
-
 var lines = []string{
 	// # indicates a semicolon present in the source
 	// $ indicates an automatically inserted semicolon
@@ -429,7 +418,6 @@ var lines = []string{
 	"package main$",
 }
 
-
 func TestSemis(t *testing.T) {
 	for _, line := range lines {
 		checkSemi(t, line, AllowIllegalChars|InsertSemis)
@@ -463,25 +451,31 @@ var segments = []segment{
 	{"\n //line foo:42\n  line44", filepath.Join("dir", "foo"), 44},           // bad line comment, ignored
 	{"\n//line foo 42\n  line46", filepath.Join("dir", "foo"), 46},            // bad line comment, ignored
 	{"\n//line foo:42 extra text\n  line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
-	{"\n//line /bar:42\n  line42", string(filepath.Separator) + "bar", 42},
 	{"\n//line ./foo:42\n  line42", filepath.Join("dir", "foo"), 42},
 	{"\n//line a/b/c/File1.go:100\n  line100", filepath.Join("dir", "a", "b", "c", "File1.go"), 100},
 }
 
+var unixsegments = []segment{
+	{"\n//line /bar:42\n  line42", "/bar", 42},
+}
+
 var winsegments = []segment{
+	{"\n//line c:\\bar:42\n  line42", "c:\\bar", 42},
 	{"\n//line c:\\dir\\File1.go:100\n  line100", "c:\\dir\\File1.go", 100},
 }
 
-
 // Verify that comments of the form "//line filename:line" are interpreted correctly.
 func TestLineComments(t *testing.T) {
+	segs := segments
 	if runtime.GOOS == "windows" {
-		segments = append(segments, winsegments...)
+		segs = append(segs, winsegments...)
+	} else {
+		segs = append(segs, unixsegments...)
 	}
 
 	// make source
 	var src string
-	for _, e := range segments {
+	for _, e := range segs {
 		src += e.srcline
 	}
 
@@ -489,7 +483,7 @@ func TestLineComments(t *testing.T) {
 	var S Scanner
 	file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src))
 	S.Init(file, []byte(src), nil, 0)
-	for _, s := range segments {
+	for _, s := range segs {
 		p, _, lit := S.Scan()
 		pos := file.Position(p)
 		checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
@@ -500,7 +494,6 @@ func TestLineComments(t *testing.T) {
 	}
 }
 
-
 // Verify that initializing the same scanner more then once works correctly.
 func TestInit(t *testing.T) {
 	var s Scanner
@@ -536,7 +529,6 @@ func TestInit(t *testing.T) {
 	}
 }
 
-
 func TestIllegalChars(t *testing.T) {
 	var s Scanner
 
@@ -558,7 +550,6 @@ func TestIllegalChars(t *testing.T) {
 	}
 }
 
-
 func TestStdErrorHander(t *testing.T) {
 	const src = "@\n" + // illegal character, cause an error
 		"@ @\n" + // two errors on the same line
@@ -601,21 +592,18 @@ func TestStdErrorHander(t *testing.T) {
 	}
 }
 
-
 type errorCollector struct {
 	cnt int            // number of errors encountered
 	msg string         // last error message encountered
 	pos token.Position // last error position encountered
 }
 
-
 func (h *errorCollector) Error(pos token.Position, msg string) {
 	h.cnt++
 	h.msg = msg
 	h.pos = pos
 }
 
-
 func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
 	var s Scanner
 	var h errorCollector
@@ -643,7 +631,6 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
 	}
 }
 
-
 var errors = []struct {
 	src string
 	tok token.Token
@@ -678,7 +665,6 @@ var errors = []struct {
 	{"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
 }
 
-
 func TestScanErrors(t *testing.T) {
 	for _, e := range errors {
 		checkError(t, e.src, e.tok, e.pos, e.err)
diff --git a/src/pkg/go/token/position.go b/src/pkg/go/token/position.go
index 23a3cc0..c559e19 100644
--- a/src/pkg/go/token/position.go
+++ b/src/pkg/go/token/position.go
@@ -12,7 +12,6 @@ import (
 	"sync"
 )
 
-
 // Position describes an arbitrary source position
 // including the file, line, and column location.
 // A Position is valid if the line number is > 0.
@@ -24,11 +23,9 @@ type Position struct {
 	Column   int    // column number, starting at 1 (character count)
 }
 
-
 // IsValid returns true if the position is valid.
 func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
-
 // String returns a string in one of several forms:
 //
 //	file:line:column    valid position with file name
@@ -50,7 +47,6 @@ func (pos Position) String() string {
 	return s
 }
 
-
 // Pos is a compact encoding of a source position within a file set.
 // It can be converted into a Position for a more convenient, but much
 // larger, representation.
@@ -73,7 +69,6 @@ func (pos Position) String() string {
 //
 type Pos int
 
-
 // The zero value for Pos is NoPos; there is no file and line information
 // associated with it, and NoPos().IsValid() is false. NoPos is always
 // smaller than any other Pos value. The corresponding Position value
@@ -81,18 +76,15 @@ type Pos int
 // 
 const NoPos Pos = 0
 
-
 // IsValid returns true if the position is valid.
 func (p Pos) IsValid() bool {
 	return p != NoPos
 }
 
-
 func searchFiles(a []*File, x int) int {
 	return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1
 }
 
-
 func (s *FileSet) file(p Pos) *File {
 	if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
 		return f
@@ -108,7 +100,6 @@ func (s *FileSet) file(p Pos) *File {
 	return nil
 }
 
-
 // File returns the file which contains the position p.
 // If no such file is found (for instance for p == NoPos),
 // the result is nil.
@@ -122,7 +113,6 @@ func (s *FileSet) File(p Pos) (f *File) {
 	return
 }
 
-
 func (f *File) position(p Pos) (pos Position) {
 	offset := int(p) - f.base
 	pos.Offset = offset
@@ -130,7 +120,6 @@ func (f *File) position(p Pos) (pos Position) {
 	return
 }
 
-
 // Position converts a Pos in the fileset into a general Position.
 func (s *FileSet) Position(p Pos) (pos Position) {
 	if p != NoPos {
@@ -147,14 +136,12 @@ func (s *FileSet) Position(p Pos) (pos Position) {
 	return
 }
 
-
 type lineInfo struct {
 	offset   int
 	filename string
 	line     int
 }
 
-
 // AddLineInfo adds alternative file and line number information for
 // a given file offset. The offset must be larger than the offset for
 // the previously added alternative line info and smaller than the
@@ -171,7 +158,6 @@ func (f *File) AddLineInfo(offset int, filename string, line int) {
 	f.set.mutex.Unlock()
 }
 
-
 // A File is a handle for a file belonging to a FileSet.
 // A File has a name, size, and line offset table.
 //
@@ -186,25 +172,21 @@ type File struct {
 	infos []lineInfo
 }
 
-
 // Name returns the file name of file f as registered with AddFile.
 func (f *File) Name() string {
 	return f.name
 }
 
-
 // Base returns the base offset of file f as registered with AddFile.
 func (f *File) Base() int {
 	return f.base
 }
 
-
 // Size returns the size of file f as registered with AddFile.
 func (f *File) Size() int {
 	return f.size
 }
 
-
 // LineCount returns the number of lines in file f.
 func (f *File) LineCount() int {
 	f.set.mutex.RLock()
@@ -213,7 +195,6 @@ func (f *File) LineCount() int {
 	return n
 }
 
-
 // AddLine adds the line offset for a new line.
 // The line offset must be larger than the offset for the previous line
 // and smaller than the file size; otherwise the line offset is ignored.
@@ -226,7 +207,6 @@ func (f *File) AddLine(offset int) {
 	f.set.mutex.Unlock()
 }
 
-
 // SetLines sets the line offsets for a file and returns true if successful.
 // The line offsets are the offsets of the first character of each line;
 // for instance for the content "ab\nc\n" the line offsets are {0, 3}.
@@ -251,7 +231,6 @@ func (f *File) SetLines(lines []int) bool {
 	return true
 }
 
-
 // SetLinesForContent sets the line offsets for the given file content.
 func (f *File) SetLinesForContent(content []byte) {
 	var lines []int
@@ -272,7 +251,6 @@ func (f *File) SetLinesForContent(content []byte) {
 	f.set.mutex.Unlock()
 }
 
-
 // Pos returns the Pos value for the given file offset;
 // the offset must be <= f.Size().
 // f.Pos(f.Offset(p)) == p.
@@ -284,7 +262,6 @@ func (f *File) Pos(offset int) Pos {
 	return Pos(f.base + offset)
 }
 
-
 // Offset returns the offset for the given file position p;
 // p must be a valid Pos value in that file.
 // f.Offset(f.Pos(offset)) == offset.
@@ -296,7 +273,6 @@ func (f *File) Offset(p Pos) int {
 	return int(p) - f.base
 }
 
-
 // Line returns the line number for the given file position p;
 // p must be a Pos value in that file or NoPos.
 //
@@ -305,7 +281,6 @@ func (f *File) Line(p Pos) int {
 	return f.Position(p).Line
 }
 
-
 // Position returns the Position value for the given file position p;
 // p must be a Pos value in that file or NoPos.
 //
@@ -319,7 +294,6 @@ func (f *File) Position(p Pos) (pos Position) {
 	return
 }
 
-
 func searchInts(a []int, x int) int {
 	// This function body is a manually inlined version of:
 	//
@@ -342,12 +316,10 @@ func searchInts(a []int, x int) int {
 	return i - 1
 }
 
-
 func searchLineInfos(a []lineInfo, x int) int {
 	return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1
 }
 
-
 // info returns the file name, line, and column number for a file offset.
 func (f *File) info(offset int) (filename string, line, column int) {
 	filename = f.name
@@ -367,7 +339,6 @@ func (f *File) info(offset int) (filename string, line, column int) {
 	return
 }
 
-
 // A FileSet represents a set of source files.
 // Methods of file sets are synchronized; multiple goroutines
 // may invoke them concurrently.
@@ -379,7 +350,6 @@ type FileSet struct {
 	last  *File        // cache of last file looked up
 }
 
-
 // NewFileSet creates a new file set.
 func NewFileSet() *FileSet {
 	s := new(FileSet)
@@ -387,7 +357,6 @@ func NewFileSet() *FileSet {
 	return s
 }
 
-
 // Base returns the minimum base offset that must be provided to
 // AddFile when adding the next file.
 //
@@ -399,7 +368,6 @@ func (s *FileSet) Base() int {
 
 }
 
-
 // AddFile adds a new file with a given filename, base offset, and file size
 // to the file set s and returns the file. Multiple files may have the same
 // name. The base offset must not be smaller than the FileSet's Base(), and
@@ -434,7 +402,6 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
 	return f
 }
 
-
 // Files returns the files added to the file set.
 func (s *FileSet) Files() <-chan *File {
 	ch := make(chan *File)
diff --git a/src/pkg/go/token/position_test.go b/src/pkg/go/token/position_test.go
index 979c9b1..30bec59 100644
--- a/src/pkg/go/token/position_test.go
+++ b/src/pkg/go/token/position_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 )
 
-
 func checkPos(t *testing.T, msg string, p, q Position) {
 	if p.Filename != q.Filename {
 		t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
@@ -25,7 +24,6 @@ func checkPos(t *testing.T, msg string, p, q Position) {
 	}
 }
 
-
 func TestNoPos(t *testing.T) {
 	if NoPos.IsValid() {
 		t.Errorf("NoPos should not be valid")
@@ -36,7 +34,6 @@ func TestNoPos(t *testing.T) {
 	checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
 }
 
-
 var tests = []struct {
 	filename string
 	source   []byte // may be nil
@@ -53,7 +50,6 @@ var tests = []struct {
 	{"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
 }
 
-
 func linecol(lines []int, offs int) (int, int) {
 	prevLineOffs := 0
 	for line, lineOffs := range lines {
@@ -65,7 +61,6 @@ func linecol(lines []int, offs int) (int, int) {
 	return len(lines), offs - prevLineOffs + 1
 }
 
-
 func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
 	for offs := 0; offs < f.Size(); offs++ {
 		p := f.Pos(offs)
@@ -80,7 +75,6 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
 	}
 }
 
-
 func makeTestSource(size int, lines []int) []byte {
 	src := make([]byte, size)
 	for _, offs := range lines {
@@ -91,7 +85,6 @@ func makeTestSource(size int, lines []int) []byte {
 	return src
 }
 
-
 func TestPositions(t *testing.T) {
 	const delta = 7 // a non-zero base offset increment
 	fset := NewFileSet()
@@ -150,7 +143,6 @@ func TestPositions(t *testing.T) {
 	}
 }
 
-
 func TestLineInfo(t *testing.T) {
 	fset := NewFileSet()
 	f := fset.AddFile("foo", fset.Base(), 500)
@@ -170,7 +162,6 @@ func TestLineInfo(t *testing.T) {
 	}
 }
 
-
 func TestFiles(t *testing.T) {
 	fset := NewFileSet()
 	for i, test := range tests {
diff --git a/src/pkg/go/token/token.go b/src/pkg/go/token/token.go
index c2ec80a..5573740 100644
--- a/src/pkg/go/token/token.go
+++ b/src/pkg/go/token/token.go
@@ -9,7 +9,6 @@ package token
 
 import "strconv"
 
-
 // Token is the set of lexical tokens of the Go programming language.
 type Token int
 
@@ -124,7 +123,6 @@ const (
 	keyword_end
 )
 
-
 var tokens = [...]string{
 	ILLEGAL: "ILLEGAL",
 
@@ -225,7 +223,6 @@ var tokens = [...]string{
 	VAR:    "var",
 }
 
-
 // String returns the string corresponding to the token tok.
 // For operators, delimiters, and keywords the string is the actual
 // token character sequence (e.g., for the token ADD, the string is
@@ -243,7 +240,6 @@ func (tok Token) String() string {
 	return s
 }
 
-
 // A set of constants for precedence-based expression parsing.
 // Non-operators have lowest precedence, followed by operators
 // starting with precedence 1 up to unary operators. The highest
@@ -256,7 +252,6 @@ const (
 	HighestPrec = 7
 )
 
-
 // Precedence returns the operator precedence of the binary
 // operator op. If op is not a binary operator, the result
 // is LowestPrecedence.
@@ -277,7 +272,6 @@ func (op Token) Precedence() int {
 	return LowestPrec
 }
 
-
 var keywords map[string]Token
 
 func init() {
@@ -287,7 +281,6 @@ func init() {
 	}
 }
 
-
 // Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
 //
 func Lookup(ident []byte) Token {
@@ -299,7 +292,6 @@ func Lookup(ident []byte) Token {
 	return IDENT
 }
 
-
 // Predicates
 
 // IsLiteral returns true for tokens corresponding to identifiers
diff --git a/src/pkg/go/typechecker/scope.go b/src/pkg/go/typechecker/scope.go
index a4bee6e..d73d1a4 100644
--- a/src/pkg/go/typechecker/scope.go
+++ b/src/pkg/go/typechecker/scope.go
@@ -12,18 +12,15 @@ package typechecker
 
 import "go/ast"
 
-
 func (tc *typechecker) openScope() *ast.Scope {
 	tc.topScope = ast.NewScope(tc.topScope)
 	return tc.topScope
 }
 
-
 func (tc *typechecker) closeScope() {
 	tc.topScope = tc.topScope.Outer
 }
 
-
 // declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
 // It returns the newly allocated object. If an object with the same name already exists in scope, an error
 // is reported and the object is not inserted.
@@ -40,13 +37,11 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast
 	return obj
 }
 
-
 // decl is the same as declInScope(tc.topScope, ...)
 func (tc *typechecker) decl(kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
 	return tc.declInScope(tc.topScope, kind, name, decl, n)
 }
 
-
 // find returns the object with the given name if visible in the current scope hierarchy.
 // If no such object is found, an error is reported and a bad object is returned instead.
 func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
@@ -61,7 +56,6 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
 	return
 }
 
-
 // findField returns the object with the given name if visible in the type's scope.
 // If no such object is found, an error is reported and a bad object is returned instead.
 func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) {
diff --git a/src/pkg/go/typechecker/type.go b/src/pkg/go/typechecker/type.go
index 62b4e9d..1b88eb5 100644
--- a/src/pkg/go/typechecker/type.go
+++ b/src/pkg/go/typechecker/type.go
@@ -6,7 +6,6 @@ package typechecker
 
 import "go/ast"
 
-
 // A Type represents a Go type.
 type Type struct {
 	Form     Form
@@ -18,13 +17,11 @@ type Type struct {
 	Expr     ast.Expr    // corresponding AST expression
 }
 
-
 // NewType creates a new type of a given form.
 func NewType(form Form) *Type {
 	return &Type{Form: form, Scope: ast.NewScope(nil)}
 }
 
-
 // Form describes the form of a type.
 type Form int
 
@@ -45,7 +42,6 @@ const (
 	Tuple
 )
 
-
 var formStrings = [...]string{
 	BadType:    "badType",
 	Unresolved: "unresolved",
@@ -62,10 +58,8 @@ var formStrings = [...]string{
 	Tuple:      "tuple",
 }
 
-
 func (form Form) String() string { return formStrings[form] }
 
-
 // The list of basic type id's.
 const (
 	Bool = iota
@@ -96,7 +90,6 @@ const (
 	// TODO(gri) ideal types are missing
 )
 
-
 var BasicTypes = map[uint]string{
 	Bool:    "bool",
 	Byte:    "byte",
diff --git a/src/pkg/go/typechecker/typechecker.go b/src/pkg/go/typechecker/typechecker.go
index b151f58..2448016 100644
--- a/src/pkg/go/typechecker/typechecker.go
+++ b/src/pkg/go/typechecker/typechecker.go
@@ -17,19 +17,16 @@ import (
 	"os"
 )
 
-
 // TODO(gri) don't report errors for objects/types that are marked as bad.
 
 
 const debug = true // set for debugging output
 
-
 // An importer takes an import path and returns the data describing the
 // respective package's exported interface. The data format is TBD.
 //
 type Importer func(path string) ([]byte, os.Error)
 
-
 // CheckPackage typechecks a package and augments the AST by setting
 // *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
 // importer is provided, it is used to handle imports, otherwise they
@@ -46,7 +43,6 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E
 	return tc.GetError(scanner.Sorted)
 }
 
-
 // CheckFile typechecks a single file, but otherwise behaves like
 // CheckPackage. If the complete package consists of more than just
 // one file, the file may not typecheck without errors.
@@ -57,7 +53,6 @@ func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error
 	return CheckPackage(fset, pkg, importer)
 }
 
-
 // ----------------------------------------------------------------------------
 // Typechecker state
 
@@ -71,19 +66,16 @@ type typechecker struct {
 	iota     int                  // current value of iota
 }
 
-
 func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) {
 	tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...))
 }
 
-
 func assert(pred bool) {
 	if !pred {
 		panic("internal error")
 	}
 }
 
-
 /*
 Typechecking is done in several phases:
 
@@ -158,7 +150,6 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) {
 	pkg.Scope = tc.topScope
 }
 
-
 func (tc *typechecker) declGlobal(global ast.Decl) {
 	switch d := global.(type) {
 	case *ast.BadDecl:
@@ -218,7 +209,6 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
 	}
 }
 
-
 // If x is of the form *T, deref returns T, otherwise it returns x.
 func deref(x ast.Expr) ast.Expr {
 	if p, isPtr := x.(*ast.StarExpr); isPtr {
@@ -227,7 +217,6 @@ func deref(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
 	// a method is declared in the receiver base type's scope
 	var scope *ast.Scope
@@ -259,7 +248,6 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
 	tc.declInScope(scope, ast.Fun, method.Name, method, 0)
 }
 
-
 func (tc *typechecker) resolve(obj *ast.Object) {
 	// check for declaration cycles
 	if tc.cyclemap[obj] {
@@ -318,7 +306,6 @@ func (tc *typechecker) resolve(obj *ast.Object) {
 	}
 }
 
-
 func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
 	tc.openScope()
 	defer tc.closeScope()
@@ -338,7 +325,6 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
 	}
 }
 
-
 // ----------------------------------------------------------------------------
 // Types
 
@@ -350,7 +336,6 @@ func unparen(x ast.Expr) ast.Expr {
 	return x
 }
 
-
 func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
 	if fields != nil {
 		for _, f := range fields.List {
@@ -365,7 +350,6 @@ func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref b
 	return n
 }
 
-
 func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
 	assert((typ.Form == Method) == (recv != nil))
 	typ.Params = ast.NewScope(nil)
@@ -374,7 +358,6 @@ func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.Field
 	typ.N = tc.declFields(typ.Params, results, true)
 }
 
-
 func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
 	x = unparen(x)
 
@@ -472,17 +455,14 @@ func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // TODO(gri) implement these place holders
 
 func (tc *typechecker) declConst(*ast.Object) {
 }
 
-
 func (tc *typechecker) declVar(*ast.Object) {
 }
 
-
 func (tc *typechecker) checkStmt(ast.Stmt) {
 }
diff --git a/src/pkg/go/typechecker/typechecker_test.go b/src/pkg/go/typechecker/typechecker_test.go
index d16e069..4bad449 100644
--- a/src/pkg/go/typechecker/typechecker_test.go
+++ b/src/pkg/go/typechecker/typechecker_test.go
@@ -41,7 +41,6 @@ import (
 	"testing"
 )
 
-
 const testDir = "./testdata" // location of test packages
 
 var fset = token.NewFileSet()
@@ -51,7 +50,6 @@ var (
 	trace  = flag.Bool("trace", false, "print package names")
 )
 
-
 // ERROR comments must be of the form /* ERROR "rx" */ and rx is
 // a regular expression that matches the expected error message.
 var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
@@ -91,12 +89,10 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
 	return
 }
 
-
 func testFilter(f *os.FileInfo) bool {
 	return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
 }
 
-
 func checkError(t *testing.T, expected, found *scanner.Error) {
 	rx, err := regexp.Compile(expected.Msg)
 	if err != nil {
@@ -120,7 +116,6 @@ func checkError(t *testing.T, expected, found *scanner.Error) {
 	}
 }
 
-
 func TestTypeCheck(t *testing.T) {
 	flag.Parse()
 	pkgRx, err := regexp.Compile(*pkgPat)
diff --git a/src/pkg/go/typechecker/universe.go b/src/pkg/go/typechecker/universe.go
index abc8bbb..81c14a0 100644
--- a/src/pkg/go/typechecker/universe.go
+++ b/src/pkg/go/typechecker/universe.go
@@ -11,7 +11,6 @@ import "go/ast"
 // The Universe scope contains all predeclared identifiers.
 var Universe *ast.Scope
 
-
 func def(obj *ast.Object) {
 	alt := Universe.Insert(obj)
 	if alt != nil {
@@ -19,7 +18,6 @@ func def(obj *ast.Object) {
 	}
 }
 
-
 func init() {
 	Universe = ast.NewScope(nil)
 
diff --git a/src/pkg/go/types/check.go b/src/pkg/go/types/check.go
index 02d6629..87e3e93 100644
--- a/src/pkg/go/types/check.go
+++ b/src/pkg/go/types/check.go
@@ -15,24 +15,20 @@ import (
 	"strconv"
 )
 
-
 const debug = false
 
-
 type checker struct {
 	fset *token.FileSet
 	scanner.ErrorVector
 	types map[ast.Expr]Type
 }
 
-
 func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string {
 	msg := fmt.Sprintf(format, args...)
 	c.Error(c.fset.Position(pos), msg)
 	return msg
 }
 
-
 // collectFields collects struct fields tok = token.STRUCT), interface methods
 // (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
 func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
@@ -87,7 +83,6 @@ func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bo
 	return
 }
 
-
 // makeType makes a new type for an AST type specification x or returns
 // the type referred to by a type name x. If cycleOk is set, a type may
 // refer to itself directly or indirectly; otherwise cycles are errors.
@@ -183,7 +178,6 @@ func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
 	panic(fmt.Sprintf("unreachable (%T)", x))
 }
 
-
 // checkObj type checks an object.
 func (c *checker) checkObj(obj *ast.Object, ref bool) {
 	if obj.Type != nil {
@@ -214,7 +208,6 @@ func (c *checker) checkObj(obj *ast.Object, ref bool) {
 	}
 }
 
-
 // Check typechecks a package.
 // It augments the AST by assigning types to all ast.Objects and returns a map
 // of types for all expression nodes in statements, and a scanner.ErrorList if
diff --git a/src/pkg/go/types/check_test.go b/src/pkg/go/types/check_test.go
index 6ecb12b..8be653f 100644
--- a/src/pkg/go/types/check_test.go
+++ b/src/pkg/go/types/check_test.go
@@ -34,7 +34,6 @@ import (
 	"testing"
 )
 
-
 // The test filenames do not end in .go so that they are invisible
 // to gofmt since they contain comments that must not change their
 // positions relative to surrounding tokens.
@@ -46,10 +45,8 @@ var tests = []struct {
 	{"test0", []string{"testdata/test0.src"}},
 }
 
-
 var fset = token.NewFileSet()
 
-
 // TODO(gri) This functionality should be in token.Fileset.
 func getFile(filename string) *token.File {
 	for f := range fset.Files() {
@@ -60,7 +57,6 @@ func getFile(filename string) *token.File {
 	return nil
 }
 
-
 // TODO(gri) This functionality should be in token.Fileset.
 func getPos(filename string, offset int) token.Pos {
 	if f := getFile(filename); f != nil {
@@ -69,7 +65,6 @@ func getPos(filename string, offset int) token.Pos {
 	return token.NoPos
 }
 
-
 // TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles
 //           or a similar function instead.
 func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, os.Error) {
@@ -95,7 +90,6 @@ func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*
 	return files, errors
 }
 
-
 // ERROR comments must be of the form /* ERROR "rx" */ and rx is
 // a regular expression that matches the expected error message.
 //
@@ -138,7 +132,6 @@ func expectedErrors(t *testing.T, testname string, files map[string]*ast.File) m
 	return errors
 }
 
-
 func eliminate(t *testing.T, expected map[token.Pos]string, errors os.Error) {
 	if errors == nil {
 		return
@@ -172,7 +165,6 @@ func eliminate(t *testing.T, expected map[token.Pos]string, errors os.Error) {
 	}
 }
 
-
 func check(t *testing.T, testname string, testfiles []string) {
 	// TODO(gri) Eventually all these different phases should be
 	//           subsumed into a single function call that takes
@@ -206,7 +198,6 @@ func check(t *testing.T, testname string, testfiles []string) {
 	}
 }
 
-
 func TestCheck(t *testing.T) {
 	// For easy debugging w/o changing the testing code,
 	// if there is a local test file, only test that file.
diff --git a/src/pkg/go/types/const.go b/src/pkg/go/types/const.go
index 6fdc22f..1ef95d9 100644
--- a/src/pkg/go/types/const.go
+++ b/src/pkg/go/types/const.go
@@ -12,7 +12,6 @@ import (
 	"strconv"
 )
 
-
 // TODO(gri) Consider changing the API so Const is an interface
 //           and operations on consts don't have to type switch.
 
@@ -28,20 +27,17 @@ type Const struct {
 	val interface{}
 }
 
-
 // Representation of complex values.
 type cmplx struct {
 	re, im *big.Rat
 }
 
-
 func assert(cond bool) {
 	if !cond {
 		panic("go/types internal error: assertion failed")
 	}
 }
 
-
 // MakeConst makes an ideal constant from a literal
 // token and the corresponding literal string.
 func MakeConst(tok token.Token, lit string) Const {
@@ -75,14 +71,12 @@ func MakeConst(tok token.Token, lit string) Const {
 	panic("unreachable")
 }
 
-
 // MakeZero returns the zero constant for the given type.
 func MakeZero(typ *Type) Const {
 	// TODO(gri) fix this
 	return Const{0}
 }
 
-
 // Match attempts to match the internal constant representations of x and y.
 // If the attempt is successful, the result is the values of x and y,
 // if necessary converted to have the same internal representation; otherwise
@@ -132,7 +126,6 @@ func (x Const) Match(y Const) (u, v Const) {
 	return
 }
 
-
 // Convert attempts to convert the constant x to a given type.
 // If the attempt is successful, the result is the new constant;
 // otherwise the result is invalid.
@@ -148,7 +141,6 @@ func (x Const) Convert(typ *Type) Const {
 	return x
 }
 
-
 func (x Const) String() string {
 	switch x := x.val.(type) {
 	case bool:
@@ -169,12 +161,10 @@ func (x Const) String() string {
 	panic("unreachable")
 }
 
-
 func (x Const) UnaryOp(op token.Token) Const {
 	panic("unimplemented")
 }
 
-
 func (x Const) BinaryOp(op token.Token, y Const) Const {
 	var z interface{}
 	switch x := x.val.(type) {
@@ -194,7 +184,6 @@ func (x Const) BinaryOp(op token.Token, y Const) Const {
 	return Const{z}
 }
 
-
 func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
 	switch op {
 	case token.EQL:
@@ -205,7 +194,6 @@ func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
 	panic("unreachable")
 }
 
-
 func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
 	var z big.Int
 	switch op {
@@ -247,7 +235,6 @@ func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
 	panic("unreachable")
 }
 
-
 func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
 	var z big.Rat
 	switch op {
@@ -275,7 +262,6 @@ func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
 	panic("unreachable")
 }
 
-
 func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
 	a, b := x.re, x.im
 	c, d := y.re, y.im
@@ -325,7 +311,6 @@ func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
 	panic("unreachable")
 }
 
-
 func binaryStringOp(x string, op token.Token, y string) interface{} {
 	switch op {
 	case token.ADD:
diff --git a/src/pkg/go/types/exportdata.go b/src/pkg/go/types/exportdata.go
index f681337..3835203 100644
--- a/src/pkg/go/types/exportdata.go
+++ b/src/pkg/go/types/exportdata.go
@@ -15,7 +15,6 @@ import (
 	"strings"
 )
 
-
 func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
 	// See $GOROOT/include/ar.h.
 	hdr := make([]byte, 64+12+6+6+8+10+2)
@@ -36,13 +35,11 @@ func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
 	return
 }
 
-
 type dataReader struct {
 	*bufio.Reader
 	io.Closer
 }
 
-
 // ExportData returns a readCloser positioned at the beginning of the
 // export data section of the given object/archive file, or an error.
 // It is the caller's responsibility to close the readCloser.
diff --git a/src/pkg/go/types/gcimporter.go b/src/pkg/go/types/gcimporter.go
index aa0bb91..6ab1806 100644
--- a/src/pkg/go/types/gcimporter.go
+++ b/src/pkg/go/types/gcimporter.go
@@ -20,7 +20,6 @@ import (
 	"strconv"
 )
 
-
 const trace = false // set to true for debugging
 
 var (
@@ -28,7 +27,6 @@ var (
 	pkgExts = [...]string{".a", ".5", ".6", ".8"}
 )
 
-
 // findPkg returns the filename and package id for an import path.
 // If no file was found, an empty filename is returned.
 func findPkg(path string) (filename, id string) {
@@ -69,7 +67,6 @@ func findPkg(path string) (filename, id string) {
 	return
 }
 
-
 // gcParser parses the exports inside a gc compiler-produced
 // object/archive file and populates its scope with the results.
 type gcParser struct {
@@ -80,7 +77,6 @@ type gcParser struct {
 	imports map[string]*ast.Object // package id -> package object
 }
 
-
 func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) {
 	p.scanner.Init(src)
 	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
@@ -92,7 +88,6 @@ func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*
 	p.imports = imports
 }
 
-
 func (p *gcParser) next() {
 	p.tok = p.scanner.Scan()
 	switch p.tok {
@@ -106,7 +101,6 @@ func (p *gcParser) next() {
 	}
 }
 
-
 // GcImporter implements the ast.Importer signature.
 func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) {
 	if path == "unsafe" {
@@ -148,7 +142,6 @@ func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, e
 	return
 }
 
-
 // ----------------------------------------------------------------------------
 // Error handling
 
@@ -158,12 +151,10 @@ type importError struct {
 	err os.Error
 }
 
-
 func (e importError) String() string {
 	return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
 }
 
-
 func (p *gcParser) error(err interface{}) {
 	if s, ok := err.(string); ok {
 		err = os.NewError(s)
@@ -172,12 +163,10 @@ func (p *gcParser) error(err interface{}) {
 	panic(importError{p.scanner.Pos(), err.(os.Error)})
 }
 
-
 func (p *gcParser) errorf(format string, args ...interface{}) {
 	p.error(fmt.Sprintf(format, args...))
 }
 
-
 func (p *gcParser) expect(tok int) string {
 	lit := p.lit
 	if p.tok != tok {
@@ -187,7 +176,6 @@ func (p *gcParser) expect(tok int) string {
 	return lit
 }
 
-
 func (p *gcParser) expectSpecial(tok string) {
 	sep := 'x' // not white space
 	i := 0
@@ -201,7 +189,6 @@ func (p *gcParser) expectSpecial(tok string) {
 	}
 }
 
-
 func (p *gcParser) expectKeyword(keyword string) {
 	lit := p.expect(scanner.Ident)
 	if lit != keyword {
@@ -209,7 +196,6 @@ func (p *gcParser) expectKeyword(keyword string) {
 	}
 }
 
-
 // ----------------------------------------------------------------------------
 // Import declarations
 
@@ -242,7 +228,6 @@ func (p *gcParser) parsePkgId() *ast.Object {
 	return pkg
 }
 
-
 // dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
 func (p *gcParser) parseDotIdent() string {
 	ident := ""
@@ -260,7 +245,6 @@ func (p *gcParser) parseDotIdent() string {
 	return ident
 }
 
-
 // ExportedName = ImportPath "." dotIdentifier .
 //
 func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
@@ -295,7 +279,6 @@ func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
 	return obj
 }
 
-
 // ----------------------------------------------------------------------------
 // Types
 
@@ -309,7 +292,6 @@ func (p *gcParser) parseBasicType() Type {
 	return obj.Type.(Type)
 }
 
-
 // ArrayType = "[" int_lit "]" Type .
 //
 func (p *gcParser) parseArrayType() Type {
@@ -324,7 +306,6 @@ func (p *gcParser) parseArrayType() Type {
 	return &Array{Len: n, Elt: elt}
 }
 
-
 // MapType = "map" "[" Type "]" Type .
 //
 func (p *gcParser) parseMapType() Type {
@@ -336,7 +317,6 @@ func (p *gcParser) parseMapType() Type {
 	return &Map{Key: key, Elt: elt}
 }
 
-
 // Name = identifier | "?" .
 //
 func (p *gcParser) parseName() (name string) {
@@ -353,7 +333,6 @@ func (p *gcParser) parseName() (name string) {
 	return
 }
 
-
 // Field = Name Type [ ":" string_lit ] .
 //
 func (p *gcParser) parseField() (fld *ast.Object, tag string) {
@@ -374,7 +353,6 @@ func (p *gcParser) parseField() (fld *ast.Object, tag string) {
 	return
 }
 
-
 // StructType = "struct" "{" [ FieldList ] "}" .
 // FieldList  = Field { ";" Field } .
 //
@@ -402,7 +380,6 @@ func (p *gcParser) parseStructType() Type {
 	return &Struct{Fields: fields, Tags: tags}
 }
 
-
 // Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
 //
 func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
@@ -425,7 +402,6 @@ func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
 	return
 }
 
-
 // Parameters    = "(" [ ParameterList ] ")" .
 // ParameterList = { Parameter "," } Parameter .
 //
@@ -454,7 +430,6 @@ func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) {
 	return
 }
 
-
 // Signature = Parameters [ Result ] .
 // Result    = Type | Parameters .
 //
@@ -481,7 +456,6 @@ func (p *gcParser) parseSignature() *Func {
 	return &Func{Params: params, Results: results, IsVariadic: isVariadic}
 }
 
-
 // MethodSpec = identifier Signature .
 //
 func (p *gcParser) parseMethodSpec() *ast.Object {
@@ -499,7 +473,6 @@ func (p *gcParser) parseMethodSpec() *ast.Object {
 	return ast.NewObj(ast.Fun, "_")
 }
 
-
 // InterfaceType = "interface" "{" [ MethodList ] "}" .
 // MethodList    = MethodSpec { ";" MethodSpec } .
 //
@@ -526,7 +499,6 @@ func (p *gcParser) parseInterfaceType() Type {
 	return &Interface{Methods: methods}
 }
 
-
 // ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
 //
 func (p *gcParser) parseChanType() Type {
@@ -546,7 +518,6 @@ func (p *gcParser) parseChanType() Type {
 	return &Chan{Dir: dir, Elt: elt}
 }
 
-
 // Type =
 //	BasicType | TypeName | ArrayType | SliceType | StructType |
 //      PointerType | FuncType | InterfaceType | MapType | ChanType |
@@ -604,7 +575,6 @@ func (p *gcParser) parseType() Type {
 	return nil
 }
 
-
 // ----------------------------------------------------------------------------
 // Declarations
 
@@ -621,7 +591,6 @@ func (p *gcParser) parseImportDecl() {
 	pkg.Name = name
 }
 
-
 // int_lit = [ "+" | "-" ] { "0" ... "9" } .
 //
 func (p *gcParser) parseInt() (sign, val string) {
@@ -636,7 +605,6 @@ func (p *gcParser) parseInt() (sign, val string) {
 	return
 }
 
-
 // number = int_lit [ "p" int_lit ] .
 //
 func (p *gcParser) parseNumber() Const {
@@ -667,7 +635,6 @@ func (p *gcParser) parseNumber() Const {
 	return Const{mant}
 }
 
-
 // ConstDecl   = "const" ExportedName [ Type ] "=" Literal .
 // Literal     = bool_lit | int_lit | float_lit | complex_lit | string_lit .
 // bool_lit    = "true" | "false" .
@@ -722,7 +689,6 @@ func (p *gcParser) parseConstDecl() {
 	obj.Data = x
 }
 
-
 // TypeDecl = "type" ExportedName Type .
 //
 func (p *gcParser) parseTypeDecl() {
@@ -742,7 +708,6 @@ func (p *gcParser) parseTypeDecl() {
 	}
 }
 
-
 // VarDecl = "var" ExportedName Type .
 //
 func (p *gcParser) parseVarDecl() {
@@ -751,7 +716,6 @@ func (p *gcParser) parseVarDecl() {
 	obj.Type = p.parseType()
 }
 
-
 // FuncDecl = "func" ExportedName Signature .
 //
 func (p *gcParser) parseFuncDecl() {
@@ -760,7 +724,6 @@ func (p *gcParser) parseFuncDecl() {
 	obj.Type = p.parseSignature()
 }
 
-
 // MethodDecl = "func" Receiver identifier Signature .
 // Receiver   = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
 //
@@ -773,7 +736,6 @@ func (p *gcParser) parseMethodDecl() {
 	p.parseSignature()
 }
 
-
 // Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
 //
 func (p *gcParser) parseDecl() {
@@ -797,7 +759,6 @@ func (p *gcParser) parseDecl() {
 	p.expect('\n')
 }
 
-
 // ----------------------------------------------------------------------------
 // Export
 
diff --git a/src/pkg/go/types/gcimporter_test.go b/src/pkg/go/types/gcimporter_test.go
index 10240ad..ec87f5d 100644
--- a/src/pkg/go/types/gcimporter_test.go
+++ b/src/pkg/go/types/gcimporter_test.go
@@ -15,7 +15,6 @@ import (
 	"time"
 )
 
-
 var gcName, gcPath string // compiler name and path
 
 func init() {
@@ -35,7 +34,6 @@ func init() {
 	gcPath, _ = exec.LookPath(gcName)
 }
 
-
 func compile(t *testing.T, dirname, filename string) {
 	cmd := exec.Command(gcPath, filename)
 	cmd.Dir = dirname
@@ -47,7 +45,6 @@ func compile(t *testing.T, dirname, filename string) {
 	t.Logf("%s", string(out))
 }
 
-
 // Use the same global imports map for all tests. The effect is
 // as if all tested packages were imported into a single package.
 var imports = make(map[string]*ast.Object)
@@ -61,7 +58,6 @@ func testPath(t *testing.T, path string) bool {
 	return true
 }
 
-
 const maxTime = 3e9 // maximum allotted testing time in ns
 
 func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
@@ -93,7 +89,6 @@ func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
 	return
 }
 
-
 func TestGcImport(t *testing.T) {
 	compile(t, "testdata", "exports.go")
 
diff --git a/src/pkg/go/types/testdata/exports.go b/src/pkg/go/types/testdata/exports.go
index 035a13f..ed63bf9 100644
--- a/src/pkg/go/types/testdata/exports.go
+++ b/src/pkg/go/types/testdata/exports.go
@@ -11,7 +11,6 @@ import (
 	"go/ast"
 )
 
-
 const (
 	C0 int = 0
 	C1     = 3.14159265
@@ -23,7 +22,6 @@ const (
 	C7     = `bar\n`
 )
 
-
 type (
 	T1  int
 	T2  [10]int
@@ -72,18 +70,15 @@ type (
 	T28 func(T28) T28
 )
 
-
 var (
 	V0 int
 	V1 = -991.0
 )
 
-
 func F1()         {}
 func F2(x int)    {}
 func F3() int     { return 0 }
 func F4() float32 { return 0 }
 func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
 
-
 func (p *T1) M1()
diff --git a/src/pkg/go/types/types.go b/src/pkg/go/types/types.go
index 10b0145..3aa8968 100644
--- a/src/pkg/go/types/types.go
+++ b/src/pkg/go/types/types.go
@@ -12,34 +12,29 @@ import (
 	"sort"
 )
 
-
 // All types implement the Type interface.
 type Type interface {
 	isType()
 }
 
-
 // All concrete types embed ImplementsType which
 // ensures that all types implement the Type interface.
 type ImplementsType struct{}
 
 func (t *ImplementsType) isType() {}
 
-
 // A Bad type is a non-nil placeholder type when we don't know a type.
 type Bad struct {
 	ImplementsType
 	Msg string // for better error reporting/debugging
 }
 
-
 // A Basic represents a (unnamed) basic type.
 type Basic struct {
 	ImplementsType
 	// TODO(gri) need a field specifying the exact basic type
 }
 
-
 // An Array represents an array type [Len]Elt.
 type Array struct {
 	ImplementsType
@@ -47,14 +42,12 @@ type Array struct {
 	Elt Type
 }
 
-
 // A Slice represents a slice type []Elt.
 type Slice struct {
 	ImplementsType
 	Elt Type
 }
 
-
 // A Struct represents a struct type struct{...}.
 // Anonymous fields are represented by objects with empty names.
 type Struct struct {
@@ -67,14 +60,12 @@ type Struct struct {
 	// - there is no scope for fast lookup (but the parser creates one)
 }
 
-
 // A Pointer represents a pointer type *Base.
 type Pointer struct {
 	ImplementsType
 	Base Type
 }
 
-
 // A Func represents a function type func(...) (...).
 // Unnamed parameters are represented by objects with empty names.
 type Func struct {
@@ -85,21 +76,18 @@ type Func struct {
 	IsVariadic bool        // true if the last parameter's type is of the form ...T
 }
 
-
 // An Interface represents an interface type interface{...}.
 type Interface struct {
 	ImplementsType
 	Methods ObjList // interface methods sorted by name; or nil
 }
 
-
 // A Map represents a map type map[Key]Elt.
 type Map struct {
 	ImplementsType
 	Key, Elt Type
 }
 
-
 // A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
 type Chan struct {
 	ImplementsType
@@ -107,7 +95,6 @@ type Chan struct {
 	Elt Type
 }
 
-
 // A Name represents a named type as declared in a type declaration.
 type Name struct {
 	ImplementsType
@@ -116,7 +103,6 @@ type Name struct {
 	// TODO(gri) need to remember fields and methods.
 }
 
-
 // If typ is a pointer type, Deref returns the pointer's base type;
 // otherwise it returns typ.
 func Deref(typ Type) Type {
@@ -126,7 +112,6 @@ func Deref(typ Type) Type {
 	return typ
 }
 
-
 // Underlying returns the underlying type of a type.
 func Underlying(typ Type) Type {
 	if typ, ok := typ.(*Name); ok {
@@ -141,7 +126,6 @@ func Underlying(typ Type) Type {
 	return typ
 }
 
-
 // An ObjList represents an ordered (in some fashion) list of objects.
 type ObjList []*ast.Object
 
@@ -153,7 +137,6 @@ func (list ObjList) Swap(i, j int)      { list[i], list[j] = list[j], list[i] }
 // Sort sorts an object list by object name.
 func (list ObjList) Sort() { sort.Sort(list) }
 
-
 // identicalTypes returns true if both lists a and b have the
 // same length and corresponding objects have identical types.
 func identicalTypes(a, b ObjList) bool {
@@ -169,7 +152,6 @@ func identicalTypes(a, b ObjList) bool {
 	return false
 }
 
-
 // Identical returns true if two types are identical.
 func Identical(x, y Type) bool {
 	if x == y {
diff --git a/src/pkg/go/types/universe.go b/src/pkg/go/types/universe.go
index 96005cf..6ae88e5 100644
--- a/src/pkg/go/types/universe.go
+++ b/src/pkg/go/types/universe.go
@@ -9,14 +9,12 @@ package types
 
 import "go/ast"
 
-
 var (
 	scope    *ast.Scope // current scope to use for initialization
 	Universe *ast.Scope
 	Unsafe   *ast.Object // package unsafe
 )
 
-
 func define(kind ast.ObjKind, name string) *ast.Object {
 	obj := ast.NewObj(kind, name)
 	if scope.Insert(obj) != nil {
@@ -25,7 +23,6 @@ func define(kind ast.ObjKind, name string) *ast.Object {
 	return obj
 }
 
-
 func defType(name string) *Name {
 	obj := define(ast.Typ, name)
 	typ := &Name{Underlying: &Basic{}, Obj: obj}
@@ -33,19 +30,16 @@ func defType(name string) *Name {
 	return typ
 }
 
-
 func defConst(name string) {
 	obj := define(ast.Con, name)
 	_ = obj // TODO(gri) fill in other properties
 }
 
-
 func defFun(name string) {
 	obj := define(ast.Fun, name)
 	_ = obj // TODO(gri) fill in other properties
 }
 
-
 var (
 	Bool,
 	Int,
@@ -54,7 +48,6 @@ var (
 	String *Name
 )
 
-
 func init() {
 	scope = ast.NewScope(nil)
 	Universe = scope
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go
index da8e59c..a5fb91c 100644
--- a/src/pkg/gob/codec_test.go
+++ b/src/pkg/gob/codec_test.go
@@ -573,30 +573,32 @@ func TestEndToEnd(t *testing.T) {
 	s1 := "string1"
 	s2 := "string2"
 	type T1 struct {
-		A, B, C int
-		M       map[string]*float64
-		N       *[3]float64
-		Strs    *[2]string
-		Int64s  *[]int64
-		RI      complex64
-		S       string
-		Y       []byte
-		T       *T2
+		A, B, C  int
+		M        map[string]*float64
+		EmptyMap map[string]int // to check that we receive a non-nil map.
+		N        *[3]float64
+		Strs     *[2]string
+		Int64s   *[]int64
+		RI       complex64
+		S        string
+		Y        []byte
+		T        *T2
 	}
 	pi := 3.14159
 	e := 2.71828
 	t1 := &T1{
-		A:      17,
-		B:      18,
-		C:      -5,
-		M:      map[string]*float64{"pi": &pi, "e": &e},
-		N:      &[3]float64{1.5, 2.5, 3.5},
-		Strs:   &[2]string{s1, s2},
-		Int64s: &[]int64{77, 89, 123412342134},
-		RI:     17 - 23i,
-		S:      "Now is the time",
-		Y:      []byte("hello, sailor"),
-		T:      &T2{"this is T2"},
+		A:        17,
+		B:        18,
+		C:        -5,
+		M:        map[string]*float64{"pi": &pi, "e": &e},
+		EmptyMap: make(map[string]int),
+		N:        &[3]float64{1.5, 2.5, 3.5},
+		Strs:     &[2]string{s1, s2},
+		Int64s:   &[]int64{77, 89, 123412342134},
+		RI:       17 - 23i,
+		S:        "Now is the time",
+		Y:        []byte("hello, sailor"),
+		T:        &T2{"this is T2"},
 	}
 	b := new(bytes.Buffer)
 	err := NewEncoder(b).Encode(t1)
@@ -611,6 +613,13 @@ func TestEndToEnd(t *testing.T) {
 	if !reflect.DeepEqual(t1, &_t1) {
 		t.Errorf("encode expected %v got %v", *t1, _t1)
 	}
+	// Be absolutely sure the received map is non-nil.
+	if t1.EmptyMap == nil {
+		t.Errorf("nil map sent")
+	}
+	if _t1.EmptyMap == nil {
+		t.Errorf("nil map received")
+	}
 }
 
 func TestOverflow(t *testing.T) {
@@ -782,7 +791,6 @@ func TestOverflow(t *testing.T) {
 	}
 }
 
-
 func TestNesting(t *testing.T) {
 	type RT struct {
 		A    string
@@ -980,7 +988,6 @@ func TestIgnoredFields(t *testing.T) {
 	}
 }
 
-
 func TestBadRecursiveType(t *testing.T) {
 	type Rec ***Rec
 	var rec Rec
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go
index 79aee77..ce8a6ff 100644
--- a/src/pkg/gob/debug.go
+++ b/src/pkg/gob/debug.go
@@ -416,7 +416,6 @@ func (deb *debugger) typeDefinition(indent tab, id typeId) {
 	deb.wireType[id] = wire
 }
 
-
 // Value:
 //	SingletonValue | StructValue
 func (deb *debugger) value(indent tab, id typeId) {
@@ -463,7 +462,6 @@ func (deb *debugger) nilInterfaceValue(indent tab) int {
 	return 0
 }
 
-
 // NonNilInterfaceValue:
 //	ConcreteTypeName TypeSequence InterfaceContents
 // ConcreteTypeName:
@@ -603,7 +601,6 @@ func (deb *debugger) printBuiltin(indent tab, id typeId) {
 	}
 }
 
-
 // ArrayValue:
 //	uint(n) FieldValue*n
 func (deb *debugger) arrayValue(indent tab, wire *wireType) {
diff --git a/src/pkg/gob/doc.go b/src/pkg/gob/doc.go
index aaf429c..35d882a 100644
--- a/src/pkg/gob/doc.go
+++ b/src/pkg/gob/doc.go
@@ -113,6 +113,11 @@ uninterpreted bytes of the value.
 All other slices and arrays are sent as an unsigned count followed by that many
 elements using the standard gob encoding for their type, recursively.
 
+Maps are sent as an unsigned count followed by that man key, element
+pairs. Empty but non-nil maps are sent, so if the sender has allocated
+a map, the receiver will allocate a map even no elements are
+transmitted.
+
 Structs are sent as a sequence of (field number, field value) pairs.  The field
 value is sent using the standard gob encoding for its type, recursively.  If a
 field has the zero value for its type, it is omitted from the transmission.  The
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index 941e260..c4c8219 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -62,7 +62,7 @@ func (state *encoderState) encodeUint(x uint64) {
 	var n, m int
 	m = uint64Size
 	for n = 1; x > 0; n++ {
-		state.buf[m] = uint8(x & 0xFF)
+		state.buf[m] = uint8(x)
 		x >>= 8
 		m--
 	}
@@ -557,7 +557,9 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
 				// the iteration.
 				v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
 				mv := reflect.Indirect(v)
-				if !state.sendZero && mv.Len() == 0 {
+				// We send zero-length (but non-nil) maps because the
+				// receiver might want to use the map.  (Maps don't use append.)
+				if !state.sendZero && mv.IsNil() {
 					return
 				}
 				state.update(i)
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go
index 792afbd..f5ee423 100644
--- a/src/pkg/gob/encoder_test.go
+++ b/src/pkg/gob/encoder_test.go
@@ -549,3 +549,32 @@ func TestMapBug1(t *testing.T) {
 		t.Errorf("mismatch: %v %v", in, out)
 	}
 }
+
+func TestGobMapInterfaceEncode(t *testing.T) {
+	m := map[string]interface{}{
+		"up": uintptr(0),
+		"i0": []int{-1},
+		"i1": []int8{-1},
+		"i2": []int16{-1},
+		"i3": []int32{-1},
+		"i4": []int64{-1},
+		"u0": []uint{1},
+		"u1": []uint8{1},
+		"u2": []uint16{1},
+		"u3": []uint32{1},
+		"u4": []uint64{1},
+		"f0": []float32{1},
+		"f1": []float64{1},
+		"c0": []complex64{complex(2, -2)},
+		"c1": []complex128{complex(2, float64(-2))},
+		"us": []uintptr{0},
+		"bo": []bool{false},
+		"st": []string{"s"},
+	}
+	buf := bytes.NewBuffer(nil)
+	enc := NewEncoder(buf)
+	err := enc.Encode(m)
+	if err != nil {
+		t.Errorf("gob.Encode map: %s", err)
+	}
+}
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index 552faa4..258a01e 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -762,7 +762,25 @@ func registerBasics() {
 	Register(float64(0))
 	Register(complex64(0i))
 	Register(complex128(0i))
+	Register(uintptr(0))
 	Register(false)
 	Register("")
 	Register([]byte(nil))
+	Register([]int(nil))
+	Register([]int8(nil))
+	Register([]int16(nil))
+	Register([]int32(nil))
+	Register([]int64(nil))
+	Register([]uint(nil))
+	Register([]uint8(nil))
+	Register([]uint16(nil))
+	Register([]uint32(nil))
+	Register([]uint64(nil))
+	Register([]float32(nil))
+	Register([]float64(nil))
+	Register([]complex64(nil))
+	Register([]complex128(nil))
+	Register([]uintptr(nil))
+	Register([]bool(nil))
+	Register([]string(nil))
 }
diff --git a/src/pkg/hash/crc32/Makefile b/src/pkg/hash/crc32/Makefile
index 31b2051..af8a64c 100644
--- a/src/pkg/hash/crc32/Makefile
+++ b/src/pkg/hash/crc32/Makefile
@@ -5,7 +5,16 @@
 include ../../../Make.inc
 
 TARG=hash/crc32
+
+ifeq ($(GOARCH), amd64)
+	ARCH_GOFILES=crc32_amd64.go
+	OFILES=crc32_amd64.6
+else
+	ARCH_GOFILES=crc32_generic.go
+endif
+
 GOFILES=\
 	crc32.go\
+	$(ARCH_GOFILES)
 
 include ../../../Make.pkg
diff --git a/src/pkg/hash/crc32/crc32.go b/src/pkg/hash/crc32/crc32.go
index 88a4499..0245b1e 100644
--- a/src/pkg/hash/crc32/crc32.go
+++ b/src/pkg/hash/crc32/crc32.go
@@ -10,6 +10,7 @@ package crc32
 import (
 	"hash"
 	"os"
+	"sync"
 )
 
 // The size of a CRC-32 checksum in bytes.
@@ -35,8 +36,34 @@ const (
 // Table is a 256-word table representing the polynomial for efficient processing.
 type Table [256]uint32
 
+// castagnoliTable points to a lazily initialized Table for the Castagnoli
+// polynomial. MakeTable will always return this value when asked to make a
+// Castagnoli table so we can compare against it to find when the caller is
+// using this polynomial.
+var castagnoliTable *Table
+var castagnoliOnce sync.Once
+
+func castagnoliInit() {
+	castagnoliTable = makeTable(Castagnoli)
+}
+
+// IEEETable is the table for the IEEE polynomial.
+var IEEETable = makeTable(IEEE)
+
 // MakeTable returns the Table constructed from the specified polynomial.
 func MakeTable(poly uint32) *Table {
+	switch poly {
+	case IEEE:
+		return IEEETable
+	case Castagnoli:
+		castagnoliOnce.Do(castagnoliInit)
+		return castagnoliTable
+	}
+	return makeTable(poly)
+}
+
+// makeTable returns the Table constructed from the specified polynomial.
+func makeTable(poly uint32) *Table {
 	t := new(Table)
 	for i := 0; i < 256; i++ {
 		crc := uint32(i)
@@ -52,9 +79,6 @@ func MakeTable(poly uint32) *Table {
 	return t
 }
 
-// IEEETable is the table for the IEEE polynomial.
-var IEEETable = MakeTable(IEEE)
-
 // digest represents the partial evaluation of a checksum.
 type digest struct {
 	crc uint32
@@ -83,11 +107,14 @@ func update(crc uint32, tab *Table, p []byte) uint32 {
 
 // Update returns the result of adding the bytes in p to the crc.
 func Update(crc uint32, tab *Table, p []byte) uint32 {
+	if tab == castagnoliTable {
+		return updateCastagnoli(crc, p)
+	}
 	return update(crc, tab, p)
 }
 
 func (d *digest) Write(p []byte) (n int, err os.Error) {
-	d.crc = update(d.crc, d.tab, p)
+	d.crc = Update(d.crc, d.tab, p)
 	return len(p), nil
 }
 
@@ -105,7 +132,7 @@ func (d *digest) Sum() []byte {
 
 // Checksum returns the CRC-32 checksum of data
 // using the polynomial represented by the Table.
-func Checksum(data []byte, tab *Table) uint32 { return update(0, tab, data) }
+func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
 
 // ChecksumIEEE returns the CRC-32 checksum of data
 // using the IEEE polynomial.
diff --git a/src/pkg/hash/crc32/crc32_amd64.go b/src/pkg/hash/crc32/crc32_amd64.go
new file mode 100644
index 0000000..83349bc
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64.go
@@ -0,0 +1,25 @@
+// 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 crc32
+
+// This file contains the code to call the SSE 4.2 version of the Castagnoli
+// CRC.
+
+// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2
+// support.
+func haveSSE42() bool
+
+// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// instruction.
+func castagnoliSSE42(uint32, []byte) uint32
+
+var sse42 = haveSSE42()
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+	if sse42 {
+		return castagnoliSSE42(crc, p)
+	}
+	return update(crc, castagnoliTable, p)
+}
diff --git a/src/pkg/hash/crc32/crc32_amd64.s b/src/pkg/hash/crc32/crc32_amd64.s
new file mode 100644
index 0000000..a9e5317
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64.s
@@ -0,0 +1,62 @@
+// 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.
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT ·castagnoliSSE42(SB),7,$0
+	MOVL crc+0(FP), AX  // CRC value
+	MOVQ p+8(FP), SI  // data pointer
+	MOVL p+16(FP), CX  // len(p)
+
+	NOTL AX
+
+	/* If there's less than 8 bytes to process, we do it byte-by-byte. */
+	CMPL CX, $8
+	JL cleanup
+
+	/* Process individual bytes until the input is 8-byte aligned. */
+startup:
+	MOVQ SI, BX
+	ANDQ $7, BX
+	JZ aligned
+
+	CRC32B (SI), AX
+	DECL CX
+	INCQ SI
+	JMP startup
+
+aligned:
+	/* The input is now 8-byte aligned and we can process 8-byte chunks. */
+	CMPL CX, $8
+	JL cleanup
+
+	CRC32Q (SI), AX
+	ADDQ $8, SI
+	SUBQ $8, CX
+	JMP aligned
+
+cleanup:
+	/* We may have some bytes left over that we process one at a time. */
+	CMPL CX, $0
+	JE done
+
+	CRC32B (SI), AX
+	INCQ SI
+	DECQ CX
+	JMP cleanup
+
+done:
+	NOTL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func haveSSE42() bool
+TEXT ·haveSSE42(SB),7,$0
+	XORQ AX, AX
+	INCL AX
+	CPUID
+	SHRQ $20, CX
+	ANDQ $1, CX
+	MOVB CX, ret+0(FP)
+	RET
+
diff --git a/src/pkg/hash/crc32/crc32_generic.go b/src/pkg/hash/crc32/crc32_generic.go
new file mode 100644
index 0000000..27aabd9
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_generic.go
@@ -0,0 +1,12 @@
+// 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 crc32
+
+// The file contains the generic version of updateCastagnoli which just calls
+// the software implementation.
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+	return update(crc, castagnoliTable, p)
+}
diff --git a/src/pkg/hash/crc32/crc32_test.go b/src/pkg/hash/crc32/crc32_test.go
index cf5743c..7e82dd7 100644
--- a/src/pkg/hash/crc32/crc32_test.go
+++ b/src/pkg/hash/crc32/crc32_test.go
@@ -10,53 +10,73 @@ import (
 )
 
 type test struct {
-	out uint32
-	in  string
+	ieee, castagnoli uint32
+	in               string
 }
 
 var golden = []test{
-	{0x0, ""},
-	{0xe8b7be43, "a"},
-	{0x9e83486d, "ab"},
-	{0x352441c2, "abc"},
-	{0xed82cd11, "abcd"},
-	{0x8587d865, "abcde"},
-	{0x4b8e39ef, "abcdef"},
-	{0x312a6aa6, "abcdefg"},
-	{0xaeef2a50, "abcdefgh"},
-	{0x8da988af, "abcdefghi"},
-	{0x3981703a, "abcdefghij"},
-	{0x6b9cdfe7, "Discard medicine more than two years old."},
-	{0xc90ef73f, "He who has a shady past knows that nice guys finish last."},
-	{0xb902341f, "I wouldn't marry him with a ten foot pole."},
-	{0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
-	{0x154c6d11, "The days of the digital watch are numbered.  -Tom Stoppard"},
-	{0x4c418325, "Nepal premier won't resign."},
-	{0x33955150, "For every action there is an equal and opposite government program."},
-	{0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine."},
-	{0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
-	{0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
-	{0xab3abe14, "size:  a.out:  bad magic"},
-	{0xbab102b6, "The major problem is with sendmail.  -Mark Horton"},
-	{0x999149d7, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
-	{0x6d52a33c, "If the enemy is within range, then so are you."},
-	{0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams."},
-	{0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway."},
-	{0x7d0a377f, "C is as portable as Stonehedge!!"},
-	{0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
-	{0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
-	{0x8e0bb443, "How can you write a big system without C++?  -Paul Glick"},
+	{0x0, 0x0, ""},
+	{0xe8b7be43, 0xc1d04330, "a"},
+	{0x9e83486d, 0xe2a22936, "ab"},
+	{0x352441c2, 0x364b3fb7, "abc"},
+	{0xed82cd11, 0x92c80a31, "abcd"},
+	{0x8587d865, 0xc450d697, "abcde"},
+	{0x4b8e39ef, 0x53bceff1, "abcdef"},
+	{0x312a6aa6, 0xe627f441, "abcdefg"},
+	{0xaeef2a50, 0xa9421b7, "abcdefgh"},
+	{0x8da988af, 0x2ddc99fc, "abcdefghi"},
+	{0x3981703a, 0xe6599437, "abcdefghij"},
+	{0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."},
+	{0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."},
+	{0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."},
+	{0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+	{0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered.  -Tom Stoppard"},
+	{0x4c418325, 0x85d3dc82, "Nepal premier won't resign."},
+	{0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."},
+	{0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."},
+	{0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+	{0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+	{0xab3abe14, 0x572b74e2, "size:  a.out:  bad magic"},
+	{0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail.  -Mark Horton"},
+	{0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+	{0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."},
+	{0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."},
+	{0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."},
+	{0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"},
+	{0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+	{0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+	{0x8e0bb443, 0xdcded527, "How can you write a big system without C++?  -Paul Glick"},
 }
 
 func TestGolden(t *testing.T) {
-	for i := 0; i < len(golden); i++ {
-		g := golden[i]
-		c := NewIEEE()
-		io.WriteString(c, g.in)
-		s := c.Sum32()
-		if s != g.out {
-			t.Errorf("crc32(%s) = 0x%x want 0x%x", g.in, s, g.out)
-			t.FailNow()
+	castagnoliTab := MakeTable(Castagnoli)
+
+	for _, g := range golden {
+		ieee := NewIEEE()
+		io.WriteString(ieee, g.in)
+		s := ieee.Sum32()
+		if s != g.ieee {
+			t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee)
+		}
+
+		castagnoli := New(castagnoliTab)
+		io.WriteString(castagnoli, g.in)
+		s = castagnoli.Sum32()
+		if s != g.castagnoli {
+			t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+		}
+
+		if len(g.in) > 0 {
+			// The SSE4.2 implementation of this has code to deal
+			// with misaligned data so we ensure that we test that
+			// too.
+			castagnoli = New(castagnoliTab)
+			io.WriteString(castagnoli, g.in[:1])
+			io.WriteString(castagnoli, g.in[1:])
+			s = castagnoli.Sum32()
+			if s != g.castagnoli {
+				t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+			}
 		}
 	}
 }
@@ -69,6 +89,7 @@ func BenchmarkCrc32KB(b *testing.B) {
 	}
 	c := NewIEEE()
 	b.StartTimer()
+	b.SetBytes(int64(len(data)))
 
 	for i := 0; i < b.N; i++ {
 		c.Write(data)
diff --git a/src/pkg/html/Makefile b/src/pkg/html/Makefile
index 00e1c05..28dc1a3 100644
--- a/src/pkg/html/Makefile
+++ b/src/pkg/html/Makefile
@@ -6,9 +6,11 @@ include ../../Make.inc
 
 TARG=html
 GOFILES=\
+	const.go\
 	doc.go\
 	entity.go\
 	escape.go\
+	node.go\
 	parse.go\
 	token.go\
 
diff --git a/src/pkg/html/const.go b/src/pkg/html/const.go
new file mode 100644
index 0000000..9078d26
--- /dev/null
+++ b/src/pkg/html/const.go
@@ -0,0 +1,90 @@
+// 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 html
+
+// Section 11.2.3.2 of the HTML5 specification says "The following elements
+// have varying levels of special parsing rules".
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
+var isSpecialElement = map[string]bool{
+	"address":    true,
+	"applet":     true,
+	"area":       true,
+	"article":    true,
+	"aside":      true,
+	"base":       true,
+	"basefont":   true,
+	"bgsound":    true,
+	"blockquote": true,
+	"body":       true,
+	"br":         true,
+	"button":     true,
+	"caption":    true,
+	"center":     true,
+	"col":        true,
+	"colgroup":   true,
+	"command":    true,
+	"dd":         true,
+	"details":    true,
+	"dir":        true,
+	"div":        true,
+	"dl":         true,
+	"dt":         true,
+	"embed":      true,
+	"fieldset":   true,
+	"figcaption": true,
+	"figure":     true,
+	"footer":     true,
+	"form":       true,
+	"frame":      true,
+	"frameset":   true,
+	"h1":         true,
+	"h2":         true,
+	"h3":         true,
+	"h4":         true,
+	"h5":         true,
+	"h6":         true,
+	"head":       true,
+	"header":     true,
+	"hgroup":     true,
+	"hr":         true,
+	"html":       true,
+	"iframe":     true,
+	"img":        true,
+	"input":      true,
+	"isindex":    true,
+	"li":         true,
+	"link":       true,
+	"listing":    true,
+	"marquee":    true,
+	"menu":       true,
+	"meta":       true,
+	"nav":        true,
+	"noembed":    true,
+	"noframes":   true,
+	"noscript":   true,
+	"object":     true,
+	"ol":         true,
+	"p":          true,
+	"param":      true,
+	"plaintext":  true,
+	"pre":        true,
+	"script":     true,
+	"section":    true,
+	"select":     true,
+	"style":      true,
+	"summary":    true,
+	"table":      true,
+	"tbody":      true,
+	"td":         true,
+	"textarea":   true,
+	"tfoot":      true,
+	"th":         true,
+	"thead":      true,
+	"title":      true,
+	"tr":         true,
+	"ul":         true,
+	"wbr":        true,
+	"xmp":        true,
+}
diff --git a/src/pkg/html/entity.go b/src/pkg/html/entity.go
index 1530290..21263e2 100644
--- a/src/pkg/html/entity.go
+++ b/src/pkg/html/entity.go
@@ -4,6 +4,9 @@
 
 package html
 
+// All entities that do not end with ';' are 6 or fewer bytes long.
+const longestEntityWithoutSemicolon = 6
+
 // entity is a map from HTML entity names to their values. The semicolon matters:
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
 // lists both "amp" and "amp;" as two separate entries.
diff --git a/src/pkg/html/entity_test.go b/src/pkg/html/entity_test.go
index a1eb4d4..2cf49d6 100644
--- a/src/pkg/html/entity_test.go
+++ b/src/pkg/html/entity_test.go
@@ -17,6 +17,9 @@ func TestEntityLength(t *testing.T) {
 		if 1+len(k) < utf8.RuneLen(v) {
 			t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v))
 		}
+		if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' {
+			t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon)
+		}
 	}
 	for k, v := range entity2 {
 		if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) {
diff --git a/src/pkg/html/escape.go b/src/pkg/html/escape.go
index 2799f69..0de97c5 100644
--- a/src/pkg/html/escape.go
+++ b/src/pkg/html/escape.go
@@ -53,7 +53,8 @@ var replacementTable = [...]int{
 // unescapeEntity reads an entity like "<" from b[src:] and writes the
 // corresponding "<" to b[dst:], returning the incremented dst and src cursors.
 // Precondition: b[src] == '&' && dst <= src.
-func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
+// attribute should be true if parsing an attribute value.
+func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
 	// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
 
 	// i starts at 1 because we already know that s[0] == '&'.
@@ -121,12 +122,11 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
 	// Consume the maximum number of characters possible, with the
 	// consumed characters matching one of the named references.
 
-	// TODO(nigeltao): unescape("¬it;") should be "¬it;"
 	for i < len(s) {
 		c := s[i]
 		i++
 		// Lower-cased characters are more common in entities, so we check for them first.
-		if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
+		if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
 			continue
 		}
 		if c != ';' {
@@ -136,11 +136,25 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
 	}
 
 	entityName := string(s[1:i])
-	if x := entity[entityName]; x != 0 {
+	if entityName == "" {
+		// No-op.
+	} else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
+		// No-op.
+	} else if x := entity[entityName]; x != 0 {
 		return dst + utf8.EncodeRune(b[dst:], x), src + i
-	} else if x := entity2[entityName]; x[0] != 0 { // Check if it's a two-character entity.
+	} else if x := entity2[entityName]; x[0] != 0 {
 		dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
 		return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+	} else if !attribute {
+		maxLen := len(entityName) - 1
+		if maxLen > longestEntityWithoutSemicolon {
+			maxLen = longestEntityWithoutSemicolon
+		}
+		for j := maxLen; j > 1; j-- {
+			if x := entity[entityName[:j]]; x != 0 {
+				return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
+			}
+		}
 	}
 
 	dst1, src1 = dst+i, src+i
@@ -152,11 +166,11 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
 func unescape(b []byte) []byte {
 	for i, c := range b {
 		if c == '&' {
-			dst, src := unescapeEntity(b, i, i)
+			dst, src := unescapeEntity(b, i, i, false)
 			for src < len(b) {
 				c := b[src]
 				if c == '&' {
-					dst, src = unescapeEntity(b, dst, src)
+					dst, src = unescapeEntity(b, dst, src, false)
 				} else {
 					b[dst] = c
 					dst, src = dst+1, src+1
diff --git a/src/pkg/html/node.go b/src/pkg/html/node.go
new file mode 100644
index 0000000..595afd5
--- /dev/null
+++ b/src/pkg/html/node.go
@@ -0,0 +1,146 @@
+// 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 html
+
+// A NodeType is the type of a Node.
+type NodeType int
+
+const (
+	ErrorNode NodeType = iota
+	TextNode
+	DocumentNode
+	ElementNode
+	CommentNode
+	scopeMarkerNode
+)
+
+// Section 11.2.3.3 says "scope markers are inserted when entering applet
+// elements, buttons, object elements, marquees, table cells, and table
+// captions, and are used to prevent formatting from 'leaking'".
+var scopeMarker = Node{Type: scopeMarkerNode}
+
+// A Node consists of a NodeType and some Data (tag name for element nodes,
+// content for text) and are part of a tree of Nodes. Element nodes may also
+// contain a slice of Attributes. Data is unescaped, so that it looks like
+// "a<b" rather than "a<b".
+type Node struct {
+	Parent *Node
+	Child  []*Node
+	Type   NodeType
+	Data   string
+	Attr   []Attribute
+}
+
+// Add adds a node as a child of n.
+// It will panic if the child's parent is not nil.
+func (n *Node) Add(child *Node) {
+	if child.Parent != nil {
+		panic("html: Node.Add called for a child Node that already has a parent")
+	}
+	child.Parent = n
+	n.Child = append(n.Child, child)
+}
+
+// Remove removes a node as a child of n.
+// It will panic if the child's parent is not n.
+func (n *Node) Remove(child *Node) {
+	if child.Parent == n {
+		child.Parent = nil
+		for i, m := range n.Child {
+			if m == child {
+				copy(n.Child[i:], n.Child[i+1:])
+				j := len(n.Child) - 1
+				n.Child[j] = nil
+				n.Child = n.Child[:j]
+				return
+			}
+		}
+	}
+	panic("html: Node.Remove called for a non-child Node")
+}
+
+// reparentChildren reparents all of src's child nodes to dst.
+func reparentChildren(dst, src *Node) {
+	for _, n := range src.Child {
+		if n.Parent != src {
+			panic("html: nodes have an inconsistent parent/child relationship")
+		}
+		n.Parent = dst
+	}
+	dst.Child = append(dst.Child, src.Child...)
+	src.Child = nil
+}
+
+// clone returns a new node with the same type, data and attributes.
+// The clone has no parent and no children.
+func (n *Node) clone() *Node {
+	m := &Node{
+		Type: n.Type,
+		Data: n.Data,
+		Attr: make([]Attribute, len(n.Attr)),
+	}
+	copy(m.Attr, n.Attr)
+	return m
+}
+
+// nodeStack is a stack of nodes.
+type nodeStack []*Node
+
+// pop pops the stack. It will panic if s is empty.
+func (s *nodeStack) pop() *Node {
+	i := len(*s)
+	n := (*s)[i-1]
+	*s = (*s)[:i-1]
+	return n
+}
+
+// top returns the most recently pushed node, or nil if s is empty.
+func (s *nodeStack) top() *Node {
+	if i := len(*s); i > 0 {
+		return (*s)[i-1]
+	}
+	return nil
+}
+
+// index returns the index of the top-most occurence of n in the stack, or -1
+// if n is not present.
+func (s *nodeStack) index(n *Node) int {
+	for i := len(*s) - 1; i >= 0; i-- {
+		if (*s)[i] == n {
+			return i
+		}
+	}
+	return -1
+}
+
+// insert inserts a node at the given index.
+func (s *nodeStack) insert(i int, n *Node) {
+	(*s) = append(*s, nil)
+	copy((*s)[i+1:], (*s)[i:])
+	(*s)[i] = n
+}
+
+// remove removes a node from the stack. It is a no-op if n is not present.
+func (s *nodeStack) remove(n *Node) {
+	i := s.index(n)
+	if i == -1 {
+		return
+	}
+	copy((*s)[i:], (*s)[i+1:])
+	j := len(*s) - 1
+	(*s)[j] = nil
+	*s = (*s)[:j]
+}
+
+// forTag returns the top-most element node with the given tag.
+func (s *nodeStack) forTag(tag string) *Node {
+	for i := len(*s) - 1; i >= 0; i-- {
+		n := (*s)[i]
+		if n.Type == ElementNode && n.Data == tag {
+			return n
+		}
+	}
+	return nil
+}
diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
index 6a2bc1e..980c470 100644
--- a/src/pkg/html/parse.go
+++ b/src/pkg/html/parse.go
@@ -9,29 +9,6 @@ import (
 	"os"
 )
 
-// A NodeType is the type of a Node.
-type NodeType int
-
-const (
-	ErrorNode NodeType = iota
-	TextNode
-	DocumentNode
-	ElementNode
-	CommentNode
-)
-
-// A Node consists of a NodeType and some Data (tag name for element nodes,
-// content for text) and are part of a tree of Nodes. Element nodes may also
-// contain a slice of Attributes. Data is unescaped, so that it looks like
-// "a<b" rather than "a<b".
-type Node struct {
-	Parent *Node
-	Child  []*Node
-	Type   NodeType
-	Data   string
-	Attr   []Attribute
-}
-
 // A parser implements the HTML5 parsing algorithm:
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
 type parser struct {
@@ -45,38 +22,23 @@ type parser struct {
 	hasSelfClosingToken bool
 	// doc is the document root element.
 	doc *Node
-	// The stack of open elements (section 10.2.3.2).
-	stack []*Node
-	// Element pointers (section 10.2.3.4).
+	// The stack of open elements (section 11.2.3.2) and active formatting
+	// elements (section 11.2.3.3).
+	oe, afe nodeStack
+	// Element pointers (section 11.2.3.4).
 	head, form *Node
-	// Other parsing state flags (section 10.2.3.5).
+	// Other parsing state flags (section 11.2.3.5).
 	scripting, framesetOK bool
 }
 
-// push pushes onto the stack of open elements.
-func (p *parser) push(n *Node) {
-	p.stack = append(p.stack, n)
-}
-
-// top returns the top of the stack of open elements.
-// This is also known as the current node.
 func (p *parser) top() *Node {
-	if n := len(p.stack); n > 0 {
-		return p.stack[n-1]
+	if n := p.oe.top(); n != nil {
+		return n
 	}
 	return p.doc
 }
 
-// pop pops the top of the stack of open elements.
-// It will panic if the stack is empty.
-func (p *parser) pop() *Node {
-	n := len(p.stack)
-	ret := p.stack[n-1]
-	p.stack = p.stack[:n-1]
-	return ret
-}
-
-// stopTags for use in popUntil. These come from section 10.2.3.2.
+// stopTags for use in popUntil. These come from section 11.2.3.2.
 var (
 	defaultScopeStopTags  = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object"}
 	listItemScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "ol", "ul"}
@@ -102,11 +64,11 @@ var (
 // popUntil([]string{"html, "table"}, "table") would return true and leave:
 // ["html", "body", "font"]
 func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
-	for i := len(p.stack) - 1; i >= 0; i-- {
-		tag := p.stack[i].Data
+	for i := len(p.oe) - 1; i >= 0; i-- {
+		tag := p.oe[i].Data
 		for _, t := range matchTags {
 			if t == tag {
-				p.stack = p.stack[:i]
+				p.oe = p.oe[:i]
 				return true
 			}
 		}
@@ -122,10 +84,9 @@ func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
 // addChild adds a child node n to the top element, and pushes n if it is an
 // element node (text nodes are not part of the stack of open elements).
 func (p *parser) addChild(n *Node) {
-	m := p.top()
-	m.Child = append(m.Child, n)
+	p.top().Add(n)
 	if n.Type == ElementNode {
-		p.push(n)
+		p.oe = append(p.oe, n)
 	}
 }
 
@@ -148,15 +109,50 @@ func (p *parser) addElement(tag string, attr []Attribute) {
 	})
 }
 
-// Section 10.2.3.3.
+// Section 11.2.3.3.
 func (p *parser) addFormattingElement(tag string, attr []Attribute) {
 	p.addElement(tag, attr)
+	p.afe = append(p.afe, p.top())
 	// TODO.
 }
 
-// Section 10.2.3.3.
+// Section 11.2.3.3.
+func (p *parser) clearActiveFormattingElements() {
+	for {
+		n := p.afe.pop()
+		if len(p.afe) == 0 || n.Type == scopeMarkerNode {
+			return
+		}
+	}
+}
+
+// Section 11.2.3.3.
 func (p *parser) reconstructActiveFormattingElements() {
-	// TODO.
+	n := p.afe.top()
+	if n == nil {
+		return
+	}
+	if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
+		return
+	}
+	i := len(p.afe) - 1
+	for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
+		if i == 0 {
+			i = -1
+			break
+		}
+		i--
+		n = p.afe[i]
+	}
+	for {
+		i++
+		n = p.afe[i]
+		p.addChild(n.clone())
+		p.afe[i] = n
+		if i == len(p.afe)-1 {
+			break
+		}
+	}
 }
 
 // read reads the next token. This is usually from the tokenizer, but it may
@@ -180,12 +176,12 @@ func (p *parser) read() os.Error {
 	return nil
 }
 
-// Section 10.2.4.
+// Section 11.2.4.
 func (p *parser) acknowledgeSelfClosingTag() {
 	p.hasSelfClosingToken = false
 }
 
-// An insertion mode (section 10.2.3.1) is the state transition function from
+// An insertion mode (section 11.2.3.1) is the state transition function from
 // a particular state in the HTML5 parser's state machine. It updates the
 // parser's fields depending on parser.token (where ErrorToken means EOF). In
 // addition to returning the next insertionMode state, it also returns whether
@@ -194,7 +190,7 @@ type insertionMode func(*parser) (insertionMode, bool)
 
 // useTheRulesFor runs the delegate insertionMode over p, returning the actual
 // insertionMode unless the delegate caused a state transition.
-// Section 10.2.3.1, "using the rules for".
+// Section 11.2.3.1, "using the rules for".
 func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
 	im, consumed := delegate(p)
 	if im != delegate {
@@ -203,13 +199,13 @@ func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, b
 	return actual, consumed
 }
 
-// Section 10.2.5.4.
+// Section 11.2.5.4.1.
 func initialIM(p *parser) (insertionMode, bool) {
 	// TODO: check p.tok for DOCTYPE.
 	return beforeHTMLIM, false
 }
 
-// Section 10.2.5.5.
+// Section 11.2.5.4.2.
 func beforeHTMLIM(p *parser) (insertionMode, bool) {
 	var (
 		add     bool
@@ -243,7 +239,7 @@ func beforeHTMLIM(p *parser) (insertionMode, bool) {
 	return beforeHeadIM, !implied
 }
 
-// Section 10.2.5.6.
+// Section 11.2.5.4.3.
 func beforeHeadIM(p *parser) (insertionMode, bool) {
 	var (
 		add     bool
@@ -280,7 +276,7 @@ func beforeHeadIM(p *parser) (insertionMode, bool) {
 	return inHeadIM, !implied
 }
 
-// Section 10.2.5.7.
+// Section 11.2.5.4.4.
 func inHeadIM(p *parser) (insertionMode, bool) {
 	var (
 		pop     bool
@@ -305,7 +301,7 @@ func inHeadIM(p *parser) (insertionMode, bool) {
 		// TODO.
 	}
 	if pop || implied {
-		n := p.pop()
+		n := p.oe.pop()
 		if n.Data != "head" {
 			panic("html: bad parser state")
 		}
@@ -314,7 +310,7 @@ func inHeadIM(p *parser) (insertionMode, bool) {
 	return inHeadIM, !implied
 }
 
-// Section 10.2.5.9.
+// Section 11.2.5.4.6.
 func afterHeadIM(p *parser) (insertionMode, bool) {
 	var (
 		add        bool
@@ -354,17 +350,18 @@ func afterHeadIM(p *parser) (insertionMode, bool) {
 	return inBodyIM, !implied
 }
 
-// Section 10.2.5.10.
+// Section 11.2.5.4.7.
 func inBodyIM(p *parser) (insertionMode, bool) {
 	var endP bool
 	switch p.tok.Type {
 	case TextToken:
+		p.reconstructActiveFormattingElements()
 		p.addText(p.tok.Data)
 		p.framesetOK = false
 	case StartTagToken:
 		switch p.tok.Data {
 		case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
-			// TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 10.2.3.2.
+			// TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 11.2.3.2.
 			n := p.top()
 			if n.Type == ElementNode && n.Data == "p" {
 				endP = true
@@ -375,16 +372,24 @@ func inBodyIM(p *parser) (insertionMode, bool) {
 			// TODO: auto-insert </p> if necessary.
 			switch n := p.top(); n.Data {
 			case "h1", "h2", "h3", "h4", "h5", "h6":
-				p.pop()
+				p.oe.pop()
 			}
 			p.addElement(p.tok.Data, p.tok.Attr)
+		case "a":
+			if n := p.afe.forTag("a"); n != nil {
+				p.inBodyEndTagFormatting("a")
+				p.oe.remove(n)
+				p.afe.remove(n)
+			}
+			p.reconstructActiveFormattingElements()
+			p.addFormattingElement(p.tok.Data, p.tok.Attr)
 		case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u":
 			p.reconstructActiveFormattingElements()
 			p.addFormattingElement(p.tok.Data, p.tok.Attr)
 		case "area", "br", "embed", "img", "input", "keygen", "wbr":
 			p.reconstructActiveFormattingElements()
 			p.addElement(p.tok.Data, p.tok.Attr)
-			p.pop()
+			p.oe.pop()
 			p.acknowledgeSelfClosingTag()
 			p.framesetOK = false
 		case "table":
@@ -395,7 +400,7 @@ func inBodyIM(p *parser) (insertionMode, bool) {
 		case "hr":
 			// TODO: auto-insert </p> if necessary.
 			p.addElement(p.tok.Data, p.tok.Attr)
-			p.pop()
+			p.oe.pop()
 			p.acknowledgeSelfClosingTag()
 			p.framesetOK = false
 		default:
@@ -408,21 +413,17 @@ func inBodyIM(p *parser) (insertionMode, bool) {
 			// TODO: autoclose the stack of open elements.
 			return afterBodyIM, true
 		case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u":
-			// TODO: implement the "adoption agency" algorithm:
-			// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
-			if p.tok.Data == p.top().Data {
-				p.pop()
-			}
+			p.inBodyEndTagFormatting(p.tok.Data)
 		default:
 			// TODO: any other end tag
 			if p.tok.Data == p.top().Data {
-				p.pop()
+				p.oe.pop()
 			}
 		}
 	}
 	if endP {
 		// TODO: do the proper algorithm.
-		n := p.pop()
+		n := p.oe.pop()
 		if n.Type != ElementNode || n.Data != "p" {
 			panic("unreachable")
 		}
@@ -430,7 +431,123 @@ func inBodyIM(p *parser) (insertionMode, bool) {
 	return inBodyIM, !endP
 }
 
-// Section 10.2.5.12.
+func (p *parser) inBodyEndTagFormatting(tag string) {
+	// This is the "adoption agency" algorithm, described at
+	// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
+
+	// TODO: this is a fairly literal line-by-line translation of that algorithm.
+	// Once the code successfully parses the comprehensive test suite, we should
+	// refactor this code to be more idiomatic.
+
+	// Steps 1-3. The outer loop.
+	for i := 0; i < 8; i++ {
+		// Step 4. Find the formatting element.
+		var formattingElement *Node
+		for j := len(p.afe) - 1; j >= 0; j-- {
+			if p.afe[j].Type == scopeMarkerNode {
+				break
+			}
+			if p.afe[j].Data == tag {
+				formattingElement = p.afe[j]
+				break
+			}
+		}
+		if formattingElement == nil {
+			return
+		}
+		feIndex := p.oe.index(formattingElement)
+		if feIndex == -1 {
+			p.afe.remove(formattingElement)
+			return
+		}
+
+		// Steps 5-6. Find the furthest block.
+		var furthestBlock *Node
+		for _, e := range p.oe[feIndex:] {
+			if isSpecialElement[e.Data] {
+				furthestBlock = e
+				break
+			}
+		}
+		if furthestBlock == nil {
+			e := p.oe.pop()
+			for e != formattingElement {
+				e = p.oe.pop()
+			}
+			p.afe.remove(e)
+			return
+		}
+
+		// Steps 7-8. Find the common ancestor and bookmark node.
+		commonAncestor := p.oe[feIndex-1]
+		bookmark := p.afe.index(formattingElement)
+
+		// Step 9. The inner loop. Find the lastNode to reparent.
+		lastNode := furthestBlock
+		node := furthestBlock
+		x := p.oe.index(node)
+		// Steps 9.1-9.3.
+		for j := 0; j < 3; j++ {
+			// Step 9.4.
+			x--
+			node = p.oe[x]
+			// Step 9.5.
+			if p.afe.index(node) == -1 {
+				p.oe.remove(node)
+				continue
+			}
+			// Step 9.6.
+			if node == formattingElement {
+				break
+			}
+			// Step 9.7.
+			clone := node.clone()
+			p.afe[p.afe.index(node)] = clone
+			p.oe[p.oe.index(node)] = clone
+			node = clone
+			// Step 9.8.
+			if lastNode == furthestBlock {
+				bookmark = p.afe.index(node) + 1
+			}
+			// Step 9.9.
+			if lastNode.Parent != nil {
+				lastNode.Parent.Remove(lastNode)
+			}
+			node.Add(lastNode)
+			// Step 9.10.
+			lastNode = node
+		}
+
+		// Step 10. Reparent lastNode to the common ancestor,
+		// or for misnested table nodes, to the foster parent.
+		if lastNode.Parent != nil {
+			lastNode.Parent.Remove(lastNode)
+		}
+		switch commonAncestor.Data {
+		case "table", "tbody", "tfoot", "thead", "tr":
+			// TODO: fix up misnested table nodes; find the foster parent.
+			fallthrough
+		default:
+			commonAncestor.Add(lastNode)
+		}
+
+		// Steps 11-13. Reparent nodes from the furthest block's children
+		// to a clone of the formatting element.
+		clone := formattingElement.clone()
+		reparentChildren(clone, furthestBlock)
+		furthestBlock.Add(clone)
+
+		// Step 14. Fix up the list of active formatting elements.
+		p.afe.remove(formattingElement)
+		p.afe.insert(bookmark, clone)
+
+		// Step 15. Fix up the stack of open elements.
+		p.oe.remove(formattingElement)
+		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
+	}
+}
+
+// Section 11.2.5.4.9.
 func inTableIM(p *parser) (insertionMode, bool) {
 	var (
 		add      bool
@@ -461,7 +578,7 @@ func inTableIM(p *parser) (insertionMode, bool) {
 		switch p.tok.Data {
 		case "table":
 			if p.popUntil(tableScopeStopTags, "table") {
-				// TODO: "reset the insertion mode appropriately" as per 10.2.3.1.
+				// TODO: "reset the insertion mode appropriately" as per 11.2.3.1.
 				return inBodyIM, false
 			}
 			// Ignore the token.
@@ -480,7 +597,7 @@ func inTableIM(p *parser) (insertionMode, bool) {
 	return inTableIM, true
 }
 
-// Section 10.2.5.16.
+// Section 11.2.5.4.13.
 func inTableBodyIM(p *parser) (insertionMode, bool) {
 	var (
 		add      bool
@@ -528,7 +645,7 @@ func inTableBodyIM(p *parser) (insertionMode, bool) {
 	return useTheRulesFor(p, inTableBodyIM, inTableIM)
 }
 
-// Section 10.2.5.17.
+// Section 11.2.5.4.14.
 func inRowIM(p *parser) (insertionMode, bool) {
 	switch p.tok.Type {
 	case ErrorToken:
@@ -540,7 +657,7 @@ func inRowIM(p *parser) (insertionMode, bool) {
 		case "td", "th":
 			// TODO: clear the stack back to a table row context.
 			p.addElement(p.tok.Data, p.tok.Attr)
-			// TODO: insert a marker at the end of the list of active formatting elements.
+			p.afe = append(p.afe, &scopeMarker)
 			return inCellIM, true
 		default:
 			// TODO.
@@ -567,7 +684,7 @@ func inRowIM(p *parser) (insertionMode, bool) {
 	return useTheRulesFor(p, inRowIM, inTableIM)
 }
 
-// Section 10.2.5.18.
+// Section 11.2.5.4.15.
 func inCellIM(p *parser) (insertionMode, bool) {
 	var (
 		closeTheCellAndReprocess bool
@@ -592,14 +709,14 @@ func inCellIM(p *parser) (insertionMode, bool) {
 	}
 	if closeTheCellAndReprocess {
 		if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
-			// TODO: clear the list of active formatting elements up to the last marker.
+			p.clearActiveFormattingElements()
 			return inRowIM, false
 		}
 	}
 	return useTheRulesFor(p, inCellIM, inBodyIM)
 }
 
-// Section 10.2.5.22.
+// Section 11.2.5.4.18.
 func afterBodyIM(p *parser) (insertionMode, bool) {
 	switch p.tok.Type {
 	case ErrorToken:
@@ -620,7 +737,7 @@ func afterBodyIM(p *parser) (insertionMode, bool) {
 	return afterBodyIM, true
 }
 
-// Section 10.2.5.25.
+// Section 11.2.5.4.21.
 func afterAfterBodyIM(p *parser) (insertionMode, bool) {
 	switch p.tok.Type {
 	case ErrorToken:
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
index 3fa35d5..f22fa27 100644
--- a/src/pkg/html/parse_test.go
+++ b/src/pkg/html/parse_test.go
@@ -85,6 +85,8 @@ func dumpLevel(w io.Writer, n *Node, level int) os.Error {
 		fmt.Fprintf(w, "%q", EscapeString(n.Data))
 	case CommentNode:
 		return os.NewError("COMMENT")
+	case scopeMarkerNode:
+		return os.NewError("unexpected scopeMarkerNode")
 	default:
 		return os.NewError("unknown node type")
 	}
@@ -119,7 +121,7 @@ func TestParser(t *testing.T) {
 		rc := make(chan io.Reader)
 		go readDat(filename, rc)
 		// TODO(nigeltao): Process all test cases, not just a subset.
-		for i := 0; i < 22; i++ {
+		for i := 0; i < 23; i++ {
 			// Parse the #data section.
 			b, err := ioutil.ReadAll(<-rc)
 			if err != nil {
diff --git a/src/pkg/html/testdata/webkit/adoption01.dat b/src/pkg/html/testdata/webkit/adoption01.dat
new file mode 100644
index 0000000..787e1b0
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/adoption01.dat
@@ -0,0 +1,194 @@
+#data
+<a><p></a></p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <p>
+|       <a>
+
+#data
+<a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <p>
+|       <a>
+|         "2"
+|       "3"
+
+#data
+<a>1<button>2</a>3</button>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <button>
+|       <a>
+|         "2"
+|       "3"
+
+#data
+<a>1<b>2</a>3</b>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|       <b>
+|         "2"
+|     <b>
+|       "3"
+
+#data
+<a>1<div>2<div>3</a>4</div>5</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <div>
+|       <a>
+|         "2"
+|       <div>
+|         <a>
+|           "3"
+|         "4"
+|       "5"
+
+#data
+<table><a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <p>
+|       <a>
+|         "2"
+|       "3"
+|     <table>
+
+#data
+<b><b><a><p></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <b>
+|         <a>
+|         <p>
+|           <a>
+
+#data
+<b><a><b><p></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <a>
+|         <b>
+|       <b>
+|         <p>
+|           <a>
+
+#data
+<a><b><b><p></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|         <b>
+|     <b>
+|       <b>
+|         <p>
+|           <a>
+
+#data
+<p>1<s id="A">2<b id="B">3</p>4</s>5</b>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "1"
+|       <s>
+|         id="A"
+|         "2"
+|         <b>
+|           id="B"
+|           "3"
+|     <s>
+|       id="A"
+|       <b>
+|         id="B"
+|         "4"
+|     <b>
+|       id="B"
+|       "5"
+
+#data
+<table><a>1<td>2</td>3</table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <a>
+|       "3"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "2"
+
+#data
+<table>A<td>B</td>C</table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "AC"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "B"
+
+#data
+<a><svg><tr><input></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <svg svg>
+|         <svg tr>
+|           <svg input>
diff --git a/src/pkg/html/testdata/webkit/adoption02.dat b/src/pkg/html/testdata/webkit/adoption02.dat
new file mode 100644
index 0000000..d18151b
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/adoption02.dat
@@ -0,0 +1,31 @@
+#data
+<b>1<i>2<p>3</b>4
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "1"
+|       <i>
+|         "2"
+|     <i>
+|       <p>
+|         <b>
+|           "3"
+|         "4"
+
+#data
+<a><div><style></style><address><a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <div>
+|       <a>
+|         <style>
+|       <address>
+|         <a>
+|         <a>
diff --git a/src/pkg/html/testdata/webkit/comments01.dat b/src/pkg/html/testdata/webkit/comments01.dat
index 388d952..44f1876 100644
--- a/src/pkg/html/testdata/webkit/comments01.dat
+++ b/src/pkg/html/testdata/webkit/comments01.dat
@@ -28,8 +28,7 @@ FOO<!-- BAR --   >BAZ
 |   <head>
 |   <body>
 |     "FOO"
-|     <!--  BAR --    -->
-|     "BAZ"
+|     <!--  BAR --   >BAZ -->
 
 #data
 FOO<!-- BAR -- <QUX> -- MUX -->BAZ
@@ -61,8 +60,7 @@ FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
 |   <head>
 |   <body>
 |     "FOO"
-|     <!--  BAR -- <QUX> -- MUX --  -->
-|     "BAZ"
+|     <!--  BAR -- <QUX> -- MUX -- >BAZ -->
 
 #data
 FOO<!---->BAZ
@@ -124,3 +122,14 @@ FOO<!-->BAZ
 | <html>
 |   <head>
 |   <body>
+
+#data
+FOO<!----->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!-- - -->
+|     "BAZ"
diff --git a/src/pkg/html/testdata/webkit/doctype01.dat b/src/pkg/html/testdata/webkit/doctype01.dat
index 575129c..ae45732 100644
--- a/src/pkg/html/testdata/webkit/doctype01.dat
+++ b/src/pkg/html/testdata/webkit/doctype01.dat
@@ -132,7 +132,7 @@
 <!DOCTYPE potato SYSTEM 'taco"'>Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "" "taco"">
 | <html>
 |   <head>
 |   <body>
@@ -142,7 +142,7 @@
 <!DOCTYPE potato SYSTEM "taco">Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "" "taco">
 | <html>
 |   <head>
 |   <body>
@@ -152,7 +152,7 @@
 <!DOCTYPE potato SYSTEM "tai'co">Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "" "tai'co">
 | <html>
 |   <head>
 |   <body>
@@ -222,7 +222,7 @@
 <!DOCTYPE potato PUBLIC "go'of">Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "go'of" "">
 | <html>
 |   <head>
 |   <body>
@@ -232,7 +232,7 @@
 <!DOCTYPE potato PUBLIC 'go'of'>Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "go" "">
 | <html>
 |   <head>
 |   <body>
@@ -242,7 +242,7 @@
 <!DOCTYPE potato PUBLIC 'go:hh   of' >Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "go:hh   of" "">
 | <html>
 |   <head>
 |   <body>
@@ -252,7 +252,7 @@
 <!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
 #errors
 #document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "W3C-//dfdf" "">
 | <html>
 |   <head>
 |   <body>
@@ -263,7 +263,7 @@
    "http://www.w3.org/TR/html4/strict.dtd">Hello
 #errors
 #document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 | <html>
 |   <head>
 |   <body>
@@ -284,7 +284,7 @@
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 #errors
 #document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 | <html>
 |   <head>
 |   <body>
@@ -294,7 +294,7 @@
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
 #errors
 #document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
 | <html>
 |   <head>
 |   <body>
@@ -309,8 +309,7 @@
 | <html>
 |   <head>
 |   <body>
-|     "
-]>"
+|     "]>"
 
 #data
 <!DOCTYPE html PUBLIC
@@ -318,7 +317,7 @@
     "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
 #errors
 #document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
 | <html>
 |   <head>
 |   <body>
@@ -327,9 +326,45 @@
 <!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
 #errors
 #document
-| <!DOCTYPE html>
+| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd">
 | <html>
 |   <head>
 |   <body>
 |     <b>
 |       "Mine!"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
diff --git a/src/pkg/html/testdata/webkit/dom2string.js b/src/pkg/html/testdata/webkit/dom2string.js
deleted file mode 100644
index 45897fd..0000000
--- a/src/pkg/html/testdata/webkit/dom2string.js
+++ /dev/null
@@ -1,135 +0,0 @@
-String.prototype.toAsciiLowerCase = function () {
-  var output = "";
-  for (var i = 0, len = this.length; i < len; ++i) {
-    if (this.charCodeAt(i) >= 0x41 && this.charCodeAt(i) <= 0x5A) {
-      output += String.fromCharCode(this.charCodeAt(i) + 0x20)
-    } else {
-      output += this.charAt(i);
-    }
-  }
-  return output;
-}
-
-function indent(ancestors) {
-  var str = "";
-  if (ancestors > 0) {
-    while (ancestors--)
-      str += "  ";
-  }
-  return str;
-}
-
-function dom2string(node, ancestors) {
-  var str = "";
-  if (typeof ancestors == "undefined")
-    var ancestors = 0;
-  if (!node.firstChild)
-    return "| ";
-  var parent = node;
-  var current = node.firstChild;
-  var next = null;
-  var misnested = null;
-  for (;;) {
-    str += "\n| " + indent(ancestors);
-    switch (current.nodeType) {
-      case 10:
-        str += '<!DOCTYPE ' + current.nodeName + '>';
-        break;
-      case 8:
-        try {
-          str += '<!-- ' + current.nodeValue + ' -->';
-        } catch (e) {
-          str += '<!--  -->';
-        }
-        if (parent != current.parentNode) {
-          return str += ' (misnested... aborting)';
-        }
-        break;
-      case 7:
-        str += '<?' + current.nodeName + current.nodeValue + '>';
-        break;
-      case 4:
-        str += '<![CDATA[ ' + current.nodeValue + ' ]]>';
-        break;
-      case 3:
-        str += '"' + current.nodeValue + '"';
-        if (parent != current.parentNode) {
-          return str += ' (misnested... aborting)';
-        }
-        break;
-      case 1:
-        str += "<";
-        switch (current.namespaceURI) {
-          case "http://www.w3.org/2000/svg":
-            str += "svg ";
-            break;
-          case "http://www.w3.org/1998/Math/MathML":
-            str += "math ";
-            break;
-        }
-        if (current.localName && current.namespaceURI && current.namespaceURI != null) {
-          str += current.localName;
-        } else {
-          str += current.nodeName.toAsciiLowerCase();
-        }
-        str += '>';
-        if (parent != current.parentNode) {
-          return str += ' (misnested... aborting)';
-        } else {
-          if (current.attributes) {
-            var attrNames = [];
-            var attrPos = {};
-            for (var j = 0; j < current.attributes.length; j += 1) {
-              if (current.attributes[j].specified) {
-                var name = "";
-                switch (current.attributes[j].namespaceURI) {
-                  case "http://www.w3.org/XML/1998/namespace":
-                    name += "xml ";
-                    break;
-                  case "http://www.w3.org/2000/xmlns/":
-                    name += "xmlns ";
-                    break;
-                  case "http://www.w3.org/1999/xlink":
-                    name += "xlink ";
-                    break;
-                }
-                if (current.attributes[j].localName) {
-                  name += current.attributes[j].localName;
-                } else {
-                  name += current.attributes[j].nodeName;
-                }
-                attrNames.push(name);
-                attrPos[name] = j;
-              }
-            }
-            if (attrNames.length > 0) {
-              attrNames.sort();
-              for (var j = 0; j < attrNames.length; j += 1) {
-                str += "\n| " + indent(1 + ancestors) + attrNames[j];
-                str += '="' + current.attributes[attrPos[attrNames[j]]].nodeValue + '"';
-              }
-            }
-          }
-          if (next = current.firstChild) {
-            parent = current;
-            current = next;
-            ancestors++;
-            continue;
-          }
-        }
-        break;
-    }
-    for (;;) {
-      if (next = current.nextSibling) {
-        current = next;
-        break;
-      }
-      current = current.parentNode;
-      parent = parent.parentNode;
-      ancestors--;
-      if (current == node) {
-        return str.substring(1);
-      }
-    }
-  }
-}
diff --git a/src/pkg/html/testdata/webkit/entities01.dat b/src/pkg/html/testdata/webkit/entities01.dat
index 926642e..c8073b7 100644
--- a/src/pkg/html/testdata/webkit/entities01.dat
+++ b/src/pkg/html/testdata/webkit/entities01.dat
@@ -189,15 +189,6 @@ FOO&#x0000;ZOO
 |     "FOO�ZOO"
 
 #data
-FOO&#x000D;ZOO
-#errors
-#document
-| <html>
-|   <head>
-|   <body>
-|     "FOO
ZOO"
-
-#data
 FOO&#x0078;ZOO
 #errors
 #document
diff --git a/src/pkg/html/testdata/webkit/entities02.dat b/src/pkg/html/testdata/webkit/entities02.dat
index 0b4dd66..e2fb42a 100644
--- a/src/pkg/html/testdata/webkit/entities02.dat
+++ b/src/pkg/html/testdata/webkit/entities02.dat
@@ -127,3 +127,123 @@
 |   <body>
 |     <div>
 |       bar="ZZ>"
+
+#data
+<div bar="ZZ&pound_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&prod_id=23"
+
+#data
+<div bar="ZZ£_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ∏_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ∏_id=23"
+
+#data
+<div bar="ZZ&pound=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&pound=23"
+
+#data
+<div bar="ZZ&prod=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&prod=23"
+
+#data
+<div>ZZ&pound_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ£_id=23"
+
+#data
+<div>ZZ&prod_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ&prod_id=23"
+
+#data
+<div>ZZ£_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ£_id=23"
+
+#data
+<div>ZZ∏_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ∏_id=23"
+
+#data
+<div>ZZ&pound=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ£=23"
+
+#data
+<div>ZZ&prod=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ&prod=23"
diff --git a/src/pkg/html/testdata/webkit/html5test-com.dat b/src/pkg/html/testdata/webkit/html5test-com.dat
new file mode 100644
index 0000000..d7cb71d
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/html5test-com.dat
@@ -0,0 +1,246 @@
+#data
+<div<div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div<div>
+
+#data
+<div foo<bar=''>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo<bar=""
+
+#data
+<div foo=`bar`>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo="`bar`"
+
+#data
+<div \"foo=''>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       \"foo=""
+
+#data
+<a href='\nbar'></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="\nbar"
+
+#data
+<!DOCTYPE html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+⟨⟩
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "⟨⟩"
+
+#data
+'
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "'"
+
+#data
+ⅈ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "ⅈ"
+
+#data
+𝕂
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "𝕂"
+
+#data
+∉
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "∉"
+
+#data
+<?import namespace="foo" implementation="#bar">
+#errors
+#document
+| <!-- ?import namespace="foo" implementation="#bar" -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!--foo--bar-->
+#errors
+#document
+| <!-- foo--bar -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<![CDATA[x]]>
+#errors
+#document
+| <!-- [CDATA[x]] -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<textarea><!--</textarea>--></textarea>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--"
+|     "-->"
+
+#data
+<textarea><!--</textarea>-->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--"
+|     "-->"
+
+#data
+<style><!--</style>--></style>
+#errors
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "-->"
+
+#data
+<style><!--</style>-->
+#errors
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "-->"
+
+#data
+<ul><li>A </li> <li>B</li></ul>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         "A "
+|       " "
+|       <li>
+|         "B"
+
+#data
+<table><form><input type=hidden><input></form><div></div></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|     <div>
+|     <table>
+|       <form>
+|       <input>
+|         type="hidden"
+
+#data
+<i>A<b>B<p></i>C</b>D
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "A"
+|       <b>
+|         "B"
+|     <b>
+|     <p>
+|       <b>
+|         <i>
+|         "C"
+|       "D"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<svg></svg>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<math></math>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
diff --git a/src/pkg/html/testdata/webkit/inbody01.dat b/src/pkg/html/testdata/webkit/inbody01.dat
new file mode 100644
index 0000000..3f2bd37
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/inbody01.dat
@@ -0,0 +1,43 @@
+#data
+<button>1</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <button>
+|       "1"
+
+#data
+<foo>1<p>2</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       "1"
+|       <p>
+|         "2"
+
+#data
+<dd>1</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <dd>
+|       "1"
+
+#data
+<foo>1<dd>2</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       "1"
+|       <dd>
+|         "2"
diff --git a/src/pkg/html/testdata/webkit/isindex.dat b/src/pkg/html/testdata/webkit/isindex.dat
new file mode 100644
index 0000000..88325ff
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/isindex.dat
@@ -0,0 +1,40 @@
+#data
+<isindex>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<isindex name="A" action="B" prompt="C" foo="D">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       action="B"
+|       <hr>
+|       <label>
+|         "C"
+|         <input>
+|           foo="D"
+|           name="isindex"
+|       <hr>
+
+#data
+<form><isindex>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
diff --git a/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat b/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
new file mode 100644
index 0000000..a5ebb1e
Binary files /dev/null and b/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat differ
diff --git a/src/pkg/html/testdata/webkit/pending-spec-changes.dat b/src/pkg/html/testdata/webkit/pending-spec-changes.dat
new file mode 100644
index 0000000..e00ee85
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/pending-spec-changes.dat
@@ -0,0 +1,28 @@
+#data
+<input type="hidden"><frameset>
+#errors
+21: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+31: “frameset” start tag seen.
+31: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><table><caption><svg>foo</table>bar
+#errors
+47: End tag “table” did not match the name of the current open element (“svg”).
+47: “table” closed but “caption” was still open.
+47: End tag “table” seen, but there were open elements.
+36: Unclosed element “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           "foo"
+|     "bar"
diff --git a/src/pkg/html/testdata/webkit/plain-text-unsafe.dat b/src/pkg/html/testdata/webkit/plain-text-unsafe.dat
new file mode 100644
index 0000000..2f40e83
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/plain-text-unsafe.dat
@@ -0,0 +1,8 @@
+#data
+FOO&#x000D;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO
ZOO"
diff --git a/src/pkg/html/testdata/webkit/scripted/adoption01.dat b/src/pkg/html/testdata/webkit/scripted/adoption01.dat
new file mode 100644
index 0000000..4e08d0e
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/scripted/adoption01.dat
@@ -0,0 +1,15 @@
+#data
+<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         id="B"
+|         <script>
+|           "document.getElementById("A").id = "B""
+|     <b>
+|       id="A"
+|       "TEXT"
diff --git a/src/pkg/html/testdata/webkit/scripted/webkit01.dat b/src/pkg/html/testdata/webkit/scripted/webkit01.dat
new file mode 100644
index 0000000..ef4a41c
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/scripted/webkit01.dat
@@ -0,0 +1,28 @@
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "1"
+|     <script>
+|       "document.write("2")"
+|     "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "1"
+|     <script>
+|       "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+|     <script>
+|       "document.write('2')"
+|     "2"
+|     <script>
+|       "document.write('3')"
+|     "34"
diff --git a/src/pkg/html/testdata/webkit/tables01.dat b/src/pkg/html/testdata/webkit/tables01.dat
new file mode 100644
index 0000000..88ef1fe
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tables01.dat
@@ -0,0 +1,197 @@
+#data
+<table><th>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <th>
+
+#data
+<table><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><col foo='bar'>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|         <col>
+|           foo="bar"
+
+#data
+<table><colgroup></html>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "foo"
+|     <table>
+|       <colgroup>
+
+#data
+<table></table><p>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|     <p>
+|       "foo"
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><select><option>3</select></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|         "3"
+|     <table>
+
+#data
+<table><select><table></table></select></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+|     <table>
+
+#data
+<table><select></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+
+#data
+<table><select><option>A<tr><td>B</td></tr></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|         "A"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "B"
+
+#data
+<table><td></body></caption></col></colgroup></html>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "foo"
+
+#data
+<table><td>A</table>B
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "A"
+|     "B"
+
+#data
+<table><tr><caption>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|       <caption>
+
+#data
+<table><tr></body></caption></col></colgroup></html></td></th><td>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "foo"
+
+#data
+<table><td><tr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|         <tr>
+
+#data
+<table><td><button><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <button>
+|           <td>
diff --git a/src/pkg/html/testdata/webkit/tests1.dat b/src/pkg/html/testdata/webkit/tests1.dat
index ad58d31..cbf8bdd 100644
--- a/src/pkg/html/testdata/webkit/tests1.dat
+++ b/src/pkg/html/testdata/webkit/tests1.dat
@@ -259,7 +259,7 @@ Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency
 |       "Z"
 
 #data
-<b><button></b></button></b>
+<b><button>foo</b>bar
 #errors
 Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
 Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
@@ -268,7 +268,23 @@ Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency
 |   <head>
 |   <body>
 |     <b>
+|     <button>
+|       <b>
+|         "foo"
+|       "bar"
+
+#data
+<!DOCTYPE html><span><button>foo</span>bar
+#errors
+39: End tag “span” seen but there were unclosed elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <span>
 |       <button>
+|         "foobar"
 
 #data
 <p><b><div><marquee></p></b></div>X
@@ -818,32 +834,6 @@ Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
 |       "D"
 
 #data
-<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
-#errors
-Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
-Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-|   <head>
-|   <body>
-|     <cite>
-|       <b>
-|         <cite>
-|           <i>
-|             <cite>
-|               <i>
-|                 <cite>
-|                   <i>
-|       <i>
-|         <i>
-|           <i>
-|             <div>
-|               <b>
-|                 "X"
-|               "TEST"
-
-#data
 
 #errors
 Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
@@ -1246,6 +1236,18 @@ Line: 1 Col: 49 Unexpected end tag (code). Ignored.
 |         <strike>
 
 #data
+<!DOCTYPE html><spacer>foo
+#errors
+26: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <spacer>
+|       "foo"
+
+#data
 <title><meta></title><link><title><meta></title>
 #errors
 Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
@@ -1474,7 +1476,8 @@ Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency
 |   <head>
 |   <body>
 |     <b>
-|       <button>
+|     <button>
+|       <b>
 
 #data
 <p><b><div><marquee></p></b></div>
diff --git a/src/pkg/html/testdata/webkit/tests10.dat b/src/pkg/html/testdata/webkit/tests10.dat
index 877c9a3..4f8df86 100644
--- a/src/pkg/html/testdata/webkit/tests10.dat
+++ b/src/pkg/html/testdata/webkit/tests10.dat
@@ -9,6 +9,18 @@
 |     <svg svg>
 
 #data
+<!DOCTYPE html><svg></svg><![CDATA[a]]>
+#errors
+29: Bogus comment
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <!-- [CDATA[a]] -->
+
+#data
 <!DOCTYPE html><body><svg></svg>
 #errors
 #document
@@ -428,3 +440,360 @@
 |         xlink href="foo"
 |         xml lang="en"
 |       "bar"
+
+#data
+<svg></path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<div><svg></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|     "a"
+
+#data
+<div><svg><path></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|     "a"
+
+#data
+<div><svg><path></svg><path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|       <path>
+
+#data
+<div><svg><path><foreignObject><math></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|           <svg foreignObject>
+|             <math math>
+|               "a"
+
+#data
+<div><svg><path><foreignObject><p></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|           <svg foreignObject>
+|             <p>
+|               "a"
+
+#data
+<!DOCTYPE html><svg><desc><div><svg><ul>a
+#errors
+40: HTML start tag “ul” in a foreign namespace context.
+41: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg desc>
+|         <div>
+|           <svg svg>
+|           <ul>
+|             "a"
+
+#data
+<!DOCTYPE html><svg><desc><svg><ul>a
+#errors
+35: HTML start tag “ul” in a foreign namespace context.
+36: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg desc>
+|         <svg svg>
+|         <ul>
+|           "a"
+
+#data
+<!DOCTYPE html><p><svg><desc><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <svg svg>
+|         <svg desc>
+|           <p>
+
+#data
+<!DOCTYPE html><p><svg><title><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <svg svg>
+|         <svg title>
+|           <p>
+
+#data
+<div><svg><path><foreignObject><p></foreignObject><p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|           <svg foreignObject>
+|             <p>
+|             <p>
+
+#data
+<math><mi><div><object><div><span></span></div></object></div></mi><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <div>
+|           <object>
+|             <div>
+|               <span>
+|       <math mi>
+
+#data
+<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <svg svg>
+|           <svg foreignObject>
+|             <div>
+|               <div>
+|       <math mi>
+
+#data
+<svg><script></script><path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg script>
+|       <svg path>
+
+#data
+<table><svg></svg><tr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<math><mi><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <math mglyph>
+
+#data
+<math><mi><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <math malignmark>
+
+#data
+<math><mo><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mo>
+|         <math mglyph>
+
+#data
+<math><mo><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mo>
+|         <math malignmark>
+
+#data
+<math><mn><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mn>
+|         <math mglyph>
+
+#data
+<math><mn><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mn>
+|         <math malignmark>
+
+#data
+<math><ms><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math ms>
+|         <math mglyph>
+
+#data
+<math><ms><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math ms>
+|         <math malignmark>
+
+#data
+<math><mtext><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mtext>
+|         <math mglyph>
+
+#data
+<math><mtext><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mtext>
+|         <math malignmark>
+
+#data
+<math><annotation-xml><svg></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|       <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|           <svg foreignObject>
+|             <div>
+|               <math math>
+|                 <math mi>
+|               <span>
+|           <svg path>
+|       <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|           <svg foreignObject>
+|             <math math>
+|               <math mi>
+|                 <svg svg>
+|               <math mo>
+|             <span>
+|           <svg path>
+|       <math mi>
diff --git a/src/pkg/html/testdata/webkit/tests13.dat b/src/pkg/html/testdata/webkit/tests13.dat
deleted file mode 100644
index d180e8e..0000000
--- a/src/pkg/html/testdata/webkit/tests13.dat
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
-<html><head>
-<title>404 Not Found</title>
-</head><body>
-<h1>Not Found</h1>
-<p>The requested URL /html5lib-tests/data/tests13.dat was not found on this server.</p>
-<p>Additionally, a 404 Not Found
-error was encountered while trying to use an ErrorDocument to handle the request.</p>
-</body></html>
diff --git a/src/pkg/html/testdata/webkit/tests14.dat b/src/pkg/html/testdata/webkit/tests14.dat
index 72f8015..b8713f8 100644
--- a/src/pkg/html/testdata/webkit/tests14.dat
+++ b/src/pkg/html/testdata/webkit/tests14.dat
@@ -71,4 +71,4 @@
 | <html>
 |   <head>
 |   <body>
-|     789="012"
\ No newline at end of file
+|     789="012"
diff --git a/src/pkg/html/testdata/webkit/tests15.dat b/src/pkg/html/testdata/webkit/tests15.dat
index 7f016ca..6ce1c0d 100644
--- a/src/pkg/html/testdata/webkit/tests15.dat
+++ b/src/pkg/html/testdata/webkit/tests15.dat
@@ -205,4 +205,4 @@ XXX: These errors are wrong, please fix me!
 | <html>
 |   <head>
 |   <body>
-|     <object>
\ No newline at end of file
+|     <object>
diff --git a/src/pkg/html/testdata/webkit/tests17.dat b/src/pkg/html/testdata/webkit/tests17.dat
new file mode 100644
index 0000000..7b555f8
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests17.dat
@@ -0,0 +1,153 @@
+#data
+<!doctype html><table><tbody><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><tr><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<!doctype html><table><tr><td><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <select>
+|           <td>
+
+#data
+<!doctype html><table><tr><th><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <th>
+|             <select>
+|           <td>
+
+#data
+<!doctype html><table><caption><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <select>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><th>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><tbody>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><thead>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><caption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><table><tr></table>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|     "a"
diff --git a/src/pkg/html/testdata/webkit/tests18.dat b/src/pkg/html/testdata/webkit/tests18.dat
new file mode 100644
index 0000000..680e1f0
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests18.dat
@@ -0,0 +1,269 @@
+#data
+<!doctype html><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+
+#data
+<!doctype html><table><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+
+#data
+<!doctype html><table><tbody><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+|       <tbody>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><td><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <plaintext>
+|               "</plaintext>"
+
+#data
+<!doctype html><table><caption><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <plaintext>
+|           "</plaintext>"
+
+#data
+<!doctype html><table><tr><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "abc"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <style>
+|             "</script>"
+
+#data
+<!doctype html><table><tr><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "abc"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <script>
+|             "</style>"
+
+#data
+<!doctype html><table><caption><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <style>
+|           "</script>"
+|         "abc"
+
+#data
+<!doctype html><table><td><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <style>
+|               "</script>"
+|             "abc"
+
+#data
+<!doctype html><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <script>
+|         "</style>"
+|       "abc"
+
+#data
+<!doctype html><table><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <script>
+|         "</style>"
+|       "abc"
+|     <table>
+
+#data
+<!doctype html><table><tr><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <script>
+|         "</style>"
+|       "abc"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><frameset></frameset><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+
+#data
+<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+|   <!-- abc -->
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><table><tr></tbody><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|       <tfoot>
+
+#data
+<!doctype html><table><td><svg></svg>abc<td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|             "abc"
+|           <td>
diff --git a/src/pkg/html/testdata/webkit/tests19.dat b/src/pkg/html/testdata/webkit/tests19.dat
new file mode 100644
index 0000000..06222f5
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests19.dat
@@ -0,0 +1,1220 @@
+#data
+<!doctype html><math><mn DefinitionUrl="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mn>
+|         definitionURL="foo"
+
+#data
+<!doctype html><html></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <!-- foo -->
+|   <head>
+|   <body>
+
+#data
+<!doctype html><head></head></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <!-- foo -->
+|   <body>
+
+#data
+<!doctype html><body><p><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <pre>
+
+#data
+<!doctype html><body><p><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <listing>
+
+#data
+<!doctype html><p><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <plaintext>
+
+#data
+<!doctype html><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <h1>
+
+#data
+<!doctype html><form><isindex>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+
+#data
+<!doctype html><isindex action="POST">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       action="POST"
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<!doctype html><isindex prompt="this is isindex">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "this is isindex"
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<!doctype html><isindex type="hidden">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|           type="hidden"
+|       <hr>
+
+#data
+<!doctype html><isindex name="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<!doctype html><ruby><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <p>
+|       <rp>
+
+#data
+<!doctype html><ruby><div><span><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <span>
+|       <rp>
+
+#data
+<!doctype html><ruby><div><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <p>
+|       <rp>
+
+#data
+<!doctype html><ruby><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <p>
+|       <rt>
+
+#data
+<!doctype html><ruby><div><span><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <span>
+|       <rt>
+
+#data
+<!doctype html><ruby><div><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <p>
+|       <rt>
+
+#data
+<!doctype html><math/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|     <foo>
+
+#data
+<!doctype html><svg/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <foo>
+
+#data
+<!doctype html><div></body><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|   <!-- foo -->
+
+#data
+<!doctype html><h1><div><h3><span></h1>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|       <div>
+|         <h3>
+|           <span>
+|         "foo"
+
+#data
+<!doctype html><p></h3>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "foo"
+
+#data
+<!doctype html><h3><li>abc</h2>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <h3>
+|       <li>
+|         "abc"
+|     "foo"
+
+#data
+<!doctype html><table>abc<!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "abc"
+|     <table>
+|       <!-- foo -->
+
+#data
+<!doctype html><table>  <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "  "
+|       <!-- foo -->
+
+#data
+<!doctype html><table> b <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " b "
+|     <table>
+|       <!-- foo -->
+
+#data
+<!doctype html><select><option><option>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|       <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!doctype html><p><math><mi><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mi>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><mo><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mo>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><mn><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mn>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><ms><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math ms>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><mtext><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mtext>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><frameset></noframes>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html c=d><body></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   a="b"
+|   c="d"
+|   <head>
+|   <body>
+
+#data
+<!doctype html><html c=d><frameset></frameset></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   a="b"
+|   c="d"
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+| <!-- foo -->
+
+#data
+<!doctype html><html><frameset></frameset></html>  
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   "  "
+
+#data
+<!doctype html><html><frameset></frameset></html>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<html><frameset></frameset></html><!doctype html>
+#errors
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!doctype html><p><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><p>a<frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "a"
+
+#data
+<!doctype html><p> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><pre><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+
+#data
+<!doctype html><listing><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <listing>
+
+#data
+<!doctype html><li><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <li>
+
+#data
+<!doctype html><dd><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <dd>
+
+#data
+<!doctype html><dt><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <dt>
+
+#data
+<!doctype html><button><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <button>
+
+#data
+<!doctype html><applet><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <applet>
+
+#data
+<!doctype html><marquee><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <marquee>
+
+#data
+<!doctype html><object><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <object>
+
+#data
+<!doctype html><table><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+
+#data
+<!doctype html><area><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <area>
+
+#data
+<!doctype html><basefont><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <basefont>
+|   <frameset>
+
+#data
+<!doctype html><bgsound><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <bgsound>
+|   <frameset>
+
+#data
+<!doctype html><br><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <br>
+
+#data
+<!doctype html><embed><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <embed>
+
+#data
+<!doctype html><img><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <img>
+
+#data
+<!doctype html><input><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+
+#data
+<!doctype html><keygen><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <keygen>
+
+#data
+<!doctype html><wbr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <wbr>
+
+#data
+<!doctype html><hr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <hr>
+
+#data
+<!doctype html><textarea></textarea><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+
+#data
+<!doctype html><xmp></xmp><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+
+#data
+<!doctype html><iframe></iframe><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+
+#data
+<!doctype html><select></select><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><svg></svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><math></math><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><svg><foreignObject><div> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><svg>a</svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "a"
+
+#data
+<!doctype html><svg> </svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<html>aaa<frameset></frameset>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "aaa"
+
+#data
+<html> a <frameset></frameset>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "a "
+
+#data
+<!doctype html><div><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><div><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<!doctype html><p><math></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|     "a"
+
+#data
+<!doctype html><p><math><mn><span></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mn>
+|           <span>
+|             <p>
+|             "a"
+
+#data
+<!doctype html><math></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+
+#data
+<!doctype html><meta charset="ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <meta>
+|       charset="ascii"
+|   <body>
+
+#data
+<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <meta>
+|       content="text/html;charset=ascii"
+|       http-equiv="content-type"
+|   <body>
+
+#data
+<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -->
+|     <meta>
+|       charset="utf8"
+|   <body>
+
+#data
+<!doctype html><html a=b><head></head><html c=d>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   a="b"
+|   c="d"
+|   <head>
+|   <body>
+
+#data
+<!doctype html><image/>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <img>
+
+#data
+<!doctype html>a<i>b<table>c<b>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "a"
+|     <i>
+|       "bc"
+|       <b>
+|         "de"
+|       "f"
+|       <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|     <div>
+|       <b>
+|         <i>
+|           "c"
+|           <a>
+|             "d"
+|         <a>
+|           "e"
+|       <a>
+|         "f"
+|     <table>
+
+#data
+<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|     <div>
+|       <b>
+|         <i>
+|           "c"
+|           <a>
+|             "d"
+|         <a>
+|           "e"
+|       <a>
+|         "f"
+
+#data
+<!doctype html><table><i>a<b>b<div>c</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|       <div>
+|         <i>
+|           "c"
+|     <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|     <div>
+|       <b>
+|         <i>
+|           "c"
+|           <a>
+|             "d"
+|         <a>
+|           "e"
+|       <a>
+|         "f"
+|     <table>
+
+#data
+<!doctype html><table><i>a<div>b<tr>c<b>d</i>e
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <div>
+|         "b"
+|     <i>
+|       "c"
+|       <b>
+|         "d"
+|     <b>
+|       "e"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><td><table><i>a<div>b<b>c</i>d
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <i>
+|               "a"
+|             <div>
+|               <i>
+|                 "b"
+|                 <b>
+|                   "c"
+|               <b>
+|                 "d"
+|             <table>
+
+#data
+<!doctype html><body><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <bgsound>
+
+#data
+<!doctype html><body><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <basefont>
+
+#data
+<!doctype html><a><b></a><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <basefont>
+
+#data
+<!doctype html><a><b></a><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <bgsound>
+
+#data
+<!doctype html><figcaption><article></figcaption>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <figcaption>
+|       <article>
+|     "a"
+
+#data
+<!doctype html><summary><article></summary>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <summary>
+|       <article>
+|     "a"
+
+#data
+<!doctype html><p><a><plaintext>b
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <a>
+|     <plaintext>
+|       <a>
+|         "b"
diff --git a/src/pkg/html/testdata/webkit/tests2.dat b/src/pkg/html/testdata/webkit/tests2.dat
index d33996e..60d8592 100644
--- a/src/pkg/html/testdata/webkit/tests2.dat
+++ b/src/pkg/html/testdata/webkit/tests2.dat
@@ -461,6 +461,19 @@ Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
 |       <optgroup>
 
 #data
+<!DOCTYPE html><datalist><option>foo</datalist>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <datalist>
+|       <option>
+|         "foo"
+|     "bar"
+
+#data
 <!DOCTYPE html><font><input><input></font>
 #errors
 #document
@@ -515,7 +528,7 @@ Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
 |     <form>
 |       <hr>
 |       <label>
-|         "This is a searchable index. Insert your search keywords here: "
+|         "This is a searchable index. Enter search keywords: "
 |         <input>
 |           name="isindex"
 |           test="x"
@@ -736,3 +749,15 @@ Line: 1 Col: 35 Unexpected character in comment found.
 |     ">"
 |     <!-- <!--x -->
 |     "-->"
+
+#data
+<!doctype html><div><form></form><div></div></div>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <form>
+|       <div>
diff --git a/src/pkg/html/testdata/webkit/tests20.dat b/src/pkg/html/testdata/webkit/tests20.dat
new file mode 100644
index 0000000..6bd8256
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests20.dat
@@ -0,0 +1,455 @@
+#data
+<!doctype html><p><button><button>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|       <button>
+
+#data
+<!doctype html><p><button><address>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <address>
+
+#data
+<!doctype html><p><button><blockquote>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <blockquote>
+
+#data
+<!doctype html><p><button><menu>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <menu>
+
+#data
+<!doctype html><p><button><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <p>
+
+#data
+<!doctype html><p><button><ul>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <ul>
+
+#data
+<!doctype html><p><button><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <h1>
+
+#data
+<!doctype html><p><button><h6>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <h6>
+
+#data
+<!doctype html><p><button><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <listing>
+
+#data
+<!doctype html><p><button><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <pre>
+
+#data
+<!doctype html><p><button><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <form>
+
+#data
+<!doctype html><p><button><li>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <li>
+
+#data
+<!doctype html><p><button><dd>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <dd>
+
+#data
+<!doctype html><p><button><dt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <dt>
+
+#data
+<!doctype html><p><button><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <plaintext>
+
+#data
+<!doctype html><p><button><table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <table>
+
+#data
+<!doctype html><p><button><hr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <hr>
+
+#data
+<!doctype html><p><button><xmp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <xmp>
+
+#data
+<!doctype html><p><button></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <p>
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <address>
+|       <button>
+|     "a"
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <address>
+|       <button>
+|     "a"
+
+#data
+<p><table></p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <p>
+|       <table>
+
+#data
+<!doctype html><svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<!doctype html><p><figcaption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <figcaption>
+
+#data
+<!doctype html><p><summary>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <summary>
+
+#data
+<!doctype html><form><table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <table>
+
+#data
+<!doctype html><table><form><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <form>
+
+#data
+<!doctype html><table><form></table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <form>
+
+#data
+<!doctype html><svg><foreignObject><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg foreignObject>
+|         <p>
+
+#data
+<!doctype html><svg><title>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         "abc"
+
+#data
+<option><span><option>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <option>
+|       <span>
+|         <option>
+
+#data
+<option><option>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <option>
+|     <option>
+
+#data
+<math><annotation-xml><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|     <div>
+
+#data
+<math><annotation-xml encoding="application/svg+xml"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="application/svg+xml"
+|     <div>
+
+#data
+<math><annotation-xml encoding="application/xhtml+xml"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="application/xhtml+xml"
+|         <div>
+
+#data
+<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="aPPlication/xhtmL+xMl"
+|         <div>
+
+#data
+<math><annotation-xml encoding="text/html"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="text/html"
+|         <div>
+
+#data
+<math><annotation-xml encoding="Text/htmL"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="Text/htmL"
+|         <div>
+
+#data
+<math><annotation-xml encoding=" text/html "><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding=" text/html "
+|     <div>
diff --git a/src/pkg/html/testdata/webkit/tests21.dat b/src/pkg/html/testdata/webkit/tests21.dat
new file mode 100644
index 0000000..1260ec0
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests21.dat
@@ -0,0 +1,221 @@
+#data
+<svg><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "foo"
+
+#data
+<math><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       "foo"
+
+#data
+<div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "foo"
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "foo"
+
+#data
+<svg><![CDATA[
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<svg><![CDATA[]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]] >"
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]] >"
+
+#data
+<svg><![CDATA[]]
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]]"
+
+#data
+<svg><![CDATA[]
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]"
+
+#data
+<svg><![CDATA[]>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]>a"
+
+#data
+<svg><foreignObject><div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg foreignObject>
+|         <div>
+|           <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[<svg>]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+
+#data
+<svg><![CDATA[</svg>a]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "</svg>a"
+
+#data
+<svg><![CDATA[<svg>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>a"
+
+#data
+<svg><![CDATA[</svg>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "</svg>a"
+
+#data
+<svg><![CDATA[<svg>]]><path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+|       <svg path>
+
+#data
+<svg><![CDATA[<svg>]]></path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+
+#data
+<svg><![CDATA[<svg>]]><!--path-->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+|       <!-- path -->
+
+#data
+<svg><![CDATA[<svg>]]>path
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>path"
+
+#data
+<svg><![CDATA[<!--svg-->]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<!--svg-->"
diff --git a/src/pkg/html/testdata/webkit/tests22.dat b/src/pkg/html/testdata/webkit/tests22.dat
new file mode 100644
index 0000000..aab27b2
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests22.dat
@@ -0,0 +1,157 @@
+#data
+<a><b><big><em><strong><div>X</a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|         <big>
+|           <em>
+|             <strong>
+|     <big>
+|       <em>
+|         <strong>
+|           <div>
+|             <a>
+|               "X"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <b>
+|       <div>
+|         id="1"
+|         <a>
+|         <div>
+|           id="2"
+|           <a>
+|           <div>
+|             id="3"
+|             <a>
+|             <div>
+|               id="4"
+|               <a>
+|               <div>
+|                 id="5"
+|                 <a>
+|                 <div>
+|                   id="6"
+|                   <a>
+|                   <div>
+|                     id="7"
+|                     <a>
+|                     <div>
+|                       id="8"
+|                       <a>
+|                         "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <b>
+|       <div>
+|         id="1"
+|         <a>
+|         <div>
+|           id="2"
+|           <a>
+|           <div>
+|             id="3"
+|             <a>
+|             <div>
+|               id="4"
+|               <a>
+|               <div>
+|                 id="5"
+|                 <a>
+|                 <div>
+|                   id="6"
+|                   <a>
+|                   <div>
+|                     id="7"
+|                     <a>
+|                     <div>
+|                       id="8"
+|                       <a>
+|                         <div>
+|                           id="9"
+|                           "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <b>
+|       <div>
+|         id="1"
+|         <a>
+|         <div>
+|           id="2"
+|           <a>
+|           <div>
+|             id="3"
+|             <a>
+|             <div>
+|               id="4"
+|               <a>
+|               <div>
+|                 id="5"
+|                 <a>
+|                 <div>
+|                   id="6"
+|                   <a>
+|                   <div>
+|                     id="7"
+|                     <a>
+|                     <div>
+|                       id="8"
+|                       <a>
+|                         <div>
+|                           id="9"
+|                           <div>
+|                             id="10"
+|                             "A"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
+Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <cite>
+|       <b>
+|         <cite>
+|           <i>
+|             <cite>
+|               <i>
+|                 <cite>
+|                   <i>
+|       <i>
+|         <i>
+|           <div>
+|             <b>
+|               "X"
+|             "TEST"
diff --git a/src/pkg/html/testdata/webkit/tests23.dat b/src/pkg/html/testdata/webkit/tests23.dat
new file mode 100644
index 0000000..34d2a73
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests23.dat
@@ -0,0 +1,155 @@
+#data
+<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X
+#errors
+3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+116: Unclosed elements.
+117: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           color="red"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|               <font>
+|                 size="4"
+|                 <font>
+|                   size="4"
+|                   <font>
+|                     size="4"
+|                     <font>
+|                       color="red"
+|     <p>
+|       <font>
+|         color="red"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|               <font>
+|                 color="red"
+|                 "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="5"
+|               <font>
+|                 size="4"
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="5"
+|             <font>
+|               size="4"
+|               "X"
+
+#data
+<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         id="a"
+|         size="4"
+|         <font>
+|           id="b"
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|     <p>
+|       <font>
+|         id="a"
+|         size="4"
+|         <font>
+|           id="b"
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|               "X"
+
+#data
+<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         id="a"
+|         <b>
+|           id="a"
+|           <b>
+|             id="a"
+|             <b>
+|               <object>
+|                 <b>
+|                   id="a"
+|                   <b>
+|                     id="a"
+|                     "X"
+|     <p>
+|       <b>
+|         id="a"
+|         <b>
+|           id="a"
+|           <b>
+|             id="a"
+|             <b>
+|               "Y"
diff --git a/src/pkg/html/testdata/webkit/tests24.dat b/src/pkg/html/testdata/webkit/tests24.dat
new file mode 100644
index 0000000..f6dc7eb
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests24.dat
@@ -0,0 +1,79 @@
+#data
+<!DOCTYPE html>≂̸
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "≂̸"
+
+#data
+<!DOCTYPE html>≂̸A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "≂̸A"
+
+#data
+<!DOCTYPE html>  
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "  "
+
+#data
+<!DOCTYPE html>  A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "  A"
+
+#data
+<!DOCTYPE html>⊂⃒
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "⊂⃒"
+
+#data
+<!DOCTYPE html>⊂⃒A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "⊂⃒A"
+
+#data
+<!DOCTYPE html>𝔾
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "𝔾"
+
+#data
+<!DOCTYPE html>𝔾A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "𝔾A"
diff --git a/src/pkg/html/testdata/webkit/tests25.dat b/src/pkg/html/testdata/webkit/tests25.dat
new file mode 100644
index 0000000..00de729
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests25.dat
@@ -0,0 +1,219 @@
+#data
+<!DOCTYPE html><body><foo>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       "A"
+
+#data
+<!DOCTYPE html><body><area>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <area>
+|     "A"
+
+#data
+<!DOCTYPE html><body><base>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <base>
+|     "A"
+
+#data
+<!DOCTYPE html><body><basefont>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <basefont>
+|     "A"
+
+#data
+<!DOCTYPE html><body><bgsound>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <bgsound>
+|     "A"
+
+#data
+<!DOCTYPE html><body><br>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <br>
+|     "A"
+
+#data
+<!DOCTYPE html><body><col>A
+#errors
+26: Stray start tag “col”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "A"
+
+#data
+<!DOCTYPE html><body><command>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <command>
+|     "A"
+
+#data
+<!DOCTYPE html><body><embed>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <embed>
+|     "A"
+
+#data
+<!DOCTYPE html><body><frame>A
+#errors
+26: Stray start tag “frame”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "A"
+
+#data
+<!DOCTYPE html><body><hr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <hr>
+|     "A"
+
+#data
+<!DOCTYPE html><body><img>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <img>
+|     "A"
+
+#data
+<!DOCTYPE html><body><input>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|     "A"
+
+#data
+<!DOCTYPE html><body><keygen>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <keygen>
+|     "A"
+
+#data
+<!DOCTYPE html><body><link>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <link>
+|     "A"
+
+#data
+<!DOCTYPE html><body><meta>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+|     "A"
+
+#data
+<!DOCTYPE html><body><param>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <param>
+|     "A"
+
+#data
+<!DOCTYPE html><body><source>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <source>
+|     "A"
+
+#data
+<!DOCTYPE html><body><track>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <track>
+|     "A"
+
+#data
+<!DOCTYPE html><body><wbr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <wbr>
+|     "A"
diff --git a/src/pkg/html/testdata/webkit/tests26.dat b/src/pkg/html/testdata/webkit/tests26.dat
new file mode 100644
index 0000000..da128e7
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests26.dat
@@ -0,0 +1,195 @@
+#data
+<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="#1"
+|       <nobr>
+|         "1"
+|       <nobr>
+|     <nobr>
+|       <br>
+|       <a>
+|         href="#2"
+|     <a>
+|       href="#2"
+|       <nobr>
+|         "2"
+|       <nobr>
+|     <nobr>
+|       <br>
+|       <a>
+|         href="#3"
+|     <a>
+|       href="#3"
+|       <nobr>
+|         "3"
+|       <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|       <nobr>
+|     <nobr>
+|       <i>
+|     <i>
+|       <nobr>
+|         "2"
+|       <nobr>
+|     <nobr>
+|       "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|         <nobr>
+|           <i>
+|         <i>
+|           <nobr>
+|             "2"
+|           <nobr>
+|         <nobr>
+|           "3"
+|         <table>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|         <table>
+|           <tbody>
+|             <tr>
+|               <td>
+|                 <nobr>
+|                   <i>
+|                 <i>
+|                   <nobr>
+|                     "2"
+|                   <nobr>
+|                 <nobr>
+|                   "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|     <div>
+|       <b>
+|         <nobr>
+|         <nobr>
+|       <nobr>
+|         <i>
+|       <i>
+|         <nobr>
+|           "2"
+|         <nobr>
+|       <nobr>
+|         "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|       <nobr>
+|     <div>
+|       <nobr>
+|         <i>
+|       <i>
+|         <nobr>
+|           "2"
+|         <nobr>
+|       <nobr>
+|         "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|       <nobr>
+|         <ins>
+|     <nobr>
+|       <i>
+|     <i>
+|       <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|         <ins>
+|       <nobr>
+|     <nobr>
+|       <i>
+|         "2"
+
+#data
+<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "1"
+|       <nobr>
+|     <nobr>
+|       <i>
+|     <i>
+|       <nobr>
+|         "2"
diff --git a/src/pkg/html/testdata/webkit/tests3.dat b/src/pkg/html/testdata/webkit/tests3.dat
index b0781a8..38dc501 100644
--- a/src/pkg/html/testdata/webkit/tests3.dat
+++ b/src/pkg/html/testdata/webkit/tests3.dat
@@ -144,6 +144,18 @@ Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
 y"
 
 #data
+<!DOCTYPE html><pre>&#x0a;&#x0a;A</pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "
+A"
+
+#data
 <!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
 #errors
 Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
diff --git a/src/pkg/html/testdata/webkit/tests6.dat b/src/pkg/html/testdata/webkit/tests6.dat
index 2fb7996..f28ece4 100644
--- a/src/pkg/html/testdata/webkit/tests6.dat
+++ b/src/pkg/html/testdata/webkit/tests6.dat
@@ -631,6 +631,16 @@ Line: 1 Col: 17 Unexpected start tag (frameset).
 |   <frameset>
 
 #data
+<track><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (track). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
 </html><frameset></frameset>
 #errors
 7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
diff --git a/src/pkg/html/testdata/webkit/tests9.dat b/src/pkg/html/testdata/webkit/tests9.dat
index 2b715f8..554e27a 100644
--- a/src/pkg/html/testdata/webkit/tests9.dat
+++ b/src/pkg/html/testdata/webkit/tests9.dat
@@ -19,6 +19,33 @@
 |     <math math>
 
 #data
+<!DOCTYPE html><math><mi>
+#errors
+25: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+
+#data
+<!DOCTYPE html><math><annotation-xml><svg><u>
+#errors
+45: HTML start tag “u” in a foreign namespace context.
+45: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|     <u>
+
+#data
 <!DOCTYPE html><body><select><math></math></select>
 #errors
 Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
diff --git a/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat b/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat
new file mode 100644
index 0000000..052fac7
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat
@@ -0,0 +1,733 @@
+#data
+<body><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<body><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+|   <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <frameset>
+
+#data
+<table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+|   <tr>
+
+#data
+</table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+|   <tr>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a><caption>a
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <caption>
+|   "a"
+
+#data
+<a><colgroup><col>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <colgroup>
+|   <col>
+
+#data
+<a><tbody><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+
+#data
+<a><tfoot><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tfoot>
+|   <tr>
+
+#data
+<a><thead><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <thead>
+|   <tr>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+
+#data
+<a><th>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+|     <th>
+
+#data
+<a><td>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+|     <td>
+
+#data
+<table></table><tbody>
+#errors
+#document-fragment
+caption
+#document
+| <table>
+
+#data
+</table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></table>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+</caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><col><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><colgroup><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><html><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><tbody><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><td><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><tfoot><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><thead><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><th><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><tr><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span></table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+</colgroup><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<a><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+|   <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+|   <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+|   <td>
+
+#data
+<td><table><tbody><a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <tr>
+|   <td>
+|     <a>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+</tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table><a><tr></tr><tr>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+|   <a>
+|   <table>
+|     <tbody>
+|       <tr>
+|       <tr>
+
+#data
+<caption><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<col><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<colgroup><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tbody><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tfoot><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<thead><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+|   <table>
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+|   <table>
+| <td>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</td><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<table><td><td>
+#errors
+#document-fragment
+td
+#document
+| <table>
+|   <tbody>
+|     <tr>
+|       <td>
+|       <td>
+
+#data
+</select><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<input><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<keygen><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<textarea><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+</html><!--abc-->
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <!-- abc -->
+
+#data
+</frameset><frame>
+#errors
+#document-fragment
+frameset
+#document
+| <frame>
diff --git a/src/pkg/html/testdata/webkit/tricky01.dat b/src/pkg/html/testdata/webkit/tricky01.dat
new file mode 100644
index 0000000..0841992
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/tricky01.dat
@@ -0,0 +1,261 @@
+#data
+<b><p>Bold </b> Not bold</p>
+Also not bold.
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <p>
+|       <b>
+|         "Bold "
+|       " Not bold"
+|     "
+Also not bold."
+
+#data
+<html>
+<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain
+<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>
+<p>Italic and red. </i> Red.</font> I should not be red.</p>
+<b>Bold <i>Bold and italic</b> Only Italic </i> Plain
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       color="red"
+|       <i>
+|         "Italic and Red"
+|     <i>
+|       <p>
+|         <font>
+|           color="red"
+|           "Italic and Red "
+|         " Just italic."
+|       " Italic only."
+|     " Plain
+"
+|     <p>
+|       "I should not be red. "
+|       <font>
+|         color="red"
+|         "Red. "
+|         <i>
+|           "Italic and red."
+|     <font>
+|       color="red"
+|       <i>
+|         "
+"
+|     <p>
+|       <font>
+|         color="red"
+|         <i>
+|           "Italic and red. "
+|         " Red."
+|       " I should not be red."
+|     "
+"
+|     <b>
+|       "Bold "
+|       <i>
+|         "Bold and italic"
+|     <i>
+|       " Only Italic "
+|     " Plain"
+
+#data
+<html><body>
+<p><font size="7">First paragraph.</p>
+<p>Second paragraph.</p></font>
+<b><p><i>Bold and Italic</b> Italic</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "
+"
+|     <p>
+|       <font>
+|         size="7"
+|         "First paragraph."
+|     <font>
+|       size="7"
+|       "
+"
+|       <p>
+|         "Second paragraph."
+|     "
+"
+|     <b>
+|     <p>
+|       <b>
+|         <i>
+|           "Bold and Italic"
+|       <i>
+|         " Italic"
+
+#data
+<html>
+<dl>
+<dt><b>Boo
+<dd>Goo?
+</dl>
+</html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <dl>
+|       "
+"
+|       <dt>
+|         <b>
+|           "Boo
+"
+|       <dd>
+|         <b>
+|           "Goo?
+"
+|     <b>
+|       "
+"
+
+#data
+<html><body>
+<label><a><div>Hello<div>World</div></a></label>  
+</body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "
+"
+|     <label>
+|       <a>
+|       <div>
+|         <a>
+|           "Hello"
+|           <div>
+|             "World"
+|         "  
+"
+
+#data
+<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <center>
+|       " "
+|       <font>
+|         "a"
+|     <font>
+|       <img>
+|       " "
+|     <table>
+|       " "
+|       <tbody>
+|         <tr>
+|           <td>
+|             " "
+|           " "
+|         " "
+
+#data
+<table><tr><p><a><p>You should see this text.
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <a>
+|     <p>
+|       <a>
+|         "You should see this text."
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<TABLE>
+<TR>
+<CENTER><CENTER><TD></TD></TR><TR>
+<FONT>
+<TABLE><tr></tr></TABLE>
+</P>
+<a></font><font></a>
+This page contains an insanely badly-nested tag sequence.
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <center>
+|       <center>
+|     <font>
+|       "
+"
+|     <table>
+|       "
+"
+|       <tbody>
+|         <tr>
+|           "
+"
+|           <td>
+|         <tr>
+|           "
+"
+|     <table>
+|       <tbody>
+|         <tr>
+|     <font>
+|       "
+"
+|       <p>
+|       "
+"
+|       <a>
+|     <a>
+|       <font>
+|     <font>
+|       "
+This page contains an insanely badly-nested tag sequence."
+
+#data
+<html>
+<body>
+<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>
+</body>
+</html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "
+"
+|     <b>
+|       <nobr>
+|     <div>
+|       <b>
+|         <nobr>
+|           "This text is in a div inside a nobr"
+|         "More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. "
+|       <pre>
+|         "A pre tag outside everything else."
+|       "
+
+"
diff --git a/src/pkg/html/testdata/webkit/webkit01.dat b/src/pkg/html/testdata/webkit/webkit01.dat
index 544da9e..4101b21 100644
--- a/src/pkg/html/testdata/webkit/webkit01.dat
+++ b/src/pkg/html/testdata/webkit/webkit01.dat
@@ -129,35 +129,6 @@ console.log("FOO<span>BAR</span>BAZ");
 |     <potato>
 
 #data
-1<script>document.write("2")</script>3
-#errors
-#document
-| <html>
-|   <head>
-|   <body>
-|     "1"
-|     <script>
-|       "document.write("2")"
-|     "23"
-
-#data
-1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
-#errors
-#document
-| <html>
-|   <head>
-|   <body>
-|     "1"
-|     <script>
-|       "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
-|     <script>
-|       "document.write('2')"
-|     "2"
-|     <script>
-|       "document.write('3')"
-|     "34"
-
-#data
 </ tttt>
 #errors
 #document
@@ -186,8 +157,7 @@ console.log("FOO<span>BAR</span>BAZ");
 |   <head>
 |   <body>
 |     <p>
-|       "Test"
-|       "Test2"
+|       "TestTest2"
 
 #data
 <rdar://problem/6869687>
@@ -209,3 +179,431 @@ console.log("FOO<span>BAR</span>BAZ");
 |   <body>
 |     <a>
 |       "test< /A>"
+
+#data
+<
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "<"
+
+#data
+<body foo='bar'><body foo='baz' yo='mama'>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     foo="bar"
+|     yo="mama"
+
+#data
+<body></br foo="bar"></body>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+
+#data
+<bdy><br foo="bar"></body>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <bdy>
+|       <br>
+|         foo="bar"
+
+#data
+<body></body></br foo="bar">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+
+#data
+<bdy></body><br foo="bar">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <bdy>
+|       <br>
+|         foo="bar"
+
+#data
+<html><body></body></html><!-- Hi there -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+| <!--  Hi there  -->
+
+#data
+<html><body></body></html>x<!-- Hi there -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <!--  Hi there  -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></html><!-- Again -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <!--  Hi there  -->
+| <!--  Again  -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <!--  Hi there  -->
+| <!--  Again  -->
+
+#data
+<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|       <rp>
+|         "xx"
+
+#data
+<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|       <rt>
+|         "xx"
+
+#data
+<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->
+#errors
+#document
+| <html>
+|   <head>
+|   <frameset>
+|     <!-- 1 -->
+|     <noframes>
+|       "A"
+|     <!-- 2 -->
+|   <!-- 3 -->
+|   <noframes>
+|     "B"
+|   <!-- 4 -->
+|   <noframes>
+|     "C"
+| <!-- 5 -->
+| <!-- 6 -->
+
+#data
+<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|         "A"
+|     <option>
+|       "B"
+|       <select>
+|         <option>
+|           "C"
+|     <option>
+|       "D"
+|       <select>
+|         <option>
+|           "E"
+|     <option>
+|       "F"
+|       <select>
+|         <option>
+|           "G"
+
+#data
+<dd><dd><dt><dt><dd><li><li>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <dd>
+|     <dd>
+|     <dt>
+|     <dt>
+|     <dd>
+|       <li>
+|       <li>
+
+#data
+<div><b></div><div><nobr>a<nobr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <b>
+|     <div>
+|       <b>
+|         <nobr>
+|           "a"
+|         <nobr>
+
+#data
+<head></head>
+<body></body>
+#errors
+#document
+| <html>
+|   <head>
+|   "
+"
+|   <body>
+
+#data
+<head></head> <style></style>ddd
+#errors
+#document
+| <html>
+|   <head>
+|     <style>
+|   " "
+|   <body>
+|     "ddd"
+
+#data
+<kbd><table></kbd><col><select><tr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <kbd>
+|       <select>
+|       <table>
+|         <colgroup>
+|           <col>
+|         <tbody>
+|           <tr>
+
+#data
+<kbd><table></kbd><col><select><tr></table><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <kbd>
+|       <select>
+|       <table>
+|         <colgroup>
+|           <col>
+|         <tbody>
+|           <tr>
+|       <div>
+
+#data
+<a><li><style></style><title></title></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <li>
+|       <a>
+|         <style>
+|         <title>
+
+#data
+<font></p><p><meta><title></title></font>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <p>
+|     <p>
+|       <font>
+|         <meta>
+|         <title>
+
+#data
+<a><center><title></title><a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <center>
+|       <a>
+|         <title>
+|       <a>
+
+#data
+<svg><title><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         <div>
+
+#data
+<svg><title><rect><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         <rect>
+|           <div>
+
+#data
+<svg><title><svg><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         <svg svg>
+|         <div>
+
+#data
+<img <="" FAIL>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <img>
+|       <=""
+|       fail=""
+
+#data
+<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         <div>
+|           id="foo"
+|           "A"
+|       <li>
+|         "B"
+|         <div>
+|           "C"
+
+#data
+<svg><em><desc></em>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <em>
+|       <desc>
+
+#data
+<table><tr><td><svg><desc><td></desc><circle>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg desc>
+|               <svg circle>
+
+#data
+<svg><tfoot></mi><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg tfoot>
+|         <svg td>
+
+#data
+<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mrow>
+|         <math mrow>
+|           <math mn>
+|             "1"
+|         <math mi>
+|           "a"
+
+#data
+<!doctype html><input type="hidden"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><input type="button"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|       type="button"
diff --git a/src/pkg/html/testdata/webkit/webkit02.dat b/src/pkg/html/testdata/webkit/webkit02.dat
new file mode 100644
index 0000000..2218f42
--- /dev/null
+++ b/src/pkg/html/testdata/webkit/webkit02.dat
@@ -0,0 +1,104 @@
+#data
+<foo bar=qux/>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       bar="qux/"
+
+#data
+<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       id="status"
+|       <noscript>
+|         "<strong>A</strong>"
+|       <span>
+|         "B"
+
+#data
+<div><sarcasm><div></div></sarcasm></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <sarcasm>
+|         <div>
+
+#data
+<html><body><img src="" border="0" alt="><div>A</div></body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<table><td></tbody>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "A"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><td></thead>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "A"
+
+#data
+<table><td></tfoot>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "A"
+
+#data
+<table><thead><td></tbody>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <thead>
+|         <tr>
+|           <td>
+|             "A"
+
+#data
+<legend>test</legend>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <legend>
+|       "test"
diff --git a/src/pkg/html/token.go b/src/pkg/html/token.go
index 23c95ec..5c6ed16 100644
--- a/src/pkg/html/token.go
+++ b/src/pkg/html/token.go
@@ -459,7 +459,7 @@ loop:
 			src++
 			break loop
 		case '&':
-			dst, src = unescapeEntity(z.buf, dst, src)
+			dst, src = unescapeEntity(z.buf, dst, src, true)
 		case '\\':
 			if src == z.p1 {
 				z.buf[dst] = '\\'
diff --git a/src/pkg/html/token_test.go b/src/pkg/html/token_test.go
index c794612..c8dcc88 100644
--- a/src/pkg/html/token_test.go
+++ b/src/pkg/html/token_test.go
@@ -107,6 +107,16 @@ var tokenTests = []tokenTest{
 		`<a b="c&noSuchEntity;d"><&alsoDoesntExist;&`,
 		`<a b="c&noSuchEntity;d">$<&alsoDoesntExist;&`,
 	},
+	{
+		"entity without semicolon",
+		`¬it;∉<a b="q=z&amp=5&notice=hello¬=world">`,
+		`¬it;∉$<a b="q=z&amp=5&notice=hello¬=world">`,
+	},
+	{
+		"entity with digits",
+		"&frac12;",
+		"½",
+	},
 
 	// Attribute tests:
 	// http://dev.w3.org/html5/spec/Overview.html#attributes-0
diff --git a/src/pkg/http/Makefile b/src/pkg/http/Makefile
index 2a2a2a3..b8bc093 100644
--- a/src/pkg/http/Makefile
+++ b/src/pkg/http/Makefile
@@ -18,6 +18,7 @@ GOFILES=\
 	response.go\
 	reverseproxy.go\
 	server.go\
+	sniff.go\
 	status.go\
 	transfer.go\
 	transport.go\
diff --git a/src/pkg/http/cgi/host.go b/src/pkg/http/cgi/host.go
index 059fc75..93825b3 100644
--- a/src/pkg/http/cgi/host.go
+++ b/src/pkg/http/cgi/host.go
@@ -187,6 +187,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		return
 	}
 	defer cmd.Wait()
+	defer stdoutRead.Close()
 
 	linebody, _ := bufio.NewReaderSize(stdoutRead, 1024)
 	headers := make(http.Header)
diff --git a/src/pkg/http/cgi/host_test.go b/src/pkg/http/cgi/host_test.go
index b08d8bb..1dc3abd 100644
--- a/src/pkg/http/cgi/host_test.go
+++ b/src/pkg/http/cgi/host_test.go
@@ -12,10 +12,14 @@ import (
 	"fmt"
 	"http"
 	"http/httptest"
+	"io"
 	"os"
+	"net"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"testing"
+	"time"
 	"runtime"
 )
 
@@ -81,7 +85,6 @@ func skipTest(t *testing.T) bool {
 	return false
 }
 
-
 func TestCGIBasicGet(t *testing.T) {
 	if skipTest(t) {
 		return
@@ -304,8 +307,75 @@ func TestInternalRedirect(t *testing.T) {
 	runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
 }
 
+// TestCopyError tests that we kill the process if there's an error copying
+// its output. (for example, from the client having gone away)
+func TestCopyError(t *testing.T) {
+	if skipTest(t) || runtime.GOOS == "windows" {
+		return
+	}
+	h := &Handler{
+		Path: "testdata/test.cgi",
+		Root: "/test.cgi",
+	}
+	ts := httptest.NewServer(h)
+	defer ts.Close()
+
+	conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	req, _ := http.NewRequest("GET", "http://example.com/test.cgi?bigresponse=1", nil)
+	err = req.Write(conn)
+	if err != nil {
+		t.Fatalf("Write: %v", err)
+	}
+
+	res, err := http.ReadResponse(bufio.NewReader(conn), req)
+	if err != nil {
+		t.Fatalf("ReadResponse: %v", err)
+	}
+
+	pidstr := res.Header.Get("X-CGI-Pid")
+	if pidstr == "" {
+		t.Fatalf("expected an X-CGI-Pid header in response")
+	}
+	pid, err := strconv.Atoi(pidstr)
+	if err != nil {
+		t.Fatalf("invalid X-CGI-Pid value")
+	}
+
+	var buf [5000]byte
+	n, err := io.ReadFull(res.Body, buf[:])
+	if err != nil {
+		t.Fatalf("ReadFull: %d bytes, %v", n, err)
+	}
+
+	childRunning := func() bool {
+		p, err := os.FindProcess(pid)
+		if err != nil {
+			return false
+		}
+		return p.Signal(os.UnixSignal(0)) == nil
+	}
+
+	if !childRunning() {
+		t.Fatalf("pre-conn.Close, expected child to be running")
+	}
+	conn.Close()
+
+	if tries := 0; childRunning() {
+		for tries < 15 && childRunning() {
+			time.Sleep(50e6 * int64(tries))
+			tries++
+		}
+		if childRunning() {
+			t.Fatalf("post-conn.Close, expected child to be gone")
+		}
+	}
+}
+
 func TestDirUnix(t *testing.T) {
-	if runtime.GOOS == "windows" {
+	if skipTest(t) || runtime.GOOS == "windows" {
 		return
 	}
 
@@ -333,7 +403,7 @@ func TestDirUnix(t *testing.T) {
 }
 
 func TestDirWindows(t *testing.T) {
-	if runtime.GOOS != "windows" {
+	if skipTest(t) || runtime.GOOS != "windows" {
 		return
 	}
 
diff --git a/src/pkg/http/cgi/testdata/test.cgi b/src/pkg/http/cgi/testdata/test.cgi
index 36c107f..b46b133 100755
--- a/src/pkg/http/cgi/testdata/test.cgi
+++ b/src/pkg/http/cgi/testdata/test.cgi
@@ -25,9 +25,17 @@ my $p = sub {
 
 # With carriage returns
 $p->("Content-Type: text/html");
+$p->("X-CGI-Pid: $$");
 $p->("X-Test-Header: X-Test-Value");
 $p->("");
 
+if ($params->{"bigresponse"}) {
+    for (1..1024) {
+        print "A" x 1024, "\n";
+    }
+    exit 0;
+}
+
 print "test=Hello CGI\n";
 
 foreach my $k (sort keys %$params) {
diff --git a/src/pkg/http/client.go b/src/pkg/http/client.go
index 4f63b44..6ea7dee 100644
--- a/src/pkg/http/client.go
+++ b/src/pkg/http/client.go
@@ -85,7 +85,6 @@ func (c *Client) Do(req *Request) (resp *Response, err os.Error) {
 	return send(req, c.Transport)
 }
 
-
 // send issues an HTTP request.  Caller should close resp.Body when done reading from it.
 func send(req *Request, t RoundTripper) (resp *Response, err os.Error) {
 	if t == nil {
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
index 0b83005..26d9311 100644
--- a/src/pkg/http/fs.go
+++ b/src/pkg/http/fs.go
@@ -78,6 +78,7 @@ func isText(b []byte) bool {
 }
 
 func dirList(w ResponseWriter, f File) {
+	w.Header().Set("Content-Type", "text/html; charset=utf-8")
 	fmt.Fprintf(w, "<pre>\n")
 	for {
 		dirs, err := f.Readdir(100)
@@ -101,8 +102,10 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 	const indexPage = "/index.html"
 
 	// redirect .../index.html to .../
+	// can't use Redirect() because that would make the path absolute,
+	// which would be a problem running under StripPrefix
 	if strings.HasSuffix(r.URL.Path, indexPage) {
-		Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
+		localRedirect(w, r, "./")
 		return
 	}
 
@@ -127,12 +130,12 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 		url := r.URL.Path
 		if d.IsDirectory() {
 			if url[len(url)-1] != '/' {
-				Redirect(w, r, url+"/", StatusMovedPermanently)
+				localRedirect(w, r, path.Base(url)+"/")
 				return
 			}
 		} else {
 			if url[len(url)-1] == '/' {
-				Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
+				localRedirect(w, r, "../"+path.Base(url))
 				return
 			}
 		}
@@ -220,9 +223,20 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 	}
 }
 
+// localRedirect gives a Moved Permanently response.
+// It does not convert relative paths to absolute paths like Redirect does.
+func localRedirect(w ResponseWriter, r *Request, newPath string) {
+	if q := r.URL.RawQuery; q != "" {
+		newPath += "?" + q
+	}
+	w.Header().Set("Location", newPath)
+	w.WriteHeader(StatusMovedPermanently)
+}
+
 // ServeFile replies to the request with the contents of the named file or directory.
 func ServeFile(w ResponseWriter, r *Request, name string) {
-	serveFile(w, r, Dir(name), "", false)
+	dir, file := filepath.Split(name)
+	serveFile(w, r, Dir(dir), file, false)
 }
 
 type fileHandler struct {
@@ -241,7 +255,12 @@ func FileServer(root FileSystem) Handler {
 }
 
 func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
-	serveFile(w, r, f.root, path.Clean(r.URL.Path), true)
+	upath := r.URL.Path
+	if !strings.HasPrefix(upath, "/") {
+		upath = "/" + upath
+		r.URL.Path = upath
+	}
+	serveFile(w, r, f.root, path.Clean(upath), true)
 }
 
 // httpRange specifies the byte range to be sent to the client.
diff --git a/src/pkg/http/fs_test.go b/src/pkg/http/fs_test.go
index dbbdf05..4d465d8 100644
--- a/src/pkg/http/fs_test.go
+++ b/src/pkg/http/fs_test.go
@@ -10,6 +10,8 @@ import (
 	"http/httptest"
 	"io/ioutil"
 	"os"
+	"path/filepath"
+	"strings"
 	"testing"
 )
 
@@ -85,6 +87,30 @@ func TestServeFile(t *testing.T) {
 	}
 }
 
+var fsRedirectTestData = []struct {
+	original, redirect string
+}{
+	{"/test/index.html", "/test/"},
+	{"/test/testdata", "/test/testdata/"},
+	{"/test/testdata/file/", "/test/testdata/file"},
+}
+
+func TestFSRedirect(t *testing.T) {
+	ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
+	defer ts.Close()
+
+	for _, data := range fsRedirectTestData {
+		res, err := Get(ts.URL + data.original)
+		if err != nil {
+			t.Fatal(err)
+		}
+		res.Body.Close()
+		if g, e := res.Request.URL.Path, data.redirect; g != e {
+			t.Errorf("redirect from %s: got %s, want %s", data.original, g, e)
+		}
+	}
+}
+
 type testFileSystem struct {
 	open func(name string) (File, os.Error)
 }
@@ -117,6 +143,36 @@ func TestFileServerCleans(t *testing.T) {
 	}
 }
 
+func TestFileServerImplicitLeadingSlash(t *testing.T) {
+	tempDir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatalf("TempDir: %v", err)
+	}
+	defer os.RemoveAll(tempDir)
+	if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
+		t.Fatalf("WriteFile: %v", err)
+	}
+	ts := httptest.NewServer(StripPrefix("/bar/", FileServer(Dir(tempDir))))
+	defer ts.Close()
+	get := func(suffix string) string {
+		res, err := Get(ts.URL + suffix)
+		if err != nil {
+			t.Fatalf("Get %s: %v", suffix, err)
+		}
+		b, err := ioutil.ReadAll(res.Body)
+		if err != nil {
+			t.Fatalf("ReadAll %s: %v", suffix, err)
+		}
+		return string(b)
+	}
+	if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
+		t.Logf("expected a directory listing with foo.txt, got %q", s)
+	}
+	if s := get("/bar/foo.txt"); s != "Hello world" {
+		t.Logf("expected %q, got %q", "Hello world", s)
+	}
+}
+
 func TestDirJoin(t *testing.T) {
 	wfi, err := os.Stat("/etc/hosts")
 	if err != nil {
@@ -131,10 +187,10 @@ func TestDirJoin(t *testing.T) {
 		defer f.Close()
 		gfi, err := f.Stat()
 		if err != nil {
-			t.Fatalf("stat of %s: %v", err)
+			t.Fatalf("stat of %s: %v", name, err)
 		}
 		if gfi.Ino != wfi.Ino {
-			t.Errorf("%s got different inode")
+			t.Errorf("%s got different inode", name)
 		}
 	}
 	test(Dir("/etc/"), "/hosts")
@@ -175,6 +231,21 @@ func TestServeFileContentType(t *testing.T) {
 	get(ctype)
 }
 
+func TestServeFileMimeType(t *testing.T) {
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		ServeFile(w, r, "testdata/style.css")
+	}))
+	defer ts.Close()
+	resp, err := Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := "text/css; charset=utf-8"
+	if h := resp.Header.Get("Content-Type"); h != want {
+		t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
+	}
+}
+
 func TestServeFileWithContentEncoding(t *testing.T) {
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		w.Header().Set("Content-Encoding", "foo")
diff --git a/src/pkg/http/httptest/server.go b/src/pkg/http/httptest/server.go
index 879f04f..2ec36d0 100644
--- a/src/pkg/http/httptest/server.go
+++ b/src/pkg/http/httptest/server.go
@@ -9,6 +9,7 @@ package httptest
 import (
 	"crypto/rand"
 	"crypto/tls"
+	"flag"
 	"fmt"
 	"http"
 	"net"
@@ -49,15 +50,34 @@ func newLocalListener() net.Listener {
 	return l
 }
 
+// When debugging a particular http server-based test,
+// this flag lets you run
+//	gotest -run=BrokenTest -httptest.serve=127.0.0.1:8000
+// to start the broken server so you can interact with it manually.
+var serve = flag.String("httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks")
+
 // NewServer starts and returns a new Server.
 // The caller should call Close when finished, to shut it down.
 func NewServer(handler http.Handler) *Server {
 	ts := new(Server)
-	l := newLocalListener()
+	var l net.Listener
+	if *serve != "" {
+		var err os.Error
+		l, err = net.Listen("tcp", *serve)
+		if err != nil {
+			panic(fmt.Sprintf("httptest: failed to listen on %v: %v", *serve, err))
+		}
+	} else {
+		l = newLocalListener()
+	}
 	ts.Listener = &historyListener{l, make([]net.Conn, 0)}
 	ts.URL = "http://" + l.Addr().String()
 	server := &http.Server{Handler: handler}
 	go server.Serve(ts.Listener)
+	if *serve != "" {
+		fmt.Println(os.Stderr, "httptest: serving on", ts.URL)
+		select {}
+	}
 	return ts
 }
 
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index 2917cc1..a1c98a1 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -12,7 +12,6 @@ import (
 	"bufio"
 	"bytes"
 	"crypto/tls"
-	"container/vector"
 	"encoding/base64"
 	"fmt"
 	"io"
@@ -674,9 +673,7 @@ func parseQuery(m Values, query string) (err os.Error) {
 			err = e
 			continue
 		}
-		vec := vector.StringVector(m[key])
-		vec.Push(value)
-		m[key] = vec
+		m[key] = append(m[key], value)
 	}
 	return err
 }
diff --git a/src/pkg/http/reverseproxy.go b/src/pkg/http/reverseproxy.go
index e4ce1e3..015f87f 100644
--- a/src/pkg/http/reverseproxy.go
+++ b/src/pkg/http/reverseproxy.go
@@ -10,7 +10,10 @@ import (
 	"io"
 	"log"
 	"net"
+	"os"
 	"strings"
+	"sync"
+	"time"
 )
 
 // ReverseProxy is an HTTP Handler that takes an incoming request and
@@ -26,6 +29,12 @@ type ReverseProxy struct {
 	// The Transport used to perform proxy requests.
 	// If nil, DefaultTransport is used.
 	Transport RoundTripper
+
+	// FlushInterval specifies the flush interval, in
+	// nanoseconds, to flush to the client while
+	// coping the response body.
+	// If zero, no periodic flushing is done.
+	FlushInterval int64
 }
 
 func singleJoiningSlash(a, b string) string {
@@ -95,6 +104,55 @@ func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
 	rw.WriteHeader(res.StatusCode)
 
 	if res.Body != nil {
-		io.Copy(rw, res.Body)
+		var dst io.Writer = rw
+		if p.FlushInterval != 0 {
+			if wf, ok := rw.(writeFlusher); ok {
+				dst = &maxLatencyWriter{dst: wf, latency: p.FlushInterval}
+			}
+		}
+		io.Copy(dst, res.Body)
+	}
+}
+
+type writeFlusher interface {
+	io.Writer
+	Flusher
+}
+
+type maxLatencyWriter struct {
+	dst     writeFlusher
+	latency int64 // nanos
+
+	lk   sync.Mutex // protects init of done, as well Write + Flush
+	done chan bool
+}
+
+func (m *maxLatencyWriter) Write(p []byte) (n int, err os.Error) {
+	m.lk.Lock()
+	defer m.lk.Unlock()
+	if m.done == nil {
+		m.done = make(chan bool)
+		go m.flushLoop()
+	}
+	n, err = m.dst.Write(p)
+	if err != nil {
+		m.done <- true
+	}
+	return
+}
+
+func (m *maxLatencyWriter) flushLoop() {
+	t := time.NewTicker(m.latency)
+	defer t.Stop()
+	for {
+		select {
+		case <-t.C:
+			m.lk.Lock()
+			m.dst.Flush()
+			m.lk.Unlock()
+		case <-m.done:
+			return
+		}
 	}
+	panic("unreached")
 }
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index 55a9cbf..9c8a122 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -110,7 +110,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
 	listener := &oneConnListener{conn}
 	handler := func(res ResponseWriter, req *Request) {
 		reqNum++
-		t.Logf("Got request #%d: %v", reqNum, req)
 		ch <- req
 	}
 
@@ -119,7 +118,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
 	}()
 
 	var req *Request
-	t.Log("Waiting for first request.")
 	req = <-ch
 	if req == nil {
 		t.Fatal("Got nil first request.")
@@ -129,7 +127,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
 			req.Method, "POST")
 	}
 
-	t.Log("Waiting for second request.")
 	req = <-ch
 	if req == nil {
 		t.Fatal("Got nil first request.")
@@ -139,7 +136,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
 			req.Method, "POST")
 	}
 
-	t.Log("Waiting for EOF.")
 	if serveerr := <-servech; serveerr != os.EOF {
 		t.Errorf("Serve returned %q; expected EOF", serveerr)
 	}
@@ -788,7 +784,24 @@ func TestZeroLengthPostAndResponse(t *testing.T) {
 }
 
 func TestHandlerPanic(t *testing.T) {
-	log.SetOutput(ioutil.Discard) // is noisy otherwise
+	// Unlike the other tests that set the log output to ioutil.Discard
+	// to quiet the output, this test uses a pipe.  The pipe serves three
+	// purposes:
+	//
+	//   1) The log.Print from the http server (generated by the caught
+	//      panic) will go to the pipe instead of stderr, making the
+	//      output quiet.
+	//
+	//   2) We read from the pipe to verify that the handler
+	//      actually caught the panic and logged something.
+	//
+	//   3) The blocking Read call prevents this TestHandlerPanic
+	//      function from exiting before the HTTP server handler
+	//      finishes crashing. If this text function exited too
+	//      early (and its defer log.SetOutput(os.Stderr) ran),
+	//      then the crash output could spill into the next test.
+	pr, pw := io.Pipe()
+	log.SetOutput(pw)
 	defer log.SetOutput(os.Stderr)
 
 	ts := httptest.NewServer(HandlerFunc(func(ResponseWriter, *Request) {
@@ -799,6 +812,26 @@ func TestHandlerPanic(t *testing.T) {
 	if err == nil {
 		t.Logf("expected an error")
 	}
+
+	// Do a blocking read on the log output pipe so its logging
+	// doesn't bleed into the next test.  But wait only 5 seconds
+	// for it.
+	done := make(chan bool)
+	go func() {
+		buf := make([]byte, 1024)
+		_, err := pr.Read(buf)
+		pr.Close()
+		if err != nil {
+			t.Fatal(err)
+		}
+		done <- true
+	}()
+	select {
+	case <-done:
+		return
+	case <-time.After(5e9):
+		t.Fatal("expected server handler to log an error")
+	}
 }
 
 func TestNoDate(t *testing.T) {
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index ab960f4..96547c4 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -98,7 +98,8 @@ type conn struct {
 	rwc        net.Conn             // i/o connection
 	buf        *bufio.ReadWriter    // buffered rwc
 	hijacked   bool                 // connection has been hijacked by handler
-	tlsState   *tls.ConnectionState // or nil when not using TLS        
+	tlsState   *tls.ConnectionState // or nil when not using TLS
+	body       []byte
 }
 
 // A response represents the server side of an HTTP response.
@@ -112,6 +113,7 @@ type response struct {
 	written       int64    // number of bytes written in body
 	contentLength int64    // explicitly-declared Content-Length; or -1
 	status        int      // status code passed to WriteHeader
+	needSniff     bool     // need to sniff to find Content-Type
 
 	// close connection after this reply.  set on request and
 	// updated after response from handler if there's a
@@ -129,7 +131,7 @@ func (r *response) ReadFrom(src io.Reader) (n int64, err os.Error) {
 	// WriteHeader if it hasn't been called yet, and WriteHeader
 	// is what sets r.chunking.
 	r.Flush()
-	if !r.chunking && r.bodyAllowed() {
+	if !r.chunking && r.bodyAllowed() && !r.needSniff {
 		if rf, ok := r.conn.rwc.(io.ReaderFrom); ok {
 			n, err = rf.ReadFrom(src)
 			r.written += n
@@ -147,6 +149,7 @@ func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
 	c.remoteAddr = rwc.RemoteAddr().String()
 	c.handler = handler
 	c.rwc = rwc
+	c.body = make([]byte, sniffLen)
 	br := bufio.NewReader(rwc)
 	bw := bufio.NewWriter(rwc)
 	c.buf = bufio.NewReadWriter(br, bw)
@@ -209,6 +212,7 @@ func (c *conn) readRequest() (w *response, err os.Error) {
 	w.req = req
 	w.header = make(Header)
 	w.contentLength = -1
+	c.body = c.body[:0]
 	return w, nil
 }
 
@@ -249,9 +253,9 @@ func (w *response) WriteHeader(code int) {
 			}
 		}
 	} else {
-		// Default output is HTML encoded in UTF-8.
+		// If no content type, apply sniffing algorithm to body.
 		if w.header.Get("Content-Type") == "" {
-			w.header.Set("Content-Type", "text/html; charset=utf-8")
+			w.needSniff = true
 		}
 	}
 
@@ -337,7 +341,36 @@ func (w *response) WriteHeader(code int) {
 	}
 	io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
 	w.header.Write(w.conn.buf)
-	io.WriteString(w.conn.buf, "\r\n")
+
+	// If we need to sniff the body, leave the header open.
+	// Otherwise, end it here.
+	if !w.needSniff {
+		io.WriteString(w.conn.buf, "\r\n")
+	}
+}
+
+// sniff uses the first block of written data,
+// stored in w.conn.body, to decide the Content-Type
+// for the HTTP body.
+func (w *response) sniff() {
+	if !w.needSniff {
+		return
+	}
+	w.needSniff = false
+
+	data := w.conn.body
+	fmt.Fprintf(w.conn.buf, "Content-Type: %s\r\n\r\n", DetectContentType(data))
+
+	if len(data) == 0 {
+		return
+	}
+	if w.chunking {
+		fmt.Fprintf(w.conn.buf, "%x\r\n", len(data))
+	}
+	_, err := w.conn.buf.Write(data)
+	if w.chunking && err == nil {
+		io.WriteString(w.conn.buf, "\r\n")
+	}
 }
 
 // bodyAllowed returns true if a Write is allowed for this response type.
@@ -369,6 +402,32 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
 		return 0, ErrContentLength
 	}
 
+	var m int
+	if w.needSniff {
+		// We need to sniff the beginning of the output to
+		// determine the content type.  Accumulate the
+		// initial writes in w.conn.body.
+		// Cap m so that append won't allocate.
+		m := cap(w.conn.body) - len(w.conn.body)
+		if m > len(data) {
+			m = len(data)
+		}
+		w.conn.body = append(w.conn.body, data[:m]...)
+		data = data[m:]
+		if len(data) == 0 {
+			// Copied everything into the buffer.
+			// Wait for next write.
+			return m, nil
+		}
+
+		// Filled the buffer; more data remains.
+		// Sniff the content (flushes the buffer)
+		// and then proceed with the remainder
+		// of the data as a normal Write.
+		// Calling sniff clears needSniff.
+		w.sniff()
+	}
+
 	// TODO(rsc): if chunking happened after the buffering,
 	// then there would be fewer chunk headers.
 	// On the other hand, it would make hijacking more difficult.
@@ -385,7 +444,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
 		}
 	}
 
-	return n, err
+	return m + n, err
 }
 
 // If this is an error reply (4xx or 5xx)
@@ -449,6 +508,9 @@ func (w *response) finishRequest() {
 	if !w.wroteHeader {
 		w.WriteHeader(StatusOK)
 	}
+	if w.needSniff {
+		w.sniff()
+	}
 	errorKludge(w)
 	if w.chunking {
 		io.WriteString(w.conn.buf, "0\r\n")
@@ -471,6 +533,7 @@ func (w *response) Flush() {
 	if !w.wroteHeader {
 		w.WriteHeader(StatusOK)
 	}
+	w.sniff()
 	w.conn.buf.Flush()
 }
 
@@ -517,6 +580,7 @@ func (c *conn) serve() {
 			if req.ContentLength == 0 {
 				w.Header().Set("Connection", "close")
 				w.WriteHeader(StatusBadRequest)
+				w.finishRequest()
 				break
 			}
 			req.Header.Del("Expect")
@@ -535,6 +599,7 @@ func (c *conn) serve() {
 			// respond with a 417 (Expectation Failed) status."
 			w.Header().Set("Connection", "close")
 			w.WriteHeader(StatusExpectationFailed)
+			w.finishRequest()
 			break
 		}
 
diff --git a/src/pkg/http/sniff.go b/src/pkg/http/sniff.go
new file mode 100644
index 0000000..97b234e
--- /dev/null
+++ b/src/pkg/http/sniff.go
@@ -0,0 +1,203 @@
+// 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 http
+
+import (
+	"bytes"
+	"encoding/binary"
+)
+
+// Content-type sniffing algorithm.
+// References in this file refer to this draft specification:
+//   http://tools.ietf.org/html/draft-ietf-websec-mime-sniff-03
+
+// The algorithm prefers to use sniffLen bytes to make its decision.
+const sniffLen = 512
+
+// DetectContentType returns the sniffed Content-Type string
+// for the given data. This function always returns a valid MIME type.
+func DetectContentType(data []byte) string {
+	if len(data) > sniffLen {
+		data = data[:sniffLen]
+	}
+
+	// Index of the first non-whitespace byte in data.
+	firstNonWS := 0
+	for ; firstNonWS < len(data) && isWS(data[firstNonWS]); firstNonWS++ {
+	}
+
+	for _, sig := range sniffSignatures {
+		if ct := sig.match(data, firstNonWS); ct != "" {
+			return ct
+		}
+	}
+
+	return "application/octet-stream" // fallback
+}
+
+func isWS(b byte) bool {
+	return bytes.IndexByte([]byte("\t\n\x0C\n "), b) != -1
+}
+
+type sniffSig interface {
+	// match returns the MIME type of the data, or "" if unknown.
+	match(data []byte, firstNonWS int) string
+}
+
+// Data matching the table in section 6.
+var sniffSignatures = []sniffSig{
+	htmlSig([]byte("<!DOCTYPE HTML")),
+	htmlSig([]byte("<HTML")),
+	htmlSig([]byte("<HEAD")),
+	htmlSig([]byte("<SCRIPT")),
+	htmlSig([]byte("<IFRAME")),
+	htmlSig([]byte("<H1")),
+	htmlSig([]byte("<DIV")),
+	htmlSig([]byte("<FONT")),
+	htmlSig([]byte("<TABLE")),
+	htmlSig([]byte("<A")),
+	htmlSig([]byte("<STYLE")),
+	htmlSig([]byte("<TITLE")),
+	htmlSig([]byte("<B")),
+	htmlSig([]byte("<BODY")),
+	htmlSig([]byte("<BR")),
+	htmlSig([]byte("<P")),
+	htmlSig([]byte("<!--")),
+
+	&maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"},
+
+	&exactSig{[]byte("%PDF-"), "application/pdf"},
+	&exactSig{[]byte("%!PS-Adobe-"), "application/postscript"},
+
+	// UTF BOMs.
+	&maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFE\xFF\x00\x00"), ct: "text/plain; charset=utf-16be"},
+	&maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFF\xFE\x00\x00"), ct: "text/plain; charset=utf-16le"},
+	&maskedSig{mask: []byte("\xFF\xFF\xFF\x00"), pat: []byte("\xEF\xBB\xBF\x00"), ct: "text/plain; charset=utf-8"},
+
+	&exactSig{[]byte("GIF87a"), "image/gif"},
+	&exactSig{[]byte("GIF89a"), "image/gif"},
+	&exactSig{[]byte("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"), "image/png"},
+	&exactSig{[]byte("\xFF\xD8\xFF"), "image/jpeg"},
+	&exactSig{[]byte("BM"), "image/bmp"},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"),
+		pat:  []byte("RIFF\x00\x00\x00\x00WEBPVP"),
+		ct:   "image/webp",
+	},
+	&exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"},
+	&exactSig{[]byte("\x4F\x67\x67\x53\x00"), "application/ogg"},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+		pat:  []byte("RIFF\x00\x00\x00\x00WAVE"),
+		ct:   "audio/wave",
+	},
+	&exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"},
+	&exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"},
+	&exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
+	&exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"},
+
+	mp4Sig(0),
+
+	textSig(0), // should be last
+}
+
+type exactSig struct {
+	sig []byte
+	ct  string
+}
+
+func (e *exactSig) match(data []byte, firstNonWS int) string {
+	if bytes.HasPrefix(data, e.sig) {
+		return e.ct
+	}
+	return ""
+}
+
+type maskedSig struct {
+	mask, pat []byte
+	skipWS    bool
+	ct        string
+}
+
+func (m *maskedSig) match(data []byte, firstNonWS int) string {
+	if m.skipWS {
+		data = data[firstNonWS:]
+	}
+	if len(data) < len(m.mask) {
+		return ""
+	}
+	for i, mask := range m.mask {
+		db := data[i] & mask
+		if db != m.pat[i] {
+			return ""
+		}
+	}
+	return m.ct
+}
+
+type htmlSig []byte
+
+func (h htmlSig) match(data []byte, firstNonWS int) string {
+	data = data[firstNonWS:]
+	if len(data) < len(h)+1 {
+		return ""
+	}
+	for i, b := range h {
+		db := data[i]
+		if 'A' <= b && b <= 'Z' {
+			db &= 0xDF
+		}
+		if b != db {
+			return ""
+		}
+	}
+	// Next byte must be space or right angle bracket.
+	if db := data[len(h)]; db != ' ' && db != '>' {
+		return ""
+	}
+	return "text/html; charset=utf-8"
+}
+
+type mp4Sig int
+
+func (mp4Sig) match(data []byte, firstNonWS int) string {
+	// c.f. section 6.1.
+	if len(data) < 8 {
+		return ""
+	}
+	boxSize := int(binary.BigEndian.Uint32(data[:4]))
+	if boxSize%4 != 0 || len(data) < boxSize {
+		return ""
+	}
+	if !bytes.Equal(data[4:8], []byte("ftyp")) {
+		return ""
+	}
+	for st := 8; st < boxSize; st += 4 {
+		if st == 12 {
+			// minor version number
+			continue
+		}
+		if bytes.Equal(data[st:st+3], []byte("mp4")) {
+			return "video/mp4"
+		}
+	}
+	return ""
+}
+
+type textSig int
+
+func (textSig) match(data []byte, firstNonWS int) string {
+	// c.f. section 5, step 4.
+	for _, b := range data[firstNonWS:] {
+		switch {
+		case 0x00 <= b && b <= 0x08,
+			b == 0x0B,
+			0x0E <= b && b <= 0x1A,
+			0x1C <= b && b <= 0x1F:
+			return ""
+		}
+	}
+	return "text/plain; charset=utf-8"
+}
diff --git a/src/pkg/http/sniff_test.go b/src/pkg/http/sniff_test.go
new file mode 100644
index 0000000..baf3a41
--- /dev/null
+++ b/src/pkg/http/sniff_test.go
@@ -0,0 +1,78 @@
+// 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 http_test
+
+import (
+	"bytes"
+	. "http"
+	"http/httptest"
+	"io/ioutil"
+	"log"
+	"strconv"
+	"testing"
+)
+
+var sniffTests = []struct {
+	desc        string
+	data        []byte
+	contentType string
+}{
+	// Some nonsense.
+	{"Empty", []byte{}, "text/plain; charset=utf-8"},
+	{"Binary", []byte{1, 2, 3}, "application/octet-stream"},
+
+	{"HTML document #1", []byte(`<HtMl><bOdY>blah blah blah</body></html>`), "text/html; charset=utf-8"},
+	{"HTML document #2", []byte(`<HTML></HTML>`), "text/html; charset=utf-8"},
+	{"HTML document #3 (leading whitespace)", []byte(`   <!DOCTYPE HTML>...`), "text/html; charset=utf-8"},
+
+	{"Plain text", []byte(`This is not HTML. It has ☃ though.`), "text/plain; charset=utf-8"},
+
+	{"XML", []byte("\n<?xml!"), "text/xml; charset=utf-8"},
+
+	// Image types.
+	{"GIF 87a", []byte(`GIF87a`), "image/gif"},
+	{"GIF 89a", []byte(`GIF89a...`), "image/gif"},
+
+	{"MP4", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
+}
+
+func TestDetectContentType(t *testing.T) {
+	for _, tt := range sniffTests {
+		ct := DetectContentType(tt.data)
+		if ct != tt.contentType {
+			t.Errorf("%v: DetectContentType = %q, want %q", tt.desc, ct, tt.contentType)
+		}
+	}
+}
+
+func TestServerContentType(t *testing.T) {
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		i, _ := strconv.Atoi(r.FormValue("i"))
+		tt := sniffTests[i]
+		n, err := w.Write(tt.data)
+		if n != len(tt.data) || err != nil {
+			log.Fatalf("%v: Write(%q) = %v, %v want %d, nil", tt.desc, tt.data, n, err, len(tt.data))
+		}
+	}))
+	defer ts.Close()
+
+	for i, tt := range sniffTests {
+		resp, err := Get(ts.URL + "/?i=" + strconv.Itoa(i))
+		if err != nil {
+			t.Errorf("%v: %v", tt.desc, err)
+			continue
+		}
+		if ct := resp.Header.Get("Content-Type"); ct != tt.contentType {
+			t.Errorf("%v: Content-Type = %q, want %q", tt.desc, ct, tt.contentType)
+		}
+		data, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			t.Errorf("%v: reading body: %v", tt.desc, err)
+		} else if !bytes.Equal(data, tt.data) {
+			t.Errorf("%v: data is %q, want %q", tt.desc, data, tt.data)
+		}
+		resp.Body.Close()
+	}
+}
diff --git a/src/pkg/http/testdata/style.css b/src/pkg/http/testdata/style.css
new file mode 100644
index 0000000..208d16d
--- /dev/null
+++ b/src/pkg/http/testdata/style.css
@@ -0,0 +1 @@
+body {}
diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go
index bff6a10..a8fd99a 100644
--- a/src/pkg/http/triv.go
+++ b/src/pkg/http/triv.go
@@ -16,7 +16,6 @@ import (
 	"strconv"
 )
 
-
 // hello world, the web server
 var helloRequests = expvar.NewInt("hello-requests")
 
@@ -126,7 +125,6 @@ func Logger(w http.ResponseWriter, req *http.Request) {
 	w.Write([]byte("oops"))
 }
 
-
 var webroot = flag.String("root", "/home/rsc", "web root directory")
 
 func main() {
@@ -138,7 +136,7 @@ func main() {
 	expvar.Publish("counter", ctr)
 
 	http.Handle("/", http.HandlerFunc(Logger))
-	http.Handle("/go/", http.FileServer(*webroot, "/go/"))
+	http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
 	http.Handle("/flags", http.HandlerFunc(FlagServer))
 	http.Handle("/args", http.HandlerFunc(ArgServer))
 	http.Handle("/go/hello", http.HandlerFunc(HelloServer))
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index e934b27..b38585a 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -56,7 +56,6 @@ const (
 	encodeOpaque
 )
 
-
 type URLEscapeError string
 
 func (e URLEscapeError) String() string {
@@ -114,7 +113,6 @@ func shouldEscape(c byte, mode encoding) bool {
 	return true
 }
 
-
 // URLUnescape unescapes a string in ``URL encoded'' form,
 // converting %AB into the byte 0xAB and '+' into ' ' (space).
 // It returns an error if any % is not followed
diff --git a/src/pkg/image/bmp/reader.go b/src/pkg/image/bmp/reader.go
index f2842ca..357da1d 100644
--- a/src/pkg/image/bmp/reader.go
+++ b/src/pkg/image/bmp/reader.go
@@ -58,10 +58,13 @@ func decodeRGBA(r io.Reader, c image.Config) (image.Image, os.Error) {
 		if err != nil {
 			return nil, err
 		}
-		p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width]
-		for x := range p {
+		p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
+		for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
 			// BMP images are stored in BGR order rather than RGB order.
-			p[x] = image.RGBAColor{b[3*x+2], b[3*x+1], b[3*x+0], 0xFF}
+			p[i+0] = b[j+2]
+			p[i+1] = b[j+1]
+			p[i+2] = b[j+0]
+			p[i+3] = 0xFF
 		}
 	}
 	return rgba, nil
diff --git a/src/pkg/image/color.go b/src/pkg/image/color.go
index c1345c0..501a882 100644
--- a/src/pkg/image/color.go
+++ b/src/pkg/image/color.go
@@ -4,14 +4,14 @@
 
 package image
 
-// All Colors can convert themselves, with a possible loss of precision,
-// to 64-bit alpha-premultiplied RGBA. Each channel value ranges within
-// [0, 0xFFFF].
+// Color can convert itself to alpha-premultiplied RGBA, with a possible loss
+// of precision. Each value ranges within [0, 0xFFFF], but is represented by a
+// uint32 so that multiplying by a blend factor up to 0xFFFF will not overflow.
 type Color interface {
 	RGBA() (r, g, b, a uint32)
 }
 
-// An RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// RGBAColor represents a traditional 32-bit alpha-premultiplied color,
 // having 8 bits for each of red, green, blue and alpha.
 type RGBAColor struct {
 	R, G, B, A uint8
@@ -29,7 +29,7 @@ func (c RGBAColor) RGBA() (r, g, b, a uint32) {
 	return
 }
 
-// An RGBA64Color represents a 64-bit alpha-premultiplied color,
+// RGBA64Color represents a 64-bit alpha-premultiplied color,
 // having 16 bits for each of red, green, blue and alpha.
 type RGBA64Color struct {
 	R, G, B, A uint16
@@ -39,7 +39,7 @@ func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
 	return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
 }
 
-// An NRGBAColor represents a non-alpha-premultiplied 32-bit color.
+// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
 type NRGBAColor struct {
 	R, G, B, A uint8
 }
@@ -62,7 +62,7 @@ func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
 	return
 }
 
-// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
 // having 16 bits for each of red, green, blue and alpha.
 type NRGBA64Color struct {
 	R, G, B, A uint16
@@ -82,7 +82,7 @@ func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
 	return
 }
 
-// An AlphaColor represents an 8-bit alpha.
+// AlphaColor represents an 8-bit alpha.
 type AlphaColor struct {
 	A uint8
 }
@@ -93,7 +93,7 @@ func (c AlphaColor) RGBA() (r, g, b, a uint32) {
 	return a, a, a, a
 }
 
-// An Alpha16Color represents a 16-bit alpha.
+// Alpha16Color represents a 16-bit alpha.
 type Alpha16Color struct {
 	A uint16
 }
@@ -103,7 +103,7 @@ func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
 	return a, a, a, a
 }
 
-// A GrayColor represents an 8-bit grayscale color.
+// GrayColor represents an 8-bit grayscale color.
 type GrayColor struct {
 	Y uint8
 }
@@ -114,7 +114,7 @@ func (c GrayColor) RGBA() (r, g, b, a uint32) {
 	return y, y, y, 0xffff
 }
 
-// A Gray16Color represents a 16-bit grayscale color.
+// Gray16Color represents a 16-bit grayscale color.
 type Gray16Color struct {
 	Y uint16
 }
@@ -124,7 +124,7 @@ func (c Gray16Color) RGBA() (r, g, b, a uint32) {
 	return y, y, y, 0xffff
 }
 
-// A ColorModel can convert foreign Colors, with a possible loss of precision,
+// ColorModel can convert foreign Colors, with a possible loss of precision,
 // to a Color from its own color model.
 type ColorModel interface {
 	Convert(c Color) Color
diff --git a/src/pkg/image/draw/bench_test.go b/src/pkg/image/draw/bench_test.go
new file mode 100644
index 0000000..a99b408
--- /dev/null
+++ b/src/pkg/image/draw/bench_test.go
@@ -0,0 +1,206 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+	"image"
+	"image/ycbcr"
+	"testing"
+)
+
+const (
+	dstw, dsth = 640, 480
+	srcw, srch = 400, 300
+)
+
+// bench benchmarks drawing src and mask images onto a dst image with the
+// given op and the color models to create those images from.
+// The created images' pixels are initialized to non-zero values.
+func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
+	b.StopTimer()
+
+	var dst Image
+	switch dcm {
+	case image.RGBAColorModel:
+		dst1 := image.NewRGBA(dstw, dsth)
+		for y := 0; y < dsth; y++ {
+			for x := 0; x < dstw; x++ {
+				dst1.SetRGBA(x, y, image.RGBAColor{
+					uint8(5 * x % 0x100),
+					uint8(7 * y % 0x100),
+					uint8((7*x + 5*y) % 0x100),
+					0xff,
+				})
+			}
+		}
+		dst = dst1
+	case image.RGBA64ColorModel:
+		dst1 := image.NewRGBA64(dstw, dsth)
+		for y := 0; y < dsth; y++ {
+			for x := 0; x < dstw; x++ {
+				dst1.SetRGBA64(x, y, image.RGBA64Color{
+					uint16(53 * x % 0x10000),
+					uint16(59 * y % 0x10000),
+					uint16((59*x + 53*y) % 0x10000),
+					0xffff,
+				})
+			}
+		}
+		dst = dst1
+	default:
+		panic("unreachable")
+	}
+
+	var src image.Image
+	switch scm {
+	case nil:
+		src = &image.ColorImage{image.RGBAColor{0x11, 0x22, 0x33, 0xff}}
+	case image.RGBAColorModel:
+		src1 := image.NewRGBA(srcw, srch)
+		for y := 0; y < srch; y++ {
+			for x := 0; x < srcw; x++ {
+				src1.SetRGBA(x, y, image.RGBAColor{
+					uint8(13 * x % 0x80),
+					uint8(11 * y % 0x80),
+					uint8((11*x + 13*y) % 0x80),
+					0x7f,
+				})
+			}
+		}
+		src = src1
+	case image.RGBA64ColorModel:
+		src1 := image.NewRGBA64(srcw, srch)
+		for y := 0; y < srch; y++ {
+			for x := 0; x < srcw; x++ {
+				src1.SetRGBA64(x, y, image.RGBA64Color{
+					uint16(103 * x % 0x8000),
+					uint16(101 * y % 0x8000),
+					uint16((101*x + 103*y) % 0x8000),
+					0x7fff,
+				})
+			}
+		}
+		src = src1
+	case image.NRGBAColorModel:
+		src1 := image.NewNRGBA(srcw, srch)
+		for y := 0; y < srch; y++ {
+			for x := 0; x < srcw; x++ {
+				src1.SetNRGBA(x, y, image.NRGBAColor{
+					uint8(13 * x % 0x100),
+					uint8(11 * y % 0x100),
+					uint8((11*x + 13*y) % 0x100),
+					0x7f,
+				})
+			}
+		}
+		src = src1
+	case ycbcr.YCbCrColorModel:
+		yy := make([]uint8, srcw*srch)
+		cb := make([]uint8, srcw*srch)
+		cr := make([]uint8, srcw*srch)
+		for i := range yy {
+			yy[i] = uint8(3 * i % 0x100)
+			cb[i] = uint8(5 * i % 0x100)
+			cr[i] = uint8(7 * i % 0x100)
+		}
+		src = &ycbcr.YCbCr{
+			Y:              yy,
+			Cb:             cb,
+			Cr:             cr,
+			YStride:        srcw,
+			CStride:        srcw,
+			SubsampleRatio: ycbcr.SubsampleRatio444,
+			Rect:           image.Rect(0, 0, srcw, srch),
+		}
+	default:
+		panic("unreachable")
+	}
+
+	var mask image.Image
+	switch mcm {
+	case nil:
+		// No-op.
+	case image.AlphaColorModel:
+		mask1 := image.NewAlpha(srcw, srch)
+		for y := 0; y < srch; y++ {
+			for x := 0; x < srcw; x++ {
+				a := uint8((23*x + 29*y) % 0x100)
+				// Glyph masks are typically mostly zero,
+				// so we only set a quarter of mask1's pixels.
+				if a >= 0xc0 {
+					mask1.SetAlpha(x, y, image.AlphaColor{a})
+				}
+			}
+		}
+		mask = mask1
+	default:
+		panic("unreachable")
+	}
+
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		// Scatter the destination rectangle to draw into.
+		x := 3 * i % (dstw - srcw)
+		y := 7 * i % (dsth - srch)
+
+		DrawMask(dst, dst.Bounds().Add(image.Point{x, y}), src, image.ZP, mask, image.ZP, op)
+	}
+}
+
+// The BenchmarkFoo functions exercise a drawFoo fast-path function in draw.go.
+
+func BenchmarkFillOver(b *testing.B) {
+	bench(b, image.RGBAColorModel, nil, nil, Over)
+}
+
+func BenchmarkFillSrc(b *testing.B) {
+	bench(b, image.RGBAColorModel, nil, nil, Src)
+}
+
+func BenchmarkCopyOver(b *testing.B) {
+	bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Over)
+}
+
+func BenchmarkCopySrc(b *testing.B) {
+	bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Src)
+}
+
+func BenchmarkNRGBAOver(b *testing.B) {
+	bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Over)
+}
+
+func BenchmarkNRGBASrc(b *testing.B) {
+	bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Src)
+}
+
+func BenchmarkYCbCr(b *testing.B) {
+	bench(b, image.RGBAColorModel, ycbcr.YCbCrColorModel, nil, Over)
+}
+
+func BenchmarkGlyphOver(b *testing.B) {
+	bench(b, image.RGBAColorModel, nil, image.AlphaColorModel, Over)
+}
+
+func BenchmarkRGBA(b *testing.B) {
+	bench(b, image.RGBAColorModel, image.RGBA64ColorModel, nil, Src)
+}
+
+// The BenchmarkGenericFoo functions exercise the generic, slow-path code.
+
+func BenchmarkGenericOver(b *testing.B) {
+	bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Over)
+}
+
+func BenchmarkGenericMaskOver(b *testing.B) {
+	bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Over)
+}
+
+func BenchmarkGenericSrc(b *testing.B) {
+	bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Src)
+}
+
+func BenchmarkGenericMaskSrc(b *testing.B) {
+	bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Src)
+}
diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go
index 0ab7b59..a748ff8 100644
--- a/src/pkg/image/draw/draw.go
+++ b/src/pkg/image/draw/draw.go
@@ -170,33 +170,53 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 }
 
 func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
-	cr, cg, cb, ca := src.RGBA()
+	sr, sg, sb, sa := src.RGBA()
 	// The 0x101 is here for the same reason as in drawRGBA.
-	a := (m - ca) * 0x101
-	x0, x1 := r.Min.X, r.Max.X
-	y0, y1 := r.Min.Y, r.Max.Y
-	for y := y0; y != y1; y++ {
-		dbase := y * dst.Stride
-		dpix := dst.Pix[dbase+x0 : dbase+x1]
-		for i, rgba := range dpix {
-			dr := (uint32(rgba.R)*a)/m + cr
-			dg := (uint32(rgba.G)*a)/m + cg
-			db := (uint32(rgba.B)*a)/m + cb
-			da := (uint32(rgba.A)*a)/m + ca
-			dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+	a := (m - sa) * 0x101
+	i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+	i1 := i0 + r.Dx()*4
+	for y := r.Min.Y; y != r.Max.Y; y++ {
+		for i := i0; i < i1; i += 4 {
+			dr := uint32(dst.Pix[i+0])
+			dg := uint32(dst.Pix[i+1])
+			db := uint32(dst.Pix[i+2])
+			da := uint32(dst.Pix[i+3])
+
+			dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
+			dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
+			dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
+			dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
 		}
+		i0 += dst.Stride
+		i1 += dst.Stride
+	}
+}
+
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+	sr, sg, sb, sa := src.RGBA()
+	// The built-in copy function is faster than a straightforward for loop to fill the destination with
+	// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
+	// then use the first row as the slice source for the remaining rows.
+	i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+	i1 := i0 + r.Dx()*4
+	for i := i0; i < i1; i += 4 {
+		dst.Pix[i+0] = uint8(sr >> 8)
+		dst.Pix[i+1] = uint8(sg >> 8)
+		dst.Pix[i+2] = uint8(sb >> 8)
+		dst.Pix[i+3] = uint8(sa >> 8)
+	}
+	firstRow := dst.Pix[i0:i1]
+	for y := r.Min.Y + 1; y < r.Max.Y; y++ {
+		i0 += dst.Stride
+		i1 += dst.Stride
+		copy(dst.Pix[i0:i1], firstRow)
 	}
 }
 
 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
-	dx0, dx1 := r.Min.X, r.Max.X
-	dy0, dy1 := r.Min.Y, r.Max.Y
-	nrows := dy1 - dy0
-	sx0, sx1 := sp.X, sp.X+dx1-dx0
-	d0 := dy0*dst.Stride + dx0
-	d1 := dy0*dst.Stride + dx1
-	s0 := sp.Y*src.Stride + sx0
-	s1 := sp.Y*src.Stride + sx1
+	dx, dy := r.Dx(), r.Dy()
+	d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+	s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
 	var (
 		ddelta, sdelta int
 		i0, i1, idelta int
@@ -204,139 +224,47 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
 	if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
 		ddelta = dst.Stride
 		sdelta = src.Stride
-		i0, i1, idelta = 0, d1-d0, +1
+		i0, i1, idelta = 0, dx*4, +4
 	} else {
 		// If the source start point is higher than the destination start point, or equal height but to the left,
 		// then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
-		d0 += (nrows - 1) * dst.Stride
-		d1 += (nrows - 1) * dst.Stride
-		s0 += (nrows - 1) * src.Stride
-		s1 += (nrows - 1) * src.Stride
+		d0 += (dy - 1) * dst.Stride
+		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
 		sdelta = -src.Stride
-		i0, i1, idelta = d1-d0-1, -1, -1
+		i0, i1, idelta = (dx-1)*4, -4, -4
 	}
-	for ; nrows > 0; nrows-- {
-		dpix := dst.Pix[d0:d1]
-		spix := src.Pix[s0:s1]
+	for ; dy > 0; dy-- {
+		dpix := dst.Pix[d0:]
+		spix := src.Pix[s0:]
 		for i := i0; i != i1; i += idelta {
-			// For unknown reasons, even though both dpix[i] and spix[i] are
-			// image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
-			// for the source but to do it manually for the destination.
-			sr, sg, sb, sa := spix[i].RGBA()
-			rgba := dpix[i]
-			dr := uint32(rgba.R)
-			dg := uint32(rgba.G)
-			db := uint32(rgba.B)
-			da := uint32(rgba.A)
+			sr := uint32(spix[i+0]) * 0x101
+			sg := uint32(spix[i+1]) * 0x101
+			sb := uint32(spix[i+2]) * 0x101
+			sa := uint32(spix[i+3]) * 0x101
+
+			dr := uint32(dpix[i+0])
+			dg := uint32(dpix[i+1])
+			db := uint32(dpix[i+2])
+			da := uint32(dpix[i+3])
+
 			// The 0x101 is here for the same reason as in drawRGBA.
 			a := (m - sa) * 0x101
-			dr = (dr*a)/m + sr
-			dg = (dg*a)/m + sg
-			db = (db*a)/m + sb
-			da = (da*a)/m + sa
-			dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+
+			dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+			dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+			dpix[i+2] = uint8((db*a/m + sb) >> 8)
+			dpix[i+3] = uint8((da*a/m + sa) >> 8)
 		}
 		d0 += ddelta
-		d1 += ddelta
 		s0 += sdelta
-		s1 += sdelta
-	}
-}
-
-func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
-	for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-		dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-		spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride]
-		for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
-			// Convert from non-premultiplied color to pre-multiplied color.
-			// The order of operations here is to match the NRGBAColor.RGBA
-			// method in image/color.go.
-			snrgba := spix[sx]
-			sa := uint32(snrgba.A)
-			sr := uint32(snrgba.R) * 0x101 * sa / 0xff
-			sg := uint32(snrgba.G) * 0x101 * sa / 0xff
-			sb := uint32(snrgba.B) * 0x101 * sa / 0xff
-			sa *= 0x101
-
-			rgba := dpix[x]
-			dr := uint32(rgba.R)
-			dg := uint32(rgba.G)
-			db := uint32(rgba.B)
-			da := uint32(rgba.A)
-			a := (m - sa) * 0x101
-			dr = (dr*a + sr*m) / m
-			dg = (dg*a + sg*m) / m
-			db = (db*a + sb*m) / m
-			da = (da*a + sa*m) / m
-			dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
-		}
-	}
-}
-
-func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
-	x0, x1 := r.Min.X, r.Max.X
-	y0, y1 := r.Min.Y, r.Max.Y
-	cr, cg, cb, ca := src.RGBA()
-	for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
-		dbase := y * dst.Stride
-		dpix := dst.Pix[dbase+x0 : dbase+x1]
-		mbase := my * mask.Stride
-		mpix := mask.Pix[mbase+mp.X:]
-		for i, rgba := range dpix {
-			ma := uint32(mpix[i].A)
-			if ma == 0 {
-				continue
-			}
-			ma |= ma << 8
-			dr := uint32(rgba.R)
-			dg := uint32(rgba.G)
-			db := uint32(rgba.B)
-			da := uint32(rgba.A)
-			// The 0x101 is here for the same reason as in drawRGBA.
-			a := (m - (ca * ma / m)) * 0x101
-			dr = (dr*a + cr*ma) / m
-			dg = (dg*a + cg*ma) / m
-			db = (db*a + cb*ma) / m
-			da = (da*a + ca*ma) / m
-			dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
-		}
-	}
-}
-
-func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
-	if r.Dy() < 1 {
-		return
-	}
-	cr, cg, cb, ca := src.RGBA()
-	color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)}
-	// The built-in copy function is faster than a straightforward for loop to fill the destination with
-	// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
-	// then use the first row as the slice source for the remaining rows.
-	dx0, dx1 := r.Min.X, r.Max.X
-	dy0, dy1 := r.Min.Y, r.Max.Y
-	dbase := dy0 * dst.Stride
-	i0, i1 := dbase+dx0, dbase+dx1
-	firstRow := dst.Pix[i0:i1]
-	for i := range firstRow {
-		firstRow[i] = color
-	}
-	for y := dy0 + 1; y < dy1; y++ {
-		i0 += dst.Stride
-		i1 += dst.Stride
-		copy(dst.Pix[i0:i1], firstRow)
 	}
 }
 
 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
-	dx0, dx1 := r.Min.X, r.Max.X
-	dy0, dy1 := r.Min.Y, r.Max.Y
-	nrows := dy1 - dy0
-	sx0, sx1 := sp.X, sp.X+dx1-dx0
-	d0 := dy0*dst.Stride + dx0
-	d1 := dy0*dst.Stride + dx1
-	s0 := sp.Y*src.Stride + sx0
-	s1 := sp.Y*src.Stride + sx1
+	n, dy := 4*r.Dx(), r.Dy()
+	d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+	s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
 	var ddelta, sdelta int
 	if r.Min.Y <= sp.Y {
 		ddelta = dst.Stride
@@ -345,38 +273,76 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
 		// If the source start point is higher than the destination start point, then we compose the rows
 		// in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
 		// check the x co-ordinates because the built-in copy function can handle overlapping slices.
-		d0 += (nrows - 1) * dst.Stride
-		d1 += (nrows - 1) * dst.Stride
-		s0 += (nrows - 1) * src.Stride
-		s1 += (nrows - 1) * src.Stride
+		d0 += (dy - 1) * dst.Stride
+		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
 		sdelta = -src.Stride
 	}
-	for ; nrows > 0; nrows-- {
-		copy(dst.Pix[d0:d1], src.Pix[s0:s1])
+	for ; dy > 0; dy-- {
+		copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
 		d0 += ddelta
-		d1 += ddelta
 		s0 += sdelta
-		s1 += sdelta
+	}
+}
+
+func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
+	i0 := (r.Min.X - dst.Rect.Min.X) * 4
+	i1 := (r.Max.X - dst.Rect.Min.X) * 4
+	si0 := (sp.X - src.Rect.Min.X) * 4
+	yMax := r.Max.Y - dst.Rect.Min.Y
+
+	y := r.Min.Y - dst.Rect.Min.Y
+	sy := sp.Y - src.Rect.Min.Y
+	for ; y != yMax; y, sy = y+1, sy+1 {
+		dpix := dst.Pix[y*dst.Stride:]
+		spix := src.Pix[sy*src.Stride:]
+
+		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
+			// Convert from non-premultiplied color to pre-multiplied color.
+			sa := uint32(spix[si+3]) * 0x101
+			sr := uint32(spix[si+0]) * sa / 0xff
+			sg := uint32(spix[si+1]) * sa / 0xff
+			sb := uint32(spix[si+2]) * sa / 0xff
+
+			dr := uint32(dpix[i+0])
+			dg := uint32(dpix[i+1])
+			db := uint32(dpix[i+2])
+			da := uint32(dpix[i+3])
+
+			// The 0x101 is here for the same reason as in drawRGBA.
+			a := (m - sa) * 0x101
+
+			dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+			dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+			dpix[i+2] = uint8((db*a/m + sb) >> 8)
+			dpix[i+3] = uint8((da*a/m + sa) >> 8)
+		}
 	}
 }
 
 func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
-	for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-		dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-		spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride]
-		for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+	i0 := (r.Min.X - dst.Rect.Min.X) * 4
+	i1 := (r.Max.X - dst.Rect.Min.X) * 4
+	si0 := (sp.X - src.Rect.Min.X) * 4
+	yMax := r.Max.Y - dst.Rect.Min.Y
+
+	y := r.Min.Y - dst.Rect.Min.Y
+	sy := sp.Y - src.Rect.Min.Y
+	for ; y != yMax; y, sy = y+1, sy+1 {
+		dpix := dst.Pix[y*dst.Stride:]
+		spix := src.Pix[sy*src.Stride:]
+
+		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
 			// Convert from non-premultiplied color to pre-multiplied color.
-			// The order of operations here is to match the NRGBAColor.RGBA
-			// method in image/color.go.
-			snrgba := spix[sx]
-			sa := uint32(snrgba.A)
-			sr := uint32(snrgba.R) * 0x101 * sa / 0xff
-			sg := uint32(snrgba.G) * 0x101 * sa / 0xff
-			sb := uint32(snrgba.B) * 0x101 * sa / 0xff
-			sa *= 0x101
-
-			dpix[x] = image.RGBAColor{uint8(sr >> 8), uint8(sg >> 8), uint8(sb >> 8), uint8(sa >> 8)}
+			sa := uint32(spix[si+3]) * 0x101
+			sr := uint32(spix[si+0]) * sa / 0xff
+			sg := uint32(spix[si+1]) * sa / 0xff
+			sb := uint32(spix[si+2]) * sa / 0xff
+
+			dpix[i+0] = uint8(sr >> 8)
+			dpix[i+1] = uint8(sg >> 8)
+			dpix[i+2] = uint8(sb >> 8)
+			dpix[i+3] = uint8(sa >> 8)
 		}
 	}
 }
@@ -386,48 +352,92 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
 	// (i.e. fully opaque) then the op is effectively always Src.
 	var (
 		yy, cb, cr uint8
-		rr, gg, bb uint8
 	)
+	x0 := (r.Min.X - dst.Rect.Min.X) * 4
+	x1 := (r.Max.X - dst.Rect.Min.X) * 4
+	y0 := r.Min.Y - dst.Rect.Min.Y
+	y1 := r.Max.Y - dst.Rect.Min.Y
 	switch src.SubsampleRatio {
 	case ycbcr.SubsampleRatio422:
-		for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-			for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
 				i := sx / 2
 				yy = src.Y[sy*src.YStride+sx]
 				cb = src.Cb[sy*src.CStride+i]
 				cr = src.Cr[sy*src.CStride+i]
-				rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
-				dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+				rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
 			}
 		}
 	case ycbcr.SubsampleRatio420:
-		for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-			for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
 				i, j := sx/2, sy/2
 				yy = src.Y[sy*src.YStride+sx]
 				cb = src.Cb[j*src.CStride+i]
 				cr = src.Cr[j*src.CStride+i]
-				rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
-				dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+				rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
 			}
 		}
 	default:
 		// Default to 4:4:4 subsampling.
-		for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-			for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
 				yy = src.Y[sy*src.YStride+sx]
 				cb = src.Cb[sy*src.CStride+sx]
 				cr = src.Cr[sy*src.CStride+sx]
-				rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
-				dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+				rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
 			}
 		}
 	}
 }
 
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
+	i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+	i1 := i0 + r.Dx()*4
+	mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+	sr, sg, sb, sa := src.RGBA()
+	for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
+		for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
+			ma := uint32(mask.Pix[mi])
+			if ma == 0 {
+				continue
+			}
+			ma |= ma << 8
+
+			dr := uint32(dst.Pix[i+0])
+			dg := uint32(dst.Pix[i+1])
+			db := uint32(dst.Pix[i+2])
+			da := uint32(dst.Pix[i+3])
+
+			// The 0x101 is here for the same reason as in drawRGBA.
+			a := (m - (sa * ma / m)) * 0x101
+
+			dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+			dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+			dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+			dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+		}
+		i0 += dst.Stride
+		i1 += dst.Stride
+		mi0 += mask.Stride
+	}
+}
+
 func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
 	x0, x1, dx := r.Min.X, r.Max.X, 1
 	y0, y1, dy := r.Min.Y, r.Max.Y, 1
@@ -440,23 +450,24 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
 
 	sy := sp.Y + y0 - r.Min.Y
 	my := mp.Y + y0 - r.Min.Y
+	sx0 := sp.X + x0 - r.Min.X
+	mx0 := mp.X + x0 - r.Min.X
+	sx1 := sx0 + (x1 - x0)
+	i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
+	di := dx * 4
 	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
-		sx := sp.X + x0 - r.Min.X
-		mx := mp.X + x0 - r.Min.X
-		dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-		for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+		for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
 			ma := uint32(m)
 			if mask != nil {
 				_, _, _, ma = mask.At(mx, my).RGBA()
 			}
 			sr, sg, sb, sa := src.At(sx, sy).RGBA()
-			var dr, dg, db, da uint32
 			if op == Over {
-				rgba := dpix[x]
-				dr = uint32(rgba.R)
-				dg = uint32(rgba.G)
-				db = uint32(rgba.B)
-				da = uint32(rgba.A)
+				dr := uint32(dst.Pix[i+0])
+				dg := uint32(dst.Pix[i+1])
+				db := uint32(dst.Pix[i+2])
+				da := uint32(dst.Pix[i+3])
+
 				// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
 				// We work in 16-bit color, and so would normally do:
 				// dr |= dr << 8
@@ -464,17 +475,19 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
 				// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
 				// This yields the same result, but is fewer arithmetic operations.
 				a := (m - (sa * ma / m)) * 0x101
-				dr = (dr*a + sr*ma) / m
-				dg = (dg*a + sg*ma) / m
-				db = (db*a + sb*ma) / m
-				da = (da*a + sa*ma) / m
+
+				dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+				dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+				dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+				dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+
 			} else {
-				dr = sr * ma / m
-				dg = sg * ma / m
-				db = sb * ma / m
-				da = sa * ma / m
+				dst.Pix[i+0] = uint8(sr * ma / m >> 8)
+				dst.Pix[i+1] = uint8(sg * ma / m >> 8)
+				dst.Pix[i+2] = uint8(sb * ma / m >> 8)
+				dst.Pix[i+3] = uint8(sa * ma / m >> 8)
 			}
-			dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
 		}
+		i0 += dy * dst.Stride
 	}
 }
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 98ac01c..e39b797 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -28,7 +28,9 @@ const (
 	fColorMapFollows = 1 << 7
 
 	// Image fields.
-	ifInterlace = 1 << 6
+	ifLocalColorTable = 1 << 7
+	ifInterlace       = 1 << 6
+	ifPixelSizeMask   = 7
 
 	// Graphic control flags.
 	gcTransparentColorSet = 1 << 0
@@ -190,7 +192,9 @@ Loop:
 			}
 
 			// Undo the interlacing if necessary.
-			d.uninterlace(m)
+			if d.imageFields&ifInterlace != 0 {
+				uninterlace(m)
+			}
 
 			d.image = append(d.image, m)
 			d.delay = append(d.delay, d.delayTime)
@@ -236,6 +240,9 @@ func (d *decoder) readColorMap() (image.PalettedColorModel, os.Error) {
 		return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
 	}
 	numColors := 1 << d.pixelSize
+	if d.imageFields&ifLocalColorTable != 0 {
+		numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
+	}
 	numValues := 3 * numColors
 	_, err := io.ReadFull(d.r, d.tmp[0:numValues])
 	if err != nil {
@@ -322,15 +329,15 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, os.Error) {
 	if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
 		return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
 	}
-	// TODO: This code (throughout) ignores the top and left values,
-	// and assumes (in interlacing, for example) that the images'
-	// widths and heights are all the same.
-	_ = int(d.tmp[0]) + int(d.tmp[1])<<8 // TODO: honor left value
-	_ = int(d.tmp[2]) + int(d.tmp[3])<<8 // TODO: honor top value
+	left := int(d.tmp[0]) + int(d.tmp[1])<<8
+	top := int(d.tmp[2]) + int(d.tmp[3])<<8
 	width := int(d.tmp[4]) + int(d.tmp[5])<<8
 	height := int(d.tmp[6]) + int(d.tmp[7])<<8
 	d.imageFields = d.tmp[8]
-	return image.NewPaletted(width, height, nil), nil
+	m := image.NewPaletted(width, height, nil)
+	// Overwrite the rectangle to take account of left and top.
+	m.Rect = image.Rect(left, top, left+width, top+height)
+	return m, nil
 }
 
 func (d *decoder) readBlock() (int, os.Error) {
@@ -354,13 +361,11 @@ var interlacing = []interlaceScan{
 	{2, 1}, // Group 4 : Every 2nd. row, starting with row 1.
 }
 
-func (d *decoder) uninterlace(m *image.Paletted) {
-	if d.imageFields&ifInterlace == 0 {
-		return
-	}
+// uninterlace rearranges the pixels in m to account for interlaced input.
+func uninterlace(m *image.Paletted) {
 	var nPix []uint8
-	dx := d.width
-	dy := d.height
+	dx := m.Bounds().Dx()
+	dy := m.Bounds().Dy()
 	nPix = make([]uint8, dx*dy)
 	offset := 0 // steps through the input by sequential scan lines.
 	for _, pass := range interlacing {
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index 5ea302d..11def94 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -5,13 +5,13 @@
 // Package image implements a basic 2-D image library.
 package image
 
-// A Config consists of an image's color model and dimensions.
+// Config holds an image's color model and dimensions.
 type Config struct {
 	ColorModel    ColorModel
 	Width, Height int
 }
 
-// An Image is a finite rectangular grid of Colors drawn from a ColorModel.
+// Image is a finite rectangular grid of Colors drawn from a ColorModel.
 type Image interface {
 	// ColorModel returns the Image's ColorModel.
 	ColorModel() ColorModel
@@ -24,10 +24,12 @@ type Image interface {
 	At(x, y int) Color
 }
 
-// An RGBA is an in-memory image of RGBAColor values.
+// RGBA is an in-memory image of RGBAColor values.
 type RGBA struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []RGBAColor
+	// Pix holds the image's pixels, in R, G, B, A order. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -41,30 +43,48 @@ func (p *RGBA) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return RGBAColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+	return RGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
 }
 
 func (p *RGBA) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+	c1 := toRGBAColor(c).(RGBAColor)
+	p.Pix[i+0] = c1.R
+	p.Pix[i+1] = c1.G
+	p.Pix[i+2] = c1.B
+	p.Pix[i+3] = c1.A
 }
 
 func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+	p.Pix[i+0] = c.R
+	p.Pix[i+1] = c.G
+	p.Pix[i+2] = c.B
+	p.Pix[i+3] = c.A
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *RGBA) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &RGBA{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
 	return &RGBA{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -73,11 +93,10 @@ func (p *RGBA) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 3, p.Rect.Dx()*4
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-		for _, c := range p.Pix[i0:i1] {
-			if c.A != 0xff {
+		for i := i0; i < i1; i += 4 {
+			if p.Pix[i] != 0xff {
 				return false
 			}
 		}
@@ -89,14 +108,16 @@ func (p *RGBA) Opaque() bool {
 
 // NewRGBA returns a new RGBA with the given width and height.
 func NewRGBA(w, h int) *RGBA {
-	buf := make([]RGBAColor, w*h)
-	return &RGBA{buf, w, Rectangle{ZP, Point{w, h}}}
+	buf := make([]uint8, 4*w*h)
+	return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An RGBA64 is an in-memory image of RGBA64Color values.
+// RGBA64 is an in-memory image of RGBA64Color values.
 type RGBA64 struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []RGBA64Color
+	// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -110,30 +131,61 @@ func (p *RGBA64) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return RGBA64Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+	return RGBA64Color{
+		uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+		uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+		uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+		uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+	}
 }
 
 func (p *RGBA64) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+	c1 := toRGBA64Color(c).(RGBA64Color)
+	p.Pix[i+0] = uint8(c1.R >> 8)
+	p.Pix[i+1] = uint8(c1.R)
+	p.Pix[i+2] = uint8(c1.G >> 8)
+	p.Pix[i+3] = uint8(c1.G)
+	p.Pix[i+4] = uint8(c1.B >> 8)
+	p.Pix[i+5] = uint8(c1.B)
+	p.Pix[i+6] = uint8(c1.A >> 8)
+	p.Pix[i+7] = uint8(c1.A)
 }
 
 func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+	p.Pix[i+0] = uint8(c.R >> 8)
+	p.Pix[i+1] = uint8(c.R)
+	p.Pix[i+2] = uint8(c.G >> 8)
+	p.Pix[i+3] = uint8(c.G)
+	p.Pix[i+4] = uint8(c.B >> 8)
+	p.Pix[i+5] = uint8(c.B)
+	p.Pix[i+6] = uint8(c.A >> 8)
+	p.Pix[i+7] = uint8(c.A)
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *RGBA64) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &RGBA64{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
 	return &RGBA64{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -142,11 +194,10 @@ func (p *RGBA64) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 6, p.Rect.Dx()*8
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-		for _, c := range p.Pix[i0:i1] {
-			if c.A != 0xffff {
+		for i := i0; i < i1; i += 8 {
+			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
 				return false
 			}
 		}
@@ -158,14 +209,16 @@ func (p *RGBA64) Opaque() bool {
 
 // NewRGBA64 returns a new RGBA64 with the given width and height.
 func NewRGBA64(w, h int) *RGBA64 {
-	pix := make([]RGBA64Color, w*h)
-	return &RGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 8*w*h)
+	return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An NRGBA is an in-memory image of NRGBAColor values.
+// NRGBA is an in-memory image of NRGBAColor values.
 type NRGBA struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []NRGBAColor
+	// Pix holds the image's pixels, in R, G, B, A order. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -179,30 +232,48 @@ func (p *NRGBA) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return NRGBAColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+	return NRGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
 }
 
 func (p *NRGBA) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+	c1 := toNRGBAColor(c).(NRGBAColor)
+	p.Pix[i+0] = c1.R
+	p.Pix[i+1] = c1.G
+	p.Pix[i+2] = c1.B
+	p.Pix[i+3] = c1.A
 }
 
 func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+	p.Pix[i+0] = c.R
+	p.Pix[i+1] = c.G
+	p.Pix[i+2] = c.B
+	p.Pix[i+3] = c.A
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *NRGBA) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &NRGBA{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
 	return &NRGBA{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -211,11 +282,10 @@ func (p *NRGBA) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 3, p.Rect.Dx()*4
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-		for _, c := range p.Pix[i0:i1] {
-			if c.A != 0xff {
+		for i := i0; i < i1; i += 4 {
+			if p.Pix[i] != 0xff {
 				return false
 			}
 		}
@@ -227,14 +297,16 @@ func (p *NRGBA) Opaque() bool {
 
 // NewNRGBA returns a new NRGBA with the given width and height.
 func NewNRGBA(w, h int) *NRGBA {
-	pix := make([]NRGBAColor, w*h)
-	return &NRGBA{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 4*w*h)
+	return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An NRGBA64 is an in-memory image of NRGBA64Color values.
+// NRGBA64 is an in-memory image of NRGBA64Color values.
 type NRGBA64 struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []NRGBA64Color
+	// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -248,30 +320,61 @@ func (p *NRGBA64) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return NRGBA64Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+	return NRGBA64Color{
+		uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+		uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+		uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+		uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+	}
 }
 
 func (p *NRGBA64) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+	c1 := toNRGBA64Color(c).(NRGBA64Color)
+	p.Pix[i+0] = uint8(c1.R >> 8)
+	p.Pix[i+1] = uint8(c1.R)
+	p.Pix[i+2] = uint8(c1.G >> 8)
+	p.Pix[i+3] = uint8(c1.G)
+	p.Pix[i+4] = uint8(c1.B >> 8)
+	p.Pix[i+5] = uint8(c1.B)
+	p.Pix[i+6] = uint8(c1.A >> 8)
+	p.Pix[i+7] = uint8(c1.A)
 }
 
 func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+	p.Pix[i+0] = uint8(c.R >> 8)
+	p.Pix[i+1] = uint8(c.R)
+	p.Pix[i+2] = uint8(c.G >> 8)
+	p.Pix[i+3] = uint8(c.G)
+	p.Pix[i+4] = uint8(c.B >> 8)
+	p.Pix[i+5] = uint8(c.B)
+	p.Pix[i+6] = uint8(c.A >> 8)
+	p.Pix[i+7] = uint8(c.A)
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *NRGBA64) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &NRGBA64{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
 	return &NRGBA64{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -280,11 +383,10 @@ func (p *NRGBA64) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 6, p.Rect.Dx()*8
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-		for _, c := range p.Pix[i0:i1] {
-			if c.A != 0xffff {
+		for i := i0; i < i1; i += 8 {
+			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
 				return false
 			}
 		}
@@ -296,14 +398,16 @@ func (p *NRGBA64) Opaque() bool {
 
 // NewNRGBA64 returns a new NRGBA64 with the given width and height.
 func NewNRGBA64(w, h int) *NRGBA64 {
-	pix := make([]NRGBA64Color, w*h)
-	return &NRGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 8*w*h)
+	return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An Alpha is an in-memory image of AlphaColor values.
+// Alpha is an in-memory image of AlphaColor values.
 type Alpha struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []AlphaColor
+	// Pix holds the image's pixels, as alpha values. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -317,30 +421,41 @@ func (p *Alpha) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return AlphaColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return AlphaColor{p.Pix[i]}
 }
 
 func (p *Alpha) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toAlphaColor(c).(AlphaColor).A
 }
 
 func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c.A
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *Alpha) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &Alpha{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
 	return &Alpha{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -349,11 +464,10 @@ func (p *Alpha) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 0, p.Rect.Dx()
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-		for _, c := range p.Pix[i0:i1] {
-			if c.A != 0xff {
+		for i := i0; i < i1; i++ {
+			if p.Pix[i] != 0xff {
 				return false
 			}
 		}
@@ -365,14 +479,16 @@ func (p *Alpha) Opaque() bool {
 
 // NewAlpha returns a new Alpha with the given width and height.
 func NewAlpha(w, h int) *Alpha {
-	pix := make([]AlphaColor, w*h)
-	return &Alpha{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 1*w*h)
+	return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An Alpha16 is an in-memory image of Alpha16Color values.
+// Alpha16 is an in-memory image of Alpha16Color values.
 type Alpha16 struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []Alpha16Color
+	// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -386,30 +502,44 @@ func (p *Alpha16) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return Alpha16Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+	return Alpha16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
 }
 
 func (p *Alpha16) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+	c1 := toAlpha16Color(c).(Alpha16Color)
+	p.Pix[i+0] = uint8(c1.A >> 8)
+	p.Pix[i+1] = uint8(c1.A)
 }
 
 func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+	p.Pix[i+0] = uint8(c.A >> 8)
+	p.Pix[i+1] = uint8(c.A)
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *Alpha16) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &Alpha16{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
 	return &Alpha16{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -418,11 +548,10 @@ func (p *Alpha16) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 0, p.Rect.Dx()*2
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-		for _, c := range p.Pix[i0:i1] {
-			if c.A != 0xffff {
+		for i := i0; i < i1; i += 2 {
+			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
 				return false
 			}
 		}
@@ -434,14 +563,16 @@ func (p *Alpha16) Opaque() bool {
 
 // NewAlpha16 returns a new Alpha16 with the given width and height.
 func NewAlpha16(w, h int) *Alpha16 {
-	pix := make([]Alpha16Color, w*h)
-	return &Alpha16{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 2*w*h)
+	return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// A Gray is an in-memory image of GrayColor values.
+// Gray is an in-memory image of GrayColor values.
 type Gray struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []GrayColor
+	// Pix holds the image's pixels, as gray values. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -455,30 +586,41 @@ func (p *Gray) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return GrayColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return GrayColor{p.Pix[i]}
 }
 
 func (p *Gray) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toGrayColor(c).(GrayColor).Y
 }
 
 func (p *Gray) SetGray(x, y int, c GrayColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c.Y
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *Gray) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &Gray{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
 	return &Gray{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -489,14 +631,16 @@ func (p *Gray) Opaque() bool {
 
 // NewGray returns a new Gray with the given width and height.
 func NewGray(w, h int) *Gray {
-	pix := make([]GrayColor, w*h)
-	return &Gray{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 1*w*h)
+	return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// A Gray16 is an in-memory image of Gray16Color values.
+// Gray16 is an in-memory image of Gray16Color values.
 type Gray16 struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []Gray16Color
+	// Pix holds the image's pixels, as gray values in big-endian format. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -510,30 +654,44 @@ func (p *Gray16) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return Gray16Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+	return Gray16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
 }
 
 func (p *Gray16) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+	c1 := toGray16Color(c).(Gray16Color)
+	p.Pix[i+0] = uint8(c1.Y >> 8)
+	p.Pix[i+1] = uint8(c1.Y)
 }
 
 func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+	p.Pix[i+0] = uint8(c.Y >> 8)
+	p.Pix[i+1] = uint8(c.Y)
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *Gray16) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &Gray16{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
 	return &Gray16{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -544,8 +702,8 @@ func (p *Gray16) Opaque() bool {
 
 // NewGray16 returns a new Gray16 with the given width and height.
 func NewGray16(w, h int) *Gray16 {
-	pix := make([]Gray16Color, w*h)
-	return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
+	pix := make([]uint8, 2*w*h)
+	return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
 }
 
 // A PalettedColorModel represents a fixed palette of at most 256 colors.
@@ -589,10 +747,12 @@ func (p PalettedColorModel) Index(c Color) int {
 	return ret
 }
 
-// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
+// Paletted is an in-memory image of uint8 indices into a given palette.
 type Paletted struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
-	Pix    []uint8
+	// Pix holds the image's pixels, as palette indices. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
 	Stride int
 	// Rect is the image's bounds.
 	Rect Rectangle
@@ -611,35 +771,49 @@ func (p *Paletted) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return p.Palette[0]
 	}
-	return p.Palette[p.Pix[y*p.Stride+x]]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Palette[p.Pix[i]]
 }
 
 func (p *Paletted) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = uint8(p.Palette.Index(c))
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = uint8(p.Palette.Index(c))
 }
 
 func (p *Paletted) ColorIndexAt(x, y int) uint8 {
 	if !(Point{x, y}.In(p.Rect)) {
 		return 0
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *Paletted) SetColorIndex(x, y int, index uint8) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = index
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = index
 }
 
 // SubImage returns an image representing the portion of the image p visible
 // through r. The returned value shares pixels with the original image.
 func (p *Paletted) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &Paletted{
+			Palette: p.Palette,
+		}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
 	return &Paletted{
-		Pix:     p.Pix,
+		Pix:     p.Pix[i:],
 		Stride:  p.Stride,
 		Rect:    p.Rect.Intersect(r),
 		Palette: p.Palette,
@@ -649,8 +823,7 @@ func (p *Paletted) SubImage(r Rectangle) Image {
 // Opaque scans the entire image and returns whether or not it is fully opaque.
 func (p *Paletted) Opaque() bool {
 	var present [256]bool
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	i0, i1 := 0, p.Rect.Dx()
 	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
 		for _, c := range p.Pix[i0:i1] {
 			present[c] = true
@@ -672,6 +845,6 @@ func (p *Paletted) Opaque() bool {
 
 // NewPaletted returns a new Paletted with the given width, height and palette.
 func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
-	pix := make([]uint8, w*h)
-	return &Paletted{pix, w, Rectangle{ZP, Point{w, h}}, m}
+	pix := make([]uint8, 1*w*h)
+	return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
 }
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
index 5469d64..a368e71 100644
--- a/src/pkg/image/image_test.go
+++ b/src/pkg/image/image_test.go
@@ -72,6 +72,11 @@ func TestImage(t *testing.T) {
 			t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
 			continue
 		}
+		// Test that taking an empty sub-image starting at a corner does not panic.
+		m.SubImage(Rect(0, 0, 0, 0))
+		m.SubImage(Rect(10, 0, 10, 0))
+		m.SubImage(Rect(0, 10, 0, 10))
+		m.SubImage(Rect(10, 10, 10, 10))
 	}
 }
 
diff --git a/src/pkg/image/jpeg/reader.go b/src/pkg/image/jpeg/reader.go
index ef8383a..3f22c52 100644
--- a/src/pkg/image/jpeg/reader.go
+++ b/src/pkg/image/jpeg/reader.go
@@ -199,8 +199,8 @@ func (d *decoder) processDQT(n int) os.Error {
 // makeImg allocates and initializes the destination image.
 func (d *decoder) makeImg(h0, v0, mxx, myy int) {
 	if d.nComp == nGrayComponent {
-		d.img1 = image.NewGray(8*mxx, 8*myy)
-		d.img1.Rect = image.Rect(0, 0, d.width, d.height)
+		m := image.NewGray(8*mxx, 8*myy)
+		d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
 		return
 	}
 	var subsampleRatio ycbcr.SubsampleRatio
@@ -319,16 +319,7 @@ func (d *decoder) processSOS(n int) os.Error {
 
 					// Perform the inverse DCT and store the MCU component to the image.
 					if d.nComp == nGrayComponent {
-						idct(d.tmp[:64], 8, &b)
-						// Convert from []uint8 to []image.GrayColor.
-						p := d.img1.Pix[8*(my*d.img1.Stride+mx):]
-						for y := 0; y < 8; y++ {
-							dst := p[y*d.img1.Stride:]
-							src := d.tmp[8*y:]
-							for x := 0; x < 8; x++ {
-								dst[x] = image.GrayColor{src[x]}
-							}
-						}
+						idct(d.img1.Pix[8*(my*d.img1.Stride+mx):], d.img1.Stride, &b)
 					} else {
 						switch i {
 						case 0:
diff --git a/src/pkg/image/jpeg/writer.go b/src/pkg/image/jpeg/writer.go
index eddaaef..2bb6df5 100644
--- a/src/pkg/image/jpeg/writer.go
+++ b/src/pkg/image/jpeg/writer.go
@@ -397,14 +397,14 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
 		if sj > ymax {
 			sj = ymax
 		}
-		yoff := sj * m.Stride
+		offset := (sj-b.Min.Y)*m.Stride - b.Min.X*4
 		for i := 0; i < 8; i++ {
 			sx := p.X + i
 			if sx > xmax {
 				sx = xmax
 			}
-			col := &m.Pix[yoff+sx]
-			yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
+			pix := m.Pix[offset+sx*4:]
+			yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
 			yBlock[8*j+i] = int(yy)
 			cbBlock[8*j+i] = int(cb)
 			crBlock[8*j+i] = int(cr)
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
index d770cfa..55ca97e 100644
--- a/src/pkg/image/png/writer.go
+++ b/src/pkg/image/png/writer.go
@@ -275,11 +275,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 
 	bpp := 0 // Bytes per pixel.
 
-	// Used by fast paths for common image types
-	var paletted *image.Paletted
-	var rgba *image.RGBA
-	rgba, _ = m.(*image.RGBA)
-
 	switch cb {
 	case cbG8:
 		bpp = 1
@@ -287,7 +282,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 		bpp = 3
 	case cbP8:
 		bpp = 1
-		paletted = m.(*image.Paletted)
 	case cbTCA8:
 		bpp = 4
 	case cbTC16:
@@ -323,12 +317,13 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 		case cbTC8:
 			// We have previously verified that the alpha value is fully opaque.
 			cr0 := cr[0]
-			if rgba != nil {
-				yoff := y * rgba.Stride
-				for _, color := range rgba.Pix[yoff+b.Min.X : yoff+b.Max.X] {
-					cr0[i+0] = color.R
-					cr0[i+1] = color.G
-					cr0[i+2] = color.B
+			if rgba, _ := m.(*image.RGBA); rgba != nil {
+				j0 := (y - b.Min.Y) * rgba.Stride
+				j1 := j0 + b.Dx()*4
+				for j := j0; j < j1; j += 4 {
+					cr0[i+0] = rgba.Pix[j+0]
+					cr0[i+1] = rgba.Pix[j+1]
+					cr0[i+2] = rgba.Pix[j+2]
 					i += 3
 				}
 			} else {
@@ -341,8 +336,9 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 				}
 			}
 		case cbP8:
-			rowOffset := y * paletted.Stride
-			copy(cr[0][1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X])
+			paletted := m.(*image.Paletted)
+			offset := (y - b.Min.Y) * paletted.Stride
+			copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
 		case cbTCA8:
 			// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
 			for x := b.Min.X; x < b.Max.X; x++ {
diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go
index 271519a..1599791 100644
--- a/src/pkg/image/png/writer_test.go
+++ b/src/pkg/image/png/writer_test.go
@@ -81,14 +81,14 @@ func TestWriter(t *testing.T) {
 	}
 }
 
-func TestSubimage(t *testing.T) {
+func TestSubImage(t *testing.T) {
 	m0 := image.NewRGBA(256, 256)
 	for y := 0; y < 256; y++ {
 		for x := 0; x < 256; x++ {
 			m0.Set(x, y, image.RGBAColor{uint8(x), uint8(y), 0, 255})
 		}
 	}
-	m0.Rect = image.Rect(50, 30, 250, 130)
+	m0 = m0.SubImage(image.Rect(50, 30, 250, 130)).(*image.RGBA)
 	m1, err := encodeDecode(m0)
 	if err != nil {
 		t.Error(err)
diff --git a/src/pkg/image/tiff/reader.go b/src/pkg/image/tiff/reader.go
index 26e5214..f565266 100644
--- a/src/pkg/image/tiff/reader.go
+++ b/src/pkg/image/tiff/reader.go
@@ -362,6 +362,10 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
 
 	// Check if we have the right number of strips, offsets and counts.
 	rps := int(d.firstVal(tRowsPerStrip))
+	if rps == 0 {
+		// Assume only one strip.
+		rps = d.config.Height
+	}
 	numStrips := (d.config.Height + rps - 1) / rps
 	if rps == 0 || len(d.features[tStripOffsets]) < numStrips || len(d.features[tStripByteCounts]) < numStrips {
 		return nil, FormatError("inconsistent header")
diff --git a/src/pkg/image/tiff/reader_test.go b/src/pkg/image/tiff/reader_test.go
new file mode 100644
index 0000000..f2122c4
--- /dev/null
+++ b/src/pkg/image/tiff/reader_test.go
@@ -0,0 +1,25 @@
+// 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 tiff
+
+import (
+	"os"
+	"testing"
+)
+
+// TestNoRPS tries to decode an image that has no RowsPerStrip tag.
+// The tag is mandatory according to the spec but some software omits
+// it in the case of a single strip.
+func TestNoRPS(t *testing.T) {
+	f, err := os.Open("testdata/no_rps.tiff")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	_, err = Decode(f)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/src/pkg/image/tiff/testdata/no_rps.tiff b/src/pkg/image/tiff/testdata/no_rps.tiff
new file mode 100644
index 0000000..3280cf8
Binary files /dev/null and b/src/pkg/image/tiff/testdata/no_rps.tiff differ
diff --git a/src/pkg/index/suffixarray/qsufsort.go b/src/pkg/index/suffixarray/qsufsort.go
index 9751b5c..30c1104 100644
--- a/src/pkg/index/suffixarray/qsufsort.go
+++ b/src/pkg/index/suffixarray/qsufsort.go
@@ -72,7 +72,6 @@ func qsufsort(data []byte) []int {
 	return sa
 }
 
-
 func sortedByFirstByte(data []byte) []int {
 	// total byte counts
 	var count [256]int
@@ -93,7 +92,6 @@ func sortedByFirstByte(data []byte) []int {
 	return sa
 }
 
-
 func initGroups(sa []int, data []byte) []int {
 	// label contiguous same-letter groups with the same group number
 	inv := make([]int, len(data))
@@ -133,7 +131,6 @@ func initGroups(sa []int, data []byte) []int {
 	return inv
 }
 
-
 type suffixSortable struct {
 	sa  []int
 	inv []int
@@ -144,7 +141,6 @@ func (x *suffixSortable) Len() int           { return len(x.sa) }
 func (x *suffixSortable) Less(i, j int) bool { return x.inv[x.sa[i]+x.h] < x.inv[x.sa[j]+x.h] }
 func (x *suffixSortable) Swap(i, j int)      { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
 
-
 func (x *suffixSortable) updateGroups(offset int) {
 	bounds := make([]int, 0, 4)
 	group := x.inv[x.sa[0]+x.h]
diff --git a/src/pkg/index/suffixarray/suffixarray.go b/src/pkg/index/suffixarray/suffixarray.go
index 9d4e932..82e98d2 100644
--- a/src/pkg/index/suffixarray/suffixarray.go
+++ b/src/pkg/index/suffixarray/suffixarray.go
@@ -22,21 +22,18 @@ import (
 	"sort"
 )
 
-
 // Index implements a suffix array for fast substring search.
 type Index struct {
 	data []byte
 	sa   []int // suffix array for data
 }
 
-
 // New creates a new Index for data.
 // Index creation time is O(N*log(N)) for N = len(data).
 func New(data []byte) *Index {
 	return &Index{data, qsufsort(data)}
 }
 
-
 // Bytes returns the data over which the index was created.
 // It must not be modified.
 //
@@ -44,12 +41,10 @@ func (x *Index) Bytes() []byte {
 	return x.data
 }
 
-
 func (x *Index) at(i int) []byte {
 	return x.data[x.sa[i]:]
 }
 
-
 // lookupAll returns a slice into the matching region of the index.
 // The runtime is O(log(N)*len(s)).
 func (x *Index) lookupAll(s []byte) []int {
@@ -61,7 +56,6 @@ func (x *Index) lookupAll(s []byte) []int {
 	return x.sa[i:j]
 }
 
-
 // Lookup returns an unsorted list of at most n indices where the byte string s
 // occurs in the indexed data. If n < 0, all occurrences are returned.
 // The result is nil if s is empty, s is not found, or n == 0.
@@ -82,7 +76,6 @@ func (x *Index) Lookup(s []byte, n int) (result []int) {
 	return
 }
 
-
 // FindAllIndex returns a sorted list of non-overlapping matches of the
 // regular expression r, where a match is a pair of indices specifying
 // the matched slice of x.Bytes(). If n < 0, all matches are returned
diff --git a/src/pkg/index/suffixarray/suffixarray_test.go b/src/pkg/index/suffixarray/suffixarray_test.go
index 385ff0e..bd37ba4 100644
--- a/src/pkg/index/suffixarray/suffixarray_test.go
+++ b/src/pkg/index/suffixarray/suffixarray_test.go
@@ -13,14 +13,12 @@ import (
 	"testing"
 )
 
-
 type testCase struct {
 	name     string   // name of test case
 	source   string   // source to index
 	patterns []string // patterns to lookup
 }
 
-
 var testCases = []testCase{
 	{
 		"empty string",
@@ -107,7 +105,6 @@ var testCases = []testCase{
 	},
 }
 
-
 // find all occurrences of s in source; report at most n occurrences
 func find(src, s string, n int) []int {
 	var res vector.IntVector
@@ -125,7 +122,6 @@ func find(src, s string, n int) []int {
 	return res
 }
 
-
 func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
 	res := x.Lookup([]byte(s), n)
 	exp := find(tc.source, s, n)
@@ -164,7 +160,6 @@ func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
 	}
 }
 
-
 func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n int) {
 	res := x.FindAllIndex(rx, n)
 	exp := rx.FindAllStringIndex(tc.source, n)
@@ -200,7 +195,6 @@ func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n
 	}
 }
 
-
 func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
 	for _, pat := range tc.patterns {
 		testLookup(t, tc, x, pat, n)
@@ -210,7 +204,6 @@ func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
 	}
 }
 
-
 // index is used to hide the sort.Interface
 type index Index
 
@@ -219,14 +212,12 @@ func (x *index) Less(i, j int) bool { return bytes.Compare(x.at(i), x.at(j)) < 0
 func (x *index) Swap(i, j int)      { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
 func (a *index) at(i int) []byte    { return a.data[a.sa[i]:] }
 
-
 func testConstruction(t *testing.T, tc *testCase, x *Index) {
 	if !sort.IsSorted((*index)(x)) {
 		t.Errorf("testConstruction failed %s", tc.name)
 	}
 }
 
-
 func TestIndex(t *testing.T) {
 	for _, tc := range testCases {
 		x := New([]byte(tc.source))
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index f79bf87..fffa132 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -108,6 +108,23 @@ func (devNull) Write(p []byte) (int, os.Error) {
 	return len(p), nil
 }
 
+var blackHole = make([]byte, 8192)
+
+func (devNull) ReadFrom(r io.Reader) (n int64, err os.Error) {
+	readSize := 0
+	for {
+		readSize, err = r.Read(blackHole)
+		n += int64(readSize)
+		if err != nil {
+			if err == os.EOF {
+				return n, nil
+			}
+			return
+		}
+	}
+	panic("unreachable")
+}
+
 // Discard is an io.Writer on which all Write calls succeed
 // without doing anything.
 var Discard io.Writer = devNull(0)
diff --git a/src/pkg/io/ioutil/ioutil_test.go b/src/pkg/io/ioutil/ioutil_test.go
index 150ee6d..55e4b2c 100644
--- a/src/pkg/io/ioutil/ioutil_test.go
+++ b/src/pkg/io/ioutil/ioutil_test.go
@@ -59,7 +59,6 @@ func TestWriteFile(t *testing.T) {
 	os.Remove(filename) // ignore error
 }
 
-
 func TestReadDir(t *testing.T) {
 	dirname := "rumpelstilzchen"
 	_, err := ReadDir(dirname)
diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go
index 35a06b0..7d474fa 100644
--- a/src/pkg/json/decode.go
+++ b/src/pkg/json/decode.go
@@ -8,7 +8,6 @@
 package json
 
 import (
-	"container/vector"
 	"encoding/base64"
 	"os"
 	"reflect"
@@ -71,7 +70,6 @@ type Unmarshaler interface {
 	UnmarshalJSON([]byte) os.Error
 }
 
-
 // An UnmarshalTypeError describes a JSON value that was
 // not appropriate for a value of a specific Go type.
 type UnmarshalTypeError struct {
@@ -670,7 +668,7 @@ func (d *decodeState) valueInterface() interface{} {
 
 // arrayInterface is like array but returns []interface{}.
 func (d *decodeState) arrayInterface() []interface{} {
-	var v vector.Vector
+	var v []interface{}
 	for {
 		// Look ahead for ] - can only happen on first iteration.
 		op := d.scanWhile(scanSkipSpace)
@@ -682,7 +680,7 @@ func (d *decodeState) arrayInterface() []interface{} {
 		d.off--
 		d.scan.undo(op)
 
-		v.Push(d.valueInterface())
+		v = append(v, d.valueInterface())
 
 		// Next token must be , or ].
 		op = d.scanWhile(scanSkipSpace)
@@ -742,7 +740,6 @@ func (d *decodeState) objectInterface() map[string]interface{} {
 	return m
 }
 
-
 // literalInterface is like literal but returns an interface value.
 func (d *decodeState) literalInterface() interface{} {
 	// All bytes inside literal return scanContinue op code.
diff --git a/src/pkg/json/decode_test.go b/src/pkg/json/decode_test.go
index 9b84bc7..c0ef5bc 100644
--- a/src/pkg/json/decode_test.go
+++ b/src/pkg/json/decode_test.go
@@ -40,13 +40,6 @@ var (
 	umtrue   = unmarshaler{true}
 )
 
-type badTag struct {
-	X string
-	Y string `json:"y"`
-	Z string `x:"@#*%(#@"`
-	W string `json:"@#$@#$"`
-}
-
 type unmarshalTest struct {
 	in  string
 	ptr interface{}
@@ -68,9 +61,6 @@ var unmarshalTests = []unmarshalTest{
 	{`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
 	{`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
 
-	// skip invalid tags
-	{`{"X":"a", "y":"b", "Z":"c", "W":"d"}`, new(badTag), badTag{"a", "b", "c", "d"}, nil},
-
 	// syntax errors
 	{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
 
@@ -218,6 +208,18 @@ func TestUnmarshalPtrPtr(t *testing.T) {
 	}
 }
 
+func TestEscape(t *testing.T) {
+	const input = `"foobar"<html>`
+	const expected = `"\"foobar\"\u003chtml\u003e"`
+	b, err := Marshal(input)
+	if err != nil {
+		t.Fatalf("Marshal error: %v", err)
+	}
+	if s := string(b); s != expected {
+		t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
+	}
+}
+
 func TestHTMLEscape(t *testing.T) {
 	b, err := MarshalForHTML("foobarbaz<>&quux")
 	if err != nil {
diff --git a/src/pkg/json/encode.go b/src/pkg/json/encode.go
index adc0f0f..3e593fe 100644
--- a/src/pkg/json/encode.go
+++ b/src/pkg/json/encode.go
@@ -14,6 +14,7 @@ import (
 	"runtime"
 	"sort"
 	"strconv"
+	"strings"
 	"unicode"
 	"utf8"
 )
@@ -36,13 +37,30 @@ import (
 // Array and slice values encode as JSON arrays, except that
 // []byte encodes as a base64-encoded string.
 //
-// Struct values encode as JSON objects.  Each exported struct field
-// becomes a member of the object.  By default the object's key string
-// is the struct field name.  If the struct field's tag has a "json" key with a
-// value that is a non-empty string consisting of only Unicode letters,
-// digits, and underscores, that value will be used as the object key.
-// For example, the field tag `json:"myName"` says to use "myName"
-// as the object key.
+// Struct values encode as JSON objects. Each exported struct field
+// becomes a member of the object unless the field is empty and its tag
+// specifies the "omitempty" option. The empty values are false, 0, any
+// nil pointer or interface value, and any array, slice, map, or string of
+// length zero. The object's default key string is the struct field name
+// but can be specified in the struct field's tag value. The "json" key in
+// struct field's tag value is the key name, followed by an optional comma
+// and options. Examples:
+//
+//   // Specifies that Field appears in JSON as key "myName"
+//   Field int `json:"myName"`
+//
+//   // Specifies that Field appears in JSON as key "myName" and
+//   // the field is omitted from the object if its value is empty,
+//   // as defined above.
+//   Field int `json:"myName,omitempty"`
+//
+//   // Field appears in JSON as key "Field" (the default), but
+//   // the field is skipped if empty.
+//   // Note the leading comma.
+//   Field int `json:",omitempty"`
+//
+// The key name will be used if it's a non-empty string consisting of
+// only Unicode letters, digits, dollar signs, hyphens, and underscores.
 //
 // Map values encode as JSON objects.
 // The map's key type must be string; the object keys are used directly
@@ -184,6 +202,24 @@ func (e *encodeState) error(err os.Error) {
 
 var byteSliceType = reflect.TypeOf([]byte(nil))
 
+func isEmptyValue(v reflect.Value) bool {
+	switch v.Kind() {
+	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+		return v.Len() == 0
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Interface, reflect.Ptr:
+		return v.IsNil()
+	}
+	return false
+}
+
 func (e *encodeState) reflectValue(v reflect.Value) {
 	if !v.IsValid() {
 		e.WriteString("null")
@@ -233,18 +269,30 @@ func (e *encodeState) reflectValue(v reflect.Value) {
 			if f.PkgPath != "" {
 				continue
 			}
+			tag, omitEmpty := f.Name, false
+			if tv := f.Tag.Get("json"); tv != "" {
+				ss := strings.SplitN(tv, ",", 2)
+				if isValidTag(ss[0]) {
+					tag = ss[0]
+				}
+				if len(ss) > 1 {
+					// Currently the only option is omitempty,
+					// so parsing is trivial.
+					omitEmpty = ss[1] == "omitempty"
+				}
+			}
+			fieldValue := v.Field(i)
+			if omitEmpty && isEmptyValue(fieldValue) {
+				continue
+			}
 			if first {
 				first = false
 			} else {
 				e.WriteByte(',')
 			}
-			if tag := f.Tag.Get("json"); tag != "" && isValidTag(tag) {
-				e.string(tag)
-			} else {
-				e.string(f.Name)
-			}
+			e.string(tag)
 			e.WriteByte(':')
-			e.reflectValue(v.Field(i))
+			e.reflectValue(fieldValue)
 		}
 		e.WriteByte('}')
 
@@ -316,7 +364,7 @@ func isValidTag(s string) bool {
 		return false
 	}
 	for _, c := range s {
-		if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+		if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
 			return false
 		}
 	}
@@ -337,17 +385,28 @@ func (e *encodeState) string(s string) {
 	start := 0
 	for i := 0; i < len(s); {
 		if b := s[i]; b < utf8.RuneSelf {
-			if 0x20 <= b && b != '\\' && b != '"' {
+			if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' {
 				i++
 				continue
 			}
 			if start < i {
 				e.WriteString(s[start:i])
 			}
-			if b == '\\' || b == '"' {
+			switch b {
+			case '\\', '"':
 				e.WriteByte('\\')
 				e.WriteByte(b)
-			} else {
+			case '\n':
+				e.WriteByte('\\')
+				e.WriteByte('n')
+			case '\r':
+				e.WriteByte('\\')
+				e.WriteByte('r')
+			default:
+				// This encodes bytes < 0x20 except for \n and \r,
+				// as well as < and >. The latter are escaped because they
+				// can lead to security holes when user-controlled strings
+				// are rendered into JSON and served to some browsers.
 				e.WriteString(`\u00`)
 				e.WriteByte(hex[b>>4])
 				e.WriteByte(hex[b&0xF])
diff --git a/src/pkg/json/encode_test.go b/src/pkg/json/encode_test.go
new file mode 100644
index 0000000..0e4b637
--- /dev/null
+++ b/src/pkg/json/encode_test.go
@@ -0,0 +1,44 @@
+// 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 json
+
+import (
+	"testing"
+)
+
+type Optionals struct {
+	Sr string `json:"sr"`
+	So string `json:"so,omitempty"`
+
+	Ir int `json:"omitempty"` // actually named omitempty, not an option
+	Io int `json:"io,omitempty"`
+
+	Slr []string `json:"slr,random"`
+	Slo []string `json:"slo,omitempty"`
+
+	Mr map[string]interface{} `json:"mr"`
+	Mo map[string]interface{} `json:",omitempty"`
+}
+
+var optionalsExpected = `{
+ "sr": "",
+ "omitempty": 0,
+ "slr": [],
+ "mr": {}
+}`
+
+func TestOmitEmpty(t *testing.T) {
+	var o Optionals
+	o.Mr = map[string]interface{}{}
+	o.Mo = map[string]interface{}{}
+
+	got, err := MarshalIndent(&o, "", " ")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got := string(got); got != optionalsExpected {
+		t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
+	}
+}
diff --git a/src/pkg/json/tagkey_test.go b/src/pkg/json/tagkey_test.go
new file mode 100644
index 0000000..31fe2be
--- /dev/null
+++ b/src/pkg/json/tagkey_test.go
@@ -0,0 +1,95 @@
+// 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 json
+
+import (
+	"testing"
+)
+
+type basicLatin2xTag struct {
+	V string `json:"$-"`
+}
+
+type basicLatin3xTag struct {
+	V string `json:"0123456789"`
+}
+
+type basicLatin4xTag struct {
+	V string `json:"ABCDEFGHIJKLMO"`
+}
+
+type basicLatin5xTag struct {
+	V string `json:"PQRSTUVWXYZ_"`
+}
+
+type basicLatin6xTag struct {
+	V string `json:"abcdefghijklmno"`
+}
+
+type basicLatin7xTag struct {
+	V string `json:"pqrstuvwxyz"`
+}
+
+type miscPlaneTag struct {
+	V string `json:"色は匂へど"`
+}
+
+type emptyTag struct {
+	W string
+}
+
+type misnamedTag struct {
+	X string `jsom:"Misnamed"`
+}
+
+type badFormatTag struct {
+	Y string `:"BadFormat"`
+}
+
+type badCodeTag struct {
+	Z string `json:" !\"#%&'()*+,./"`
+}
+
+var structTagObjectKeyTests = []struct {
+	raw   interface{}
+	value string
+	key   string
+}{
+	{basicLatin2xTag{"2x"}, "2x", "$-"},
+	{basicLatin3xTag{"3x"}, "3x", "0123456789"},
+	{basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
+	{basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
+	{basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
+	{basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
+	{miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
+	{emptyTag{"Pour Moi"}, "Pour Moi", "W"},
+	{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
+	{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
+	{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
+}
+
+func TestStructTagObjectKey(t *testing.T) {
+	for _, tt := range structTagObjectKeyTests {
+		b, err := Marshal(tt.raw)
+		if err != nil {
+			t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
+		}
+		var f interface{}
+		err = Unmarshal(b, &f)
+		if err != nil {
+			t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
+		}
+		for i, v := range f.(map[string]interface{}) {
+			switch i {
+			case tt.key:
+				if s, ok := v.(string); !ok || s != tt.value {
+					t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
+				}
+			default:
+				t.Fatalf("Unexpected key: %#q", i)
+			}
+		}
+	}
+}
diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go
index 00bce6a..ec09743 100644
--- a/src/pkg/log/log.go
+++ b/src/pkg/log/log.go
@@ -41,9 +41,9 @@ const (
 // the Writer's Write method.  A Logger can be used simultaneously from
 // multiple goroutines; it guarantees to serialize access to the Writer.
 type Logger struct {
+	mu     sync.Mutex   // ensures atomic writes; protects the following fields
 	prefix string       // prefix to write at beginning of each line
 	flag   int          // properties
-	mu     sync.Mutex   // ensures atomic writes; protects the following fields
 	out    io.Writer    // destination for output
 	buf    bytes.Buffer // for accumulating text to write
 }
@@ -134,19 +134,21 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int
 // paths it will be 2.
 func (l *Logger) Output(calldepth int, s string) os.Error {
 	now := time.Nanoseconds() // get this early.
-	// get caller info (if required) before locking - it's expensive.
 	var file string
 	var line int
+	l.mu.Lock()
+	defer l.mu.Unlock()
 	if l.flag&(Lshortfile|Llongfile) != 0 {
+		// release lock while getting caller info - it's expensive.
+		l.mu.Unlock()
 		var ok bool
 		_, file, line, ok = runtime.Caller(calldepth)
 		if !ok {
 			file = "???"
 			line = 0
 		}
+		l.mu.Lock()
 	}
-	l.mu.Lock()
-	defer l.mu.Unlock()
 	l.buf.Reset()
 	l.formatHeader(&l.buf, now, file, line)
 	l.buf.WriteString(s)
@@ -212,26 +214,36 @@ func (l *Logger) Panicln(v ...interface{}) {
 
 // Flags returns the output flags for the logger.
 func (l *Logger) Flags() int {
+	l.mu.Lock()
+	defer l.mu.Unlock()
 	return l.flag
 }
 
 // SetFlags sets the output flags for the logger.
 func (l *Logger) SetFlags(flag int) {
+	l.mu.Lock()
+	defer l.mu.Unlock()
 	l.flag = flag
 }
 
 // Prefix returns the output prefix for the logger.
 func (l *Logger) Prefix() string {
+	l.mu.Lock()
+	defer l.mu.Unlock()
 	return l.prefix
 }
 
 // SetPrefix sets the output prefix for the logger.
 func (l *Logger) SetPrefix(prefix string) {
+	l.mu.Lock()
+	defer l.mu.Unlock()
 	l.prefix = prefix
 }
 
 // SetOutput sets the output destination for the standard logger.
 func SetOutput(w io.Writer) {
+	std.mu.Lock()
+	defer std.mu.Unlock()
 	std.out = w
 }
 
diff --git a/src/pkg/math/acosh.go b/src/pkg/math/acosh.go
index d8067c0..7e8740b 100644
--- a/src/pkg/math/acosh.go
+++ b/src/pkg/math/acosh.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c
 // and came with this notice.  The go code is a simplified
diff --git a/src/pkg/math/asin.go b/src/pkg/math/asin.go
index 3bace8f..0a0b0a1 100644
--- a/src/pkg/math/asin.go
+++ b/src/pkg/math/asin.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating-point arcsine and arccosine.
 
diff --git a/src/pkg/math/asinh.go b/src/pkg/math/asinh.go
index 90dcd27..c1cad56 100644
--- a/src/pkg/math/asinh.go
+++ b/src/pkg/math/asinh.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c
 // and came with this notice.  The go code is a simplified
diff --git a/src/pkg/math/atanh.go b/src/pkg/math/atanh.go
index 6aecb7b..ed38fca 100644
--- a/src/pkg/math/atanh.go
+++ b/src/pkg/math/atanh.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c
 // and came with this notice.  The go code is a simplified
diff --git a/src/pkg/math/erf.go b/src/pkg/math/erf.go
index b608999..6d3d9b7 100644
--- a/src/pkg/math/erf.go
+++ b/src/pkg/math/erf.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating-point error function and complementary error function.
 */
diff --git a/src/pkg/math/exp_port.go b/src/pkg/math/exp_port.go
index 071420c..618c31a 100644
--- a/src/pkg/math/exp_port.go
+++ b/src/pkg/math/exp_port.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
 // and came with this notice.  The go code is a simplified
diff --git a/src/pkg/math/expm1.go b/src/pkg/math/expm1.go
index 35100ca..e9f8331 100644
--- a/src/pkg/math/expm1.go
+++ b/src/pkg/math/expm1.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.c
 // and came with this notice.  The go code is a simplified
diff --git a/src/pkg/math/floor.go b/src/pkg/math/floor.go
index b22b94a..babbf64 100644
--- a/src/pkg/math/floor.go
+++ b/src/pkg/math/floor.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // Floor returns the greatest integer value less than or equal to x.
 //
 // Special cases are:
diff --git a/src/pkg/math/fmod.go b/src/pkg/math/fmod.go
index fc57f74..75c6146 100644
--- a/src/pkg/math/fmod.go
+++ b/src/pkg/math/fmod.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating-point mod function.
 */
diff --git a/src/pkg/math/log1p.go b/src/pkg/math/log1p.go
index e1fc275..c25d73b 100644
--- a/src/pkg/math/log1p.go
+++ b/src/pkg/math/log1p.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
 // and came with this notice.  The go code is a simplified
diff --git a/src/pkg/math/sin.go b/src/pkg/math/sin.go
index 35220cb..8a2edd7 100644
--- a/src/pkg/math/sin.go
+++ b/src/pkg/math/sin.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating-point sine and cosine.
 
diff --git a/src/pkg/math/sinh.go b/src/pkg/math/sinh.go
index 23a8719..eaf28a5 100644
--- a/src/pkg/math/sinh.go
+++ b/src/pkg/math/sinh.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating-point hyperbolic sine and cosine.
 
diff --git a/src/pkg/math/tan.go b/src/pkg/math/tan.go
index a36ebbf..6d7a60b 100644
--- a/src/pkg/math/tan.go
+++ b/src/pkg/math/tan.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating point tangent.
 */
diff --git a/src/pkg/math/tanh.go b/src/pkg/math/tanh.go
index 8bcf2dd..f4a8a5a 100644
--- a/src/pkg/math/tanh.go
+++ b/src/pkg/math/tanh.go
@@ -4,7 +4,6 @@
 
 package math
 
-
 /*
 	Floating-point hyperbolic tangent.
 
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 4711fd7..2533bd3 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -21,7 +21,6 @@ import (
 	"mime"
 	"net/textproto"
 	"os"
-	"regexp"
 )
 
 // TODO(bradfitz): inline these once the compiler can inline them in
@@ -29,8 +28,6 @@ import (
 var lf = []byte("\n")
 var crlf = []byte("\r\n")
 
-var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
-
 var emptyParams = make(map[string]string)
 
 // A Part represents a single part in a multipart body.
@@ -61,7 +58,6 @@ func (p *Part) FormName() string {
 	return p.dispositionParams["name"]
 }
 
-
 // FileName returns the filename parameter of the Part's
 // Content-Disposition header.
 func (p *Part) FileName() string {
@@ -106,22 +102,12 @@ func newPart(mr *Reader) (*Part, os.Error) {
 }
 
 func (bp *Part) populateHeaders() os.Error {
-	for {
-		lineBytes, err := bp.mr.bufReader.ReadSlice('\n')
-		if err != nil {
-			return err
-		}
-		line := string(lineBytes)
-		if line == "\n" || line == "\r\n" {
-			return nil
-		}
-		if matches := headerRegexp.FindStringSubmatch(line); len(matches) == 3 {
-			bp.Header.Add(matches[1], matches[2])
-			continue
-		}
-		return os.NewError("Unexpected header line found parsing multipart body")
+	r := textproto.NewReader(bp.mr.bufReader)
+	header, err := r.ReadMIMEHeader()
+	if err == nil {
+		bp.Header = header
 	}
-	panic("unreachable")
+	return err
 }
 
 // Read reads the body of a part, after its headers and before the
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
index 1357466..38079e5 100644
--- a/src/pkg/mime/multipart/multipart_test.go
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -141,14 +141,14 @@ func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
 		t.Error("Expected part1")
 		return
 	}
-	if part.Header.Get("Header1") != "value1" {
-		t.Error("Expected Header1: value")
+	if x := part.Header.Get("Header1"); x != "value1" {
+		t.Errorf("part.Header.Get(%q) = %q, want %q", "Header1", x, "value1")
 	}
-	if part.Header.Get("foo-bar") != "baz" {
-		t.Error("Expected foo-bar: baz")
+	if x := part.Header.Get("foo-bar"); x != "baz" {
+		t.Errorf("part.Header.Get(%q) = %q, want %q", "foo-bar", x, "baz")
 	}
-	if part.Header.Get("Foo-Bar") != "baz" {
-		t.Error("Expected Foo-Bar: baz")
+	if x := part.Header.Get("Foo-Bar"); x != "baz" {
+		t.Errorf("part.Header.Get(%q) = %q, want %q", "Foo-Bar", x, "baz")
 	}
 	buf.Reset()
 	if _, err := io.Copy(buf, part); err != nil {
@@ -352,3 +352,29 @@ func (s *slowReader) Read(p []byte) (int, os.Error) {
 	}
 	return s.r.Read(p[:1])
 }
+
+func TestLineContinuation(t *testing.T) {
+	// This body, extracted from an email, contains headers that span multiple
+	// lines.
+
+	// TODO: The original mail ended with a double-newline before the
+	// final delimiter; this was manually edited to use a CRLF.
+	testBody :=
+		"\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: 7bit\nContent-Type: text/plain;\n\tcharset=US-ASCII;\n\tdelsp=yes;\n\tformat=flowed\n\nI'm finding the same thing happening on my system (10.4.1).\n\n\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: quoted-printable\nContent-Type: text/html;\n\tcharset=ISO-8859-1\n\n<HTML><BODY>I'm finding the same thing =\nhappening on my system (10.4.1).=A0 But I built it with XCode =\n2.0.</BODY></=\nHTML>=\n\r\n--Apple-Mail-2-292336769--\n"
+
+	r := NewReader(strings.NewReader(testBody), "Apple-Mail-2-292336769")
+
+	for i := 0; i < 2; i++ {
+		part, err := r.NextPart()
+		if err != nil {
+			t.Fatalf("didn't get a part")
+		}
+		n, err := io.Copy(ioutil.Discard, part)
+		if err != nil {
+			t.Errorf("error reading part: %v", err)
+		}
+		if n <= 0 {
+			t.Errorf("read %d bytes; expected >0", n)
+		}
+	}
+}
diff --git a/src/pkg/mime/type.go b/src/pkg/mime/type.go
index 8c43b81..8ecfe9a 100644
--- a/src/pkg/mime/type.go
+++ b/src/pkg/mime/type.go
@@ -19,7 +19,7 @@ var typeFiles = []string{
 }
 
 var mimeTypes = map[string]string{
-	".css":  "text/css",
+	".css":  "text/css; charset=utf-8",
 	".gif":  "image/gif",
 	".htm":  "text/html; charset=utf-8",
 	".html": "text/html; charset=utf-8",
diff --git a/src/pkg/net/dict/dict.go b/src/pkg/net/dict/dict.go
index 42f6553..b146ea2 100644
--- a/src/pkg/net/dict/dict.go
+++ b/src/pkg/net/dict/dict.go
@@ -7,7 +7,6 @@
 package dict
 
 import (
-	"container/vector"
 	"net/textproto"
 	"os"
 	"strconv"
@@ -144,7 +143,7 @@ func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
 // Fields are space separated unquoted words
 // or quoted with single or double quote.
 func fields(s string) ([]string, os.Error) {
-	var v vector.StringVector
+	var v []string
 	i := 0
 	for {
 		for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
@@ -170,7 +169,7 @@ func fields(s string) ([]string, os.Error) {
 					break
 				}
 			}
-			v.Push(unquote(s[i+1 : j-1]))
+			v = append(v, unquote(s[i+1:j-1]))
 			i = j
 		} else {
 			// atom
@@ -180,7 +179,7 @@ func fields(s string) ([]string, os.Error) {
 					break
 				}
 			}
-			v.Push(s[i:j])
+			v = append(v, s[i:j])
 			i = j
 		}
 		if i < len(s) {
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index 7f3ef28..f407b17 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/net/dnsclient_unix.go
@@ -68,7 +68,6 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er
 	return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
 }
 
-
 // Do a lookup for a single name, which must be rooted
 // (otherwise answer will not find the answers).
 func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index 640973b..7595aa2 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -635,7 +635,6 @@ type dnsMsg struct {
 	extra    []dnsRR
 }
 
-
 func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
 	var dh dnsHeader
 
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 41d0612..3757e14 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -113,7 +113,6 @@ func (s *resultSrv) Run() {
 	}
 }
 
-
 // ioSrv executes net io requests.
 type ioSrv struct {
 	submchan chan anOpIface // submit io requests
@@ -155,7 +154,7 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error)
 	case 0:
 		// IO completed immediately, but we need to get our completion message anyway.
 	case syscall.ERROR_IO_PENDING:
-		// IO started, and we have to wait for it's completion.
+		// IO started, and we have to wait for its completion.
 	default:
 		return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
 	}
@@ -273,7 +272,7 @@ func (fd *netFD) incref() {
 func (fd *netFD) decref() {
 	fd.sysmu.Lock()
 	fd.sysref--
-	if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+	if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
 		// In case the user has set linger, switch to blocking mode so
 		// the close blocks.  As long as this doesn't happen often, we
 		// can handle the extra OS processes.  Otherwise we'll need to
@@ -338,13 +337,13 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
 
 type readFromOp struct {
 	bufOp
-	rsa syscall.RawSockaddrAny
+	rsa  syscall.RawSockaddrAny
+	rsan int32
 }
 
 func (o *readFromOp) Submit() (errno int) {
 	var d, f uint32
-	l := int32(unsafe.Sizeof(o.rsa))
-	return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil)
+	return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
 }
 
 func (o *readFromOp) Name() string {
@@ -367,7 +366,11 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error)
 	}
 	var o readFromOp
 	o.Init(fd, buf)
+	o.rsan = int32(unsafe.Sizeof(o.rsa))
 	n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+	if err != nil {
+		return 0, nil, err
+	}
 	sa, _ = o.rsa.Sockaddr()
 	return
 }
@@ -493,7 +496,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
 	}
 
 	// Inherit properties of the listening socket.
-	e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, int(fd.sysfd))
+	e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
 	if e != 0 {
 		closesocket(s)
 		return nil, err
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
index 198e409..571f74c 100644
--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -55,7 +55,6 @@ func getInterfaceList() ([]syscall.InterfaceInfo, os.Error) {
 	return ii[:c-1], nil
 }
 
-
 // If the ifindex is zero, interfaceTable returns mappings of all
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 7cc9604..6894ce6 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-
 // TODO(cw): ListenPacket test, Read() test, ipv6 test &
 // Dial()/Listen() level tests
 
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
index e653749..ce0ddc7 100644
--- a/src/pkg/net/textproto/reader.go
+++ b/src/pkg/net/textproto/reader.go
@@ -7,7 +7,6 @@ package textproto
 import (
 	"bufio"
 	"bytes"
-	"container/vector"
 	"io"
 	"io/ioutil"
 	"os"
@@ -33,22 +32,25 @@ func NewReader(r *bufio.Reader) *Reader {
 // ReadLine reads a single line from r,
 // eliding the final \n or \r\n from the returned string.
 func (r *Reader) ReadLine() (string, os.Error) {
-	line, err := r.ReadLineBytes()
+	line, err := r.readLineSlice()
 	return string(line), err
 }
 
 // ReadLineBytes is like ReadLine but returns a []byte instead of a string.
 func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
-	r.closeDot()
-	line, err := r.R.ReadBytes('\n')
-	n := len(line)
-	if n > 0 && line[n-1] == '\n' {
-		n--
-		if n > 0 && line[n-1] == '\r' {
-			n--
-		}
+	line, err := r.readLineSlice()
+	if line != nil {
+		buf := make([]byte, len(line))
+		copy(buf, line)
+		line = buf
 	}
-	return line[0:n], err
+	return line, err
+}
+
+func (r *Reader) readLineSlice() ([]byte, os.Error) {
+	r.closeDot()
+	line, _, err := r.R.ReadLine()
+	return line, err
 }
 
 // ReadContinuedLine reads a possibly continued line from r,
@@ -71,7 +73,7 @@ func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
 // A line consisting of only white space is never continued.
 //
 func (r *Reader) ReadContinuedLine() (string, os.Error) {
-	line, err := r.ReadContinuedLineBytes()
+	line, err := r.readContinuedLineSlice()
 	return string(line), err
 }
 
@@ -92,8 +94,18 @@ func trim(s []byte) []byte {
 // ReadContinuedLineBytes is like ReadContinuedLine but
 // returns a []byte instead of a string.
 func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+	line, err := r.readContinuedLineSlice()
+	if line != nil {
+		buf := make([]byte, len(line))
+		copy(buf, line)
+		line = buf
+	}
+	return line, err
+}
+
+func (r *Reader) readContinuedLineSlice() ([]byte, os.Error) {
 	// Read the first line.
-	line, err := r.ReadLineBytes()
+	line, err := r.readLineSlice()
 	if err != nil {
 		return line, err
 	}
@@ -102,6 +114,13 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
 	}
 	line = trim(line)
 
+	copied := false
+	if r.R.Buffered() < 1 {
+		// ReadByte will flush the buffer; make a copy of the slice.
+		copied = true
+		line = append([]byte(nil), line...)
+	}
+
 	// Look for a continuation line.
 	c, err := r.R.ReadByte()
 	if err != nil {
@@ -114,6 +133,11 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
 		return line, nil
 	}
 
+	if !copied {
+		// The next readLineSlice will invalidate the previous one.
+		line = append(make([]byte, 0, len(line)*2), line...)
+	}
+
 	// Read continuation lines.
 	for {
 		// Consume leading spaces; one already gone.
@@ -128,7 +152,7 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
 			}
 		}
 		var cont []byte
-		cont, err = r.ReadLineBytes()
+		cont, err = r.readLineSlice()
 		cont = trim(cont)
 		line = append(line, ' ')
 		line = append(line, cont...)
@@ -375,7 +399,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
 	// We could use ReadDotBytes and then Split it,
 	// but reading a line at a time avoids needing a
 	// large contiguous block of memory and is simpler.
-	var v vector.StringVector
+	var v []string
 	var err os.Error
 	for {
 		var line string
@@ -394,7 +418,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
 			}
 			line = line[1:]
 		}
-		v.Push(line)
+		v = append(v, line)
 	}
 	return v, err
 }
@@ -422,7 +446,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
 func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
 	m := make(MIMEHeader)
 	for {
-		kv, err := r.ReadContinuedLineBytes()
+		kv, err := r.readContinuedLineSlice()
 		if len(kv) == 0 {
 			return m, err
 		}
@@ -441,9 +465,7 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
 		}
 		value := string(kv[i:])
 
-		v := vector.StringVector(m[key])
-		v.Push(value)
-		m[key] = v
+		m[key] = append(m[key], value)
 
 		if err != nil {
 			return m, err
diff --git a/src/pkg/os/env_unix.go b/src/pkg/os/env_unix.go
index 8aa71e8..9cc0b03 100644
--- a/src/pkg/os/env_unix.go
+++ b/src/pkg/os/env_unix.go
@@ -16,7 +16,6 @@ var ENOENV = NewError("no such environment variable")
 var env map[string]string
 var once sync.Once
 
-
 func copyenv() {
 	env = make(map[string]string)
 	for _, s := range Envs {
diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go
index e2234f1..33e223f 100644
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -13,10 +13,11 @@ import (
 type Process struct {
 	Pid    int
 	handle int
+	done   bool // process has been successfuly waited on
 }
 
 func newProcess(pid, handle int) *Process {
-	p := &Process{pid, handle}
+	p := &Process{Pid: pid, handle: handle}
 	runtime.SetFinalizer(p, (*Process).Release)
 	return p
 }
@@ -45,6 +46,11 @@ type ProcAttr struct {
 	Sys *syscall.SysProcAttr
 }
 
+// A Signal can represent any operating system signal.
+type Signal interface {
+	String() string
+}
+
 // Getpid returns the process id of the caller.
 func Getpid() int { return syscall.Getpid() }
 
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
index 2590dd6..6f0722a 100644
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -38,6 +38,27 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
 	return newProcess(pid, h), nil
 }
 
+// Plan9Note implements the Signal interface on Plan 9.
+type Plan9Note string
+
+func (note Plan9Note) String() string {
+	return string(note)
+}
+
+func (p *Process) Signal(sig Signal) Error {
+	if p.done {
+		return NewError("os: process already finished")
+	}
+
+	f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
+	if iserror(e) {
+		return NewSyscallError("signal", e)
+	}
+	defer f.Close()
+	_, e = f.Write([]byte(sig.String()))
+	return e
+}
+
 // Kill causes the Process to exit immediately.
 func (p *Process) Kill() Error {
 	f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
@@ -85,6 +106,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
 		}
 
 		if waitmsg.Pid == p.Pid {
+			p.done = true
 			break
 		}
 	}
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index e209770..f37bfab 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -9,11 +9,6 @@ import (
 	"syscall"
 )
 
-// A Signal can represent any operating system signal.
-type Signal interface {
-	String() string
-}
-
 type UnixSignal int32
 
 func (sig UnixSignal) String() string {
@@ -26,6 +21,9 @@ func (sig UnixSignal) String() string {
 
 // StartProcess starts a new process with the program, arguments and attributes
 // specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The exec package provides
+// higher-level interfaces.
 func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
 	sysattr := &syscall.ProcAttr{
 		Dir: attr.Dir,
@@ -54,7 +52,9 @@ func (p *Process) Kill() Error {
 // Exec replaces the current process with an execution of the
 // named binary, with arguments argv and environment envv.
 // If successful, Exec never returns.  If it fails, it returns an Error.
-// StartProcess is almost always a better way to execute a program.
+//
+// To run a child process, see StartProcess (for a low-level interface)
+// or the exec package (for higher-level interfaces).
 func Exec(name string, argv []string, envv []string) Error {
 	if envv == nil {
 		envv = Environ()
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index cf5ea9b..8a4b2e1 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/os/exec_unix.go
@@ -38,6 +38,9 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
 	if e != 0 {
 		return nil, NewSyscallError("wait", e)
 	}
+	if options&WSTOPPED == 0 {
+		p.done = true
+	}
 	w = new(Waitmsg)
 	w.Pid = pid1
 	w.WaitStatus = status
@@ -47,6 +50,9 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
 
 // Signal sends a signal to the Process.
 func (p *Process) Signal(sig Signal) Error {
+	if p.done {
+		return NewError("os: process already finished")
+	}
 	if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 {
 		return Errno(e)
 	}
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
index 5b432d3..65e94ac 100644
--- a/src/pkg/os/exec_windows.go
+++ b/src/pkg/os/exec_windows.go
@@ -24,11 +24,15 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
 	if e != 0 {
 		return nil, NewSyscallError("GetExitCodeProcess", e)
 	}
+	p.done = true
 	return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
 }
 
 // Signal sends a signal to the Process.
 func (p *Process) Signal(sig Signal) Error {
+	if p.done {
+		return NewError("os: process already finished")
+	}
 	switch sig.(UnixSignal) {
 	case SIGKILL:
 		e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 0379219..1e94fb7 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -14,7 +14,6 @@ type File struct {
 	fd      int
 	name    string
 	dirinfo *dirInfo // nil unless directory being read
-	nepipe  int      // number of consecutive EPIPE in Write
 }
 
 // Fd returns the integer Unix file descriptor referencing the open file.
@@ -45,7 +44,6 @@ type dirInfo struct {
 func epipecheck(file *File, e syscall.Error) {
 }
 
-
 // DevNull is the name of the operating system's ``null device.''
 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
 const DevNull = "/dev/null"
@@ -273,20 +271,6 @@ func Chmod(name string, mode uint32) Error {
 	return nil
 }
 
-// ChownPlan9 changes the uid and gid strings of the named file.
-func ChownPlan9(name, uid, gid string) Error {
-	var d Dir
-	d.Null()
-
-	d.Uid = uid
-	d.Gid = gid
-
-	if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
-		return &PathError{"chown_plan9", name, e}
-	}
-	return nil
-}
-
 // Chtimes changes the access and modification times of the named
 // file, similar to the Unix utime() or utimes() functions.
 //
@@ -319,7 +303,6 @@ func Pipe() (r *File, w *File, err Error) {
 	return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
 }
 
-
 // not supported on Plan 9
 
 // Link creates a hard link.
diff --git a/src/pkg/os/inotify/inotify_linux.go b/src/pkg/os/inotify/inotify_linux.go
index 7c7b769..99fa516 100644
--- a/src/pkg/os/inotify/inotify_linux.go
+++ b/src/pkg/os/inotify/inotify_linux.go
@@ -34,7 +34,6 @@ import (
 	"unsafe"
 )
 
-
 type Event struct {
 	Mask   uint32 // Mask of events
 	Cookie uint32 // Unique cookie associating related events (for rename(2))
@@ -56,7 +55,6 @@ type Watcher struct {
 	isClosed bool              // Set to true when Close() is first called
 }
 
-
 // NewWatcher creates and returns a new inotify instance using inotify_init(2)
 func NewWatcher() (*Watcher, os.Error) {
 	fd, errno := syscall.InotifyInit()
@@ -76,7 +74,6 @@ func NewWatcher() (*Watcher, os.Error) {
 	return w, nil
 }
 
-
 // Close closes an inotify watcher instance
 // It sends a message to the reader goroutine to quit and removes all watches
 // associated with the inotify instance
@@ -119,13 +116,11 @@ func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
 	return nil
 }
 
-
 // Watch adds path to the watched file set, watching all events.
 func (w *Watcher) Watch(path string) os.Error {
 	return w.AddWatch(path, IN_ALL_EVENTS)
 }
 
-
 // RemoveWatch removes path from the watched file set.
 func (w *Watcher) RemoveWatch(path string) os.Error {
 	watch, ok := w.watches[path]
@@ -140,7 +135,6 @@ func (w *Watcher) RemoveWatch(path string) os.Error {
 	return nil
 }
 
-
 // readEvents reads from the inotify file descriptor, converts the
 // received events into Event objects and sends them via the Event channel
 func (w *Watcher) readEvents() {
@@ -208,7 +202,6 @@ func (w *Watcher) readEvents() {
 	}
 }
 
-
 // String formats the event e in the form
 // "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
 func (e *Event) String() string {
diff --git a/src/pkg/os/inotify/inotify_linux_test.go b/src/pkg/os/inotify/inotify_linux_test.go
index e29a46d..aa72604 100644
--- a/src/pkg/os/inotify/inotify_linux_test.go
+++ b/src/pkg/os/inotify/inotify_linux_test.go
@@ -74,7 +74,6 @@ func TestInotifyEvents(t *testing.T) {
 	}
 }
 
-
 func TestInotifyClose(t *testing.T) {
 	watcher, _ := NewWatcher()
 	watcher.Close()
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index c22b536..4d60333 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -895,7 +895,14 @@ func run(t *testing.T, cmd []string) string {
 
 	var b bytes.Buffer
 	io.Copy(&b, r)
-	p.Wait(0)
+	_, err = p.Wait(0)
+	if err != nil {
+		t.Fatalf("run hostname Wait: %v", err)
+	}
+	err = p.Kill()
+	if err == nil {
+		t.Errorf("expected an error from Kill running 'hostname'")
+	}
 	output := b.String()
 	if n := len(output); n > 0 && output[n-1] == '\n' {
 		output = output[0 : n-1]
@@ -907,7 +914,6 @@ func run(t *testing.T, cmd []string) string {
 	return output
 }
 
-
 func TestHostname(t *testing.T) {
 	// There is no other way to fetch hostname on windows, but via winapi.
 	// On Plan 9 it is can be taken from #c/sysname as Hostname() does.
diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go
index 7b93036..a8dfce3 100644
--- a/src/pkg/os/path.go
+++ b/src/pkg/os/path.go
@@ -4,7 +4,6 @@
 
 package os
 
-
 // MkdirAll creates a directory named path,
 // along with any necessary parents, and returns nil,
 // or else returns an error.
diff --git a/src/pkg/os/proc.go b/src/pkg/os/proc.go
index 481ef60..dfe388f 100644
--- a/src/pkg/os/proc.go
+++ b/src/pkg/os/proc.go
@@ -11,7 +11,6 @@ import "syscall"
 var Args []string // provided by runtime
 var Envs []string // provided by runtime
 
-
 // Getuid returns the numeric user id of the caller.
 func Getuid() int { return syscall.Getuid() }
 
diff --git a/src/pkg/os/stat_plan9.go b/src/pkg/os/stat_plan9.go
index d2300d5..173a23f 100644
--- a/src/pkg/os/stat_plan9.go
+++ b/src/pkg/os/stat_plan9.go
@@ -69,7 +69,6 @@ func dirstat(arg interface{}) (d *Dir, err Error) {
 	return nil, &PathError{"stat", name, Ebadstat}
 }
 
-
 // Stat returns a FileInfo structure describing the named file and an error, if any.
 func Stat(name string) (fi *FileInfo, err Error) {
 	d, err := dirstat(name)
diff --git a/src/pkg/os/sys_linux.go b/src/pkg/os/sys_linux.go
index 408d667..2accd6c 100644
--- a/src/pkg/os/sys_linux.go
+++ b/src/pkg/os/sys_linux.go
@@ -6,7 +6,6 @@
 
 package os
 
-
 // Hostname returns the host name reported by the kernel.
 func Hostname() (name string, err Error) {
 	f, err := Open("/proc/sys/kernel/hostname")
diff --git a/src/pkg/os/sys_plan9.go b/src/pkg/os/sys_plan9.go
index f6af28b..c24cde0 100644
--- a/src/pkg/os/sys_plan9.go
+++ b/src/pkg/os/sys_plan9.go
@@ -6,7 +6,6 @@
 
 package os
 
-
 func Hostname() (name string, err Error) {
 	f, err := Open("#c/sysname")
 	if err != nil {
diff --git a/src/pkg/os/time.go b/src/pkg/os/time.go
index 8e87a49..949574d 100644
--- a/src/pkg/os/time.go
+++ b/src/pkg/os/time.go
@@ -6,7 +6,6 @@ package os
 
 import "syscall"
 
-
 // Time returns the current time, in whole seconds and
 // fractional nanoseconds, plus an Error if any. The current
 // time is thus 1e9*sec+nsec, in nanoseconds.  The zero of
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index b181483..3d5b915 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/path/filepath/path.go
@@ -38,19 +38,19 @@ const (
 // Getting Dot-Dot right,''
 // http://plan9.bell-labs.com/sys/doc/lexnames.html
 func Clean(path string) string {
+	vol := VolumeName(path)
+	path = path[len(vol):]
 	if path == "" {
-		return "."
+		return vol + "."
 	}
 
-	rooted := IsAbs(path)
+	rooted := os.IsPathSeparator(path[0])
 
 	// Invariants:
 	//	reading from path; r is index of next byte to process.
 	//	writing to buf; w is index of next byte to write.
 	//	dotdot is index in buf where .. must stop, either because
 	//		it is the leading slash or it is a leading ../../.. prefix.
-	prefix := volumeName(path)
-	path = path[len(prefix):]
 	n := len(path)
 	buf := []byte(path)
 	r, w, dotdot := 0, 0, 0
@@ -110,7 +110,7 @@ func Clean(path string) string {
 		w++
 	}
 
-	return prefix + string(buf[0:w])
+	return FromSlash(vol + string(buf[0:w]))
 }
 
 // ToSlash returns the result of replacing each separator character
@@ -140,8 +140,8 @@ func SplitList(path string) []string {
 }
 
 // Split splits path immediately following the final Separator,
-// partitioning it into a directory and a file name components.
-// If there are no separators in path, Split returns an empty base
+// separating it into a directory and file name component.
+// If there is no Separator in path, Split returns an empty dir
 // and file set to path.
 func Split(path string) (dir, file string) {
 	i := len(path) - 1
diff --git a/src/pkg/path/filepath/path_plan9.go b/src/pkg/path/filepath/path_plan9.go
index 47990e0..17b873f 100644
--- a/src/pkg/path/filepath/path_plan9.go
+++ b/src/pkg/path/filepath/path_plan9.go
@@ -11,8 +11,13 @@ func IsAbs(path string) bool {
 	return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
 }
 
-// volumeName returns the leading volume name on Windows.
+// VolumeName returns the leading volume name on Windows.
 // It returns "" elsewhere
-func volumeName(path string) string {
+func VolumeName(path string) string {
 	return ""
 }
+
+// HasPrefix tests whether the path p begins with prefix.
+func HasPrefix(p, prefix string) bool {
+	return strings.HasPrefix(p, prefix)
+}
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index 58c4c03..d2a1069 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -67,9 +67,27 @@ var cleantests = []PathTest{
 	{"abc/../../././../def", "../../def"},
 }
 
+var wincleantests = []PathTest{
+	{`c:`, `c:.`},
+	{`c:\`, `c:\`},
+	{`c:\abc`, `c:\abc`},
+	{`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
+	{`c:\abc\def\..\..`, `c:\`},
+	{`c:..\abc`, `c:..\abc`},
+	{`\`, `\`},
+	{`/`, `\`},
+}
+
 func TestClean(t *testing.T) {
-	for _, test := range cleantests {
-		if s := filepath.ToSlash(filepath.Clean(test.path)); s != test.result {
+	tests := cleantests
+	if runtime.GOOS == "windows" {
+		for i, _ := range tests {
+			tests[i].result = filepath.FromSlash(tests[i].result)
+		}
+		tests = append(tests, wincleantests...)
+	}
+	for _, test := range tests {
+		if s := filepath.Clean(test.path); s != test.result {
 			t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
 		}
 	}
@@ -399,16 +417,30 @@ var winisabstests = []IsAbsTest{
 	{`C:\`, true},
 	{`c\`, false},
 	{`c::`, false},
-	{`/`, true},
-	{`\`, true},
-	{`\Windows`, true},
+	{`c:`, false},
+	{`/`, false},
+	{`\`, false},
+	{`\Windows`, false},
+	{`c:a\b`, false},
 }
 
 func TestIsAbs(t *testing.T) {
+	var tests []IsAbsTest
 	if runtime.GOOS == "windows" {
-		isabstests = append(isabstests, winisabstests...)
+		tests = append(tests, winisabstests...)
+		// All non-windows tests should fail, because they have no volume letter.
+		for _, test := range isabstests {
+			tests = append(tests, IsAbsTest{test.path, false})
+		}
+		// All non-windows test should work as intended if prefixed with volume letter.
+		for _, test := range isabstests {
+			tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
+		}
+	} else {
+		tests = isabstests
 	}
-	for _, test := range isabstests {
+
+	for _, test := range tests {
 		if r := filepath.IsAbs(test.path); r != test.isAbs {
 			t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
 		}
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
index ea555fc..b2a4151 100644
--- a/src/pkg/path/filepath/path_unix.go
+++ b/src/pkg/path/filepath/path_unix.go
@@ -11,8 +11,13 @@ func IsAbs(path string) bool {
 	return strings.HasPrefix(path, "/")
 }
 
-// volumeName returns the leading volume name on Windows.
+// VolumeName returns the leading volume name on Windows.
 // It returns "" elsewhere.
-func volumeName(path string) string {
+func VolumeName(path string) string {
 	return ""
 }
+
+// HasPrefix tests whether the path p begins with prefix.
+func HasPrefix(p, prefix string) bool {
+	return strings.HasPrefix(p, prefix)
+}
diff --git a/src/pkg/path/filepath/path_windows.go b/src/pkg/path/filepath/path_windows.go
index 35302eb..2535697 100644
--- a/src/pkg/path/filepath/path_windows.go
+++ b/src/pkg/path/filepath/path_windows.go
@@ -4,25 +4,43 @@
 
 package filepath
 
-import "os"
+import "strings"
 
 // IsAbs returns true if the path is absolute.
-func IsAbs(path string) bool {
-	return path != "" && (volumeName(path) != "" || os.IsPathSeparator(path[0]))
+func IsAbs(path string) (b bool) {
+	v := VolumeName(path)
+	if v == "" {
+		return false
+	}
+	path = path[len(v):]
+	if path == "" {
+		return false
+	}
+	return path[0] == '/' || path[0] == '\\'
 }
 
-// volumeName return leading volume name.  
-// If given "C:\foo\bar", return "C:" on windows.
-func volumeName(path string) string {
-	if path == "" {
+// VolumeName returns leading volume name.  
+// Given "C:\foo\bar" it returns "C:" under windows.
+// On other platforms it returns "".
+func VolumeName(path string) (v string) {
+	if len(path) < 2 {
 		return ""
 	}
 	// with drive letter
 	c := path[0]
-	if len(path) > 2 && path[1] == ':' && os.IsPathSeparator(path[2]) &&
+	if path[1] == ':' &&
 		('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
 			'A' <= c && c <= 'Z') {
-		return path[0:2]
+		return path[:2]
 	}
 	return ""
 }
+
+// HasPrefix tests whether the path p begins with prefix.
+// It ignores case while comparing.
+func HasPrefix(p, prefix string) bool {
+	if strings.HasPrefix(p, prefix) {
+		return true
+	}
+	return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
+}
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 34d74b3..257278e 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -380,7 +380,6 @@ func TestMapSetNil(t *testing.T) {
 	}
 }
 
-
 func TestAll(t *testing.T) {
 	testType(t, 1, TypeOf((int8)(0)), "int8")
 	testType(t, 2, TypeOf((*int8)(nil)).Elem(), "int8")
@@ -744,7 +743,6 @@ func TestDeepEqualUnexportedMap(t *testing.T) {
 	}
 }
 
-
 func check2ndField(x interface{}, offs uintptr, t *testing.T) {
 	s := ValueOf(x)
 	f := s.Type().Field(1)
@@ -1329,8 +1327,8 @@ func TestImportPath(t *testing.T) {
 	}
 }
 
-func TestDotDotDot(t *testing.T) {
-	// Test example from FuncType.DotDotDot documentation.
+func TestVariadicType(t *testing.T) {
+	// Test example from Type documentation.
 	var f func(x int, y ...float64)
 	typ := TypeOf(f)
 	if typ.NumIn() == 2 && typ.In(0) == TypeOf(int(0)) {
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index a120da7..4c377e1 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -114,11 +114,11 @@ type Type interface {
 	// is a "..." parameter.  If so, t.In(t.NumIn() - 1) returns the parameter's
 	// implicit actual type []T.
 	//
-	// For concreteness, if t represents func(x int, y ... float), then
+	// For concreteness, if t represents func(x int, y ... float64), then
 	//
 	//	t.NumIn() == 2
 	//	t.In(0) is the reflect.Type for "int"
-	//	t.In(1) is the reflect.Type for "[]float"
+	//	t.In(1) is the reflect.Type for "[]float64"
 	//	t.IsVariadic() == true
 	//
 	// IsVariadic panics if the type's Kind is not Func.
@@ -232,8 +232,8 @@ const (
 
 // commonType is the common implementation of most values.
 // It is embedded in other, public struct types, but always
-// with a unique tag like "uint" or "float" so that the client cannot
-// convert from, say, *UintType to *FloatType.
+// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
+// so that code cannot convert from, say, *arrayType to *ptrType.
 
 type commonType struct {
 	size       uintptr
@@ -271,7 +271,6 @@ const (
 	BothDir = RecvDir | SendDir
 )
 
-
 // arrayType represents a fixed array type.
 type arrayType struct {
 	commonType `reflect:"array"`
@@ -342,7 +341,6 @@ type structType struct {
 	fields     []structField
 }
 
-
 /*
  * The compiler knows the exact layout of all the data structures above.
  * The compiler does not know about the data structures and methods below.
@@ -448,7 +446,7 @@ func (t *commonType) common() *commonType { return t }
 
 func (t *uncommonType) Method(i int) (m Method) {
 	if t == nil || i < 0 || i >= len(t.methods) {
-		return
+		panic("reflect: Method index out of range")
 	}
 	p := &t.methods[i]
 	if p.name != nil {
@@ -906,7 +904,7 @@ func toCommonType(p *runtime.Type) *commonType {
 	}
 	x := unsafe.Pointer(p)
 	if uintptr(x)&reflectFlags != 0 {
-		panic("invalid interface value")
+		panic("reflect: invalid interface value")
 	}
 	return &(*hdr)(x).t
 }
@@ -979,8 +977,8 @@ func PtrTo(t Type) Type {
 	}
 	rt.i = (*runtime.PtrType)(unsafe.Pointer(&rt.ptrType))
 
-	// initialize p using *byte's PtrType as a prototype.
-	// have to do assignment as PtrType, not runtime.PtrType,
+	// initialize p using *byte's ptrType as a prototype.
+	// have to do assignment as ptrType, not runtime.PtrType,
 	// in order to write to unexported fields.
 	p = &rt.ptrType
 	bp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index bfeb326..82985c5 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -1025,6 +1025,15 @@ func (v Value) Method(i int) Value {
 	return Value{v.Internal, i + 1}
 }
 
+// NumMethod returns the number of methods in the value's method set.
+func (v Value) NumMethod() int {
+	iv := v.internal()
+	if iv.kind == Invalid {
+		panic(&ValueError{"reflect.Value.NumMethod", Invalid})
+	}
+	return iv.typ.NumMethod()
+}
+
 // MethodByName returns a function value corresponding to the method
 // of v with the given name.
 // The arguments to a Call on the returned function should not include
diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go
index b182861..4acfdf6 100644
--- a/src/pkg/rpc/client.go
+++ b/src/pkg/rpc/client.go
@@ -197,7 +197,6 @@ func (c *gobClientCodec) Close() os.Error {
 	return c.rwc.Close()
 }
 
-
 // DialHTTP connects to an HTTP RPC server at the specified network address
 // listening on the default HTTP RPC path.
 func DialHTTP(network, address string) (*Client, os.Error) {
diff --git a/src/pkg/rpc/debug.go b/src/pkg/rpc/debug.go
index 32dc8a1..ae76a45 100644
--- a/src/pkg/rpc/debug.go
+++ b/src/pkg/rpc/debug.go
@@ -10,33 +10,33 @@ package rpc
 */
 
 import (
+	"exp/template"
 	"fmt"
 	"http"
 	"sort"
-	"template"
 )
 
 const debugText = `<html>
 	<body>
 	<title>Services</title>
-	{.repeated section @}
+	{{range .}}
 	<hr>
-	Service {Name}
+	Service {{.Name}}
 	<hr>
 		<table>
 		<th align=center>Method</th><th align=center>Calls</th>
-		{.repeated section Method}
+		{{range .Method}}
 			<tr>
-			<td align=left font=fixed>{Name}({Type.ArgType}, {Type.ReplyType}) os.Error</td>
-			<td align=center>{Type.NumCalls}</td>
+			<td align=left font=fixed>{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) os.Error</td>
+			<td align=center>{{.Type.NumCalls}}</td>
 			</tr>
-		{.end}
+		{{end}}
 		</table>
-	{.end}
+	{{end}}
 	</body>
 	</html>`
 
-var debug = template.MustParse(debugText, nil)
+var debug = template.Must(template.New("RPC debug").Parse(debugText))
 
 type debugMethod struct {
 	Type *methodType
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go
index 07845d1..86767ab 100644
--- a/src/pkg/rpc/server.go
+++ b/src/pkg/rpc/server.go
@@ -196,12 +196,14 @@ func isExported(name string) bool {
 	return unicode.IsUpper(rune)
 }
 
-// Is this type exported or local to this package?
-func isExportedOrLocalType(t reflect.Type) bool {
+// Is this type exported or a builtin?
+func isExportedOrBuiltinType(t reflect.Type) bool {
 	for t.Kind() == reflect.Ptr {
 		t = t.Elem()
 	}
-	return t.PkgPath() == "" || isExported(t.Name())
+	// PkgPath will be non-empty even for an exported type,
+	// so we need to check the type name as well.
+	return isExported(t.Name()) || t.PkgPath() == ""
 }
 
 // Register publishes in the server the set of methods of the
@@ -239,7 +241,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
 	if sname == "" {
 		log.Fatal("rpc: no service name for type", s.typ.String())
 	}
-	if s.typ.PkgPath() != "" && !isExported(sname) && !useName {
+	if !isExported(sname) && !useName {
 		s := "rpc Register: type " + sname + " is not exported"
 		log.Print(s)
 		return os.NewError(s)
@@ -255,7 +257,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
 		method := s.typ.Method(m)
 		mtype := method.Type
 		mname := method.Name
-		if mtype.PkgPath() != "" || !isExported(mname) {
+		if method.PkgPath != "" {
 			continue
 		}
 		// Method needs three ins: receiver, *args, *reply.
@@ -265,7 +267,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
 		}
 		// First arg need not be a pointer.
 		argType := mtype.In(1)
-		if !isExportedOrLocalType(argType) {
+		if !isExportedOrBuiltinType(argType) {
 			log.Println(mname, "argument type not exported or local:", argType)
 			continue
 		}
@@ -275,7 +277,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
 			log.Println("method", mname, "reply type not a pointer:", replyType)
 			continue
 		}
-		if !isExportedOrLocalType(replyType) {
+		if !isExportedOrBuiltinType(replyType) {
 			log.Println("method", mname, "reply type not exported or local:", replyType)
 			continue
 		}
@@ -376,7 +378,6 @@ func (c *gobServerCodec) Close() os.Error {
 	return c.rwc.Close()
 }
 
-
 // ServeConn runs the server on a single connection.
 // ServeConn blocks, serving the connection until the client hangs up.
 // The caller typically invokes ServeConn in a go statement.
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go
index 1692168..459dd59 100644
--- a/src/pkg/rpc/server_test.go
+++ b/src/pkg/rpc/server_test.go
@@ -360,6 +360,7 @@ func countMallocs(dial func() (*Client, os.Error), t *testing.T) uint64 {
 	}
 	args := &Args{7, 8}
 	reply := new(Reply)
+	runtime.UpdateMemStats()
 	mallocs := 0 - runtime.MemStats.Mallocs
 	const count = 100
 	for i := 0; i < count; i++ {
@@ -371,6 +372,7 @@ func countMallocs(dial func() (*Client, os.Error), t *testing.T) uint64 {
 			t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
 		}
 	}
+	runtime.UpdateMemStats()
 	mallocs += runtime.MemStats.Mallocs
 	return mallocs / count
 }
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index e2cabef..a145188 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -28,15 +28,18 @@ TEXT _rt0_386(SB),7,$0
 	TESTL	AX, AX
 	JZ	4(PC)
 	CALL	AX
+	// skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows
 	CMPL runtime·iswindows(SB), $0
 	JEQ ok
 
+	// skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases
+	CMPL	runtime·isplan9(SB), $1
+	JEQ	ok
+
 	// set up %gs
 	CALL	runtime·ldt0setup(SB)
 
 	// store through it, to make sure it works
-	CMPL	runtime·isplan9(SB), $1
-	JEQ	ok
 	get_tls(BX)
 	MOVL	$0x123, g(BX)
 	MOVL	runtime·tls0(SB), AX
@@ -318,6 +321,45 @@ TEXT runtime·casp(SB), 7, $0
 	MOVL	$1, AX
 	RET
 
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+//	*val += delta;
+//	return *val;
+TEXT runtime·xadd(SB), 7, $0
+	MOVL	4(SP), BX
+	MOVL	8(SP), AX
+	MOVL	AX, CX
+	LOCK
+	XADDL	AX, 0(BX)
+	ADDL	CX, AX
+	RET
+
+TEXT runtime·xchg(SB), 7, $0
+	MOVL	4(SP), BX
+	MOVL	8(SP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT runtime·procyield(SB),7,$0
+	MOVL	4(SP), AX
+again:
+	PAUSE
+	SUBL	$1, AX
+	JNZ	again
+	RET
+
+TEXT runtime·atomicstorep(SB), 7, $0
+	MOVL	4(SP), BX
+	MOVL	8(SP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT runtime·atomicstore(SB), 7, $0
+	MOVL	4(SP), BX
+	MOVL	8(SP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -460,12 +502,16 @@ TEXT runtime·stackcheck(SB), 7, $0
 TEXT runtime·memclr(SB),7,$0
 	MOVL	4(SP), DI		// arg 1 addr
 	MOVL	8(SP), CX		// arg 2 count
-	ADDL	$3, CX
+	MOVL	CX, BX
+	ANDL	$3, BX
 	SHRL	$2, CX
 	MOVL	$0, AX
 	CLD
 	REP
 	STOSL
+	MOVL	BX, CX
+	REP
+	STOSB
 	RET
 
 TEXT runtime·getcallerpc(SB),7,$0
diff --git a/src/pkg/runtime/386/atomic.c b/src/pkg/runtime/386/atomic.c
index c031cc4..a4f2a11 100644
--- a/src/pkg/runtime/386/atomic.c
+++ b/src/pkg/runtime/386/atomic.c
@@ -10,3 +10,10 @@ runtime·atomicload(uint32 volatile* addr)
 {
 	return *addr;
 }
+
+#pragma textflag 7
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+	return *addr;
+}
diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/386/closure.c
index b0d4cc4..b4d8677 100644
--- a/src/pkg/runtime/386/closure.c
+++ b/src/pkg/runtime/386/closure.c
@@ -45,7 +45,7 @@ runtime·closure(int32 siz, byte *fn, byte *arg0)
 	q = p + n - siz;
 
 	if(siz > 0) {
-		runtime·mcpy(q, (byte*)&arg0, siz);
+		runtime·memmove(q, (byte*)&arg0, siz);
 
 		// SUBL $siz, SP
 		*p++ = 0x81;
diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/386/memmove.s
index 471553b..203a818 100644
--- a/src/pkg/runtime/386/memmove.s
+++ b/src/pkg/runtime/386/memmove.s
@@ -27,9 +27,6 @@ TEXT runtime·memmove(SB), 7, $0
 	MOVL	to+0(FP), DI
 	MOVL	fr+4(FP), SI
 	MOVL	n+8(FP), BX
-	CMPL	BX, $0
-	JLT	fault
-
 /*
  * check and set for backwards
  */
@@ -87,12 +84,3 @@ back:
 	MOVL	to+0(FP),AX
 	RET
 
-/*
- * if called with negative count,
- * treat as error rather than
- * rotating all of memory
- */
-fault:
-	MOVL	$0,SI
-	MOVL	0(SI), AX
-	RET
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 03f960c..64bd2b7 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -120,7 +120,7 @@ $(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH)
 	mv -f $@.x $@
 
 goc2c: goc2c.c
-	quietgcc -o $@ $<
+	quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
 
 mkversion: mkversion.c
 	quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s
index 46d82e3..3e3818c 100644
--- a/src/pkg/runtime/amd64/asm.s
+++ b/src/pkg/runtime/amd64/asm.s
@@ -18,7 +18,8 @@ TEXT _rt0_amd64(SB),7,$-8
 	TESTQ	AX, AX
 	JZ	needtls
 	CALL	AX
-	JMP ok
+	CMPL	runtime·iswindows(SB), $0
+	JEQ ok
 
 needtls:
 	LEAQ	runtime·tls0(SB), DI
@@ -364,6 +365,45 @@ TEXT runtime·casp(SB), 7, $0
 	MOVL	$1, AX
 	RET
 
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+//	*val += delta;
+//	return *val;
+TEXT runtime·xadd(SB), 7, $0
+	MOVQ	8(SP), BX
+	MOVL	16(SP), AX
+	MOVL	AX, CX
+	LOCK
+	XADDL	AX, 0(BX)
+	ADDL	CX, AX
+	RET
+
+TEXT runtime·xchg(SB), 7, $0
+	MOVQ	8(SP), BX
+	MOVL	16(SP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT runtime·procyield(SB),7,$0
+	MOVL	8(SP), AX
+again:
+	PAUSE
+	SUBL	$1, AX
+	JNZ	again
+	RET
+
+TEXT runtime·atomicstorep(SB), 7, $0
+	MOVQ	8(SP), BX
+	MOVQ	16(SP), AX
+	XCHGQ	AX, 0(BX)
+	RET
+
+TEXT runtime·atomicstore(SB), 7, $0
+	MOVQ	8(SP), BX
+	MOVL	16(SP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -413,6 +453,7 @@ TEXT runtime·asmcgocall(SB),7,$0
 	MOVQ	DI, 16(SP)	// save g
 	MOVQ	DX, 8(SP)	// save SP
 	MOVQ	BX, DI		// DI = first argument in AMD64 ABI
+	MOVQ	BX, CX		// CX = first argument in Win64
 	CALL	AX
 
 	// Restore registers, g, stack pointer.
@@ -506,12 +547,16 @@ TEXT runtime·stackcheck(SB), 7, $0
 TEXT runtime·memclr(SB),7,$0
 	MOVQ	8(SP), DI		// arg 1 addr
 	MOVQ	16(SP), CX		// arg 2 count
-	ADDQ	$7, CX
+	MOVQ	CX, BX
+	ANDQ	$7, BX
 	SHRQ	$3, CX
 	MOVQ	$0, AX
 	CLD
 	REP
 	STOSQ
+	MOVQ	BX, CX
+	REP
+	STOSB
 	RET
 
 TEXT runtime·getcallerpc(SB),7,$0
diff --git a/src/pkg/runtime/amd64/atomic.c b/src/pkg/runtime/amd64/atomic.c
index c031cc4..a4f2a11 100644
--- a/src/pkg/runtime/amd64/atomic.c
+++ b/src/pkg/runtime/amd64/atomic.c
@@ -10,3 +10,10 @@ runtime·atomicload(uint32 volatile* addr)
 {
 	return *addr;
 }
+
+#pragma textflag 7
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+	return *addr;
+}
diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/amd64/closure.c
index 5033468..481b4a8 100644
--- a/src/pkg/runtime/amd64/closure.c
+++ b/src/pkg/runtime/amd64/closure.c
@@ -45,7 +45,7 @@ runtime·closure(int32 siz, byte *fn, byte *arg0)
 	q = p + n - siz;
 
 	if(siz > 0) {
-		runtime·mcpy(q, (byte*)&arg0, siz);
+		runtime·memmove(q, (byte*)&arg0, siz);
 
 		// SUBQ $siz, SP
 		*p++ = 0x48;
diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/amd64/memmove.s
index fc9573f..e78be81 100644
--- a/src/pkg/runtime/amd64/memmove.s
+++ b/src/pkg/runtime/amd64/memmove.s
@@ -28,8 +28,6 @@ TEXT runtime·memmove(SB), 7, $0
 	MOVQ	to+0(FP), DI
 	MOVQ	fr+8(FP), SI
 	MOVLQSX	n+16(FP), BX
-	CMPQ	BX, $0
-	JLT	fault
 
 /*
  * check and set for backwards
@@ -88,12 +86,3 @@ back:
 	MOVQ	to+0(FP),AX
 	RET
 
-/*
- * if called with negative count,
- * treat as error rather than
- * rotating all of memory
- */
-fault:
-	MOVQ	$0,SI
-	MOVQ	0(SI), AX
-	RET
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c
index d422cb6..3e85d36 100644
--- a/src/pkg/runtime/amd64/traceback.c
+++ b/src/pkg/runtime/amd64/traceback.c
@@ -10,6 +10,7 @@ void runtime·deferproc(void);
 void runtime·newproc(void);
 void runtime·newstack(void);
 void runtime·morestack(void);
+void runtime·sigpanic(void);
 
 // This code is also used for the 386 tracebacks.
 // Use uintptr for an appropriate word-sized integer.
@@ -27,11 +28,13 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
 	byte *fp;
 	Stktop *stk;
 	Func *f;
+	bool waspanic;
 
 	USED(lr0);
 	pc = (uintptr)pc0;
 	lr = 0;
 	fp = nil;
+	waspanic = false;
 	
 	// If the PC is goexit, the goroutine hasn't started yet.
 	if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) {
@@ -127,7 +130,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
 			if(pc > f->entry)
 				runtime·printf("+%p", (uintptr)(pc - f->entry));
 			tracepc = pc;	// back up to CALL instruction for funcline.
-			if(n > 0 && pc > f->entry)
+			if(n > 0 && pc > f->entry && !waspanic)
 				tracepc--;
 			runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
 			runtime·printf("\t%S(", f->name);
@@ -144,6 +147,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
 			n++;
 		}
 		
+		waspanic = f->entry == (uintptr)runtime·sigpanic;
+
 		if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
 			fp += 2*sizeof(uintptr);
 
diff --git a/src/pkg/runtime/append_test.go b/src/pkg/runtime/append_test.go
index 75a6353..b855222 100644
--- a/src/pkg/runtime/append_test.go
+++ b/src/pkg/runtime/append_test.go
@@ -36,7 +36,7 @@ func BenchmarkAppendSpecialCase(b *testing.B) {
 	}
 }
 
-var x = make([]int, 0, 10)
+var x []int
 
 func f() int {
 	x[:1][0] = 3
@@ -44,6 +44,7 @@ func f() int {
 }
 
 func TestSideEffectOrder(t *testing.T) {
+	x = make([]int, 0, 10)
 	x = append(x, 1, f())
 	if x[0] != 1 || x[1] != 2 {
 		t.Error("append failed: ", x[0], x[1])
diff --git a/src/pkg/runtime/arm/atomic.c b/src/pkg/runtime/arm/atomic.c
index 9fd47ba..52e4059 100644
--- a/src/pkg/runtime/arm/atomic.c
+++ b/src/pkg/runtime/arm/atomic.c
@@ -4,9 +4,80 @@
 
 #include "runtime.h"
 
+// Atomic add and return new value.
+#pragma textflag 7
+uint32
+runtime·xadd(uint32 volatile *val, int32 delta)
+{
+	uint32 oval, nval;
+
+	for(;;){
+		oval = *val;
+		nval = oval + delta;
+		if(runtime·cas(val, oval, nval))
+			return nval;
+	}
+}
+
+#pragma textflag 7
+uint32
+runtime·xchg(uint32 volatile* addr, uint32 v)
+{
+	uint32 old;
+
+	for(;;) {
+		old = *addr;
+		if(runtime·cas(addr, old, v))
+			return old;
+	}
+}
+
+#pragma textflag 7
+void
+runtime·procyield(uint32 cnt)
+{
+	uint32 volatile i;
+
+	for(i = 0; i < cnt; i++) {
+	}
+}
+
 #pragma textflag 7
 uint32
 runtime·atomicload(uint32 volatile* addr)
 {
 	return runtime·xadd(addr, 0);
 }
+
+#pragma textflag 7
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+	return (void*)runtime·xadd((uint32 volatile*)addr, 0);
+}
+
+#pragma textflag 7
+void
+runtime·atomicstorep(void* volatile* addr, void* v)
+{
+	void *old;
+
+	for(;;) {
+		old = *addr;
+		if(runtime·casp(addr, old, v))
+			return;
+	}
+}
+
+#pragma textflag 7
+void
+runtime·atomicstore(uint32 volatile* addr, uint32 v)
+{
+	uint32 old;
+	
+	for(;;) {
+		old = *addr;
+		if(runtime·cas(addr, old, v))
+			return;
+	}
+}
\ No newline at end of file
diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c
index 36a93bc..119e91b 100644
--- a/src/pkg/runtime/arm/closure.c
+++ b/src/pkg/runtime/arm/closure.c
@@ -83,7 +83,7 @@ runtime·closure(int32 siz, byte *fn, byte *arg0)
 	*pc++ = 0xe52de000 | (siz + 4);
 
 	if(siz > 0) {
-		runtime·mcpy(q, (byte*)&arg0, siz);
+		runtime·memmove(q, (byte*)&arg0, siz);
 
 		//	MOVW	$vars(PC), R0
 		*pc = 0xe28f0000 | (int32)(q - (byte*)pc - 8);
diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/arm/traceback.c
index c3934c3..5628b83 100644
--- a/src/pkg/runtime/arm/traceback.c
+++ b/src/pkg/runtime/arm/traceback.c
@@ -9,6 +9,7 @@ void runtime·deferproc(void);
 void runtime·newproc(void);
 void runtime·newstack(void);
 void runtime·morestack(void);
+void runtime·sigpanic(void);
 void _div(void);
 void _mod(void);
 void _divu(void);
@@ -20,12 +21,14 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
 	int32 i, n, iter;
 	uintptr pc, lr, tracepc, x;
 	byte *fp, *p;
+	bool waspanic;
 	Stktop *stk;
 	Func *f;
 	
 	pc = (uintptr)pc0;
 	lr = (uintptr)lr0;
 	fp = nil;
+	waspanic = false;
 
 	// If the PC is goexit, the goroutine hasn't started yet.
 	if(pc == (uintptr)runtime·goexit) {
@@ -121,7 +124,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
 			if(pc > f->entry)
 				runtime·printf("+%p", (uintptr)(pc - f->entry));
 			tracepc = pc;	// back up to CALL instruction for funcline.
-			if(n > 0 && pc > f->entry)
+			if(n > 0 && pc > f->entry && !waspanic)
 				tracepc -= sizeof(uintptr);
 			runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
 			runtime·printf("\t%S(", f->name);
@@ -137,6 +140,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
 			runtime·prints(")\n");
 			n++;
 		}
+		
+		waspanic = f->entry == (uintptr)runtime·sigpanic;
 
 		if(pcbuf == nil && f->entry == (uintptr)runtime·newstack && g == m->g0) {
 			runtime·printf("----- newstack called from goroutine %d -----\n", m->curg->goid);
diff --git a/src/pkg/runtime/cgo/windows_amd64.c b/src/pkg/runtime/cgo/windows_amd64.c
index fd5b397..e8313e2 100755
--- a/src/pkg/runtime/cgo/windows_amd64.c
+++ b/src/pkg/runtime/cgo/windows_amd64.c
@@ -30,6 +30,7 @@ static void*
 threadentry(void *v)
 {
 	ThreadStart ts;
+	void *tls0;
 
 	ts = *(ThreadStart*)v;
 	free(v);
@@ -45,11 +46,13 @@ threadentry(void *v)
 	/*
 	 * Set specific keys in thread local storage.
 	 */
+	tls0 = (void*)LocalAlloc(LPTR, 64);
 	asm volatile (
+	  "movq %0, %%gs:0x58\n"	// MOVL tls0, 0x58(GS)
 	  "movq %%gs:0x58, %%rax\n" // MOVQ 0x58(GS), tmp
-	  "movq %0, 0(%%rax)\n" // MOVQ g, 0(GS)
-	  "movq %1, 8(%%rax)\n" // MOVQ m, 8(GS)
-	  :: "r"(ts.g), "r"(ts.m) : "%rax"
+	  "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
+	  "movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
+	  :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
 	);
 
 	crosscall_amd64(ts.fn);
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 58f287e..829448b 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -83,7 +83,6 @@
 // callee-save registers for gcc and returns to GoF, which returns to f.
 
 void *initcgo;	/* filled in by dynamic linker when Cgo is available */
-int64 ncgocall;
 
 static void unlockm(void);
 static void unwindm(void);
@@ -101,7 +100,7 @@ runtime·cgocall(void (*fn)(void*), void *arg)
 	if(fn == 0)
 		runtime·throw("cgocall nil");
 
-	ncgocall++;
+	m->ncgocall++;
 
 	/*
 	 * Lock g to m to ensure we stay on the same stack if we do a
@@ -155,7 +154,11 @@ unlockm(void)
 void
 runtime·Cgocalls(int64 ret)
 {
-	ret = ncgocall;
+	M *m;
+
+	ret = 0;
+	for(m=runtime·atomicloadp(&runtime·allm); m; m=m->alllink)
+		ret += m->ncgocall;
 	FLUSH(&ret);
 }
 
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index f94c3ef..b77e51b 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -6,6 +6,7 @@
 #include "type.h"
 
 #define	MAXALIGN	7
+#define	NOSELGEN	1
 
 static	int32	debug	= 0;
 
@@ -18,10 +19,8 @@ struct	SudoG
 {
 	G*	g;		// g and selgen constitute
 	uint32	selgen;		// a weak pointer to g
-	int16	offset;		// offset of case number
-	int8	isfree;		// offset of case number
 	SudoG*	link;
-	byte	elem[8];	// synch data element (+ more)
+	byte*	elem;		// data element
 };
 
 struct	WaitQ
@@ -38,11 +37,10 @@ struct	Hchan
 	bool	closed;
 	uint8	elemalign;
 	Alg*	elemalg;		// interface for element type
-	uint32	sendx;	// send index
-	uint32	recvx;	// receive index
+	uint32	sendx;			// send index
+	uint32	recvx;			// receive index
 	WaitQ	recvq;			// list of recv waiters
 	WaitQ	sendq;			// list of send waiters
-	SudoG*	free;			// freelist
 	Lock;
 };
 
@@ -60,34 +58,26 @@ enum
 
 struct	Scase
 {
+	SudoG	sg;			// must be first member (cast to Scase)
 	Hchan*	chan;			// chan
 	byte*	pc;			// return pc
 	uint16	kind;
 	uint16	so;			// vararg of selected bool
-	union {
-		byte	elem[2*sizeof(void*)];	// element (send)
-		struct {
-			byte*	elemp;		// pointer to element (recv)
-			bool*	receivedp;	// pointer to received bool (recv2)
-		} recv;
-	} u;
+	bool*	receivedp;		// pointer to received bool (recv2)
 };
 
 struct	Select
 {
 	uint16	tcase;			// total count of scase[]
 	uint16	ncase;			// currently filled scase[]
-	Select*	link;			// for freelist
-	uint16*	order;
-	Scase*	scase[1];		// one per case
+	uint16*	pollorder;		// case poll order
+	Hchan**	lockorder;		// channel lock order
+	Scase	scase[1];		// one per case (in order of appearance)
 };
 
-static	void	dequeueg(WaitQ*, Hchan*);
-static	SudoG*	dequeue(WaitQ*, Hchan*);
+static	void	dequeueg(WaitQ*);
+static	SudoG*	dequeue(WaitQ*);
 static	void	enqueue(WaitQ*, SudoG*);
-static	SudoG*	allocsg(Hchan*);
-static	void	freesg(Hchan*, SudoG*);
-static	uint32	fastrandn(uint32);
 static	void	destroychan(Hchan*);
 
 Hchan*
@@ -97,7 +87,7 @@ runtime·makechan_c(Type *elem, int64 hint)
 	int32 n;
 	byte *by;
 
-	if(hint < 0 || (int32)hint != hint || hint > ((uintptr)-1) / elem->size)
+	if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintptr)-1) / elem->size))
 		runtime·panicstring("makechan: size out of range");
 
 	if(elem->alg >= nelem(runtime·algarray)) {
@@ -170,6 +160,7 @@ void
 runtime·chansend(Hchan *c, byte *ep, bool *pres)
 {
 	SudoG *sg;
+	SudoG mysg;
 	G* gp;
 
 	if(c == nil)
@@ -185,21 +176,20 @@ runtime·chansend(Hchan *c, byte *ep, bool *pres)
 	}
 
 	runtime·lock(c);
-loop:
 	if(c->closed)
 		goto closed;
 
 	if(c->dataqsiz > 0)
 		goto asynch;
 
-	sg = dequeue(&c->recvq, c);
+	sg = dequeue(&c->recvq);
 	if(sg != nil) {
-		if(ep != nil)
-			c->elemalg->copy(c->elemsize, sg->elem, ep);
-
+		runtime·unlock(c);
+		
 		gp = sg->g;
 		gp->param = sg;
-		runtime·unlock(c);
+		if(sg->elem != nil)
+			c->elemalg->copy(c->elemsize, sg->elem, ep);
 		runtime·ready(gp);
 
 		if(pres != nil)
@@ -213,21 +203,22 @@ loop:
 		return;
 	}
 
-	sg = allocsg(c);
-	if(ep != nil)
-		c->elemalg->copy(c->elemsize, sg->elem, ep);
+	mysg.elem = ep;
+	mysg.g = g;
+	mysg.selgen = NOSELGEN;
 	g->param = nil;
 	g->status = Gwaiting;
-	enqueue(&c->sendq, sg);
+	enqueue(&c->sendq, &mysg);
 	runtime·unlock(c);
 	runtime·gosched();
 
-	runtime·lock(c);
-	sg = g->param;
-	if(sg == nil)
-		goto loop;
-	freesg(c, sg);
-	runtime·unlock(c);
+	if(g->param == nil) {
+		runtime·lock(c);
+		if(!c->closed)
+			runtime·throw("chansend: spurious wakeup");
+		goto closed;
+	}
+
 	return;
 
 asynch:
@@ -240,25 +231,25 @@ asynch:
 			*pres = false;
 			return;
 		}
-		sg = allocsg(c);
+		mysg.g = g;
+		mysg.elem = nil;
+		mysg.selgen = NOSELGEN;
 		g->status = Gwaiting;
-		enqueue(&c->sendq, sg);
+		enqueue(&c->sendq, &mysg);
 		runtime·unlock(c);
 		runtime·gosched();
 
 		runtime·lock(c);
 		goto asynch;
 	}
-	if(ep != nil)
-		c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
+	c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
 	if(++c->sendx == c->dataqsiz)
 		c->sendx = 0;
 	c->qcount++;
 
-	sg = dequeue(&c->recvq, c);
+	sg = dequeue(&c->recvq);
 	if(sg != nil) {
 		gp = sg->g;
-		freesg(c, sg);
 		runtime·unlock(c);
 		runtime·ready(gp);
 	} else
@@ -277,6 +268,7 @@ void
 runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received)
 {
 	SudoG *sg;
+	SudoG mysg;
 	G *gp;
 
 	if(c == nil)
@@ -289,23 +281,20 @@ runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received)
 		runtime·printf("chanrecv: chan=%p\n", c);
 
 	runtime·lock(c);
-
-loop:
 	if(c->dataqsiz > 0)
 		goto asynch;
 
 	if(c->closed)
 		goto closed;
 
-	sg = dequeue(&c->sendq, c);
+	sg = dequeue(&c->sendq);
 	if(sg != nil) {
+		runtime·unlock(c);
+
 		if(ep != nil)
 			c->elemalg->copy(c->elemsize, ep, sg->elem);
-		c->elemalg->copy(c->elemsize, sg->elem, nil);
-
 		gp = sg->g;
 		gp->param = sg;
-		runtime·unlock(c);
 		runtime·ready(gp);
 
 		if(selected != nil)
@@ -321,25 +310,24 @@ loop:
 		return;
 	}
 
-	sg = allocsg(c);
+	mysg.elem = ep;
+	mysg.g = g;
+	mysg.selgen = NOSELGEN;
 	g->param = nil;
 	g->status = Gwaiting;
-	enqueue(&c->recvq, sg);
+	enqueue(&c->recvq, &mysg);
 	runtime·unlock(c);
 	runtime·gosched();
 
-	runtime·lock(c);
-	sg = g->param;
-	if(sg == nil)
-		goto loop;
+	if(g->param == nil) {
+		runtime·lock(c);
+		if(!c->closed)
+			runtime·throw("chanrecv: spurious wakeup");
+		goto closed;
+	}
 
-	if(ep != nil)
-		c->elemalg->copy(c->elemsize, ep, sg->elem);
-	c->elemalg->copy(c->elemsize, sg->elem, nil);
 	if(received != nil)
 		*received = true;
-	freesg(c, sg);
-	runtime·unlock(c);
 	return;
 
 asynch:
@@ -354,9 +342,11 @@ asynch:
 				*received = false;
 			return;
 		}
-		sg = allocsg(c);
+		mysg.g = g;
+		mysg.elem = nil;
+		mysg.selgen = NOSELGEN;
 		g->status = Gwaiting;
-		enqueue(&c->recvq, sg);
+		enqueue(&c->recvq, &mysg);
 		runtime·unlock(c);
 		runtime·gosched();
 
@@ -369,10 +359,10 @@ asynch:
 	if(++c->recvx == c->dataqsiz)
 		c->recvx = 0;
 	c->qcount--;
-	sg = dequeue(&c->sendq, c);
+
+	sg = dequeue(&c->sendq);
 	if(sg != nil) {
 		gp = sg->g;
-		freesg(c, sg);
 		runtime·unlock(c);
 		runtime·ready(gp);
 	} else
@@ -437,7 +427,7 @@ runtime·chanrecv2(Hchan* c, ...)
 
 	o = runtime·rnd(sizeof(c), Structrnd);
 	ae = (byte*)&c + o;
-	o = runtime·rnd(o+c->elemsize, 1);
+	o += c->elemsize;
 	ac = (byte*)&c + o;
 
 	runtime·chanrecv(c, ae, nil, ac);
@@ -619,57 +609,56 @@ newselect(int32 size, Select **selp)
 	if(size > 1)
 		n = size-1;
 
-	sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0]) + size*sizeof(sel->order[0]));
+	sel = runtime·mal(sizeof(*sel) +
+		n*sizeof(sel->scase[0]) +
+		size*sizeof(sel->lockorder[0]) +
+		size*sizeof(sel->pollorder[0]));
 
 	sel->tcase = size;
 	sel->ncase = 0;
-	sel->order = (void*)(sel->scase + size);
+	sel->pollorder = (void*)(sel->scase + size);
+	sel->lockorder = (void*)(sel->pollorder + size);
 	*selp = sel;
+
 	if(debug)
 		runtime·printf("newselect s=%p size=%d\n", sel, size);
 }
 
 // cut in half to give stack a chance to split
-static void selectsend(Select **selp, Hchan *c, void *pc);
+static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so);
 
-// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
 #pragma textflag 7
 void
-runtime·selectsend(Select *sel, Hchan *c, ...)
+runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected)
 {
+	selected = false;
+	FLUSH(&selected);
+
 	// nil cases do not compete
 	if(c == nil)
 		return;
 	
-	selectsend(&sel, c, runtime·getcallerpc(&sel));
+	selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
 }
 
 static void
-selectsend(Select **selp, Hchan *c, void *pc)
+selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
 {
-	int32 i, eo;
+	int32 i;
 	Scase *cas;
-	byte *ae;
-	Select *sel;
 	
-	sel = *selp;
 	i = sel->ncase;
 	if(i >= sel->tcase)
 		runtime·throw("selectsend: too many cases");
 	sel->ncase = i+1;
-	cas = runtime·mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
-	sel->scase[i] = cas;
+	cas = &sel->scase[i];
 
 	cas->pc = pc;
 	cas->chan = c;
-
-	eo = runtime·rnd(sizeof(sel), sizeof(c));
-	eo = runtime·rnd(eo+sizeof(c), c->elemsize);
-	cas->so = runtime·rnd(eo+c->elemsize, Structrnd);
+	cas->so = so;
 	cas->kind = CaseSend;
-
-	ae = (byte*)selp + eo;
-	c->elemalg->copy(c->elemsize, cas->u.elem, ae);
+	cas->sg.elem = elem;
 
 	if(debug)
 		runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n",
@@ -684,6 +673,9 @@ static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32
 void
 runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
 {
+	selected = false;
+	FLUSH(&selected);
+
 	// nil cases do not compete
 	if(c == nil)
 		return;
@@ -696,6 +688,9 @@ runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
 void
 runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected)
 {
+	selected = false;
+	FLUSH(&selected);
+
 	// nil cases do not compete
 	if(c == nil)
 		return;
@@ -713,16 +708,14 @@ selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so
 	if(i >= sel->tcase)
 		runtime·throw("selectrecv: too many cases");
 	sel->ncase = i+1;
-	cas = runtime·mal(sizeof *cas);
-	sel->scase[i] = cas;
+	cas = &sel->scase[i];
 	cas->pc = pc;
 	cas->chan = c;
 
 	cas->so = so;
 	cas->kind = CaseRecv;
-	cas->u.recv.elemp = elem;
-	cas->u.recv.receivedp = nil;
-	cas->u.recv.receivedp = received;
+	cas->sg.elem = elem;
+	cas->receivedp = received;
 
 	if(debug)
 		runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n",
@@ -737,6 +730,9 @@ static void selectdefault(Select*, void*, int32);
 void
 runtime·selectdefault(Select *sel, bool selected)
 {
+	selected = false;
+	FLUSH(&selected);
+
 	selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
 }
 
@@ -750,8 +746,7 @@ selectdefault(Select *sel, void *callerpc, int32 so)
 	if(i >= sel->tcase)
 		runtime·throw("selectdefault: too many cases");
 	sel->ncase = i+1;
-	cas = runtime·mal(sizeof *cas);
-	sel->scase[i] = cas;
+	cas = &sel->scase[i];
 	cas->pc = callerpc;
 	cas->chan = nil;
 
@@ -764,25 +759,16 @@ selectdefault(Select *sel, void *callerpc, int32 so)
 }
 
 static void
-freesel(Select *sel)
-{
-	uint32 i;
-
-	for(i=0; i<sel->ncase; i++)
-		runtime·free(sel->scase[i]);
-	runtime·free(sel);
-}
-
-static void
 sellock(Select *sel)
 {
 	uint32 i;
-	Hchan *c;
+	Hchan *c, *c0;
 
 	c = nil;
 	for(i=0; i<sel->ncase; i++) {
-		if(sel->scase[i]->chan != c) {
-			c = sel->scase[i]->chan;
+		c0 = sel->lockorder[i];
+		if(c0 && c0 != c) {
+			c = sel->lockorder[i];
 			runtime·lock(c);
 		}
 	}
@@ -792,12 +778,13 @@ static void
 selunlock(Select *sel)
 {
 	uint32 i;
-	Hchan *c;
+	Hchan *c, *c0;
 
 	c = nil;
-	for(i=sel->ncase; i>0; i--) {
-		if(sel->scase[i-1]->chan && sel->scase[i-1]->chan != c) {
-			c = sel->scase[i-1]->chan;
+	for(i=sel->ncase; i-->0;) {
+		c0 = sel->lockorder[i];
+		if(c0 && c0 != c) {
+			c = c0;
 			runtime·unlock(c);
 		}
 	}
@@ -852,20 +839,20 @@ selectgo(Select **selp)
 
 	// generate permuted order
 	for(i=0; i<sel->ncase; i++)
-		sel->order[i] = i;
+		sel->pollorder[i] = i;
 	for(i=1; i<sel->ncase; i++) {
-		o = sel->order[i];
-		j = fastrandn(i+1);
-		sel->order[i] = sel->order[j];
-		sel->order[j] = o;
+		o = sel->pollorder[i];
+		j = runtime·fastrand1()%(i+1);
+		sel->pollorder[i] = sel->pollorder[j];
+		sel->pollorder[j] = o;
 	}
 
 	// sort the cases by Hchan address to get the locking order.
-	for(i=1; i<sel->ncase; i++) {
-		cas = sel->scase[i];
-		for(j=i; j>0 && sel->scase[j-1]->chan >= cas->chan; j--)
-			sel->scase[j] = sel->scase[j-1];
-		sel->scase[j] = cas;
+	for(i=0; i<sel->ncase; i++) {
+		c = sel->scase[i].chan;
+		for(j=i; j>0 && sel->lockorder[j-1] >= c; j--)
+			sel->lockorder[j] = sel->lockorder[j-1];
+		sel->lockorder[j] = c;
 	}
 	sellock(sel);
 
@@ -873,8 +860,8 @@ loop:
 	// pass 1 - look for something already waiting
 	dfl = nil;
 	for(i=0; i<sel->ncase; i++) {
-		o = sel->order[i];
-		cas = sel->scase[o];
+		o = sel->pollorder[i];
+		cas = &sel->scase[o];
 		c = cas->chan;
 
 		switch(cas->kind) {
@@ -883,7 +870,7 @@ loop:
 				if(c->qcount > 0)
 					goto asyncrecv;
 			} else {
-				sg = dequeue(&c->sendq, c);
+				sg = dequeue(&c->sendq);
 				if(sg != nil)
 					goto syncrecv;
 			}
@@ -898,7 +885,7 @@ loop:
 				if(c->qcount < c->dataqsiz)
 					goto asyncsend;
 			} else {
-				sg = dequeue(&c->recvq, c);
+				sg = dequeue(&c->recvq);
 				if(sg != nil)
 					goto syncsend;
 			}
@@ -911,6 +898,7 @@ loop:
 	}
 
 	if(dfl != nil) {
+		selunlock(sel);
 		cas = dfl;
 		goto retc;
 	}
@@ -918,11 +906,11 @@ loop:
 
 	// pass 2 - enqueue on all chans
 	for(i=0; i<sel->ncase; i++) {
-		o = sel->order[i];
-		cas = sel->scase[o];
+		cas = &sel->scase[i];
 		c = cas->chan;
-		sg = allocsg(c);
-		sg->offset = o;
+		sg = &cas->sg;
+		sg->g = g;
+		sg->selgen = g->selgen;
 
 		switch(cas->kind) {
 		case CaseRecv:
@@ -930,8 +918,6 @@ loop:
 			break;
 		
 		case CaseSend:
-			if(c->dataqsiz == 0)
-				c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
 			enqueue(&c->sendq, sg);
 			break;
 		}
@@ -948,85 +934,82 @@ loop:
 	// pass 3 - dequeue from unsuccessful chans
 	// otherwise they stack up on quiet channels
 	for(i=0; i<sel->ncase; i++) {
-		if(sg == nil || i != sg->offset) {
-			cas = sel->scase[i];
+		cas = &sel->scase[i];
+		if(cas != (Scase*)sg) {
 			c = cas->chan;
 			if(cas->kind == CaseSend)
-				dequeueg(&c->sendq, c);
+				dequeueg(&c->sendq);
 			else
-				dequeueg(&c->recvq, c);
+				dequeueg(&c->recvq);
 		}
 	}
 
 	if(sg == nil)
 		goto loop;
 
-	o = sg->offset;
-	cas = sel->scase[o];
+	cas = (Scase*)sg;
 	c = cas->chan;
 
-	if(c->dataqsiz > 0) {
-//		prints("shouldnt happen\n");
-		goto loop;
-	}
+	if(c->dataqsiz > 0)
+		runtime·throw("selectgo: shouldnt happen");
 
 	if(debug)
-		runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d o=%d\n",
-			sel, c, cas, cas->kind, o);
+		runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
+			sel, c, cas, cas->kind);
 
 	if(cas->kind == CaseRecv) {
-		if(cas->u.recv.receivedp != nil)
-			*cas->u.recv.receivedp = true;
-		if(cas->u.recv.elemp != nil)
-			c->elemalg->copy(c->elemsize, cas->u.recv.elemp, sg->elem);
-		c->elemalg->copy(c->elemsize, sg->elem, nil);
+		if(cas->receivedp != nil)
+			*cas->receivedp = true;
 	}
 
-	freesg(c, sg);
+	selunlock(sel);
 	goto retc;
 
 asyncrecv:
 	// can receive from buffer
-	if(cas->u.recv.receivedp != nil)
-		*cas->u.recv.receivedp = true;
-	if(cas->u.recv.elemp != nil)
-		c->elemalg->copy(c->elemsize, cas->u.recv.elemp, chanbuf(c, c->recvx));
+	if(cas->receivedp != nil)
+		*cas->receivedp = true;
+	if(cas->sg.elem != nil)
+		c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
 	c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
 	if(++c->recvx == c->dataqsiz)
 		c->recvx = 0;
 	c->qcount--;
-	sg = dequeue(&c->sendq, c);
+	sg = dequeue(&c->sendq);
 	if(sg != nil) {
 		gp = sg->g;
-		freesg(c, sg);
+		selunlock(sel);
 		runtime·ready(gp);
+	} else {
+		selunlock(sel);
 	}
 	goto retc;
 
 asyncsend:
 	// can send to buffer
-	if(cas->u.elem != nil)
-		c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->u.elem);
+	c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
 	if(++c->sendx == c->dataqsiz)
 		c->sendx = 0;
 	c->qcount++;
-	sg = dequeue(&c->recvq, c);
+	sg = dequeue(&c->recvq);
 	if(sg != nil) {
 		gp = sg->g;
-		freesg(c, sg);
+		selunlock(sel);
 		runtime·ready(gp);
+	} else {
+		selunlock(sel);
 	}
 	goto retc;
 
 syncrecv:
 	// can receive from sleeping sender (sg)
+	selunlock(sel);
 	if(debug)
 		runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
-	if(cas->u.recv.receivedp != nil)
-		*cas->u.recv.receivedp = true;
-	if(cas->u.recv.elemp != nil)
-		c->elemalg->copy(c->elemsize, cas->u.recv.elemp, sg->elem);
-	c->elemalg->copy(c->elemsize, sg->elem, nil);
+	if(cas->receivedp != nil)
+		*cas->receivedp = true;
+	if(cas->sg.elem != nil)
+		c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem);
 	gp = sg->g;
 	gp->param = sg;
 	runtime·ready(gp);
@@ -1034,30 +1017,28 @@ syncrecv:
 
 rclose:
 	// read at end of closed channel
-	if(cas->u.recv.receivedp != nil)
-		*cas->u.recv.receivedp = false;
-	if(cas->u.recv.elemp != nil)
-		c->elemalg->copy(c->elemsize, cas->u.recv.elemp, nil);
+	selunlock(sel);
+	if(cas->receivedp != nil)
+		*cas->receivedp = false;
+	if(cas->sg.elem != nil)
+		c->elemalg->copy(c->elemsize, cas->sg.elem, nil);
 	goto retc;
 
 syncsend:
 	// can send to sleeping receiver (sg)
+	selunlock(sel);
 	if(debug)
 		runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
-	if(c->closed)
-		goto sclose;
-	c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+	c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
 	gp = sg->g;
 	gp->param = sg;
 	runtime·ready(gp);
 
 retc:
-	selunlock(sel);
-
 	// return to pc corresponding to chosen case
 	pc = cas->pc;
 	as = (byte*)selp + cas->so;
-	freesel(sel);
+	runtime·free(sel);
 	*as = true;
 	return pc;
 
@@ -1088,23 +1069,21 @@ runtime·closechan(Hchan *c)
 
 	// release all readers
 	for(;;) {
-		sg = dequeue(&c->recvq, c);
+		sg = dequeue(&c->recvq);
 		if(sg == nil)
 			break;
 		gp = sg->g;
 		gp->param = nil;
-		freesg(c, sg);
 		runtime·ready(gp);
 	}
 
 	// release all writers
 	for(;;) {
-		sg = dequeue(&c->sendq, c);
+		sg = dequeue(&c->sendq);
 		if(sg == nil)
 			break;
 		gp = sg->g;
 		gp->param = nil;
-		freesg(c, sg);
 		runtime·ready(gp);
 	}
 
@@ -1144,7 +1123,7 @@ reflect·chancap(Hchan *c, int32 cap)
 }
 
 static SudoG*
-dequeue(WaitQ *q, Hchan *c)
+dequeue(WaitQ *q)
 {
 	SudoG *sgp;
 
@@ -1155,9 +1134,10 @@ loop:
 	q->first = sgp->link;
 
 	// if sgp is stale, ignore it
-	if(!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) {
+	if(sgp->selgen != NOSELGEN &&
+		(sgp->selgen != sgp->g->selgen ||
+		!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
 		//prints("INVALID PSEUDOG POINTER\n");
-		freesg(c, sgp);
 		goto loop;
 	}
 
@@ -1165,14 +1145,16 @@ loop:
 }
 
 static void
-dequeueg(WaitQ *q, Hchan *c)
+dequeueg(WaitQ *q)
 {
-	SudoG **l, *sgp;
-	
-	for(l=&q->first; (sgp=*l) != nil; l=&sgp->link) {
+	SudoG **l, *sgp, *prevsgp;
+
+	prevsgp = nil;
+	for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
 		if(sgp->g == g) {
 			*l = sgp->link;
-			freesg(c, sgp);
+			if(q->last == sgp)
+				q->last = prevsgp;
 			break;
 		}
 	}
@@ -1190,62 +1172,3 @@ enqueue(WaitQ *q, SudoG *sgp)
 	q->last->link = sgp;
 	q->last = sgp;
 }
-
-static SudoG*
-allocsg(Hchan *c)
-{
-	SudoG* sg;
-
-	sg = c->free;
-	if(sg != nil) {
-		c->free = sg->link;
-	} else
-		sg = runtime·mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
-	sg->selgen = g->selgen;
-	sg->g = g;
-	sg->offset = 0;
-	sg->isfree = 0;
-
-	return sg;
-}
-
-static void
-freesg(Hchan *c, SudoG *sg)
-{
-	if(sg != nil) {
-		if(sg->isfree)
-			runtime·throw("chan.freesg: already free");
-		sg->isfree = 1;
-		sg->link = c->free;
-		c->free = sg;
-	}
-}
-
-static uint32
-fastrand1(void)
-{
-	static uint32 x = 0x49f6428aUL;
-
-	x += x;
-	if(x & 0x80000000L)
-		x ^= 0x88888eefUL;
-	return x;
-}
-
-static uint32
-fastrandn(uint32 n)
-{
-	uint32 max, r;
-
-	if(n <= 1)
-		return 0;
-
-	r = fastrand1();
-	if(r < (1ULL<<31)-n)  // avoid computing max in common case
-		return r%n;
-
-	max = (1ULL<<31)/n * n;
-	while(r >= max)
-		r = fastrand1();
-	return r%n;
-}
diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go
new file mode 100644
index 0000000..c5ffe93
--- /dev/null
+++ b/src/pkg/runtime/chan_test.go
@@ -0,0 +1,267 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+	"runtime"
+	"sync/atomic"
+	"testing"
+)
+
+func TestChanSendInterface(t *testing.T) {
+	type mt struct{}
+	m := &mt{}
+	c := make(chan interface{}, 1)
+	c <- m
+	select {
+	case c <- m:
+	default:
+	}
+	select {
+	case c <- m:
+	case c <- &mt{}:
+	default:
+	}
+}
+
+func BenchmarkSelectUncontended(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			myc1 := make(chan int, 1)
+			myc2 := make(chan int, 1)
+			myc1 <- 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				for g := 0; g < CallsPerSched; g++ {
+					select {
+					case <-myc1:
+						myc2 <- 0
+					case <-myc2:
+						myc1 <- 0
+					}
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkSelectContended(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	myc1 := make(chan int, procs)
+	myc2 := make(chan int, procs)
+	for p := 0; p < procs; p++ {
+		myc1 <- 0
+		go func() {
+			for atomic.AddInt32(&N, -1) >= 0 {
+				for g := 0; g < CallsPerSched; g++ {
+					select {
+					case <-myc1:
+						myc2 <- 0
+					case <-myc2:
+						myc1 <- 0
+					}
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkSelectNonblock(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			myc1 := make(chan int)
+			myc2 := make(chan int)
+			myc3 := make(chan int, 1)
+			myc4 := make(chan int, 1)
+			for atomic.AddInt32(&N, -1) >= 0 {
+				for g := 0; g < CallsPerSched; g++ {
+					select {
+					case <-myc1:
+					default:
+					}
+					select {
+					case myc2 <- 0:
+					default:
+					}
+					select {
+					case <-myc3:
+					default:
+					}
+					select {
+					case myc4 <- 0:
+					default:
+					}
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkChanUncontended(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			myc := make(chan int, CallsPerSched)
+			for atomic.AddInt32(&N, -1) >= 0 {
+				for g := 0; g < CallsPerSched; g++ {
+					myc <- 0
+				}
+				for g := 0; g < CallsPerSched; g++ {
+					<-myc
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkChanContended(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	myc := make(chan int, procs*CallsPerSched)
+	for p := 0; p < procs; p++ {
+		go func() {
+			for atomic.AddInt32(&N, -1) >= 0 {
+				for g := 0; g < CallsPerSched; g++ {
+					myc <- 0
+				}
+				for g := 0; g < CallsPerSched; g++ {
+					<-myc
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkChanSync(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := 2
+	N := int32(b.N / CallsPerSched / procs * procs)
+	c := make(chan bool, procs)
+	myc := make(chan int)
+	for p := 0; p < procs; p++ {
+		go func() {
+			for {
+				i := atomic.AddInt32(&N, -1)
+				if i < 0 {
+					break
+				}
+				for g := 0; g < CallsPerSched; g++ {
+					if i%2 == 0 {
+						<-myc
+						myc <- 0
+					} else {
+						myc <- 0
+						<-myc
+					}
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, 2*procs)
+	myc := make(chan int, chanSize)
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				for g := 0; g < CallsPerSched; g++ {
+					for i := 0; i < localWork; i++ {
+						foo *= 2
+						foo /= 2
+					}
+					myc <- 1
+				}
+			}
+			myc <- 0
+			c <- foo == 42
+		}()
+		go func() {
+			foo := 0
+			for {
+				v := <-myc
+				if v == 0 {
+					break
+				}
+				for i := 0; i < localWork; i++ {
+					foo *= 2
+					foo /= 2
+				}
+			}
+			c <- foo == 42
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+		<-c
+	}
+}
+
+func BenchmarkChanProdCons0(b *testing.B) {
+	benchmarkChanProdCons(b, 0, 0)
+}
+
+func BenchmarkChanProdCons10(b *testing.B) {
+	benchmarkChanProdCons(b, 10, 0)
+}
+
+func BenchmarkChanProdCons100(b *testing.B) {
+	benchmarkChanProdCons(b, 100, 0)
+}
+
+func BenchmarkChanProdConsWork0(b *testing.B) {
+	benchmarkChanProdCons(b, 0, 100)
+}
+
+func BenchmarkChanProdConsWork10(b *testing.B) {
+	benchmarkChanProdCons(b, 10, 100)
+}
+
+func BenchmarkChanProdConsWork100(b *testing.B) {
+	benchmarkChanProdCons(b, 100, 100)
+}
diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.c
index 6233bcb..74b795b 100644
--- a/src/pkg/runtime/cpuprof.c
+++ b/src/pkg/runtime/cpuprof.c
@@ -121,6 +121,10 @@ runtime·SetCPUProfileRate(int32 hz)
 {
 	uintptr *p;
 	uintptr n;
+	
+	// Call findfunc now so that it won't have to
+	// build tables during the signal handler.
+	runtime·findfunc(0);
 
 	// Clamp hz to something reasonable.
 	if(hz < 0)
diff --git a/src/pkg/runtime/debug/stack_test.go b/src/pkg/runtime/debug/stack_test.go
index 4aeea13..94293bb 100644
--- a/src/pkg/runtime/debug/stack_test.go
+++ b/src/pkg/runtime/debug/stack_test.go
@@ -23,7 +23,7 @@ func (t T) method() []byte {
 	Don't worry much about the base levels, but check the ones in our own package.
 
 		/Users/r/go/src/pkg/runtime/debug/stack_test.go:15 (0x13878)
-			*T.ptrmethod: return Stack()
+			(*T).ptrmethod: return Stack()
 		/Users/r/go/src/pkg/runtime/debug/stack_test.go:18 (0x138dd)
 			T.method: return t.ptrmethod()
 		/Users/r/go/src/pkg/runtime/debug/stack_test.go:23 (0x13920)
@@ -40,7 +40,7 @@ func TestStack(t *testing.T) {
 		t.Fatal("too few lines")
 	}
 	check(t, lines[0], "src/pkg/runtime/debug/stack_test.go")
-	check(t, lines[1], "\t*T.ptrmethod: return Stack()")
+	check(t, lines[1], "\t(*T).ptrmethod: return Stack()")
 	check(t, lines[2], "src/pkg/runtime/debug/stack_test.go")
 	check(t, lines[3], "\tT.method: return t.ptrmethod()")
 	check(t, lines[4], "src/pkg/runtime/debug/stack_test.go")
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index 58631c7..53c5fcb 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -15,3 +15,9 @@ var F32to64 = f32to64
 var Fcmp64 = fcmp64
 var Fintto64 = fintto64
 var F64toint = f64toint
+
+func entersyscall()
+func exitsyscall()
+
+var Entersyscall = entersyscall
+var Exitsyscall = exitsyscall
diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c
index 3600f07..2fe7ecd 100644
--- a/src/pkg/runtime/freebsd/386/signal.c
+++ b/src/pkg/runtime/freebsd/386/signal.c
@@ -111,6 +111,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 	runtime·exit(2);
 }
 
+// Called from kernel on signal stack, so no stack split.
+#pragma textflag 7
 void
 runtime·sigignore(void)
 {
diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c
index 85cb1d8..8015e36 100644
--- a/src/pkg/runtime/freebsd/amd64/signal.c
+++ b/src/pkg/runtime/freebsd/amd64/signal.c
@@ -119,6 +119,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 	runtime·exit(2);
 }
 
+// Called from kernel on signal stack, so no stack split.
+#pragma textflag 7
 void
 runtime·sigignore(void)
 {
diff --git a/src/pkg/runtime/goc2c.c b/src/pkg/runtime/goc2c.c
index 826ceff..61236e2 100644
--- a/src/pkg/runtime/goc2c.c
+++ b/src/pkg/runtime/goc2c.c
@@ -2,26 +2,27 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-/* Translate a .goc file into a .c file.  A .goc file is a combination
-   of a limited form of Go with C.  */
+/*
+ * Translate a .goc file into a .c file.  A .goc file is a combination
+ * of a limited form of Go with C.
+ */
 
 /*
-   package PACKAGENAME
-   {# line}
-   func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
-     C code with proper brace nesting
-   \}
+	package PACKAGENAME
+	{# line}
+	func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
+	  C code with proper brace nesting
+	\}
 */
 
-/* We generate C code which implements the function such that it can
-   be called from Go and executes the C code.  */
+/*
+ * We generate C code which implements the function such that it can
+ * be called from Go and executes the C code.
+ */
 
-#include <assert.h>
-#include <ctype.h>
+#include <u.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
+#include <libc.h>
 
 /* Whether we're emitting for gcc */
 static int gcc;
@@ -88,16 +89,14 @@ int structround = 4;
 static void
 bad_eof(void)
 {
-	fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
-	exit(1);
+	sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
 }
 
 /* Out of memory.  */
 static void
 bad_mem(void)
 {
-	fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
-	exit(1);
+	sysfatal("%s:%ud: out of memory\n", file, lineno);
 }
 
 /* Allocate memory without fail.  */
@@ -196,8 +195,10 @@ getchar_skipping_comments(void)
 	}
 }
 
-/* Read and return a token.  Tokens are delimited by whitespace or by
-   [(),{}].  The latter are all returned as single characters.  */
+/*
+ * Read and return a token.  Tokens are delimited by whitespace or by
+ * [(),{}].  The latter are all returned as single characters.
+ */
 static char *
 read_token(void)
 {
@@ -259,11 +260,11 @@ read_package(void)
 	char *token;
 
 	token = read_token_no_eof();
+	if (token == nil)
+		sysfatal("%s:%ud: no token\n", file, lineno);
 	if (strcmp(token, "package") != 0) {
-		fprintf(stderr,
-			"%s:%u: expected \"package\", got \"%s\"\n",
+		sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
 			file, lineno, token);
-		exit(1);
 	}
 	return read_token_no_eof();
 }
@@ -290,8 +291,10 @@ read_preprocessor_lines(void)
 	}
 }
 
-/* Read a type in Go syntax and return a type in C syntax.  We only
-   permit basic types and pointers.  */
+/*
+ * Read a type in Go syntax and return a type in C syntax.  We only
+ * permit basic types and pointers.
+ */
 static char *
 read_type(void)
 {
@@ -333,13 +336,14 @@ type_size(char *p)
 	for(i=0; type_table[i].name; i++)
 		if(strcmp(type_table[i].name, p) == 0)
 			return type_table[i].size;
-	fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p);
-	exit(1);
+	sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
 	return 0;
 }
 
-/* Read a list of parameters.  Each parameter is a name and a type.
-   The list ends with a ')'.  We have already read the '('.  */
+/*
+ * Read a list of parameters.  Each parameter is a name and a type.
+ * The list ends with a ')'.  We have already read the '('.
+ */
 static struct params *
 read_params(int *poffset)
 {
@@ -375,17 +379,18 @@ read_params(int *poffset)
 		}
 	}
 	if (strcmp(token, ")") != 0) {
-		fprintf(stderr, "%s:%u: expected '('\n",
+		sysfatal("%s:%ud: expected '('\n",
 			file, lineno);
-		exit(1);
 	}
 	if (poffset != NULL)
 		*poffset = offset;
 	return ret;
 }
 
-/* Read a function header.  This reads up to and including the initial
-   '{' character.  Returns 1 if it read a header, 0 at EOF.  */
+/*
+ * Read a function header.  This reads up to and including the initial
+ * '{' character.  Returns 1 if it read a header, 0 at EOF.
+ */
 static int
 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
 {
@@ -416,9 +421,8 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
 
 	token = read_token();
 	if (token == NULL || strcmp(token, "(") != 0) {
-		fprintf(stderr, "%s:%u: expected \"(\"\n",
+		sysfatal("%s:%ud: expected \"(\"\n",
 			file, lineno);
-		exit(1);
 	}
 	*params = read_params(paramwid);
 
@@ -430,9 +434,8 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
 		token = read_token();
 	}
 	if (token == NULL || strcmp(token, "{") != 0) {
-		fprintf(stderr, "%s:%u: expected \"{\"\n",
+		sysfatal("%s:%ud: expected \"{\"\n",
 			file, lineno);
-		exit(1);
 	}
 	return 1;
 }
@@ -581,8 +584,10 @@ write_func_trailer(char *package, char *name,
 		write_6g_func_trailer(rets);
 }
 
-/* Read and write the body of the function, ending in an unnested }
-   (which is read but not written).  */
+/*
+ * Read and write the body of the function, ending in an unnested }
+ * (which is read but not written).
+ */
 static void
 copy_body(void)
 {
@@ -669,15 +674,15 @@ process_file(void)
 static void
 usage(void)
 {
-	fprintf(stderr, "Usage: goc2c [--6g | --gc] [file]\n");
-	exit(1);
+	sysfatal("Usage: goc2c [--6g | --gc] [file]\n");
 }
 
-int
+void
 main(int argc, char **argv)
 {
 	char *goarch;
 
+	argv0 = argv[0];
 	while(argc > 1 && argv[1][0] == '-') {
 		if(strcmp(argv[1], "-") == 0)
 			break;
@@ -694,7 +699,7 @@ main(int argc, char **argv)
 	if(argc <= 1 || strcmp(argv[1], "-") == 0) {
 		file = "<stdin>";
 		process_file();
-		return 0;
+		exits(0);
 	}
 
 	if(argc > 2)
@@ -702,8 +707,7 @@ main(int argc, char **argv)
 
 	file = argv[1];
 	if(freopen(file, "r", stdin) == 0) {
-		fprintf(stderr, "open %s: %s\n", file, strerror(errno));
-		exit(1);
+		sysfatal("open %s: %r\n", file);
 	}
 
 	if(!gcc) {
@@ -719,5 +723,5 @@ main(int argc, char **argv)
 	}
 
 	process_file();
-	return 0;
+	exits(0);
 }
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index 5ba1eb2..179a563 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -753,12 +753,12 @@ runtime·makemap_c(Type *key, Type *val, int64 hint)
 	// func(key) (val[, pres])
 	h->ko1 = runtime·rnd(sizeof(h), key->align);
 	h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd);
-	h->po1 = runtime·rnd(h->vo1+valsize, 1);
+	h->po1 = h->vo1 + valsize;
 
 	// func(key, val[, pres])
 	h->ko2 = runtime·rnd(sizeof(h), key->align);
 	h->vo2 = runtime·rnd(h->ko2+keysize, val->align);
-	h->po2 = runtime·rnd(h->vo2+valsize, 1);
+	h->po2 = h->vo2 + valsize;
 
 	if(debug) {
 		runtime·printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index d0fd352..19ff416 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -65,7 +65,7 @@
 
 #define	malloc		runtime·mal
 #define	memset(a,b,c)	runtime·memclr((byte*)(a), (uint32)(c))
-#define	memcpy(a,b,c)	runtime·mcpy((byte*)(a),(byte*)(b),(uint32)(c))
+#define	memcpy(a,b,c)	runtime·memmove((byte*)(a),(byte*)(b),(uint32)(c))
 #define	assert(a)	if(!(a)) runtime·throw("assert")
 #define free(x)	runtime·free(x)
 #define memmove(a,b,c)	runtime·memmove(a, b, c)
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index b1015f6..000f834 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -81,7 +81,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
 	for(locked=0; locked<2; locked++) {
 		if(locked)
 			runtime·lock(&ifacelock);
-		for(m=hash[h]; m!=nil; m=m->link) {
+		for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) {
 			if(m->inter == inter && m->type == type) {
 				if(m->bad) {
 					m = nil;
@@ -145,10 +145,11 @@ search:
 	}
 
 out:
+	if(!locked)
+		runtime·panicstring("invalid itab locking");
 	m->link = hash[h];
-	hash[h] = m;
-	if(locked)
-		runtime·unlock(&ifacelock);
+	runtime·atomicstorep(&hash[h], m);
+	runtime·unlock(&ifacelock);
 	if(m->bad)
 		return nil;
 	return m;
@@ -264,7 +265,7 @@ runtime·assertI2T2(Type *t, Iface i, ...)
 
 	ret = (byte*)(&i+1);
 	wid = t->size;
-	ok = (bool*)(ret+runtime·rnd(wid, 1));
+	ok = (bool*)(ret + wid);
 
 	if(i.tab == nil || i.tab->type != t) {
 		*ok = false;
@@ -326,7 +327,7 @@ runtime·assertE2T2(Type *t, Eface e, ...)
 		runtime·throw("invalid interface value");
 	ret = (byte*)(&e+1);
 	wid = t->size;
-	ok = (bool*)(ret+runtime·rnd(wid, 1));
+	ok = (bool*)(ret + wid);
 
 	if(t != e.type) {
 		*ok = false;
diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h
index 6ae1c4e..73fe23e 100644
--- a/src/pkg/runtime/linux/386/defs.h
+++ b/src/pkg/runtime/linux/386/defs.h
@@ -61,6 +61,8 @@ enum {
 	ITIMER_REAL = 0,
 	ITIMER_VIRTUAL = 0x1,
 	ITIMER_PROF = 0x2,
+	O_RDONLY = 0,
+	O_CLOEXEC = 02000000,
 };
 
 // Types
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
index e8b4233..0b4a349 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -22,9 +22,31 @@ TEXT runtime·exit1(SB),7,$0
 	INT $3	// not reached
 	RET
 
+TEXT runtime·open(SB),7,$0
+	MOVL	$5, AX		// syscall - open
+	MOVL	4(SP), BX
+	MOVL	8(SP), CX
+	MOVL	12(SP), DX
+	INT	$0x80
+	RET
+
+TEXT runtime·close(SB),7,$0
+	MOVL	$6, AX		// syscall - close
+	MOVL	4(SP), BX
+	INT	$0x80
+	RET
+
 TEXT runtime·write(SB),7,$0
 	MOVL	$4, AX		// syscall - write
-	MOVL	4(SP),  BX
+	MOVL	4(SP), BX
+	MOVL	8(SP), CX
+	MOVL	12(SP), DX
+	INT	$0x80
+	RET
+
+TEXT runtime·read(SB),7,$0
+	MOVL	$3, AX		// syscall - read
+	MOVL	4(SP), BX
 	MOVL	8(SP), CX
 	MOVL	12(SP), DX
 	INT	$0x80
@@ -315,3 +337,8 @@ TEXT runtime·setldt(SB),7,$32
 	MOVW	AX, GS
 
 	RET
+
+TEXT runtime·osyield(SB),7,$0
+	MOVL	$158, AX
+	INT	$0x80
+	RET
diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h
index 70d6314..8053dd1 100644
--- a/src/pkg/runtime/linux/amd64/defs.h
+++ b/src/pkg/runtime/linux/amd64/defs.h
@@ -61,6 +61,8 @@ enum {
 	ITIMER_REAL = 0,
 	ITIMER_VIRTUAL = 0x1,
 	ITIMER_PROF = 0x2,
+	O_RDONLY = 0,
+	O_CLOEXEC = 02000000,
 };
 
 // Types
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
index 66fdab2..8b4dcd9 100644
--- a/src/pkg/runtime/linux/amd64/sys.s
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -28,6 +28,12 @@ TEXT runtime·open(SB),7,$0-16
 	SYSCALL
 	RET
 
+TEXT runtime·close(SB),7,$0-16
+	MOVL	8(SP), DI
+	MOVL	$3, AX			// syscall entry
+	SYSCALL
+	RET
+
 TEXT runtime·write(SB),7,$0-24
 	MOVL	8(SP), DI
 	MOVQ	16(SP), SI
@@ -36,6 +42,14 @@ TEXT runtime·write(SB),7,$0-24
 	SYSCALL
 	RET
 
+TEXT runtime·read(SB),7,$0-24
+	MOVL	8(SP), DI
+	MOVQ	16(SP), SI
+	MOVL	24(SP), DX
+	MOVL	$0, AX			// syscall entry
+	SYSCALL
+	RET
+
 TEXT runtime·raisesigpipe(SB),7,$12
 	MOVL	$186, AX	// syscall - gettid
 	SYSCALL
@@ -232,3 +246,7 @@ TEXT runtime·settls(SB),7,$32
 	CALL	runtime·notok(SB)
 	RET
 
+TEXT runtime·osyield(SB),7,$0
+	MOVL	$24, AX
+	SYSCALL
+	RET
diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/linux/arm/defs.h
index 6b2f22c..09b558e 100644
--- a/src/pkg/runtime/linux/arm/defs.h
+++ b/src/pkg/runtime/linux/arm/defs.h
@@ -61,6 +61,8 @@ enum {
 	ITIMER_REAL = 0,
 	ITIMER_PROF = 0x2,
 	ITIMER_VIRTUAL = 0x1,
+	O_RDONLY = 0,
+	O_CLOEXEC = 02000000,
 };
 
 // Types
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
index ab53498..8619f09 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -15,7 +15,10 @@
 #define SYS_BASE 0x0
 
 #define SYS_exit (SYS_BASE + 1)
+#define SYS_read (SYS_BASE + 3)
 #define SYS_write (SYS_BASE + 4)
+#define SYS_open (SYS_BASE + 5)
+#define SYS_close (SYS_BASE + 6)
 #define SYS_gettimeofday (SYS_BASE + 78)
 #define SYS_clone (SYS_BASE + 120)
 #define SYS_rt_sigreturn (SYS_BASE + 173)
@@ -29,10 +32,25 @@
 #define SYS_mincore (SYS_BASE + 219)
 #define SYS_gettid (SYS_BASE + 224)
 #define SYS_tkill (SYS_BASE + 238)
+#define SYS_sched_yield (SYS_BASE + 158)
 
 #define ARM_BASE (SYS_BASE + 0x0f0000)
 #define SYS_ARM_cacheflush (ARM_BASE + 2)
 
+TEXT runtime·open(SB),7,$0
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
+	MOVW	$SYS_open, R7
+	SWI	$0
+	RET
+
+TEXT runtime·close(SB),7,$0
+	MOVW	0(FP), R0
+	MOVW	$SYS_close, R7
+	SWI	$0
+	RET
+
 TEXT runtime·write(SB),7,$0
 	MOVW	0(FP), R0
 	MOVW	4(FP), R1
@@ -41,6 +59,14 @@ TEXT runtime·write(SB),7,$0
 	SWI	$0
 	RET
 
+TEXT runtime·read(SB),7,$0
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
+	MOVW	$SYS_read, R7
+	SWI	$0
+	RET
+
 TEXT runtime·exit(SB),7,$-4
 	MOVW	0(FP), R0
 	MOVW	$SYS_exit_group, R7
@@ -287,3 +313,7 @@ cascheck:
 TEXT runtime·casp(SB),7,$0
 	B	runtime·cas(SB)
 
+TEXT runtime·osyield(SB),7,$0
+	MOVW	$SYS_sched_yield, R7
+	SWI	$0
+	RET
diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c
index 7c7ca7b..8efba2b 100644
--- a/src/pkg/runtime/linux/thread.c
+++ b/src/pkg/runtime/linux/thread.c
@@ -8,6 +8,11 @@
 #include "stack.h"
 
 extern SigTab runtime·sigtab[];
+static int32 proccount;
+
+int32 runtime·open(uint8*, int32, int32);
+int32 runtime·close(int32);
+int32 runtime·read(int32, void*, int32);
 
 // Linux futex.
 //
@@ -15,11 +20,19 @@ extern SigTab runtime·sigtab[];
 //	futexwakeup(uint32 *addr)
 //
 // Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
-// Futexwakeup wakes up one thread sleeping on addr.
+// Futexwakeup wakes up threads sleeping on addr.
 // Futexsleep is allowed to wake up spuriously.
 
 enum
 {
+	MUTEX_UNLOCKED = 0,
+	MUTEX_LOCKED = 1,
+	MUTEX_SLEEPING = 2,
+
+	ACTIVE_SPIN = 4,
+	ACTIVE_SPIN_CNT = 30,
+	PASSIVE_SPIN = 1,
+
 	FUTEX_WAIT = 0,
 	FUTEX_WAKE = 1,
 
@@ -52,13 +65,13 @@ futexsleep(uint32 *addr, uint32 val)
 	runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
 }
 
-// If any procs are sleeping on addr, wake up at least one.
+// If any procs are sleeping on addr, wake up at most cnt.
 static void
-futexwakeup(uint32 *addr)
+futexwakeup(uint32 *addr, uint32 cnt)
 {
 	int64 ret;
 
-	ret = runtime·futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
+	ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0);
 
 	if(ret >= 0)
 		return;
@@ -66,70 +79,96 @@ futexwakeup(uint32 *addr)
 	// I don't know that futex wakeup can return
 	// EAGAIN or EINTR, but if it does, it would be
 	// safe to loop and call futex again.
-
-	runtime·prints("futexwakeup addr=");
-	runtime·printpointer(addr);
-	runtime·prints(" returned ");
-	runtime·printint(ret);
-	runtime·prints("\n");
+	runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret);
 	*(int32*)0x1006 = 0x1006;
 }
 
+static int32
+getproccount(void)
+{
+	int32 fd, rd, cnt, cpustrlen;
+	byte *cpustr, *pos, *bufpos;
+	byte buf[256];
+
+	fd = runtime·open((byte*)"/proc/stat", O_RDONLY|O_CLOEXEC, 0);
+	if(fd == -1)
+		return 1;
+	cnt = 0;
+	bufpos = buf;
+	cpustr = (byte*)"\ncpu";
+	cpustrlen = runtime·findnull(cpustr);
+	for(;;) {
+		rd = runtime·read(fd, bufpos, sizeof(buf)-cpustrlen);
+		if(rd == -1)
+			break;
+		bufpos[rd] = 0;
+		for(pos=buf; pos=runtime·strstr(pos, cpustr); cnt++, pos++) {
+		}
+		if(rd < cpustrlen)
+			break;
+		runtime·memmove(buf, bufpos+rd-cpustrlen+1, cpustrlen-1);
+		bufpos = buf+cpustrlen-1;
+	}
+	runtime·close(fd);
+	return cnt ? cnt : 1;
+}
 
-// Lock and unlock.
-//
-// The lock state is a single 32-bit word that holds
-// a 31-bit count of threads waiting for the lock
-// and a single bit (the low bit) saying whether the lock is held.
-// The uncontended case runs entirely in user space.
-// When contention is detected, we defer to the kernel (futex).
-//
-// A reminder: compare-and-swap runtime·cas(addr, old, new) does
-//	if(*addr == old) { *addr = new; return 1; }
-//	else return 0;
-// but atomically.
-
+// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
+// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
+// Note that there can be spinning threads during all states - they do not
+// affect mutex's state.
 static void
 futexlock(Lock *l)
 {
-	uint32 v;
+	uint32 i, v, wait, spin;
 
-again:
-	v = l->key;
-	if((v&1) == 0){
-		if(runtime·cas(&l->key, v, v|1)){
-			// Lock wasn't held; we grabbed it.
-			return;
+	// Speculative grab for lock.
+	v = runtime·xchg(&l->key, MUTEX_LOCKED);
+	if(v == MUTEX_UNLOCKED)
+		return;
+
+	// wait is either MUTEX_LOCKED or MUTEX_SLEEPING
+	// depending on whether there is a thread sleeping
+	// on this mutex.  If we ever change l->key from
+	// MUTEX_SLEEPING to some other value, we must be
+	// careful to change it back to MUTEX_SLEEPING before
+	// returning, to ensure that the sleeping thread gets
+	// its wakeup call.
+	wait = v;
+
+	if(proccount == 0)
+		proccount = getproccount();
+
+	// On uniprocessor's, no point spinning.
+	// On multiprocessors, spin for ACTIVE_SPIN attempts.
+	spin = 0;
+	if(proccount > 1)
+		spin = ACTIVE_SPIN;
+
+	for(;;) {
+		// Try for lock, spinning.
+		for(i = 0; i < spin; i++) {
+			while(l->key == MUTEX_UNLOCKED)
+				if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+						return;
+			runtime·procyield(ACTIVE_SPIN_CNT);
 		}
-		goto again;
-	}
 
-	// Lock was held; try to add ourselves to the waiter count.
-	if(!runtime·cas(&l->key, v, v+2))
-		goto again;
-
-	// We're accounted for, now sleep in the kernel.
-	//
-	// We avoid the obvious lock/unlock race because
-	// the kernel won't put us to sleep if l->key has
-	// changed underfoot and is no longer v+2.
-	//
-	// We only really care that (v&1) == 1 (the lock is held),
-	// and in fact there is a futex variant that could
-	// accommodate that check, but let's not get carried away.)
-	futexsleep(&l->key, v+2);
-
-	// We're awake: remove ourselves from the count.
-	for(;;){
-		v = l->key;
-		if(v < 2)
-			runtime·throw("bad lock key");
-		if(runtime·cas(&l->key, v, v-2))
-			break;
-	}
+		// Try for lock, rescheduling.
+		for(i=0; i < PASSIVE_SPIN; i++) {
+			while(l->key == MUTEX_UNLOCKED)
+				if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+					return;
+			runtime·osyield();
+		}
 
-	// Try for the lock again.
-	goto again;
+		// Sleep.
+		v = runtime·xchg(&l->key, MUTEX_SLEEPING);
+		if(v == MUTEX_UNLOCKED)
+			return;
+		wait = MUTEX_SLEEPING;
+		futexsleep(&l->key, MUTEX_SLEEPING);
+	}
 }
 
 static void
@@ -137,34 +176,26 @@ futexunlock(Lock *l)
 {
 	uint32 v;
 
-	// Atomically get value and clear lock bit.
-again:
-	v = l->key;
-	if((v&1) == 0)
+	v = runtime·xchg(&l->key, MUTEX_UNLOCKED);
+	if(v == MUTEX_UNLOCKED)
 		runtime·throw("unlock of unlocked lock");
-	if(!runtime·cas(&l->key, v, v&~1))
-		goto again;
-
-	// If there were waiters, wake one.
-	if(v & ~1)
-		futexwakeup(&l->key);
+	if(v == MUTEX_SLEEPING)
+		futexwakeup(&l->key, 1);
 }
 
 void
 runtime·lock(Lock *l)
 {
-	if(m->locks < 0)
-		runtime·throw("lock count");
-	m->locks++;
+	if(m->locks++ < 0)
+		runtime·throw("runtime·lock: lock count");
 	futexlock(l);
 }
 
 void
 runtime·unlock(Lock *l)
 {
-	m->locks--;
-	if(m->locks < 0)
-		runtime·throw("lock count");
+	if(--m->locks < 0)
+		runtime·throw("runtime·unlock: lock count");
 	futexunlock(l);
 }
 
@@ -175,35 +206,24 @@ runtime·destroylock(Lock*)
 
 
 // One-time notifications.
-//
-// Since the lock/unlock implementation already
-// takes care of sleeping in the kernel, we just reuse it.
-// (But it's a weird use, so it gets its own interface.)
-//
-// We use a lock to represent the event:
-// unlocked == event has happened.
-// Thus the lock starts out locked, and to wait for the
-// event you try to lock the lock.  To signal the event,
-// you unlock the lock.
-
 void
 runtime·noteclear(Note *n)
 {
-	n->lock.key = 0;	// memset(n, 0, sizeof *n)
-	futexlock(&n->lock);
+	n->state = 0;
 }
 
 void
 runtime·notewakeup(Note *n)
 {
-	futexunlock(&n->lock);
+	runtime·xchg(&n->state, 1);
+	futexwakeup(&n->state, 1<<30);
 }
 
 void
 runtime·notesleep(Note *n)
 {
-	futexlock(&n->lock);
-	futexunlock(&n->lock);	// Let other sleepers find out too.
+	while(runtime·atomicload(&n->state) == 0)
+		futexsleep(&n->state, 0);
 }
 
 
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index 49ab24d..b9fe36d 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -18,21 +18,6 @@ extern MStats mstats;	// defined in extern.go
 
 extern volatile int32 runtime·MemProfileRate;
 
-// Same algorithm from chan.c, but a different
-// instance of the static uint32 x.
-// Not protected by a lock - let the threads use
-// the same random number if they like.
-static uint32
-fastrand1(void)
-{
-	static uint32 x = 0x49f6428aUL;
-
-	x += x;
-	if(x & 0x80000000L)
-		x ^= 0x88888eefUL;
-	return x;
-}
-
 // Allocate an object of at least size bytes.
 // Small objects are allocated from the per-thread cache's free lists.
 // Large objects (> 32 kB) are allocated straight from the heap.
@@ -53,18 +38,18 @@ runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
 	if(size == 0)
 		size = 1;
 
-	mstats.nmalloc++;
+	c = m->mcache;
+	c->local_nmalloc++;
 	if(size <= MaxSmallSize) {
 		// Allocate from mcache free lists.
 		sizeclass = runtime·SizeToClass(size);
 		size = runtime·class_to_size[sizeclass];
-		c = m->mcache;
 		v = runtime·MCache_Alloc(c, sizeclass, size, zeroed);
 		if(v == nil)
 			runtime·throw("out of memory");
-		mstats.alloc += size;
-		mstats.total_alloc += size;
-		mstats.by_size[sizeclass].nmalloc++;
+		c->local_alloc += size;
+		c->local_total_alloc += size;
+		c->local_by_size[sizeclass].nmalloc++;
 	} else {
 		// TODO(rsc): Report tracebacks for very large allocations.
 
@@ -76,8 +61,8 @@ runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
 		if(s == nil)
 			runtime·throw("out of memory");
 		size = npages<<PageShift;
-		mstats.alloc += size;
-		mstats.total_alloc += size;
+		c->local_alloc += size;
+		c->local_total_alloc += size;
 		v = (void*)(s->start << PageShift);
 
 		// setup for mark sweep
@@ -97,7 +82,7 @@ runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
 			// pick next profile time
 			if(rate > 0x3fffffff)	// make 2*rate not overflow
 				rate = 0x3fffffff;
-			m->mcache->next_sample = fastrand1() % (2*rate);
+			m->mcache->next_sample = runtime·fastrand1() % (2*rate);
 		profile:
 			runtime·setblockspecial(v);
 			runtime·MProf_Malloc(v, size);
@@ -143,6 +128,7 @@ runtime·free(void *v)
 
 	// Find size class for v.
 	sizeclass = s->sizeclass;
+	c = m->mcache;
 	if(sizeclass == 0) {
 		// Large object.
 		size = s->npages<<PageShift;
@@ -154,7 +140,6 @@ runtime·free(void *v)
 		runtime·MHeap_Free(&runtime·mheap, s, 1);
 	} else {
 		// Small object.
-		c = m->mcache;
 		size = runtime·class_to_size[sizeclass];
 		if(size > sizeof(uintptr))
 			((uintptr*)v)[1] = 1;	// mark as "needs to be zeroed"
@@ -162,10 +147,10 @@ runtime·free(void *v)
 		// it might coalesce v and other blocks into a bigger span
 		// and change the bitmap further.
 		runtime·markfreed(v, size);
-		mstats.by_size[sizeclass].nfree++;
+		c->local_by_size[sizeclass].nfree++;
 		runtime·MCache_Free(c, v, sizeclass, size);
 	}
-	mstats.alloc -= size;
+	c->local_alloc -= size;
 	if(prof)
 		runtime·MProf_Free(v, size);
 	m->mallocing = 0;
@@ -178,7 +163,7 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
 	byte *p;
 	MSpan *s;
 
-	mstats.nlookup++;
+	m->mcache->local_nlookup++;
 	s = runtime·MHeap_LookupMaybe(&runtime·mheap, v);
 	if(sp)
 		*sp = s;
@@ -207,9 +192,10 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
 	}
 
 	n = runtime·class_to_size[s->sizeclass];
-	i = ((byte*)v - p)/n;
-	if(base)
+	if(base) {
+		i = ((byte*)v - p)/n;
 		*base = p + i*n;
+	}
 	if(size)
 		*size = n;
 
@@ -229,6 +215,29 @@ runtime·allocmcache(void)
 	return c;
 }
 
+void
+runtime·purgecachedstats(M* m)
+{
+	MCache *c;
+
+	// Protected by either heap or GC lock.
+	c = m->mcache;
+	mstats.heap_alloc += c->local_cachealloc;
+	c->local_cachealloc = 0;
+	mstats.heap_objects += c->local_objects;
+	c->local_objects = 0;
+	mstats.nmalloc += c->local_nmalloc;
+	c->local_nmalloc = 0;
+	mstats.nfree += c->local_nfree;
+	c->local_nfree = 0;
+	mstats.nlookup += c->local_nlookup;
+	c->local_nlookup = 0;
+	mstats.alloc += c->local_alloc;
+	c->local_alloc= 0;
+	mstats.total_alloc += c->local_total_alloc;
+	c->local_total_alloc= 0;
+}
+
 uintptr runtime·sizeof_C_MStats = sizeof(MStats);
 
 #define MaxArena32 (2U<<30)
@@ -373,46 +382,28 @@ func new(n uint32) (ret *uint8) {
 	ret = runtime·mal(n);
 }
 
-// Stack allocator uses malloc/free most of the time,
-// but if we're in the middle of malloc and need stack,
-// we have to do something else to avoid deadlock.
-// In that case, we fall back on a fixed-size free-list
-// allocator, assuming that inside malloc all the stack
-// frames are small, so that all the stack allocations
-// will be a single size, the minimum (right now, 5k).
-static struct {
-	Lock;
-	FixAlloc;
-} stacks;
-
-enum {
-	FixedStack = StackMin,
-};
-
 void*
 runtime·stackalloc(uint32 n)
 {
-	void *v;
-
 	// Stackalloc must be called on scheduler stack, so that we
 	// never try to grow the stack during the code that stackalloc runs.
 	// Doing so would cause a deadlock (issue 1547).
 	if(g != m->g0)
 		runtime·throw("stackalloc not on scheduler stack");
 
+	// Stack allocator uses malloc/free most of the time,
+	// but if we're in the middle of malloc and need stack,
+	// we have to do something else to avoid deadlock.
+	// In that case, we fall back on a fixed-size free-list
+	// allocator, assuming that inside malloc all the stack
+	// frames are small, so that all the stack allocations
+	// will be a single size, the minimum (right now, 5k).
 	if(m->mallocing || m->gcing || n == FixedStack) {
-		runtime·lock(&stacks);
-		if(stacks.size == 0)
-			runtime·FixAlloc_Init(&stacks, n, runtime·SysAlloc, nil, nil);
-		if(stacks.size != n) {
-			runtime·printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
+		if(n != FixedStack) {
+			runtime·printf("stackalloc: in malloc, size=%d want %d", FixedStack, n);
 			runtime·throw("stackalloc");
 		}
-		v = runtime·FixAlloc_Alloc(&stacks);
-		mstats.stacks_inuse = stacks.inuse;
-		mstats.stacks_sys = stacks.sys;
-		runtime·unlock(&stacks);
-		return v;
+		return runtime·FixAlloc_Alloc(m->stackalloc);
 	}
 	return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0);
 }
@@ -421,11 +412,7 @@ void
 runtime·stackfree(void *v, uintptr n)
 {
 	if(m->mallocing || m->gcing || n == FixedStack) {
-		runtime·lock(&stacks);
-		runtime·FixAlloc_Free(&stacks, v);
-		mstats.stacks_inuse = stacks.inuse;
-		mstats.stacks_sys = stacks.sys;
-		runtime·unlock(&stacks);
+		runtime·FixAlloc_Free(m->stackalloc, v);
 		return;
 	}
 	runtime·free(v);
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 4e27945..5bc80f4 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -80,7 +80,6 @@
 // This C code was written with an eye toward translating to Go
 // in the future.  Methods have the form Type_Method(Type *t, ...).
 
-typedef struct FixAlloc	FixAlloc;
 typedef struct MCentral	MCentral;
 typedef struct MHeap	MHeap;
 typedef struct MSpan	MSpan;
@@ -186,10 +185,10 @@ void	runtime·FixAlloc_Free(FixAlloc *f, void *p);
 // Shared with Go: if you edit this structure, also edit extern.go.
 struct MStats
 {
-	// General statistics.  No locking; approximate.
+	// General statistics.
 	uint64	alloc;		// bytes allocated and still in use
 	uint64	total_alloc;	// bytes allocated (even if freed)
-	uint64	sys;		// bytes obtained from system (should be sum of xxx_sys below)
+	uint64	sys;		// bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
 	uint64	nlookup;	// number of pointer lookups
 	uint64	nmalloc;	// number of mallocs
 	uint64	nfree;  // number of frees
@@ -222,7 +221,6 @@ struct MStats
 	bool	debuggc;
 	
 	// Statistics about allocation size classes.
-	// No locking; approximate.
 	struct {
 		uint32 size;
 		uint64 nmalloc;
@@ -268,9 +266,20 @@ struct MCache
 {
 	MCacheList list[NumSizeClasses];
 	uint64 size;
+	int64 local_cachealloc;	// bytes allocated (or freed) from cache since last lock of heap
+	int64 local_objects;	// objects allocated (or freed) from cache since last lock of heap
 	int64 local_alloc;	// bytes allocated (or freed) since last lock of heap
-	int64 local_objects;	// objects allocated (or freed) since last lock of heap
+	int64 local_total_alloc;	// bytes allocated (even if freed) since last lock of heap
+	int64 local_nmalloc;	// number of mallocs since last lock of heap
+	int64 local_nfree;	// number of frees since last lock of heap
+	int64 local_nlookup;	// number of pointer lookups since last lock of heap
 	int32 next_sample;	// trigger heap sample after allocating this many bytes
+	// Statistics about allocation size classes since last lock of heap
+	struct {
+		int64 nmalloc;
+		int64 nfree;
+	} local_by_size[NumSizeClasses];
+	
 };
 
 void*	runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
@@ -379,6 +388,7 @@ void	runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
 void	runtime·unmarkspan(void *v, uintptr size);
 bool	runtime·blockspecial(void*);
 void	runtime·setblockspecial(void*);
+void	runtime·purgecachedstats(M*);
 
 enum
 {
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index e406211..711e938 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -48,7 +48,7 @@ runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
 			v->next = nil;
 		}
 	}
-	c->local_alloc += size;
+	c->local_cachealloc += size;
 	c->local_objects++;
 	return v;
 }
@@ -90,7 +90,7 @@ runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
 	l->list = p;
 	l->nlist++;
 	c->size += size;
-	c->local_alloc -= size;
+	c->local_cachealloc -= size;
 	c->local_objects--;
 
 	if(l->nlist >= MaxMCacheListLen) {
diff --git a/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
index c3316d4..93d155a 100644
--- a/src/pkg/runtime/mem.go
+++ b/src/pkg/runtime/mem.go
@@ -62,8 +62,13 @@ func init() {
 }
 
 // MemStats holds statistics about the memory system.
-// The statistics are only approximate, as they are not interlocked on update.
+// The statistics may be out of date, as the information is
+// updated lazily from per-thread caches.
+// Use UpdateMemStats to bring the statistics up to date.
 var MemStats MemStatsType
 
+// UpdateMemStats brings MemStats up to date.
+func UpdateMemStats()
+
 // GC runs a garbage collection.
 func GC()
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index ac6a1fa..6325aad 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -484,6 +484,7 @@ sweep(void)
 			// Mark freed; restore block boundary bit.
 			*bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
 
+			c = m->mcache;
 			if(s->sizeclass == 0) {
 				// Free large span.
 				runtime·unmarkspan(p, 1<<PageShift);
@@ -491,14 +492,13 @@ sweep(void)
 				runtime·MHeap_Free(&runtime·mheap, s, 1);
 			} else {
 				// Free small object.
-				c = m->mcache;
 				if(size > sizeof(uintptr))
 					((uintptr*)p)[1] = 1;	// mark as "needs to be zeroed"
-				mstats.by_size[s->sizeclass].nfree++;
+				c->local_by_size[s->sizeclass].nfree++;
 				runtime·MCache_Free(c, p, s->sizeclass, size);
 			}
-			mstats.alloc -= size;
-			mstats.nfree++;
+			c->local_alloc -= size;
+			c->local_nfree++;
 		}
 	}
 }
@@ -533,14 +533,26 @@ cachestats(void)
 {
 	M *m;
 	MCache *c;
+	int32 i;
+	uint64 stacks_inuse;
+	uint64 stacks_sys;
 
+	stacks_inuse = 0;
+	stacks_sys = 0;
 	for(m=runtime·allm; m; m=m->alllink) {
+		runtime·purgecachedstats(m);
+		stacks_inuse += m->stackalloc->inuse;
+		stacks_sys += m->stackalloc->sys;
 		c = m->mcache;
-		mstats.heap_alloc += c->local_alloc;
-		c->local_alloc = 0;
-		mstats.heap_objects += c->local_objects;
-		c->local_objects = 0;
+		for(i=0; i<nelem(c->local_by_size); i++) {
+			mstats.by_size[i].nmalloc += c->local_by_size[i].nmalloc;
+			c->local_by_size[i].nmalloc = 0;
+			mstats.by_size[i].nfree += c->local_by_size[i].nfree;
+			c->local_by_size[i].nfree = 0;
+		}
 	}
+	mstats.stacks_inuse = stacks_inuse;
+	mstats.stacks_sys = stacks_sys;
 }
 
 void
@@ -603,6 +615,7 @@ runtime·gc(int32 force)
 	sweep();
 	t2 = runtime·nanotime();
 	stealcache();
+	cachestats();
 
 	mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
 	m->gcing = 0;
@@ -650,6 +663,22 @@ runtime·gc(int32 force)
 		runtime·gc(1);
 }
 
+void
+runtime·UpdateMemStats(void)
+{
+	// Have to acquire gcsema to stop the world,
+	// because stoptheworld can only be used by
+	// one goroutine at a time, and there might be
+	// a pending garbage collection already calling it.
+	runtime·semacquire(&gcsema);
+	m->gcing = 1;
+	runtime·stoptheworld();
+	cachestats();
+	m->gcing = 0;
+	runtime·semrelease(&gcsema);
+	runtime·starttheworld();
+}
+
 static void
 runfinq(void)
 {
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index dde31ce..37d5056 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -57,10 +57,7 @@ runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
 	MSpan *s;
 
 	runtime·lock(h);
-	mstats.heap_alloc += m->mcache->local_alloc;
-	m->mcache->local_alloc = 0;
-	mstats.heap_objects += m->mcache->local_objects;
-	m->mcache->local_objects = 0;
+	runtime·purgecachedstats(m);
 	s = MHeap_AllocLocked(h, npage, sizeclass);
 	if(s != nil) {
 		mstats.heap_inuse += npage<<PageShift;
@@ -258,10 +255,7 @@ void
 runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
 {
 	runtime·lock(h);
-	mstats.heap_alloc += m->mcache->local_alloc;
-	m->mcache->local_alloc = 0;
-	mstats.heap_objects += m->mcache->local_objects;
-	m->mcache->local_objects = 0;
+	runtime·purgecachedstats(m);
 	mstats.heap_inuse -= s->npages<<PageShift;
 	if(acct) {
 		mstats.heap_alloc -= s->npages<<PageShift;
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c
index 9dfdf2c..f795b2c 100644
--- a/src/pkg/runtime/plan9/mem.c
+++ b/src/pkg/runtime/plan9/mem.c
@@ -8,6 +8,7 @@
 
 extern byte end[];
 static byte *bloc = { end };
+static Lock memlock;
 
 enum
 {
@@ -19,23 +20,31 @@ runtime·SysAlloc(uintptr nbytes)
 {
 	uintptr bl;
 	
+	runtime·lock(&memlock);
+	mstats.sys += nbytes;
 	// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
 	bl = ((uintptr)bloc + Round) & ~Round;
-	if(runtime·brk_((void*)(bl + nbytes)) < 0)
+	if(runtime·brk_((void*)(bl + nbytes)) < 0) {
+		runtime·unlock(&memlock);
 		return (void*)-1;
+	}
 	bloc = (byte*)bl + nbytes;
+	runtime·unlock(&memlock);
 	return (void*)bl;
 }
 
 void
 runtime·SysFree(void *v, uintptr nbytes)
 {
+	runtime·lock(&memlock);
+	mstats.sys -= nbytes;
 	// from tiny/mem.c
 	// Push pointer back if this is a free
 	// of the most recent SysAlloc.
 	nbytes += (nbytes + Round) & ~Round;
 	if(bloc == (byte*)v+nbytes)
 		bloc -= nbytes;	
+	runtime·unlock(&memlock);
 }
 
 void
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
index ef9a23e..b091c59 100644
--- a/src/pkg/runtime/plan9/thread.c
+++ b/src/pkg/runtime/plan9/thread.c
@@ -47,11 +47,11 @@ runtime·exit(int32)
 		pid = pid/10;
 	}
 	p = buf;
-	runtime·mcpy((void*)p, (void*)"/proc/", 6);
+	runtime·memmove((void*)p, (void*)"/proc/", 6);
 	p += 6;
 	for(q--; q >= tmp;)
 		*p++ = *q--;
-	runtime·mcpy((void*)p, (void*)"/notepg", 7);
+	runtime·memmove((void*)p, (void*)"/notepg", 7);
 	
 	/* post interrupt note */
 	fd = runtime·open(buf, OWRITE);
@@ -167,3 +167,14 @@ os·sigpipe(void)
 {
 	runtime·throw("too many writes on closed pipe");
 }
+
+/*
+ * placeholder - once notes are implemented,
+ * a signal generating a panic must appear as
+ * a call to this function for correct handling by
+ * traceback.
+ */
+void
+runtime·sigpanic(void)
+{
+}
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index b8069aa..3ce7794 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -320,7 +320,7 @@ runtime·printpointer(void *p)
 void
 runtime·printstring(String v)
 {
-	extern int32 runtime·maxstring;
+	extern uint32 runtime·maxstring;
 
 	if(v.len > runtime·maxstring) {
 		runtime·write(2, "[invalid string]", 16);
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index a8f3a79..6d8f699 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -28,10 +28,10 @@ int32	runtime·gcwaiting;
 // Go scheduler
 //
 // The go scheduler's job is to match ready-to-run goroutines (`g's)
-// with waiting-for-work schedulers (`m's).  If there are ready gs
-// and no waiting ms, ready() will start a new m running in a new
-// OS thread, so that all ready gs can run simultaneously, up to a limit.
-// For now, ms never go away.
+// with waiting-for-work schedulers (`m's).  If there are ready g's
+// and no waiting m's, ready() will start a new m running in a new
+// OS thread, so that all ready g's can run simultaneously, up to a limit.
+// For now, m's never go away.
 //
 // By default, Go keeps only one kernel thread (m) running user code
 // at a single time; other threads may be blocked in the operating system.
@@ -41,10 +41,10 @@ int32	runtime·gcwaiting;
 // approximation of the maximum number of cores to use.
 //
 // Even a program that can run without deadlock in a single process
-// might use more ms if given the chance.  For example, the prime
-// sieve will use as many ms as there are primes (up to runtime·sched.mmax),
+// might use more m's if given the chance.  For example, the prime
+// sieve will use as many m's as there are primes (up to runtime·sched.mmax),
 // allowing different stages of the pipeline to execute in parallel.
-// We could revisit this choice, only kicking off new ms for blocking
+// We could revisit this choice, only kicking off new m's for blocking
 // system calls, but that would limit the amount of parallel computation
 // that go would try to do.
 //
@@ -55,27 +55,75 @@ int32	runtime·gcwaiting;
 struct Sched {
 	Lock;
 
-	G *gfree;	// available gs (status == Gdead)
+	G *gfree;	// available g's (status == Gdead)
+	int32 goidgen;
 
-	G *ghead;	// gs waiting to run
+	G *ghead;	// g's waiting to run
 	G *gtail;
-	int32 gwait;	// number of gs waiting to run
-	int32 gcount;	// number of gs that are alive
+	int32 gwait;	// number of g's waiting to run
+	int32 gcount;	// number of g's that are alive
+	int32 grunning;	// number of g's running on cpu or in syscall
 
-	M *mhead;	// ms waiting for work
-	int32 mwait;	// number of ms waiting for work
-	int32 mcount;	// number of ms that have been created
-	int32 mcpu;	// number of ms executing on cpu
-	int32 mcpumax;	// max number of ms allowed on cpu
-	int32 msyscall;	// number of ms in system calls
+	M *mhead;	// m's waiting for work
+	int32 mwait;	// number of m's waiting for work
+	int32 mcount;	// number of m's that have been created
 
-	int32 predawn;	// running initialization, don't run new gs.
+	volatile uint32 atomic;	// atomic scheduling word (see below)
+
+	int32 predawn;		// running initialization, don't run new g's.
 	int32 profilehz;	// cpu profiling rate
 
-	Note	stopped;	// one g can wait here for ms to stop
-	int32 waitstop;	// after setting this flag
+	Note	stopped;	// one g can set waitstop and wait here for m's to stop
+};
+
+// The atomic word in sched is an atomic uint32 that
+// holds these fields.
+//
+//	[15 bits] mcpu		number of m's executing on cpu
+//	[15 bits] mcpumax	max number of m's allowed on cpu
+//	[1 bit] waitstop	some g is waiting on stopped
+//	[1 bit] gwaiting	gwait != 0
+//
+// These fields are the information needed by entersyscall
+// and exitsyscall to decide whether to coordinate with the
+// scheduler.  Packing them into a single machine word lets
+// them use a fast path with a single atomic read/write and
+// no lock/unlock.  This greatly reduces contention in
+// syscall- or cgo-heavy multithreaded programs.
+//
+// Except for entersyscall and exitsyscall, the manipulations
+// to these fields only happen while holding the schedlock,
+// so the routines holding schedlock only need to worry about
+// what entersyscall and exitsyscall do, not the other routines
+// (which also use the schedlock).
+//
+// In particular, entersyscall and exitsyscall only read mcpumax,
+// waitstop, and gwaiting.  They never write them.  Thus, writes to those
+// fields can be done (holding schedlock) without fear of write conflicts.
+// There may still be logic conflicts: for example, the set of waitstop must
+// be conditioned on mcpu >= mcpumax or else the wait may be a
+// spurious sleep.  The Promela model in proc.p verifies these accesses.
+enum {
+	mcpuWidth = 15,
+	mcpuMask = (1<<mcpuWidth) - 1,
+	mcpuShift = 0,
+	mcpumaxShift = mcpuShift + mcpuWidth,
+	waitstopShift = mcpumaxShift + mcpuWidth,
+	gwaitingShift = waitstopShift+1,
+
+	// The max value of GOMAXPROCS is constrained
+	// by the max value we can store in the bit fields
+	// of the atomic word.  Reserve a few high values
+	// so that we can detect accidental decrement
+	// beyond zero.
+	maxgomaxprocs = mcpuMask - 10,
 };
 
+#define atomic_mcpu(v)		(((v)>>mcpuShift)&mcpuMask)
+#define atomic_mcpumax(v)	(((v)>>mcpumaxShift)&mcpuMask)
+#define atomic_waitstop(v)	(((v)>>waitstopShift)&1)
+#define atomic_gwaiting(v)	(((v)>>gwaitingShift)&1)
+
 Sched runtime·sched;
 int32 runtime·gomaxprocs;
 
@@ -93,9 +141,25 @@ static void mput(M*);	// put/get on mhead
 static M* mget(G*);
 static void gfput(G*);	// put/get on gfree
 static G* gfget(void);
-static void matchmg(void);	// match ms to gs
+static void matchmg(void);	// match m's to g's
 static void readylocked(G*);	// ready, but sched is locked
 static void mnextg(M*, G*);
+static void mcommoninit(M*);
+
+void
+setmcpumax(uint32 n)
+{
+	uint32 v, w;
+
+	for(;;) {
+		v = runtime·sched.atomic;
+		w = v;
+		w &= ~(mcpuMask<<mcpumaxShift);
+		w |= n<<mcpumaxShift;
+		if(runtime·cas(&runtime·sched.atomic, v, w))
+			break;
+	}
+}
 
 // The bootstrap sequence is:
 //
@@ -115,10 +179,10 @@ runtime·schedinit(void)
 	int32 n;
 	byte *p;
 
-	runtime·allm = m;
 	m->nomemprof++;
-
 	runtime·mallocinit();
+	mcommoninit(m);
+
 	runtime·goargs();
 	runtime·goenvs();
 
@@ -129,10 +193,12 @@ runtime·schedinit(void)
 
 	runtime·gomaxprocs = 1;
 	p = runtime·getenv("GOMAXPROCS");
-	if(p != nil && (n = runtime·atoi(p)) != 0)
+	if(p != nil && (n = runtime·atoi(p)) != 0) {
+		if(n > maxgomaxprocs)
+			n = maxgomaxprocs;
 		runtime·gomaxprocs = n;
-	runtime·sched.mcpumax = runtime·gomaxprocs;
-	runtime·sched.mcount = 1;
+	}
+	setmcpumax(runtime·gomaxprocs);
 	runtime·sched.predawn = 1;
 
 	m->nomemprof--;
@@ -167,7 +233,7 @@ runtime·initdone(void)
 	mstats.enablegc = 1;
 
 	// If main·init_function started other goroutines,
-	// kick off new ms to handle them, like ready
+	// kick off new m's to handle them, like ready
 	// would have, had it not been pre-dawn.
 	schedlock();
 	matchmg();
@@ -206,6 +272,37 @@ runtime·idlegoroutine(void)
 	g->idlem = m;
 }
 
+static void
+mcommoninit(M *m)
+{
+	// Add to runtime·allm so garbage collector doesn't free m
+	// when it is just in a register or thread-local storage.
+	m->alllink = runtime·allm;
+	// runtime·Cgocalls() iterates over allm w/o schedlock,
+	// so we need to publish it safely.
+	runtime·atomicstorep(&runtime·allm, m);
+
+	m->id = runtime·sched.mcount++;
+	m->fastrand = 0x49f6428aUL + m->id;
+	m->stackalloc = runtime·malloc(sizeof(*m->stackalloc));
+	runtime·FixAlloc_Init(m->stackalloc, FixedStack, runtime·SysAlloc, nil, nil);
+}
+
+// Try to increment mcpu.  Report whether succeeded.
+static bool
+canaddmcpu(void)
+{
+	uint32 v;
+
+	for(;;) {
+		v = runtime·sched.atomic;
+		if(atomic_mcpu(v) >= atomic_mcpumax(v))
+			return 0;
+		if(runtime·cas(&runtime·sched.atomic, v, v+(1<<mcpuShift)))
+			return 1;
+	}
+}
+
 // Put on `g' queue.  Sched must be locked.
 static void
 gput(G *g)
@@ -213,11 +310,11 @@ gput(G *g)
 	M *m;
 
 	// If g is wired, hand it off directly.
-	if(runtime·sched.mcpu < runtime·sched.mcpumax && (m = g->lockedm) != nil) {
+	if((m = g->lockedm) != nil && canaddmcpu()) {
 		mnextg(m, g);
 		return;
 	}
-	
+
 	// If g is the idle goroutine for an m, hand it off.
 	if(g->idlem != nil) {
 		if(g->idlem->idleg != nil) {
@@ -236,7 +333,18 @@ gput(G *g)
 	else
 		runtime·sched.gtail->schedlink = g;
 	runtime·sched.gtail = g;
-	runtime·sched.gwait++;
+
+	// increment gwait.
+	// if it transitions to nonzero, set atomic gwaiting bit.
+	if(runtime·sched.gwait++ == 0)
+		runtime·xadd(&runtime·sched.atomic, 1<<gwaitingShift);
+}
+
+// Report whether gget would return something.
+static bool
+haveg(void)
+{
+	return runtime·sched.ghead != nil || m->idleg != nil;
 }
 
 // Get from `g' queue.  Sched must be locked.
@@ -250,7 +358,10 @@ gget(void)
 		runtime·sched.ghead = g->schedlink;
 		if(runtime·sched.ghead == nil)
 			runtime·sched.gtail = nil;
-		runtime·sched.gwait--;
+		// decrement gwait.
+		// if it transitions to zero, clear atomic gwaiting bit.
+		if(--runtime·sched.gwait == 0)
+			runtime·xadd(&runtime·sched.atomic, -1<<gwaitingShift);
 	} else if(m->idleg != nil) {
 		g = m->idleg;
 		m->idleg = nil;
@@ -335,10 +446,11 @@ newprocreadylocked(G *g)
 }
 
 // Pass g to m for running.
+// Caller has already incremented mcpu.
 static void
 mnextg(M *m, G *g)
 {
-	runtime·sched.mcpu++;
+	runtime·sched.grunning++;
 	m->nextg = g;
 	if(m->waitnextg) {
 		m->waitnextg = 0;
@@ -350,18 +462,19 @@ mnextg(M *m, G *g)
 
 // Get the next goroutine that m should run.
 // Sched must be locked on entry, is unlocked on exit.
-// Makes sure that at most $GOMAXPROCS gs are
+// Makes sure that at most $GOMAXPROCS g's are
 // running on cpus (not in system calls) at any given time.
 static G*
 nextgandunlock(void)
 {
 	G *gp;
+	uint32 v;
 
-	if(runtime·sched.mcpu < 0)
-		runtime·throw("negative runtime·sched.mcpu");
+	if(atomic_mcpu(runtime·sched.atomic) >= maxgomaxprocs)
+		runtime·throw("negative mcpu");
 
-	// If there is a g waiting as m->nextg,
-	// mnextg took care of the runtime·sched.mcpu++.
+	// If there is a g waiting as m->nextg, the mcpu++
+	// happened before it was passed to mnextg.
 	if(m->nextg != nil) {
 		gp = m->nextg;
 		m->nextg = nil;
@@ -373,29 +486,62 @@ nextgandunlock(void)
 		// We can only run one g, and it's not available.
 		// Make sure some other cpu is running to handle
 		// the ordinary run queue.
-		if(runtime·sched.gwait != 0)
+		if(runtime·sched.gwait != 0) {
 			matchmg();
+			// m->lockedg might have been on the queue.
+			if(m->nextg != nil) {
+				gp = m->nextg;
+				m->nextg = nil;
+				schedunlock();
+				return gp;
+			}
+		}
 	} else {
 		// Look for work on global queue.
-		while(runtime·sched.mcpu < runtime·sched.mcpumax && (gp=gget()) != nil) {
+		while(haveg() && canaddmcpu()) {
+			gp = gget();
+			if(gp == nil)
+				runtime·throw("gget inconsistency");
+
 			if(gp->lockedm) {
 				mnextg(gp->lockedm, gp);
 				continue;
 			}
-			runtime·sched.mcpu++;		// this m will run gp
+			runtime·sched.grunning++;
 			schedunlock();
 			return gp;
 		}
-		// Otherwise, wait on global m queue.
+
+		// The while loop ended either because the g queue is empty
+		// or because we have maxed out our m procs running go
+		// code (mcpu >= mcpumax).  We need to check that
+		// concurrent actions by entersyscall/exitsyscall cannot
+		// invalidate the decision to end the loop.
+		//
+		// We hold the sched lock, so no one else is manipulating the
+		// g queue or changing mcpumax.  Entersyscall can decrement
+		// mcpu, but if does so when there is something on the g queue,
+		// the gwait bit will be set, so entersyscall will take the slow path
+		// and use the sched lock.  So it cannot invalidate our decision.
+		//
+		// Wait on global m queue.
 		mput(m);
 	}
-	if(runtime·sched.mcpu == 0 && runtime·sched.msyscall == 0)
+
+	v = runtime·atomicload(&runtime·sched.atomic);
+	if(runtime·sched.grunning == 0)
 		runtime·throw("all goroutines are asleep - deadlock!");
 	m->nextg = nil;
 	m->waitnextg = 1;
 	runtime·noteclear(&m->havenextg);
-	if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
-		runtime·sched.waitstop = 0;
+
+	// Stoptheworld is waiting for all but its cpu to go to stop.
+	// Entersyscall might have decremented mcpu too, but if so
+	// it will see the waitstop and take the slow path.
+	// Exitsyscall never increments mcpu beyond mcpumax.
+	if(atomic_waitstop(v) && atomic_mcpu(v) <= atomic_mcpumax(v)) {
+		// set waitstop = 0 (known to be 1)
+		runtime·xadd(&runtime·sched.atomic, -1<<waitstopShift);
 		runtime·notewakeup(&runtime·sched.stopped);
 	}
 	schedunlock();
@@ -407,21 +553,34 @@ nextgandunlock(void)
 	return gp;
 }
 
-// TODO(rsc): Remove. This is only temporary,
-// for the mark and sweep collector.
 void
 runtime·stoptheworld(void)
 {
+	uint32 v;
+
 	schedlock();
 	runtime·gcwaiting = 1;
-	runtime·sched.mcpumax = 1;
-	while(runtime·sched.mcpu > 1) {
+
+	setmcpumax(1);
+
+	// while mcpu > 1
+	for(;;) {
+		v = runtime·sched.atomic;
+		if(atomic_mcpu(v) <= 1)
+			break;
+
 		// It would be unsafe for multiple threads to be using
 		// the stopped note at once, but there is only
-		// ever one thread doing garbage collection,
-		// so this is okay.
+		// ever one thread doing garbage collection.
 		runtime·noteclear(&runtime·sched.stopped);
-		runtime·sched.waitstop = 1;
+		if(atomic_waitstop(v))
+			runtime·throw("invalid waitstop");
+
+		// atomic { waitstop = 1 }, predicated on mcpu <= 1 check above
+		// still being true.
+		if(!runtime·cas(&runtime·sched.atomic, v, v+(1<<waitstopShift)))
+			continue;
+
 		schedunlock();
 		runtime·notesleep(&runtime·sched.stopped);
 		schedlock();
@@ -436,7 +595,7 @@ runtime·starttheworld(void)
 {
 	schedlock();
 	runtime·gcwaiting = 0;
-	runtime·sched.mcpumax = runtime·gomaxprocs;
+	setmcpumax(runtime·gomaxprocs);
 	matchmg();
 	schedunlock();
 }
@@ -473,7 +632,7 @@ struct CgoThreadStart
 	void (*fn)(void);
 };
 
-// Kick off new ms as needed (up to mcpumax).
+// Kick off new m's as needed (up to mcpumax).
 // There are already `other' other cpus that will
 // start looking for goroutines shortly.
 // Sched is locked.
@@ -484,17 +643,17 @@ matchmg(void)
 
 	if(m->mallocing || m->gcing)
 		return;
-	while(runtime·sched.mcpu < runtime·sched.mcpumax && (g = gget()) != nil){
-		M *m;
+
+	while(haveg() && canaddmcpu()) {
+		g = gget();
+		if(g == nil)
+			runtime·throw("gget inconsistency");
 
 		// Find the m that will run g.
+		M *m;
 		if((m = mget(g)) == nil){
 			m = runtime·malloc(sizeof(M));
-			// Add to runtime·allm so garbage collector doesn't free m
-			// when it is just in a register or thread-local storage.
-			m->alllink = runtime·allm;
-			runtime·allm = m;
-			m->id = runtime·sched.mcount++;
+			mcommoninit(m);
 
 			if(runtime·iscgo) {
 				CgoThreadStart ts;
@@ -528,6 +687,7 @@ static void
 schedule(G *gp)
 {
 	int32 hz;
+	uint32 v;
 
 	schedlock();
 	if(gp != nil) {
@@ -536,10 +696,13 @@ schedule(G *gp)
 
 		// Just finished running gp.
 		gp->m = nil;
-		runtime·sched.mcpu--;
+		runtime·sched.grunning--;
+
+		// atomic { mcpu-- }
+		v = runtime·xadd(&runtime·sched.atomic, -1<<mcpuShift);
+		if(atomic_mcpu(v) > maxgomaxprocs)
+			runtime·throw("negative mcpu in scheduler");
 
-		if(runtime·sched.mcpu < 0)
-			runtime·throw("runtime·sched.mcpu < 0 in scheduler");
 		switch(gp->status){
 		case Grunnable:
 		case Gdead:
@@ -574,7 +737,7 @@ schedule(G *gp)
 	gp->status = Grunning;
 	m->curg = gp;
 	gp->m = m;
-	
+
 	// Check whether the profiler needs to be turned on or off.
 	hz = runtime·sched.profilehz;
 	if(m->profilehz != hz)
@@ -618,31 +781,50 @@ runtime·gosched(void)
 void
 runtime·entersyscall(void)
 {
+	uint32 v;
+
 	if(runtime·sched.predawn)
 		return;
-	schedlock();
-	g->status = Gsyscall;
-	runtime·sched.mcpu--;
-	runtime·sched.msyscall++;
-	if(runtime·sched.gwait != 0)
-		matchmg();
-
-	if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
-		runtime·sched.waitstop = 0;
-		runtime·notewakeup(&runtime·sched.stopped);
-	}
 
 	// Leave SP around for gc and traceback.
-	// Do before schedunlock so that gc
-	// never sees Gsyscall with wrong stack.
 	runtime·gosave(&g->sched);
 	g->gcsp = g->sched.sp;
 	g->gcstack = g->stackbase;
 	g->gcguard = g->stackguard;
+	g->status = Gsyscall;
 	if(g->gcsp < g->gcguard-StackGuard || g->gcstack < g->gcsp) {
-		runtime·printf("entersyscall inconsistent %p [%p,%p]\n", g->gcsp, g->gcguard-StackGuard, g->gcstack);
+		// runtime·printf("entersyscall inconsistent %p [%p,%p]\n",
+		//	g->gcsp, g->gcguard-StackGuard, g->gcstack);
 		runtime·throw("entersyscall");
 	}
+
+	// Fast path.
+	// The slow path inside the schedlock/schedunlock will get
+	// through without stopping if it does:
+	//	mcpu--
+	//	gwait not true
+	//	waitstop && mcpu <= mcpumax not true
+	// If we can do the same with a single atomic add,
+	// then we can skip the locks.
+	v = runtime·xadd(&runtime·sched.atomic, -1<<mcpuShift);
+	if(!atomic_gwaiting(v) && (!atomic_waitstop(v) || atomic_mcpu(v) > atomic_mcpumax(v)))
+		return;
+
+	schedlock();
+	v = runtime·atomicload(&runtime·sched.atomic);
+	if(atomic_gwaiting(v)) {
+		matchmg();
+		v = runtime·atomicload(&runtime·sched.atomic);
+	}
+	if(atomic_waitstop(v) && atomic_mcpu(v) <= atomic_mcpumax(v)) {
+		runtime·xadd(&runtime·sched.atomic, -1<<waitstopShift);
+		runtime·notewakeup(&runtime·sched.stopped);
+	}
+
+	// Re-save sched in case one of the calls
+	// (notewakeup, matchmg) triggered something using it.
+	runtime·gosave(&g->sched);
+
 	schedunlock();
 }
 
@@ -653,22 +835,28 @@ runtime·entersyscall(void)
 void
 runtime·exitsyscall(void)
 {
+	uint32 v;
+
 	if(runtime·sched.predawn)
 		return;
 
-	schedlock();
-	runtime·sched.msyscall--;
-	runtime·sched.mcpu++;
-	// Fast path - if there's room for this m, we're done.
-	if(m->profilehz == runtime·sched.profilehz && runtime·sched.mcpu <= runtime·sched.mcpumax) {
+	// Fast path.
+	// If we can do the mcpu++ bookkeeping and
+	// find that we still have mcpu <= mcpumax, then we can
+	// start executing Go code immediately, without having to
+	// schedlock/schedunlock.
+	v = runtime·xadd(&runtime·sched.atomic, (1<<mcpuShift));
+	if(m->profilehz == runtime·sched.profilehz && atomic_mcpu(v) <= atomic_mcpumax(v)) {
 		// There's a cpu for us, so we can run.
 		g->status = Grunning;
 		// Garbage collector isn't running (since we are),
 		// so okay to clear gcstack.
 		g->gcstack = nil;
-		schedunlock();
 		return;
 	}
+
+	schedlock();
+
 	// Tell scheduler to put g back on the run queue:
 	// mostly equivalent to g->status = Grunning,
 	// but keeps the garbage collector from thinking
@@ -676,12 +864,12 @@ runtime·exitsyscall(void)
 	g->readyonstop = 1;
 	schedunlock();
 
-	// Slow path - all the cpus are taken.
+	// All the cpus are taken.
 	// The scheduler will ready g and put this m to sleep.
 	// When the scheduler takes g away from m,
 	// it will undo the runtime·sched.mcpu++ above.
 	runtime·gosched();
-	
+
 	// Gosched returned, so we're allowed to run now.
 	// Delete the gcstack information that we left for
 	// the garbage collector during the system call.
@@ -698,7 +886,7 @@ runtime·oldstack(void)
 	uint32 argsize;
 	byte *sp;
 	G *g1;
-	static int32 goid;
+	int32 goid;
 
 //printf("oldstack m->cret=%p\n", m->cret);
 
@@ -709,9 +897,10 @@ runtime·oldstack(void)
 	argsize = old.argsize;
 	if(argsize > 0) {
 		sp -= argsize;
-		runtime·mcpy(top->argp, sp, argsize);
+		runtime·memmove(top->argp, sp, argsize);
 	}
 	goid = old.gobuf.g->goid;	// fault if g is bad, before gogo
+	USED(goid);
 
 	if(old.free != 0)
 		runtime·stackfree(g1->stackguard - StackGuard, old.free);
@@ -790,7 +979,7 @@ runtime·newstack(void)
 	sp = (byte*)top;
 	if(argsize > 0) {
 		sp -= argsize;
-		runtime·mcpy(sp, m->moreargp, argsize);
+		runtime·memmove(sp, m->moreargp, argsize);
 	}
 	if(thechar == '5') {
 		// caller would have saved its LR below args.
@@ -855,7 +1044,7 @@ void
 runtime·newproc(int32 siz, byte* fn, ...)
 {
 	byte *argp;
-	
+
 	if(thechar == '5')
 		argp = (byte*)(&fn+2);  // skip caller's saved LR
 	else
@@ -873,8 +1062,13 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
 //printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret);
 	siz = narg + nret;
 	siz = (siz+7) & ~7;
-	if(siz > 1024)
-		runtime·throw("runtime.newproc: too many args");
+	
+	// We could instead create a secondary stack frame
+	// and make it look like goexit was on the original but
+	// the call to the actual goroutine function was split.
+	// Not worth it: this is almost always an error.
+	if(siz > StackMin - 1024)
+		runtime·throw("runtime.newproc: function arguments too large for new goroutine");
 
 	schedlock();
 
@@ -891,7 +1085,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
 
 	sp = newg->stackbase;
 	sp -= siz;
-	runtime·mcpy(sp, argp, narg);
+	runtime·memmove(sp, argp, narg);
 	if(thechar == '5') {
 		// caller's LR
 		sp -= sizeof(void*);
@@ -905,8 +1099,8 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
 	newg->gopc = (uintptr)callerpc;
 
 	runtime·sched.gcount++;
-	runtime·goidgen++;
-	newg->goid = runtime·goidgen;
+	runtime·sched.goidgen++;
+	newg->goid = runtime·sched.goidgen;
 
 	newprocreadylocked(newg);
 	schedunlock();
@@ -929,11 +1123,11 @@ runtime·deferproc(int32 siz, byte* fn, ...)
 		d->argp = (byte*)(&fn+2);  // skip caller's saved link register
 	else
 		d->argp = (byte*)(&fn+1);
-	runtime·mcpy(d->args, d->argp, d->siz);
+	runtime·memmove(d->args, d->argp, d->siz);
 
 	d->link = g->defer;
 	g->defer = d;
-	
+
 	// deferproc returns 0 normally.
 	// a deferred func that stops a panic
 	// makes the deferproc return 1.
@@ -956,7 +1150,7 @@ runtime·deferreturn(uintptr arg0)
 	argp = (byte*)&arg0;
 	if(d->argp != argp)
 		return;
-	runtime·mcpy(argp, d->args, d->siz);
+	runtime·memmove(argp, d->args, d->siz);
 	g->defer = d->link;
 	fn = d->fn;
 	runtime·free(d);
@@ -965,9 +1159,9 @@ runtime·deferreturn(uintptr arg0)
 
 static void
 rundefer(void)
-{	
+{
 	Defer *d;
-	
+
 	while((d = g->defer) != nil) {
 		g->defer = d->link;
 		reflect·call(d->fn, d->args, d->siz);
@@ -982,7 +1176,7 @@ unwindstack(G *gp, byte *sp)
 {
 	Stktop *top;
 	byte *stk;
-	
+
 	// Must be called from a different goroutine, usually m->g0.
 	if(g == gp)
 		runtime·throw("unwindstack on self");
@@ -1018,7 +1212,7 @@ printpanics(Panic *p)
 }
 
 static void recovery(G*);
-	
+
 void
 runtime·panic(Eface e)
 {
@@ -1068,7 +1262,7 @@ recovery(G *gp)
 	// Rewind gp's stack; we're running on m->g0's stack.
 	d = gp->defer;
 	gp->defer = d->link;
-	
+
 	// Unwind to the stack frame with d's arguments in it.
 	unwindstack(gp, d->argp);
 
@@ -1216,25 +1410,29 @@ int32
 runtime·gomaxprocsfunc(int32 n)
 {
 	int32 ret;
+	uint32 v;
 
 	schedlock();
 	ret = runtime·gomaxprocs;
-	if (n <= 0)
+	if(n <= 0)
 		n = ret;
+	if(n > maxgomaxprocs)
+		n = maxgomaxprocs;
 	runtime·gomaxprocs = n;
- 	if (runtime·gcwaiting != 0) {
- 		if (runtime·sched.mcpumax != 1)
- 			runtime·throw("invalid runtime·sched.mcpumax during gc");
+ 	if(runtime·gcwaiting != 0) {
+ 		if(atomic_mcpumax(runtime·sched.atomic) != 1)
+ 			runtime·throw("invalid mcpumax during gc");
 		schedunlock();
 		return ret;
 	}
-	runtime·sched.mcpumax = n;
-	// handle fewer procs?
-	if(runtime·sched.mcpu > runtime·sched.mcpumax) {
+
+	setmcpumax(n);
+
+	// If there are now fewer allowed procs
+	// than procs running, stop.
+	v = runtime·atomicload(&runtime·sched.atomic);
+	if(atomic_mcpu(v) > n) {
 		schedunlock();
-		// just give up the cpu.
-		// we'll only get rescheduled once the
-		// number has come down.
 		runtime·gosched();
 		return ret;
 	}
@@ -1301,10 +1499,10 @@ void
 runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
 {
 	int32 n;
-	
+
 	if(prof.fn == nil || prof.hz == 0)
 		return;
-	
+
 	runtime·lock(&prof);
 	if(prof.fn == nil) {
 		runtime·unlock(&prof);
@@ -1339,7 +1537,7 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
 	runtime·lock(&runtime·sched);
 	runtime·sched.profilehz = hz;
 	runtime·unlock(&runtime·sched);
-	
+
 	if(hz != 0)
 		runtime·resetcpuprofiler(hz);
 }
@@ -1355,11 +1553,11 @@ os·setenv_c(String k, String v)
 		return;
 
 	arg[0] = runtime·malloc(k.len + 1);
-	runtime·mcpy(arg[0], k.str, k.len);
+	runtime·memmove(arg[0], k.str, k.len);
 	arg[0][k.len] = 0;
 
 	arg[1] = runtime·malloc(v.len + 1);
-	runtime·mcpy(arg[1], v.str, v.len);
+	runtime·memmove(arg[1], v.str, v.len);
 	arg[1][v.len] = 0;
 
 	runtime·asmcgocall(libcgo_setenv, arg);
diff --git a/src/pkg/runtime/proc.p b/src/pkg/runtime/proc.p
new file mode 100644
index 0000000..f0b46de
--- /dev/null
+++ b/src/pkg/runtime/proc.p
@@ -0,0 +1,526 @@
+// 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.
+
+/*
+model for proc.c as of 2011/07/22.
+
+takes 4900 seconds to explore 1189070 states
+with G=3, var_gomaxprocs=1
+on a Core i7 L640 2.13 GHz Lenovo X201s.
+
+rm -f proc.p.trail pan.* pan
+spin -a proc.p
+gcc -DSAFETY -DREACH -DMEMLIM'='4000 -o pan pan.c
+pan -w28 -n -i -m500000
+test -f proc.p.trail && pan -r proc.p.trail
+*/
+
+/*
+ * scheduling parameters
+ */
+
+/*
+ * the number of goroutines G doubles as the maximum
+ * number of OS threads; the max is reachable when all
+ * the goroutines are blocked in system calls.
+ */
+#define G 3
+
+/*
+ * whether to allow gomaxprocs to vary during execution.
+ * enabling this checks the scheduler even when code is
+ * calling GOMAXPROCS, but it also slows down the verification
+ * by about 10x.
+ */
+#define var_gomaxprocs 1  /* allow gomaxprocs to vary */
+
+/* gomaxprocs */
+#if var_gomaxprocs
+byte gomaxprocs = 3;
+#else
+#define gomaxprocs 3
+#endif
+
+/* queue of waiting M's: sched_mhead[:mwait] */
+byte mwait;
+byte sched_mhead[G];
+
+/* garbage collector state */
+bit gc_lock, gcwaiting;
+
+/* goroutines sleeping, waiting to run */
+byte gsleep, gwait;
+
+/* scheduler state */
+bit sched_lock;
+bit sched_stopped;
+bit atomic_gwaiting, atomic_waitstop;
+byte atomic_mcpu, atomic_mcpumax;
+
+/* M struct fields - state for handing off g to m. */
+bit m_waitnextg[G];
+bit m_havenextg[G];
+bit m_nextg[G];
+
+/*
+ * opt_atomic/opt_dstep mark atomic/deterministics
+ * sequences that are marked only for reasons of
+ * optimization, not for correctness of the algorithms.
+ *
+ * in general any code that runs while holding the
+ * schedlock and does not refer to or modify the atomic_*
+ * fields can be marked atomic/dstep without affecting
+ * the usefulness of the model.  since we trust the lock
+ * implementation, what we really want to test is the
+ * interleaving of the atomic fast paths with entersyscall
+ * and exitsyscall.
+ */
+#define opt_atomic atomic
+#define opt_dstep d_step
+
+/* locks */
+inline lock(x) {
+	d_step { x == 0; x = 1 }
+}
+
+inline unlock(x) {
+	d_step { assert x == 1; x = 0 }
+}
+
+/* notes */
+inline noteclear(x) {
+	x = 0
+}
+
+inline notesleep(x) {
+	x == 1
+}
+
+inline notewakeup(x) {
+	opt_dstep { assert x == 0; x = 1 }
+}
+
+/*
+ * scheduler
+ */
+inline schedlock() {
+	lock(sched_lock)
+}
+
+inline schedunlock() {
+	unlock(sched_lock)
+}
+
+/*
+ * canaddmcpu is like the C function but takes
+ * an extra argument to include in the test, to model
+ * "cannget() && canaddmcpu()" as "canaddmcpu(cangget())"
+ */
+inline canaddmcpu(g) {
+	d_step {
+		g && atomic_mcpu < atomic_mcpumax;
+		atomic_mcpu++;
+	}
+}
+
+/*
+ * gput is like the C function.
+ * instead of tracking goroutines explicitly we
+ * maintain only the count of the number of
+ * waiting goroutines.
+ */
+inline gput() {
+	/* omitted: lockedm, idlem concerns */
+	opt_dstep {
+		gwait++;
+		if
+		:: gwait == 1 ->
+			atomic_gwaiting = 1
+		:: else
+		fi
+	}
+}
+
+/*
+ * cangget is a macro so it can be passed to
+ * canaddmcpu (see above).
+ */
+#define cangget()  (gwait>0)
+
+/*
+ * gget is like the C function.
+ */
+inline gget() {
+	opt_dstep {
+		assert gwait > 0;
+		gwait--;
+		if
+		:: gwait == 0 ->
+			atomic_gwaiting = 0
+		:: else
+		fi
+	}
+}
+
+/*
+ * mput is like the C function.
+ * here we do keep an explicit list of waiting M's,
+ * so that we know which ones can be awakened.
+ * we use _pid-1 because the monitor is proc 0.
+ */
+inline mput() {
+	opt_dstep {
+		sched_mhead[mwait] = _pid - 1;
+		mwait++
+	}
+}
+
+/*
+ * mnextg is like the C function mnextg(m, g).
+ * it passes an unspecified goroutine to m to start running.
+ */
+inline mnextg(m) {
+	opt_dstep {
+		m_nextg[m] = 1;
+		if
+		:: m_waitnextg[m] ->
+			m_waitnextg[m] = 0;
+			notewakeup(m_havenextg[m])
+		:: else
+		fi
+	}
+}
+
+/*
+ * mgetnextg handles the main m handoff in matchmg.
+ * it is like mget() || new M followed by mnextg(m, g),
+ * but combined to avoid a local variable.
+ * unlike the C code, a new M simply assumes it is
+ * running a g instead of using the mnextg coordination
+ * to obtain one.
+ */
+inline mgetnextg() {
+	opt_atomic {
+		if
+		:: mwait > 0 ->
+			mwait--;
+			mnextg(sched_mhead[mwait]);
+			sched_mhead[mwait] = 0;
+		:: else ->
+			run mstart();
+		fi
+	}
+}
+
+/*
+ * nextgandunlock is like the C function.
+ * it pulls a g off the queue or else waits for one.
+ */
+inline nextgandunlock() {
+	assert atomic_mcpu <= G;
+
+	if
+	:: m_nextg[_pid-1] ->
+		m_nextg[_pid-1] = 0;
+		schedunlock();
+	:: canaddmcpu(!m_nextg[_pid-1] && cangget()) ->
+		gget();
+		schedunlock();
+	:: else ->
+		opt_dstep {
+			mput();
+			m_nextg[_pid-1] = 0;
+			m_waitnextg[_pid-1] = 1;
+			noteclear(m_havenextg[_pid-1]);
+		}
+		if
+		:: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+			atomic_waitstop = 0;
+			notewakeup(sched_stopped)
+		:: else
+		fi;
+		schedunlock();
+		opt_dstep {
+			notesleep(m_havenextg[_pid-1]);
+			assert m_nextg[_pid-1];
+			m_nextg[_pid-1] = 0;
+		}
+	fi
+}
+
+/*
+ * stoptheworld is like the C function.
+ */
+inline stoptheworld() {
+	schedlock();
+	gcwaiting = 1;
+	atomic_mcpumax = 1;
+	do
+	:: d_step { atomic_mcpu > 1 ->
+		noteclear(sched_stopped);
+		assert !atomic_waitstop;
+		atomic_waitstop = 1 }
+		schedunlock();
+		notesleep(sched_stopped);
+		schedlock();
+	:: else ->
+		break
+	od;
+	schedunlock();
+}
+
+/*
+ * starttheworld is like the C function.
+ */
+inline starttheworld() {
+	schedlock();
+	gcwaiting = 0;
+	atomic_mcpumax = gomaxprocs;
+	matchmg();
+	schedunlock();
+}
+
+/*
+ * matchmg is like the C function.
+ */
+inline matchmg() {
+	do
+	:: canaddmcpu(cangget()) ->
+		gget();
+		mgetnextg();
+	:: else -> break
+	od
+}
+
+/*
+ * ready is like the C function.
+ * it puts a g on the run queue.
+ */
+inline ready() {
+	schedlock();
+	gput()
+	matchmg()
+	schedunlock()
+}
+
+/*
+ * schedule simulates the C scheduler.
+ * it assumes that there is always a goroutine
+ * running already, and the goroutine has entered
+ * the scheduler for an unspecified reason,
+ * either to yield or to block.
+ */
+inline schedule() {
+	schedlock();
+
+	mustsched = 0;
+	atomic_mcpu--;
+	assert atomic_mcpu <= G;
+	if
+	:: skip ->
+		// goroutine yields, still runnable
+		gput();
+	:: gsleep+1 < G ->
+		// goroutine goes to sleep (but there is another that can wake it)
+		gsleep++
+	fi;
+
+	// Find goroutine to run.
+	nextgandunlock()
+}
+
+/*
+ * schedpend is > 0 if a goroutine is about to committed to
+ * entering the scheduler but has not yet done so.
+ * Just as we don't test for the undesirable conditions when a
+ * goroutine is in the scheduler, we don't test for them when
+ * a goroutine will be in the scheduler shortly.
+ * Modeling this state lets us replace mcpu cas loops with
+ * simpler mcpu atomic adds.
+ */
+byte schedpend;
+
+/*
+ * entersyscall is like the C function.
+ */
+inline entersyscall() {
+	bit willsched;
+
+	/*
+	 * Fast path.  Check all the conditions tested during schedlock/schedunlock
+	 * below, and if we can get through the whole thing without stopping, run it
+	 * in one atomic cas-based step.
+	 */
+	atomic {
+		atomic_mcpu--;
+		if
+		:: atomic_gwaiting ->
+			skip
+		:: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+			skip
+		:: else ->
+			goto Lreturn_entersyscall;
+		fi;
+		willsched = 1;
+		schedpend++;
+	}
+
+	/*
+	 * Normal path.
+	 */
+	schedlock()
+	opt_dstep {
+		if
+		:: willsched ->
+			schedpend--;
+			willsched = 0
+		:: else
+		fi
+	}
+	if
+	:: atomic_gwaiting ->
+		matchmg()
+	:: else
+	fi;
+	if
+	:: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+		atomic_waitstop = 0;
+		notewakeup(sched_stopped)
+	:: else
+	fi;
+	schedunlock();
+Lreturn_entersyscall:
+	skip
+}
+
+/*
+ * exitsyscall is like the C function.
+ */
+inline exitsyscall() {
+	/*
+	 * Fast path.  If there's a cpu available, use it.
+	 */
+	atomic {
+		// omitted profilehz check
+		atomic_mcpu++;
+		if
+		:: atomic_mcpu >= atomic_mcpumax ->
+			skip
+		:: else ->
+			goto Lreturn_exitsyscall
+		fi
+	}
+
+	/*
+	 * Normal path.
+	 */
+	schedlock();
+	d_step {
+		if
+		:: atomic_mcpu <= atomic_mcpumax ->
+			skip
+		:: else ->
+			mustsched = 1
+		fi
+	}
+	schedunlock()
+Lreturn_exitsyscall:
+	skip
+}
+
+#if var_gomaxprocs
+inline gomaxprocsfunc() {
+	schedlock();
+	opt_atomic {
+		if
+		:: gomaxprocs != 1 -> gomaxprocs = 1
+		:: gomaxprocs != 2 -> gomaxprocs = 2
+		:: gomaxprocs != 3 -> gomaxprocs = 3
+		fi;
+	}
+	if
+	:: gcwaiting != 0 ->
+		assert atomic_mcpumax == 1
+	:: else ->
+		atomic_mcpumax = gomaxprocs;
+		if
+		:: atomic_mcpu > gomaxprocs ->
+			mustsched = 1
+		:: else ->
+			matchmg()
+		fi
+	fi;
+	schedunlock();
+}
+#endif
+
+/*
+ * mstart is the entry point for a new M.
+ * our model of an M is always running some
+ * unspecified goroutine.
+ */
+proctype mstart() {
+	/*
+	 * mustsched is true if the goroutine must enter the
+	 * scheduler instead of continuing to execute.
+	 */
+	bit mustsched;
+
+	do
+	:: skip ->
+		// goroutine reschedules.
+		schedule()
+	:: !mustsched ->
+		// goroutine does something.
+		if
+		:: skip ->
+			// goroutine executes system call
+			entersyscall();
+			exitsyscall()
+		:: atomic { gsleep > 0; gsleep-- } ->
+			// goroutine wakes another goroutine
+			ready()
+		:: lock(gc_lock) ->
+			// goroutine runs a garbage collection
+			stoptheworld();
+			starttheworld();
+			unlock(gc_lock)
+#if var_gomaxprocs
+		:: skip ->
+			// goroutine picks a new gomaxprocs
+			gomaxprocsfunc()
+#endif
+		fi
+	od;
+
+	assert 0;
+}
+
+/*
+ * monitor initializes the scheduler state
+ * and then watches for impossible conditions.
+ */
+active proctype monitor() {
+	opt_dstep {
+		byte i = 1;
+		do
+		:: i < G ->
+			gput();
+			i++
+		:: else -> break
+		od;
+		atomic_mcpu = 1;
+		atomic_mcpumax = 1;
+	}
+	run mstart();
+
+	do
+	// Should never have goroutines waiting with procs available.
+	:: !sched_lock && schedpend==0 && gwait > 0 && atomic_mcpu < atomic_mcpumax ->
+		assert 0
+	// Should never have gc waiting for stop if things have already stopped.
+	:: !sched_lock && schedpend==0 && atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
+		assert 0
+	od
+}
diff --git a/src/pkg/runtime/proc_test.go b/src/pkg/runtime/proc_test.go
index cac4f9e..3211108 100644
--- a/src/pkg/runtime/proc_test.go
+++ b/src/pkg/runtime/proc_test.go
@@ -6,6 +6,7 @@ package runtime_test
 
 import (
 	"runtime"
+	"sync/atomic"
 	"testing"
 )
 
@@ -44,3 +45,81 @@ func TestStopTheWorldDeadlock(t *testing.T) {
 	stop <- true
 	runtime.GOMAXPROCS(maxprocs)
 }
+
+func stackGrowthRecursive(i int) {
+	var pad [128]uint64
+	if i != 0 && pad[0] == 0 {
+		stackGrowthRecursive(i - 1)
+	}
+}
+
+func BenchmarkStackGrowth(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					stackGrowthRecursive(10)
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkSyscall(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					runtime.Entersyscall()
+					runtime.Exitsyscall()
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkSyscallWork(b *testing.B) {
+	const CallsPerSched = 1000
+	const LocalWork = 100
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 42
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					runtime.Entersyscall()
+					for i := 0; i < LocalWork; i++ {
+						foo *= 2
+						foo /= 2
+					}
+					runtime.Exitsyscall()
+				}
+			}
+			c <- foo == 42
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 1a3653f..c572897 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -11,6 +11,14 @@ enum {
 
 uint32	runtime·panicking;
 
+/*
+ * We assume that all architectures turn faults and the like
+ * into apparent calls to runtime.sigpanic.  If we see a "call"
+ * to runtime.sigpanic, we do not back up the PC to find the
+ * line number of the CALL instruction, because there is no CALL.
+ */
+void	runtime·sigpanic(void);
+
 int32
 runtime·gotraceback(void)
 {
@@ -116,17 +124,6 @@ runtime·panicstring(int8 *s)
 	runtime·panic(err);
 }
 
-void
-runtime·mcpy(byte *t, byte *f, uint32 n)
-{
-	while(n > 0) {
-		*t = *f;
-		t++;
-		f++;
-		n--;
-	}
-}
-
 int32
 runtime·mcmp(byte *s1, byte *s2, uint32 n)
 {
@@ -218,20 +215,6 @@ runtime·goenvs_unix(void)
 	os·Envs.cap = n;
 }
 
-// Atomic add and return new value.
-uint32
-runtime·xadd(uint32 volatile *val, int32 delta)
-{
-	uint32 oval, nval;
-
-	for(;;){
-		oval = *val;
-		nval = oval + delta;
-		if(runtime·cas(val, oval, nval))
-			return nval;
-	}
-}
-
 byte*
 runtime·getenv(int8 *s)
 {
@@ -406,18 +389,11 @@ memprint(uint32 s, void *a)
 static void
 memcopy(uint32 s, void *a, void *b)
 {
-	byte *ba, *bb;
-	uint32 i;
-
-	ba = a;
-	bb = b;
-	if(bb == nil) {
-		for(i=0; i<s; i++)
-			ba[i] = 0;
+	if(b == nil) {
+		runtime·memclr(a,s);
 		return;
 	}
-	for(i=0; i<s; i++)
-		ba[i] = bb[i];
+	runtime·memmove(a,b,s);
 }
 
 static uint32
@@ -551,25 +527,35 @@ runtime·nanotime(void)
 void
 runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
 {
-	Func *f;
+	Func *f, *g;
 	uintptr pc;
-
-	if(runtime·callers(1+skip, &retpc, 1) == 0) {
+	uintptr rpc[2];
+
+	/*
+	 * Ask for two PCs: the one we were asked for
+	 * and what it called, so that we can see if it
+	 * "called" sigpanic.
+	 */
+	retpc = 0;
+	if(runtime·callers(1+skip-1, rpc, 2) < 2) {
 		retfile = runtime·emptystring;
 		retline = 0;
 		retbool = false;
-	} else if((f = runtime·findfunc(retpc)) == nil) {
+	} else if((f = runtime·findfunc(rpc[1])) == nil) {
 		retfile = runtime·emptystring;
 		retline = 0;
 		retbool = true;  // have retpc at least
 	} else {
+		retpc = rpc[1];
 		retfile = f->src;
 		pc = retpc;
-		if(pc > f->entry)
+		g = runtime·findfunc(rpc[0]);
+		if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
 			pc--;
 		retline = runtime·funcline(f, pc);
 		retbool = true;
 	}
+	FLUSH(&retpc);
 	FLUSH(&retfile);
 	FLUSH(&retline);
 	FLUSH(&retbool);
@@ -588,3 +574,16 @@ runtime·FuncForPC(uintptr pc, void *retf)
 	retf = runtime·findfunc(pc);
 	FLUSH(&retf);
 }
+
+uint32
+runtime·fastrand1(void)
+{
+	uint32 x;
+
+	x = m->fastrand;
+	x += x;
+	if(x & 0x80000000L)
+		x ^= 0x88888eefUL;
+	m->fastrand = x;
+	return x;
+}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index ad5da0a..44511da 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -57,6 +57,7 @@ typedef	struct	String		String;
 typedef	struct	Usema		Usema;
 typedef	struct	SigTab		SigTab;
 typedef	struct	MCache		MCache;
+typedef struct	FixAlloc	FixAlloc;
 typedef	struct	Iface		Iface;
 typedef	struct	Itab		Itab;
 typedef	struct	Eface		Eface;
@@ -130,7 +131,10 @@ struct	Usema
 union	Note
 {
 	struct {	// Linux
-		Lock	lock;
+		uint32	state;
+	};
+	struct {	// Windows
+		Lock lock;
 	};
 	struct {	// OS X
 		int32	wakeup;
@@ -229,12 +233,15 @@ struct	M
 	int32	waitnextg;
 	int32	dying;
 	int32	profilehz;
+	uint32	fastrand;
+	uint64	ncgocall;
 	Note	havenextg;
 	G*	nextg;
 	M*	alllink;	// on allm
 	M*	schedlink;
 	uint32	machport;	// Return address for Mach IPC (OS X)
 	MCache	*mcache;
+	FixAlloc	*stackalloc;
 	G*	lockedg;
 	G*	idleg;
 	uint32	freglo[16];	// D[i] lsb and F[i]
@@ -368,7 +375,6 @@ extern	Alg	runtime·algarray[Amax];
 extern	String	runtime·emptystring;
 G*	runtime·allg;
 M*	runtime·allm;
-int32	runtime·goidgen;
 extern	int32	runtime·gomaxprocs;
 extern	uint32	runtime·panicking;
 extern	int32	runtime·gcwaiting;		// gc is waiting to run
@@ -379,6 +385,7 @@ extern	bool	runtime·iscgo;
  * common functions and data
  */
 int32	runtime·strcmp(byte*, byte*);
+byte*	runtime·strstr(byte*, byte*);
 int32	runtime·findnull(byte*);
 int32	runtime·findnullw(uint16*);
 void	runtime·dump(byte*, int32);
@@ -404,13 +411,13 @@ uint32	runtime·rnd(uint32, uint32);
 void	runtime·prints(int8*);
 void	runtime·printf(int8*, ...);
 byte*	runtime·mchr(byte*, byte, byte*);
-void	runtime·mcpy(byte*, byte*, uint32);
 int32	runtime·mcmp(byte*, byte*, uint32);
 void	runtime·memmove(void*, void*, uint32);
 void*	runtime·mal(uintptr);
 String	runtime·catstring(String, String);
 String	runtime·gostring(byte*);
 String  runtime·gostringn(byte*, int32);
+Slice	runtime·gobytes(byte*, int32);
 String	runtime·gostringnocopy(byte*);
 String	runtime·gostringw(uint16*);
 void	runtime·initsig(int32);
@@ -424,7 +431,11 @@ bool	runtime·casp(void**, void*, void*);
 // Don't confuse with XADD x86 instruction,
 // this one is actually 'addx', that is, add-and-fetch.
 uint32	runtime·xadd(uint32 volatile*, int32);
-uint32  runtime·atomicload(uint32 volatile*);
+uint32	runtime·xchg(uint32 volatile*, uint32);
+uint32	runtime·atomicload(uint32 volatile*);
+void	runtime·atomicstore(uint32 volatile*, uint32);
+void*	runtime·atomicloadp(void* volatile*);
+void	runtime·atomicstorep(void* volatile*, void*);
 void	runtime·jmpdefer(byte*, void*);
 void	runtime·exit1(int32);
 void	runtime·ready(G*);
@@ -454,6 +465,7 @@ void	runtime·runpanic(Panic*);
 void*	runtime·getcallersp(void*);
 int32	runtime·mcount(void);
 void	runtime·mcall(void(*)(G*));
+uint32	runtime·fastrand1(void);
 
 void	runtime·exit(int32);
 void	runtime·breakpoint(void);
@@ -590,6 +602,8 @@ void	runtime·semacquire(uint32*);
 void	runtime·semrelease(uint32*);
 String	runtime·signame(int32 sig);
 int32	runtime·gomaxprocsfunc(int32 n);
+void	runtime·procyield(uint32);
+void	runtime·osyield(void);
 
 void	runtime·mapassign(Hmap*, byte*, byte*);
 void	runtime·mapaccess(Hmap*, byte*, byte*, bool*);
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
index 9146c17..7053427 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -20,7 +20,7 @@ runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
 {
 	if(len < 0 || (int32)len != len)
 		runtime·panicstring("makeslice: len out of range");
-	if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
+	if(cap < len || (int32)cap != cap || t->elem->size > 0 && cap > ((uintptr)-1) / t->elem->size)
 		runtime·panicstring("makeslice: cap out of range");
 
 	makeslice1(t, len, cap, &ret);
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
index 2b6b0e3..44d5533 100644
--- a/src/pkg/runtime/stack.h
+++ b/src/pkg/runtime/stack.h
@@ -71,6 +71,7 @@ enum {
 	// If the amount needed for the splitting frame + StackExtra
 	// is less than this number, the stack will have this size instead.
 	StackMin = 4096,
+	FixedStack = StackMin + StackSystem,
 
 	// Functions that need frames bigger than this call morestack
 	// unconditionally.  That is, on entry to a function it is assumed
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index b72aa93..48bf318 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -32,19 +32,23 @@ runtime·findnullw(uint16 *s)
 	return l;
 }
 
-int32 runtime·maxstring = 256;
+uint32 runtime·maxstring = 256;
 
 String
 runtime·gostringsize(int32 l)
 {
 	String s;
+	uint32 ms;
 
 	if(l == 0)
 		return runtime·emptystring;
 	s.str = runtime·mal(l+1);	// leave room for NUL for C runtime (e.g., callers of getenv)
 	s.len = l;
-	if(l > runtime·maxstring)
-		runtime·maxstring = l;
+	for(;;) {
+		ms = runtime·maxstring;
+		if((uint32)l <= ms || runtime·cas(&runtime·maxstring, ms, (uint32)l))
+			break;
+	}
 	return s;
 }
 
@@ -56,7 +60,7 @@ runtime·gostring(byte *str)
 
 	l = runtime·findnull(str);
 	s = runtime·gostringsize(l);
-	runtime·mcpy(s.str, str, l);
+	runtime·memmove(s.str, str, l);
 	return s;
 }
 
@@ -66,10 +70,20 @@ runtime·gostringn(byte *str, int32 l)
 	String s;
 
 	s = runtime·gostringsize(l);
-	runtime·mcpy(s.str, str, l);
+	runtime·memmove(s.str, str, l);
 	return s;
 }
 
+Slice
+runtime·gobytes(byte *p, int32 n)
+{
+	Slice sl;
+
+	sl.array = runtime·mallocgc(n, FlagNoPointers, 1, 0);
+	runtime·memmove(sl.array, p, n);
+	return sl;
+}
+
 String
 runtime·gostringnocopy(byte *str)
 {
@@ -109,8 +123,8 @@ runtime·catstring(String s1, String s2)
 		return s1;
 
 	s3 = runtime·gostringsize(s1.len + s2.len);
-	runtime·mcpy(s3.str, s1.str, s1.len);
-	runtime·mcpy(s3.str+s1.len, s2.str, s2.len);
+	runtime·memmove(s3.str, s1.str, s1.len);
+	runtime·memmove(s3.str+s1.len, s2.str, s2.len);
 	return s3;
 }
 
@@ -130,7 +144,7 @@ concatstring(int32 n, String *s)
 	out = runtime·gostringsize(l);
 	l = 0;
 	for(i=0; i<n; i++) {
-		runtime·mcpy(out.str+l, s[i].str, s[i].len);
+		runtime·memmove(out.str+l, s[i].str, s[i].len);
 		l += s[i].len;
 	}
 	return out;
@@ -189,6 +203,28 @@ runtime·strcmp(byte *s1, byte *s2)
 	}
 }
 
+byte*
+runtime·strstr(byte *s1, byte *s2)
+{
+	byte *sp1, *sp2;
+
+	if(*s2 == 0)
+		return s1;
+	for(; *s1; s1++) {
+		if(*s1 != *s2)
+			continue;
+		sp1 = s1;
+		sp2 = s2;
+		for(;;) {
+			if(*sp2 == 0)
+				return s1;
+			if(*sp1++ != *sp2++)
+				break;
+		}
+	}
+	return nil;
+}
+
 func slicestring(si String, lindex int32, hindex int32) (so String) {
 	int32 l;
 
@@ -221,14 +257,14 @@ func intstring(v int64) (s String) {
 
 func slicebytetostring(b Slice) (s String) {
 	s = runtime·gostringsize(b.len);
-	runtime·mcpy(s.str, b.array, s.len);
+	runtime·memmove(s.str, b.array, s.len);
 }
 
 func stringtoslicebyte(s String) (b Slice) {
 	b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 1);
 	b.len = s.len;
 	b.cap = s.len;
-	runtime·mcpy(b.array, s.str, s.len);
+	runtime·memmove(b.array, s.str, s.len);
 }
 
 func sliceinttostring(b Slice) (s String) {
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index da45797..d2ebf9b 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -78,6 +78,7 @@ static int32 nfunc;
 static byte **fname;
 static int32 nfname;
 
+static uint32 funcinit;
 static Lock funclock;
 
 static void
@@ -159,7 +160,7 @@ makepath(byte *buf, int32 nbuf, byte *path)
 			break;
 		if(p > buf && p[-1] != '/')
 			*p++ = '/';
-		runtime·mcpy(p, q, len+1);
+		runtime·memmove(p, q, len+1);
 		p += len;
 	}
 }
@@ -420,10 +421,21 @@ runtime·findfunc(uintptr addr)
 	Func *f;
 	int32 nf, n;
 
-	runtime·lock(&funclock);
-	if(func == nil)
-		buildfuncs();
-	runtime·unlock(&funclock);
+	// Use atomic double-checked locking,
+	// because when called from pprof signal
+	// handler, findfunc must run without
+	// grabbing any locks.
+	// (Before enabling the signal handler,
+	// SetCPUProfileRate calls findfunc to trigger
+	// the initialization outside the handler.)
+	if(runtime·atomicload(&funcinit) == 0) {
+		runtime·lock(&funclock);
+		if(funcinit == 0) {
+			buildfuncs();
+			runtime·atomicstore(&funcinit, 1);
+		}
+		runtime·unlock(&funclock);
+	}
 
 	if(nfunc == 0)
 		return nil;
diff --git a/src/pkg/runtime/symtab_test.go b/src/pkg/runtime/symtab_test.go
new file mode 100644
index 0000000..bd9fe18
--- /dev/null
+++ b/src/pkg/runtime/symtab_test.go
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+	"runtime"
+	"strings"
+	"testing"
+)
+
+func TestCaller(t *testing.T) {
+	procs := runtime.GOMAXPROCS(-1)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			for i := 0; i < 1000; i++ {
+				testCallerFoo(t)
+			}
+			c <- true
+		}()
+		defer func() {
+			<-c
+		}()
+	}
+}
+
+func testCallerFoo(t *testing.T) {
+	testCallerBar(t)
+}
+
+func testCallerBar(t *testing.T) {
+	for i := 0; i < 2; i++ {
+		pc, file, line, ok := runtime.Caller(i)
+		f := runtime.FuncForPC(pc)
+		if !ok ||
+			!strings.HasSuffix(file, "symtab_test.go") ||
+			(i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) ||
+			(i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) ||
+			line < 5 || line > 1000 ||
+			f.Entry() >= pc {
+			t.Errorf("incorrect symbol info %d: %t %d %d %s %s %d",
+				i, ok, f.Entry(), pc, f.Name(), file, line)
+		}
+	}
+}
diff --git a/src/pkg/runtime/windows/amd64/rt0.s b/src/pkg/runtime/windows/amd64/rt0.s
index e54e7ed..35978bc 100644
--- a/src/pkg/runtime/windows/amd64/rt0.s
+++ b/src/pkg/runtime/windows/amd64/rt0.s
@@ -8,3 +8,6 @@ TEXT	_rt0_amd64_windows(SB),7,$-8
 	MOVQ	$_rt0_amd64(SB), AX
 	MOVQ	SP, DI
 	JMP	AX
+
+DATA  runtime·iswindows(SB)/4, $1
+GLOBL runtime·iswindows(SB), $4
diff --git a/src/pkg/runtime/windows/amd64/sys.s b/src/pkg/runtime/windows/amd64/sys.s
index b1eacfc..2009d16 100644
--- a/src/pkg/runtime/windows/amd64/sys.s
+++ b/src/pkg/runtime/windows/amd64/sys.s
@@ -20,6 +20,7 @@ TEXT runtime·stdcall_raw(SB),7,$8
 	CMPQ	g(DI), SI
 	JEQ 3(PC)
 	MOVQ	(g_sched+gobuf_sp)(SI), SP
+	ANDQ	$~15, SP
 	MOVQ	SI, g(DI)
 	
 	SUBQ	$0x60, SP
diff --git a/src/pkg/scanner/scanner.go b/src/pkg/scanner/scanner.go
index e79d392..d0c32e7 100644
--- a/src/pkg/scanner/scanner.go
+++ b/src/pkg/scanner/scanner.go
@@ -34,7 +34,6 @@ import (
 	"utf8"
 )
 
-
 // TODO(gri): Consider changing this to use the new (token) Position package.
 
 // A source position is represented by a Position value.
@@ -46,11 +45,9 @@ type Position struct {
 	Column   int    // column number, starting at 1 (character count per line)
 }
 
-
 // IsValid returns true if the position is valid.
 func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
-
 func (pos Position) String() string {
 	s := pos.Filename
 	if pos.IsValid() {
@@ -65,7 +62,6 @@ func (pos Position) String() string {
 	return s
 }
 
-
 // Predefined mode bits to control recognition of tokens. For instance,
 // to configure a Scanner such that it only recognizes (Go) identifiers,
 // integers, and skips comments, set the Scanner's Mode field to:
@@ -84,7 +80,6 @@ const (
 	GoTokens       = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
 )
 
-
 // The result of Scan is one of the following tokens or a Unicode character.
 const (
 	EOF = -(iota + 1)
@@ -98,7 +93,6 @@ const (
 	skipComment
 )
 
-
 var tokenString = map[int]string{
 	EOF:       "EOF",
 	Ident:     "Ident",
@@ -110,7 +104,6 @@ var tokenString = map[int]string{
 	Comment:   "Comment",
 }
 
-
 // TokenString returns a (visible) string for a token or Unicode character.
 func TokenString(tok int) string {
 	if s, found := tokenString[tok]; found {
@@ -119,12 +112,10 @@ func TokenString(tok int) string {
 	return fmt.Sprintf("%q", string(tok))
 }
 
-
 // GoWhitespace is the default value for the Scanner's Whitespace field.
 // Its value selects Go's white space characters.
 const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
 
-
 const bufLen = 1024 // at least utf8.UTFMax
 
 // A Scanner implements reading of Unicode characters and tokens from an io.Reader.
@@ -179,7 +170,6 @@ type Scanner struct {
 	Position
 }
 
-
 // Init initializes a Scanner with a new source and returns s.
 // Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens,
 // and Whitespace is set to GoWhitespace.
@@ -215,7 +205,6 @@ func (s *Scanner) Init(src io.Reader) *Scanner {
 	return s
 }
 
-
 // TODO(gri): The code for next() and the internal scanner state could benefit
 //            from a rethink. While next() is optimized for the common ASCII
 //            case, the "corrections" needed for proper position tracking undo
@@ -300,7 +289,6 @@ func (s *Scanner) next() int {
 	return ch
 }
 
-
 // Next reads and returns the next Unicode character.
 // It returns EOF at the end of the source. It reports
 // a read error by calling s.Error, if not nil; otherwise
@@ -314,7 +302,6 @@ func (s *Scanner) Next() int {
 	return ch
 }
 
-
 // Peek returns the next Unicode character in the source without advancing
 // the scanner. It returns EOF if the scanner's position is at the last
 // character of the source.
@@ -325,7 +312,6 @@ func (s *Scanner) Peek() int {
 	return s.ch
 }
 
-
 func (s *Scanner) error(msg string) {
 	s.ErrorCount++
 	if s.Error != nil {
@@ -335,7 +321,6 @@ func (s *Scanner) error(msg string) {
 	fmt.Fprintf(os.Stderr, "%s: %s\n", s.Position, msg)
 }
 
-
 func (s *Scanner) scanIdentifier() int {
 	ch := s.next() // read character after first '_' or letter
 	for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) {
@@ -344,7 +329,6 @@ func (s *Scanner) scanIdentifier() int {
 	return ch
 }
 
-
 func digitVal(ch int) int {
 	switch {
 	case '0' <= ch && ch <= '9':
@@ -357,10 +341,8 @@ func digitVal(ch int) int {
 	return 16 // larger than any legal digit val
 }
 
-
 func isDecimal(ch int) bool { return '0' <= ch && ch <= '9' }
 
-
 func (s *Scanner) scanMantissa(ch int) int {
 	for isDecimal(ch) {
 		ch = s.next()
@@ -368,7 +350,6 @@ func (s *Scanner) scanMantissa(ch int) int {
 	return ch
 }
 
-
 func (s *Scanner) scanFraction(ch int) int {
 	if ch == '.' {
 		ch = s.scanMantissa(s.next())
@@ -376,7 +357,6 @@ func (s *Scanner) scanFraction(ch int) int {
 	return ch
 }
 
-
 func (s *Scanner) scanExponent(ch int) int {
 	if ch == 'e' || ch == 'E' {
 		ch = s.next()
@@ -388,7 +368,6 @@ func (s *Scanner) scanExponent(ch int) int {
 	return ch
 }
 
-
 func (s *Scanner) scanNumber(ch int) (int, int) {
 	// isDecimal(ch)
 	if ch == '0' {
@@ -433,7 +412,6 @@ func (s *Scanner) scanNumber(ch int) (int, int) {
 	return Int, ch
 }
 
-
 func (s *Scanner) scanDigits(ch, base, n int) int {
 	for n > 0 && digitVal(ch) < base {
 		ch = s.next()
@@ -445,7 +423,6 @@ func (s *Scanner) scanDigits(ch, base, n int) int {
 	return ch
 }
 
-
 func (s *Scanner) scanEscape(quote int) int {
 	ch := s.next() // read character after '/'
 	switch ch {
@@ -466,7 +443,6 @@ func (s *Scanner) scanEscape(quote int) int {
 	return ch
 }
 
-
 func (s *Scanner) scanString(quote int) (n int) {
 	ch := s.next() // read character after quote
 	for ch != quote {
@@ -484,7 +460,6 @@ func (s *Scanner) scanString(quote int) (n int) {
 	return
 }
 
-
 func (s *Scanner) scanRawString() {
 	ch := s.next() // read character after '`'
 	for ch != '`' {
@@ -496,14 +471,12 @@ func (s *Scanner) scanRawString() {
 	}
 }
 
-
 func (s *Scanner) scanChar() {
 	if s.scanString('\'') != 1 {
 		s.error("illegal char literal")
 	}
 }
 
-
 func (s *Scanner) scanComment(ch int) int {
 	// ch == '/' || ch == '*'
 	if ch == '/' {
@@ -532,7 +505,6 @@ func (s *Scanner) scanComment(ch int) int {
 	return ch
 }
 
-
 // Scan reads the next token or Unicode character from source and returns it.
 // It only recognizes tokens t for which the respective Mode bit (1<<-t) is set.
 // It returns EOF at the end of the source. It reports scanner errors (read and
@@ -635,7 +607,6 @@ redo:
 	return tok
 }
 
-
 // Pos returns the position of the character immediately after
 // the character or token returned by the last call to Next or Scan.
 func (s *Scanner) Pos() (pos Position) {
@@ -658,7 +629,6 @@ func (s *Scanner) Pos() (pos Position) {
 	return
 }
 
-
 // TokenText returns the string corresponding to the most recently scanned token.
 // Valid after calling Scan().
 func (s *Scanner) TokenText() string {
diff --git a/src/pkg/scanner/scanner_test.go b/src/pkg/scanner/scanner_test.go
index cf9ad01..4ba1587 100644
--- a/src/pkg/scanner/scanner_test.go
+++ b/src/pkg/scanner/scanner_test.go
@@ -13,14 +13,12 @@ import (
 	"utf8"
 )
 
-
 // A StringReader delivers its data one string segment at a time via Read.
 type StringReader struct {
 	data []string
 	step int
 }
 
-
 func (r *StringReader) Read(p []byte) (n int, err os.Error) {
 	if r.step < len(r.data) {
 		s := r.data[r.step]
@@ -32,7 +30,6 @@ func (r *StringReader) Read(p []byte) (n int, err os.Error) {
 	return
 }
 
-
 func readRuneSegments(t *testing.T, segments []string) {
 	got := ""
 	want := strings.Join(segments, "")
@@ -49,7 +46,6 @@ func readRuneSegments(t *testing.T, segments []string) {
 	}
 }
 
-
 var segmentList = [][]string{
 	{},
 	{""},
@@ -61,14 +57,12 @@ var segmentList = [][]string{
 	{"Hello", ", ", "", "World", "!"},
 }
 
-
 func TestNext(t *testing.T) {
 	for _, s := range segmentList {
 		readRuneSegments(t, s)
 	}
 }
 
-
 type token struct {
 	tok  int
 	text string
@@ -234,7 +228,6 @@ var tokenList = []token{
 	{'(', "("},
 }
 
-
 func makeSource(pattern string) *bytes.Buffer {
 	var buf bytes.Buffer
 	for _, k := range tokenList {
@@ -243,7 +236,6 @@ func makeSource(pattern string) *bytes.Buffer {
 	return &buf
 }
 
-
 func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
 	if got != want {
 		t.Fatalf("tok = %s, want %s for %q", TokenString(got), TokenString(want), text)
@@ -263,7 +255,6 @@ func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
 	}
 }
 
-
 func countNewlines(s string) int {
 	n := 0
 	for _, ch := range s {
@@ -274,7 +265,6 @@ func countNewlines(s string) int {
 	return n
 }
 
-
 func testScan(t *testing.T, mode uint) {
 	s := new(Scanner).Init(makeSource(" \t%s\n"))
 	s.Mode = mode
@@ -290,13 +280,11 @@ func testScan(t *testing.T, mode uint) {
 	checkTok(t, s, line, tok, EOF, "")
 }
 
-
 func TestScan(t *testing.T) {
 	testScan(t, GoTokens)
 	testScan(t, GoTokens&^SkipComments)
 }
 
-
 func TestPosition(t *testing.T) {
 	src := makeSource("\t\t\t\t%s\n")
 	s := new(Scanner).Init(src)
@@ -323,7 +311,6 @@ func TestPosition(t *testing.T) {
 	}
 }
 
-
 func TestScanZeroMode(t *testing.T) {
 	src := makeSource("%s\n")
 	str := src.String()
@@ -345,7 +332,6 @@ func TestScanZeroMode(t *testing.T) {
 	}
 }
 
-
 func testScanSelectedMode(t *testing.T, mode uint, class int) {
 	src := makeSource("%s\n")
 	s := new(Scanner).Init(src)
@@ -362,7 +348,6 @@ func testScanSelectedMode(t *testing.T, mode uint, class int) {
 	}
 }
 
-
 func TestScanSelectedMask(t *testing.T) {
 	testScanSelectedMode(t, 0, 0)
 	testScanSelectedMode(t, ScanIdents, Ident)
@@ -375,7 +360,6 @@ func TestScanSelectedMask(t *testing.T) {
 	testScanSelectedMode(t, ScanComments, Comment)
 }
 
-
 func TestScanNext(t *testing.T) {
 	s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n} // line comment ending in eof"))
 	checkTok(t, s, 1, s.Scan(), Ident, "if")
@@ -397,7 +381,6 @@ func TestScanNext(t *testing.T) {
 	}
 }
 
-
 func TestScanWhitespace(t *testing.T) {
 	var buf bytes.Buffer
 	var ws uint64
@@ -418,7 +401,6 @@ func TestScanWhitespace(t *testing.T) {
 	}
 }
 
-
 func testError(t *testing.T, src, msg string, tok int) {
 	s := new(Scanner).Init(bytes.NewBufferString(src))
 	errorCalled := false
@@ -443,7 +425,6 @@ func testError(t *testing.T, src, msg string, tok int) {
 	}
 }
 
-
 func TestError(t *testing.T) {
 	testError(t, "\x00", "illegal character NUL", 0)
 	testError(t, "\xff", "illegal UTF-8 encoding", utf8.RuneError)
@@ -459,7 +440,6 @@ func TestError(t *testing.T) {
 	testError(t, `"abc`+"\xff"+`def"`, "illegal UTF-8 encoding", String)
 }
 
-
 func checkPos(t *testing.T, got, want Position) {
 	if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column {
 		t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d",
@@ -467,7 +447,6 @@ func checkPos(t *testing.T, got, want Position) {
 	}
 }
 
-
 func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) {
 	if ch := s.Next(); ch != char {
 		t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
@@ -476,7 +455,6 @@ func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) {
 	checkPos(t, s.Pos(), want)
 }
 
-
 func checkScanPos(t *testing.T, s *Scanner, offset, line, column, char int) {
 	want := Position{Offset: offset, Line: line, Column: column}
 	checkPos(t, s.Pos(), want)
@@ -489,7 +467,6 @@ func checkScanPos(t *testing.T, s *Scanner, offset, line, column, char int) {
 	checkPos(t, s.Position, want)
 }
 
-
 func TestPos(t *testing.T) {
 	// corner case: empty source
 	s := new(Scanner).Init(bytes.NewBufferString(""))
diff --git a/src/pkg/sort/search.go b/src/pkg/sort/search.go
index 7d468da..4f0ce55 100644
--- a/src/pkg/sort/search.go
+++ b/src/pkg/sort/search.go
@@ -71,7 +71,6 @@ func Search(n int, f func(int) bool) int {
 	return i
 }
 
-
 // Convenience wrappers for common cases.
 
 // SearchInts searches for x in a sorted slice of ints and returns the index
@@ -81,7 +80,6 @@ func SearchInts(a []int, x int) int {
 	return Search(len(a), func(i int) bool { return a[i] >= x })
 }
 
-
 // SearchFloat64s searches for x in a sorted slice of float64s and returns the index
 // as specified by Search. The slice must be sorted in ascending order.
 // 
@@ -89,7 +87,6 @@ func SearchFloat64s(a []float64, x float64) int {
 	return Search(len(a), func(i int) bool { return a[i] >= x })
 }
 
-
 // SearchStrings searches for x slice a sorted slice of strings and returns the index
 // as specified by Search. The slice must be sorted in ascending order.
 // 
@@ -97,14 +94,11 @@ func SearchStrings(a []string, x string) int {
 	return Search(len(a), func(i int) bool { return a[i] >= x })
 }
 
-
 // Search returns the result of applying SearchInts to the receiver and x.
 func (p IntSlice) Search(x int) int { return SearchInts(p, x) }
 
-
 // Search returns the result of applying SearchFloat64s to the receiver and x.
 func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }
 
-
 // Search returns the result of applying SearchStrings to the receiver and x.
 func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }
diff --git a/src/pkg/sort/search_test.go b/src/pkg/sort/search_test.go
index 2a9a858..07295ff 100644
--- a/src/pkg/sort/search_test.go
+++ b/src/pkg/sort/search_test.go
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package sort
-
-import "testing"
+package sort_test
 
+import (
+	. "sort"
+	"testing"
+)
 
 func f(a []int, x int) func(int) bool {
 	return func(i int) bool {
@@ -13,7 +15,6 @@ func f(a []int, x int) func(int) bool {
 	}
 }
 
-
 var data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}
 
 var tests = []struct {
@@ -46,7 +47,6 @@ var tests = []struct {
 	{"overflow", 2e9, func(i int) bool { return false }, 2e9},
 }
 
-
 func TestSearch(t *testing.T) {
 	for _, e := range tests {
 		i := Search(e.n, e.f)
@@ -56,7 +56,6 @@ func TestSearch(t *testing.T) {
 	}
 }
 
-
 // log2 computes the binary logarithm of x, rounded up to the next integer.
 // (log2(0) == 0, log2(1) == 0, log2(2) == 1, log2(3) == 2, etc.)
 //
@@ -70,7 +69,6 @@ func log2(x int) int {
 	return n
 }
 
-
 func TestSearchEfficiency(t *testing.T) {
 	n := 100
 	step := 1
@@ -93,7 +91,6 @@ func TestSearchEfficiency(t *testing.T) {
 	}
 }
 
-
 // Smoke tests for convenience wrappers - not comprehensive.
 
 var fdata = []float64{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
@@ -112,7 +109,6 @@ var wrappertests = []struct {
 	{"StringSlice.Search", StringSlice(sdata).Search("x"), 3},
 }
 
-
 func TestSearchWrappers(t *testing.T) {
 	for _, e := range wrappertests {
 		if e.result != e.i {
@@ -121,7 +117,6 @@ func TestSearchWrappers(t *testing.T) {
 	}
 }
 
-
 // Abstract exhaustive test: all sizes up to 100,
 // all possible return values.  If there are any small
 // corner cases, this test exercises them.
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index daed61e..0a4a437 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -6,6 +6,8 @@
 // collections.
 package sort
 
+import "math"
+
 // A type, typically a collection, that satisfies sort.Interface can be
 // sorted by the routines in this package.  The methods require that the
 // elements of the collection be enumerated by an integer index.
@@ -141,7 +143,6 @@ func quickSort(data Interface, a, b int) {
 
 func Sort(data Interface) { quickSort(data, 0, data.Len()) }
 
-
 func IsSorted(data Interface) bool {
 	n := data.Len()
 	for i := n - 1; i > 0; i-- {
@@ -152,7 +153,6 @@ func IsSorted(data Interface) bool {
 	return true
 }
 
-
 // Convenience types for common cases
 
 // IntSlice attaches the methods of Interface to []int, sorting in increasing order.
@@ -165,18 +165,16 @@ func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 // Sort is a convenience method.
 func (p IntSlice) Sort() { Sort(p) }
 
-
 // Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
 type Float64Slice []float64
 
 func (p Float64Slice) Len() int           { return len(p) }
-func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || math.IsNaN(p[i]) && !math.IsNaN(p[j]) }
 func (p Float64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 
 // Sort is a convenience method.
 func (p Float64Slice) Sort() { Sort(p) }
 
-
 // StringSlice attaches the methods of Interface to []string, sorting in increasing order.
 type StringSlice []string
 
@@ -187,7 +185,6 @@ func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 // Sort is a convenience method.
 func (p StringSlice) Sort() { Sort(p) }
 
-
 // Convenience wrappers for common cases
 
 // Ints sorts a slice of ints in increasing order.
@@ -197,7 +194,6 @@ func Float64s(a []float64) { Sort(Float64Slice(a)) }
 // Strings sorts a slice of strings in increasing order.
 func Strings(a []string) { Sort(StringSlice(a)) }
 
-
 // IntsAreSorted tests whether a slice of ints is sorted in increasing order.
 func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
 // Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
diff --git a/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go
index 4da2626..5007a92 100644
--- a/src/pkg/sort/sort_test.go
+++ b/src/pkg/sort/sort_test.go
@@ -2,18 +2,19 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package sort
+package sort_test
 
 import (
 	"fmt"
+	"math"
 	"rand"
+	. "sort"
 	"strconv"
 	"testing"
 )
 
-
 var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
-var float64s = [...]float64{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8}
+var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
 var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
 
 func TestSortIntSlice(t *testing.T) {
@@ -272,3 +273,10 @@ func TestBentleyMcIlroy(t *testing.T) {
 		}
 	}
 }
+
+func min(a, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index a91e8bf..38b3805 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -43,11 +43,13 @@ func special(s string) (f float64, ok bool) {
 	switch {
 	case equalIgnoreCase(s, "nan"):
 		return math.NaN(), true
-	case equalIgnoreCase(s, "-inf"):
+	case equalIgnoreCase(s, "-inf"),
+		equalIgnoreCase(s, "-infinity"):
 		return math.Inf(-1), true
-	case equalIgnoreCase(s, "+inf"):
-		return math.Inf(1), true
-	case equalIgnoreCase(s, "inf"):
+	case equalIgnoreCase(s, "+inf"),
+		equalIgnoreCase(s, "+infinity"),
+		equalIgnoreCase(s, "inf"),
+		equalIgnoreCase(s, "infinity"):
 		return math.Inf(1), true
 	}
 	return
diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go
index 6d8396e..0fdd0ea 100644
--- a/src/pkg/strconv/atof_test.go
+++ b/src/pkg/strconv/atof_test.go
@@ -47,6 +47,9 @@ var atoftests = []atofTest{
 	{"inf", "+Inf", nil},
 	{"-Inf", "-Inf", nil},
 	{"+INF", "+Inf", nil},
+	{"-Infinity", "-Inf", nil},
+	{"+INFINITY", "+Inf", nil},
+	{"Infinity", "+Inf", nil},
 
 	// largest float64
 	{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index e115478..5845942 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -13,7 +13,6 @@ type NumError struct {
 
 func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
 
-
 func computeIntsize() uint {
 	siz := uint(8)
 	for 1<<siz != 0 {
@@ -173,7 +172,6 @@ func Btoi64(s string, base int) (i int64, err os.Error) {
 // returns its result in an int64.
 func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) }
 
-
 // Atoui is like Atoui64 but returns its result as a uint.
 func Atoui(s string) (i uint, err os.Error) {
 	i1, e1 := Atoui64(s)
diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
index 8423f7e..eb515de 100644
--- a/src/pkg/strings/reader.go
+++ b/src/pkg/strings/reader.go
@@ -43,7 +43,6 @@ func (r *Reader) ReadByte() (b byte, err os.Error) {
 	return
 }
 
-
 // UnreadByte moves the reading position back by one byte.
 // It is an error to call UnreadByte if nothing has been
 // read yet.
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index 6afbc7d..c547297 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -363,7 +363,6 @@ func Repeat(s string, count int) string {
 	return string(b)
 }
 
-
 // ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
 func ToUpper(s string) string { return Map(unicode.ToUpper, s) }
 
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index c546173..409d4da 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -170,7 +170,6 @@ func BenchmarkIndex(b *testing.B) {
 	}
 }
 
-
 type ExplodeTest struct {
 	s string
 	n int
@@ -325,7 +324,6 @@ func TestFieldsFunc(t *testing.T) {
 	}
 }
 
-
 // Test case for any function which accepts and returns a single string.
 type StringTest struct {
 	in, out string
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
index a9360ef..914d2fe 100644
--- a/src/pkg/sync/atomic/asm_386.s
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -85,3 +85,12 @@ addloop:
 	MOVL	BX, retlo+12(FP)
 	MOVL	CX, rethi+16(FP)
 	RET
+
+TEXT ·LoadInt32(SB),7,$0
+	JMP	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),7,$0
+	MOVL	addrptr+0(FP), AX
+	MOVL	0(AX), AX
+	MOVL	AX, ret+4(FP)
+	RET
diff --git a/src/pkg/sync/atomic/asm_amd64.s b/src/pkg/sync/atomic/asm_amd64.s
index a260902..4282950 100644
--- a/src/pkg/sync/atomic/asm_amd64.s
+++ b/src/pkg/sync/atomic/asm_amd64.s
@@ -57,3 +57,13 @@ TEXT ·AddUint64(SB),7,$0
 	ADDQ	AX, CX
 	MOVQ	CX, ret+16(FP)
 	RET
+
+TEXT ·LoadInt32(SB),7,$0
+	JMP	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),7,$0
+	MOVQ	addrptr+0(FP), AX
+	MOVL	0(AX), AX
+	MOVL	AX, ret+8(FP)
+	RET
+
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index 72f8d74..9ac4119 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -83,3 +83,16 @@ TEXT ·AddInt64(SB),7,$0
 
 TEXT ·AddUint64(SB),7,$0
 	B	·armAddUint64(SB)
+
+TEXT ·LoadInt32(SB),7,$0
+	B	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),7,$0
+	MOVW	addrptr+0(FP), R2
+loadloop1:
+	MOVW	0(R2), R0
+	MOVW	R0, R1
+	BL	cas<>(SB)
+	BCC	loadloop1
+	MOVW	R1, val+4(FP)
+	RET
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index 119ad00..2229e58 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -308,6 +308,46 @@ func TestCompareAndSwapUintptr(t *testing.T) {
 	}
 }
 
+func TestLoadInt32(t *testing.T) {
+	var x struct {
+		before int32
+		i      int32
+		after  int32
+	}
+	x.before = magic32
+	x.after = magic32
+	for delta := int32(1); delta+delta > delta; delta += delta {
+		k := LoadInt32(&x.i)
+		if k != x.i {
+			t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+		}
+		x.i += delta
+	}
+	if x.before != magic32 || x.after != magic32 {
+		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+	}
+}
+
+func TestLoadUint32(t *testing.T) {
+	var x struct {
+		before uint32
+		i      uint32
+		after  uint32
+	}
+	x.before = magic32
+	x.after = magic32
+	for delta := uint32(1); delta+delta > delta; delta += delta {
+		k := LoadUint32(&x.i)
+		if k != x.i {
+			t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+		}
+		x.i += delta
+	}
+	if x.before != magic32 || x.after != magic32 {
+		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+	}
+}
+
 // Tests of correct behavior, with contention.
 // (Is the function atomic?)
 //
@@ -537,3 +577,65 @@ func TestHammer64(t *testing.T) {
 		}
 	}
 }
+
+func hammerLoadInt32(t *testing.T, uval *uint32) {
+	val := (*int32)(unsafe.Pointer(uval))
+	for {
+		v := LoadInt32(val)
+		vlo := v & ((1 << 16) - 1)
+		vhi := v >> 16
+		if vlo != vhi {
+			t.Fatalf("LoadInt32: %#x != %#x", vlo, vhi)
+		}
+		new := v + 1 + 1<<16
+		if vlo == 1e4 {
+			new = 0
+		}
+		if CompareAndSwapInt32(val, v, new) {
+			break
+		}
+	}
+}
+
+func hammerLoadUint32(t *testing.T, val *uint32) {
+	for {
+		v := LoadUint32(val)
+		vlo := v & ((1 << 16) - 1)
+		vhi := v >> 16
+		if vlo != vhi {
+			t.Fatalf("LoadUint32: %#x != %#x", vlo, vhi)
+		}
+		new := v + 1 + 1<<16
+		if vlo == 1e4 {
+			new = 0
+		}
+		if CompareAndSwapUint32(val, v, new) {
+			break
+		}
+	}
+}
+
+func TestHammerLoad(t *testing.T) {
+	tests := [...]func(*testing.T, *uint32){hammerLoadInt32, hammerLoadUint32}
+	n := 100000
+	if testing.Short() {
+		n = 10000
+	}
+	const procs = 8
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
+	for _, tt := range tests {
+		c := make(chan int)
+		var val uint32
+		for p := 0; p < procs; p++ {
+			go func() {
+				for i := 0; i < n; i++ {
+					tt(t, &val)
+				}
+				c <- 1
+			}()
+		}
+		for p := 0; p < procs; p++ {
+			<-c
+		}
+	}
+}
diff --git a/src/pkg/sync/atomic/doc.go b/src/pkg/sync/atomic/doc.go
index ec5a0d3..b35eb53 100644
--- a/src/pkg/sync/atomic/doc.go
+++ b/src/pkg/sync/atomic/doc.go
@@ -56,6 +56,12 @@ func AddUint64(val *uint64, delta uint64) (new uint64)
 // AddUintptr atomically adds delta to *val and returns the new value.
 func AddUintptr(val *uintptr, delta uintptr) (new uintptr)
 
+// LoadInt32 atomically loads *addr.
+func LoadInt32(addr *int32) (val int32)
+
+// LoadUint32 atomically loads *addr.
+func LoadUint32(addr *uint32) (val uint32)
+
 // Helper for ARM.  Linker will discard on other systems
 func panic64() {
 	panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index d5ada85..4775884 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -53,7 +53,6 @@ func BenchmarkContendedSemaphore(b *testing.B) {
 	<-c
 }
 
-
 func HammerMutex(m *Mutex, loops int, cdone chan bool) {
 	for i := 0; i < loops; i++ {
 		m.Lock()
diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go
index 447b71d..04b714a 100644
--- a/src/pkg/sync/once.go
+++ b/src/pkg/sync/once.go
@@ -11,7 +11,7 @@ import (
 // Once is an object that will perform exactly one action.
 type Once struct {
 	m    Mutex
-	done int32
+	done uint32
 }
 
 // Do calls the function f if and only if the method is being called for the
@@ -30,7 +30,7 @@ type Once struct {
 // Do to be called, it will deadlock.
 //
 func (o *Once) Do(f func()) {
-	if atomic.AddInt32(&o.done, 0) == 1 {
+	if atomic.LoadUint32(&o.done) == 1 {
 		return
 	}
 	// Slow-path.
@@ -38,6 +38,6 @@ func (o *Once) Do(f func()) {
 	defer o.m.Unlock()
 	if o.done == 0 {
 		f()
-		atomic.CompareAndSwapInt32(&o.done, 0, 1)
+		atomic.CompareAndSwapUint32(&o.done, 0, 1)
 	}
 }
diff --git a/src/pkg/sync/rwmutex.go b/src/pkg/sync/rwmutex.go
index 9248b4b..cb1a477 100644
--- a/src/pkg/sync/rwmutex.go
+++ b/src/pkg/sync/rwmutex.go
@@ -4,7 +4,10 @@
 
 package sync
 
-import "sync/atomic"
+import (
+	"runtime"
+	"sync/atomic"
+)
 
 // An RWMutex is a reader/writer mutual exclusion lock.
 // The lock can be held by an arbitrary number of readers
@@ -12,35 +15,22 @@ import "sync/atomic"
 // RWMutexes can be created as part of other
 // structures; the zero value for a RWMutex is
 // an unlocked mutex.
-//
-// Writers take priority over Readers: no new RLocks
-// are granted while a blocked Lock call is waiting.
 type RWMutex struct {
-	w           Mutex // held if there are pending readers or writers
-	r           Mutex // held if the w is being rd
-	readerCount int32 // number of pending readers
+	w           Mutex  // held if there are pending writers
+	writerSem   uint32 // semaphore for writers to wait for completing readers
+	readerSem   uint32 // semaphore for readers to wait for completing writers
+	readerCount int32  // number of pending readers
+	readerWait  int32  // number of departing readers
 }
 
+const rwmutexMaxReaders = 1 << 30
+
 // RLock locks rw for reading.
-// If the lock is already locked for writing or there is a writer already waiting
-// to release the lock, RLock blocks until the writer has released the lock.
 func (rw *RWMutex) RLock() {
-	// Use rw.r.Lock() to block granting the RLock if a goroutine
-	// is waiting for its Lock. This is the prevent starvation of W in
-	// this situation:
-	//   A: rw.RLock()  // granted
-	//   W: rw.Lock()   // waiting for rw.w().Lock()
-	//   B: rw.RLock()  // granted
-	//   C: rw.RLock()  // granted
-	//   B: rw.RUnlock()
-	//   ... (new readers come and go indefinitely, W is starving)
-	rw.r.Lock()
-	if atomic.AddInt32(&rw.readerCount, 1) == 1 {
-		// The first reader locks rw.w, so writers will be blocked
-		// while the readers have the RLock.
-		rw.w.Lock()
+	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
+		// A writer is pending, wait for it.
+		runtime.Semacquire(&rw.readerSem)
 	}
-	rw.r.Unlock()
 }
 
 // RUnlock undoes a single RLock call;
@@ -48,9 +38,12 @@ func (rw *RWMutex) RLock() {
 // It is a run-time error if rw is not locked for reading
 // on entry to RUnlock.
 func (rw *RWMutex) RUnlock() {
-	if atomic.AddInt32(&rw.readerCount, -1) == 0 {
-		// last reader finished, enable writers
-		rw.w.Unlock()
+	if atomic.AddInt32(&rw.readerCount, -1) < 0 {
+		// A writer is pending.
+		if atomic.AddInt32(&rw.readerWait, -1) == 0 {
+			// The last reader unblocks the writer.
+			runtime.Semrelease(&rw.writerSem)
+		}
 	}
 }
 
@@ -61,9 +54,14 @@ func (rw *RWMutex) RUnlock() {
 // a blocked Lock call excludes new readers from acquiring
 // the lock.
 func (rw *RWMutex) Lock() {
-	rw.r.Lock()
+	// First, resolve competition with other writers.
 	rw.w.Lock()
-	rw.r.Unlock()
+	// Announce to readers there is a pending writer.
+	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
+	// Wait for active readers.
+	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
+		runtime.Semacquire(&rw.writerSem)
+	}
 }
 
 // Unlock unlocks rw for writing.  It is a run-time error if rw is
@@ -72,7 +70,16 @@ func (rw *RWMutex) Lock() {
 // As with Mutexes, a locked RWMutex is not associated with a particular
 // goroutine.  One goroutine may RLock (Lock) an RWMutex and then
 // arrange for another goroutine to RUnlock (Unlock) it.
-func (rw *RWMutex) Unlock() { rw.w.Unlock() }
+func (rw *RWMutex) Unlock() {
+	// Announce to readers there is no active writer.
+	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
+	// Unblock blocked readers, if any.
+	for i := 0; i < int(r); i++ {
+		runtime.Semrelease(&rw.readerSem)
+	}
+	// Allow other writers to proceed.
+	rw.w.Unlock()
+}
 
 // RLocker returns a Locker interface that implements
 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
diff --git a/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
index 0480a66..dc8ce96 100644
--- a/src/pkg/sync/rwmutex_test.go
+++ b/src/pkg/sync/rwmutex_test.go
@@ -154,3 +154,84 @@ func TestRLocker(t *testing.T) {
 		wl.Unlock()
 	}
 }
+
+func BenchmarkRWMutexUncontended(b *testing.B) {
+	type PaddedRWMutex struct {
+		RWMutex
+		pad [32]uint32
+	}
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			var rwm PaddedRWMutex
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					rwm.RLock()
+					rwm.RLock()
+					rwm.RUnlock()
+					rwm.RUnlock()
+					rwm.Lock()
+					rwm.Unlock()
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	var rwm RWMutex
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					foo++
+					if foo%writeRatio == 0 {
+						rwm.Lock()
+						rwm.Unlock()
+					} else {
+						rwm.RLock()
+						for i := 0; i != localWork; i += 1 {
+							foo *= 2
+							foo /= 2
+						}
+						rwm.RUnlock()
+					}
+				}
+			}
+			c <- foo == 42
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkRWMutexWrite100(b *testing.B) {
+	benchmarkRWMutex(b, 0, 100)
+}
+
+func BenchmarkRWMutexWrite10(b *testing.B) {
+	benchmarkRWMutex(b, 0, 10)
+}
+
+func BenchmarkRWMutexWorkWrite100(b *testing.B) {
+	benchmarkRWMutex(b, 100, 100)
+}
+
+func BenchmarkRWMutexWorkWrite10(b *testing.B) {
+	benchmarkRWMutex(b, 100, 10)
+}
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
index 05478c6..a4c9b7e 100644
--- a/src/pkg/sync/waitgroup.go
+++ b/src/pkg/sync/waitgroup.go
@@ -4,7 +4,10 @@
 
 package sync
 
-import "runtime"
+import (
+	"runtime"
+	"sync/atomic"
+)
 
 // A WaitGroup waits for a collection of goroutines to finish.
 // The main goroutine calls Add to set the number of
@@ -28,8 +31,8 @@ import "runtime"
 // 
 type WaitGroup struct {
 	m       Mutex
-	counter int
-	waiters int
+	counter int32
+	waiters int32
 	sema    *uint32
 }
 
@@ -48,19 +51,19 @@ type WaitGroup struct {
 // Add adds delta, which may be negative, to the WaitGroup counter.
 // If the counter becomes zero, all goroutines blocked on Wait() are released.
 func (wg *WaitGroup) Add(delta int) {
-	wg.m.Lock()
-	if delta < -wg.counter {
-		wg.m.Unlock()
+	v := atomic.AddInt32(&wg.counter, int32(delta))
+	if v < 0 {
 		panic("sync: negative WaitGroup count")
 	}
-	wg.counter += delta
-	if wg.counter == 0 && wg.waiters > 0 {
-		for i := 0; i < wg.waiters; i++ {
-			runtime.Semrelease(wg.sema)
-		}
-		wg.waiters = 0
-		wg.sema = nil
+	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
+		return
 	}
+	wg.m.Lock()
+	for i := int32(0); i < wg.waiters; i++ {
+		runtime.Semrelease(wg.sema)
+	}
+	wg.waiters = 0
+	wg.sema = nil
 	wg.m.Unlock()
 }
 
@@ -71,12 +74,20 @@ func (wg *WaitGroup) Done() {
 
 // Wait blocks until the WaitGroup counter is zero.
 func (wg *WaitGroup) Wait() {
+	if atomic.LoadInt32(&wg.counter) == 0 {
+		return
+	}
 	wg.m.Lock()
-	if wg.counter == 0 {
+	atomic.AddInt32(&wg.waiters, 1)
+	// This code is racing with the unlocked path in Add above.
+	// The code above modifies counter and then reads waiters.
+	// We must modify waiters and then read counter (the opposite order)
+	// to avoid missing an Add.
+	if atomic.LoadInt32(&wg.counter) == 0 {
+		atomic.AddInt32(&wg.waiters, -1)
 		wg.m.Unlock()
 		return
 	}
-	wg.waiters++
 	if wg.sema == nil {
 		wg.sema = new(uint32)
 	}
diff --git a/src/pkg/sync/waitgroup_test.go b/src/pkg/sync/waitgroup_test.go
index fe35732..34430fc 100644
--- a/src/pkg/sync/waitgroup_test.go
+++ b/src/pkg/sync/waitgroup_test.go
@@ -5,7 +5,9 @@
 package sync_test
 
 import (
+	"runtime"
 	. "sync"
+	"sync/atomic"
 	"testing"
 )
 
@@ -58,3 +60,106 @@ func TestWaitGroupMisuse(t *testing.T) {
 	wg.Done()
 	t.Fatal("Should panic")
 }
+
+func BenchmarkWaitGroupUncontended(b *testing.B) {
+	type PaddedWaitGroup struct {
+		WaitGroup
+		pad [128]uint8
+	}
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			var wg PaddedWaitGroup
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					wg.Add(1)
+					wg.Done()
+					wg.Wait()
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	var wg WaitGroup
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					wg.Add(1)
+					for i := 0; i < localWork; i++ {
+						foo *= 2
+						foo /= 2
+					}
+					wg.Done()
+				}
+			}
+			c <- foo == 42
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkWaitGroupAddDone(b *testing.B) {
+	benchmarkWaitGroupAddDone(b, 0)
+}
+
+func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
+	benchmarkWaitGroupAddDone(b, 100)
+}
+
+func benchmarkWaitGroupWait(b *testing.B, localWork int) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	var wg WaitGroup
+	wg.Add(procs)
+	for p := 0; p < procs; p++ {
+		go wg.Done()
+	}
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					wg.Wait()
+					for i := 0; i < localWork; i++ {
+						foo *= 2
+						foo /= 2
+					}
+				}
+			}
+			c <- foo == 42
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkWaitGroupWait(b *testing.B) {
+	benchmarkWaitGroupWait(b, 0)
+}
+
+func BenchmarkWaitGroupWaitWork(b *testing.B) {
+	benchmarkWaitGroupWait(b, 100)
+}
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
index 212b6f8..fa0fe8b 100644
--- a/src/pkg/syscall/Makefile
+++ b/src/pkg/syscall/Makefile
@@ -36,6 +36,7 @@ GOFILES_linux=\
 	exec_unix.go\
 	lsf_linux.go\
 	netlink_linux.go\
+	sockcmsg_linux.go\
 	sockcmsg_unix.go\
 	syscall_unix.go\
 
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index 46f05ef..94f0756 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -87,7 +87,6 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
 	return err
 }
 
-
 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
 // If a dup or exec fails, write the errno int to pipe.
 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
diff --git a/src/pkg/syscall/sockcmsg_linux.go b/src/pkg/syscall/sockcmsg_linux.go
new file mode 100644
index 0000000..b025ca5
--- /dev/null
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -0,0 +1,38 @@
+// 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.
+
+// Socket control messages
+
+package syscall
+
+import (
+	"unsafe"
+)
+
+// UnixCredentials encodes credentials into a socket control message
+// for sending to another process. This can be used for
+// authentication.
+func UnixCredentials(ucred *Ucred) []byte {
+	buf := make([]byte, CmsgSpace(SizeofUcred))
+	cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
+	cmsg.Level = SOL_SOCKET
+	cmsg.Type = SCM_CREDENTIALS
+	cmsg.SetLen(CmsgLen(SizeofUcred))
+	*((*Ucred)(cmsgData(cmsg))) = *ucred
+	return buf
+}
+
+// ParseUnixCredentials decodes a socket control message that contains
+// credentials in a Ucred structure. To receive such a message, the
+// SO_PASSCRED option must be enabled on the socket.
+func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, int) {
+	if msg.Header.Level != SOL_SOCKET {
+		return nil, EINVAL
+	}
+	if msg.Header.Type != SCM_CREDENTIALS {
+		return nil, EINVAL
+	}
+	ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
+	return &ucred, 0
+}
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index f0c05ea..b437560 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -24,10 +24,22 @@ func cmsgAlignOf(salen int) int {
 	return (salen + salign - 1) & ^(salign - 1)
 }
 
-func cmsgLen(datalen int) int {
+// CmsgLen returns the value to store in the Len field of the Cmsghdr
+// structure, taking into account any necessary alignment.
+func CmsgLen(datalen int) int {
 	return cmsgAlignOf(SizeofCmsghdr) + datalen
 }
 
+// CmsgSpace returns the number of bytes an ancillary element with
+// payload of the passed data length occupies.
+func CmsgSpace(datalen int) int {
+	return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
+}
+
+func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
+}
+
 type SocketControlMessage struct {
 	Header Cmsghdr
 	Data   []byte
@@ -41,7 +53,7 @@ func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
 		cmsgs []SocketControlMessage
 	)
 
-	for len(buf) >= cmsgLen(0) {
+	for len(buf) >= CmsgLen(0) {
 		h, dbuf, e = socketControlMessageHeaderAndData(buf)
 		if e != 0 {
 			break
@@ -63,3 +75,39 @@ func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, int) {
 	}
 	return h, buf[cmsgAlignOf(SizeofCmsghdr):], 0
 }
+
+// UnixRights encodes a set of open file descriptors into a socket
+// control message for sending to another process.
+func UnixRights(fds ...int) []byte {
+	datalen := len(fds) * 4
+	buf := make([]byte, CmsgSpace(datalen))
+	cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
+	cmsg.Level = SOL_SOCKET
+	cmsg.Type = SCM_RIGHTS
+	cmsg.SetLen(CmsgLen(datalen))
+
+	data := uintptr(cmsgData(cmsg))
+	for _, fd := range fds {
+		*(*int32)(unsafe.Pointer(data)) = int32(fd)
+		data += 4
+	}
+
+	return buf
+}
+
+// ParseUnixRights decodes a socket control message that contains an
+// integer array of open file descriptors from another process.
+func ParseUnixRights(msg *SocketControlMessage) ([]int, int) {
+	if msg.Header.Level != SOL_SOCKET {
+		return nil, EINVAL
+	}
+	if msg.Header.Type != SCM_RIGHTS {
+		return nil, EINVAL
+	}
+	fds := make([]int, len(msg.Data)>>2)
+	for i, j := 0, 0; i < len(msg.Data); i += 4 {
+		fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
+		j++
+	}
+	return fds, 0
+}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 2df7591..7fd85a3 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -135,16 +135,6 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
 	return
 }
 
-//sysnb	pipe() (r int, w int, errno int)
-
-func Pipe(p []int) (errno int) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	p[0], p[1], errno = pipe()
-	return
-}
-
 func Sleep(ns int64) (errno int) {
 	tv := NsecToTimeval(ns)
 	return Select(0, nil, nil, nil, &tv)
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index fabd481..11dc8aa 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -60,6 +60,16 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
 func PtraceAttach(pid int) (errno int) { return ptrace(PT_ATTACH, pid, 0, 0) }
 func PtraceDetach(pid int) (errno int) { return ptrace(PT_DETACH, pid, 0, 0) }
 
+//sysnb pipe() (r int, w int, errno int)
+
+func Pipe(p []int) (errno int) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	p[0], p[1], errno = pipe()
+	return
+}
+
 // TODO
 func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
 	return -1, ENOSYS
@@ -159,7 +169,6 @@ func Kill(pid int, signum int) (errno int) { return kill(pid, signum, 1) }
 //sys	read(fd int, buf *byte, nbuf int) (n int, errno int)
 //sys	write(fd int, buf *byte, nbuf int) (n int, errno int)
 
-
 /*
  * Unimplemented
  */
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index a38c8ec..c2bddd9 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -56,6 +56,16 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
 	return origlen - len(buf), count, names
 }
 
+//sysnb pipe() (r int, w int, errno int)
+
+func Pipe(p []int) (errno int) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	p[0], p[1], errno = pipe()
+	return
+}
+
 // TODO
 func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
 	return -1, ENOSYS
@@ -148,7 +158,6 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno
 //sys	read(fd int, buf *byte, nbuf int) (n int, errno int)
 //sys	write(fd int, buf *byte, nbuf int) (n int, errno int)
 
-
 /*
  * Unimplemented
  */
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 1d6fc76..9fc2605 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -774,6 +774,7 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
 //sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int)
 //sys	fcntl(fd int, cmd int, arg int) (val int, errno int)
 //sys	Fdatasync(fd int) (errno int)
+//sys	Flock(fd int, how int) (errno int)
 //sys	Fsync(fd int) (errno int)
 //sys	Getdents(fd int, buf []byte) (n int, errno int) = SYS_GETDENTS64
 //sysnb	Getpgid(pid int) (pgid int, errno int)
@@ -878,7 +879,6 @@ func Munmap(b []byte) (errno int) {
 // Fadvise64
 // Fgetxattr
 // Flistxattr
-// Flock
 // Fork
 // Fremovexattr
 // Fsetxattr
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index 4104050..a158b95 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -121,7 +121,6 @@ func Getppid() (ppid int) {
 	return int(n)
 }
 
-
 func Read(fd int, p []byte) (n int, err Error) {
 	return Pread(fd, p, -1)
 }
@@ -164,7 +163,6 @@ func Pipe(p []int) (err Error) {
 	return
 }
 
-
 //sys	sleep(millisecs int32) (err Error)
 func Sleep(nsec int64) (err Error) {
 	return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index 20c8a13..c298b91 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -9,7 +9,6 @@ import (
 	"unsafe"
 )
 
-
 var (
 	Stdin  = 0
 	Stdout = 1
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 5b8143a..9b1a9de 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -76,7 +76,7 @@ func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
 
 // dll helpers
 
-// implemented in ../runtime/windows/syscall.cgo
+// Implemented in ../runtime/windows/syscall.goc
 func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr)
 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr)
@@ -105,14 +105,9 @@ func Getpagesize() int { return 4096 }
 // Converts a Go function to a function pointer conforming
 // to the stdcall calling convention.  This is useful when
 // interoperating with Windows code requiring callbacks.
-// Implemented in ../runtime/windows/syscall.cgo
+// Implemented in ../runtime/windows/syscall.goc
 func NewCallback(fn interface{}) uintptr
 
-// TODO
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
-	return -1, ENOSYS
-}
-
 // windows api calls
 
 //sys	GetLastError() (lasterrno int)
@@ -476,7 +471,7 @@ func Chmod(path string, mode uint32) (errno int) {
 //sys	WSACleanup() (errno int) [failretval==-1] = wsock32.WSACleanup
 //sys	WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) [failretval==-1] = ws2_32.WSAIoctl
 //sys	socket(af int32, typ int32, protocol int32) (handle Handle, errno int) [failretval==InvalidHandle] = wsock32.socket
-//sys	setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
+//sys	Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
 //sys	bind(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
 //sys	connect(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.connect
 //sys	getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getsockname
@@ -594,7 +589,7 @@ func Socket(domain, typ, proto int) (fd Handle, errno int) {
 
 func SetsockoptInt(fd Handle, level, opt int, value int) (errno int) {
 	v := int32(value)
-	return int(setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
+	return int(Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
 }
 
 func Bind(fd Handle, sa Sockaddr) (errno int) {
@@ -728,24 +723,3 @@ func Geteuid() (euid int)                { return -1 }
 func Getgid() (gid int)                  { return -1 }
 func Getegid() (egid int)                { return -1 }
 func Getgroups() (gids []int, errno int) { return nil, EWINDOWS }
-
-// TODO(brainman): fix all this meaningless code, it is here to compile exec.go
-
-func read(fd Handle, buf *byte, nbuf int) (n int, errno int) {
-	return 0, EWINDOWS
-}
-
-func fcntl(fd Handle, cmd, arg int) (val int, errno int) {
-	return 0, EWINDOWS
-}
-
-const (
-	PTRACE_TRACEME = 1 + iota
-	WNOHANG
-	WSTOPPED
-	WUNTRACED
-	SYS_CLOSE
-	SYS_WRITE
-	SYS_EXIT
-	SYS_READ
-)
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
index 33cc7fd..a769fd3 100644
--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -1087,7 +1087,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:   "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go
index 571ce90..3165fee 100644
--- a/src/pkg/syscall/zerrors_darwin_amd64.go
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -1087,7 +1087,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:   "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index d045cab..a77e264 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -1307,7 +1307,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:  "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 871b381..ce3c7dd 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -1307,7 +1307,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:  "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index 2987540..f482096 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -1194,7 +1194,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:   "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index 728eefd..5d1f310 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -1195,7 +1195,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:   "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_linux_arm.go b/src/pkg/syscall/zerrors_linux_arm.go
index 7d57271..bebc00a 100644
--- a/src/pkg/syscall/zerrors_linux_arm.go
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -1184,7 +1184,6 @@ const (
 
 // Types
 
-
 // Error table
 var errors = [...]string{
 	1:   "operation not permitted",
diff --git a/src/pkg/syscall/zerrors_plan9_386.go b/src/pkg/syscall/zerrors_plan9_386.go
index e452079..65198c3 100644
--- a/src/pkg/syscall/zerrors_plan9_386.go
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -10,7 +10,6 @@ const (
 	O_SYNC     = 0x00000
 	O_ASYNC    = 0x00000
 
-
 	S_IFMT   = 0x1f000
 	S_IFIFO  = 0x1000
 	S_IFCHR  = 0x2000
diff --git a/src/pkg/syscall/zsyscall_linux_386.go b/src/pkg/syscall/zsyscall_linux_386.go
index 8df29f1..4eb522a 100644
--- a/src/pkg/syscall/zsyscall_linux_386.go
+++ b/src/pkg/syscall/zsyscall_linux_386.go
@@ -277,6 +277,14 @@ func Fdatasync(fd int) (errno int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Flock(fd int, how int) (errno int) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	errno = int(e1)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Fsync(fd int) (errno int) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index fa20ff5..999ed64 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -277,6 +277,14 @@ func Fdatasync(fd int) (errno int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Flock(fd int, how int) (errno int) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	errno = int(e1)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Fsync(fd int) (errno int) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 560a65b..cd49dab 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -277,6 +277,14 @@ func Fdatasync(fd int) (errno int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Flock(fd int, how int) (errno int) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	errno = int(e1)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Fsync(fd int) (errno int) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 350ad23..ccb63ab 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1076,7 +1076,7 @@ func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
 	return
 }
 
-func setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
 	r1, _, e1 := Syscall6(procsetsockopt, 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index e7d09fb..af237e8 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -1076,7 +1076,7 @@ func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
 	return
 }
 
-func setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
 	r1, _, e1 := Syscall6(procsetsockopt, 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
index 1a264a4..10780f7 100644
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -1,22 +1,5 @@
 package syscall
 
-// TODO(brainman): autogenerate types in ztypes_windows_386.go
-
-//import "unsafe"
-
-// Constants
-const (
-	sizeofPtr      = 0x4
-	sizeofShort    = 0x2
-	sizeofInt      = 0x4
-	sizeofLong     = 0x4
-	sizeofLongLong = 0x8
-	PathMax        = 0x1000
-	SizeofLinger   = 0x8
-	SizeofMsghdr   = 0x1c
-	SizeofCmsghdr  = 0xc
-)
-
 const (
 	// Windows errors.
 	ERROR_FILE_NOT_FOUND      = 2
@@ -179,16 +162,6 @@ const (
 	CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
 )
 
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
-
 // Invented values to support what package os expects.
 type Timeval struct {
 	Sec  int32
@@ -212,8 +185,8 @@ type SecurityAttributes struct {
 }
 
 type Overlapped struct {
-	Internal     uint32
-	InternalHigh uint32
+	Internal     uintptr
+	InternalHigh uintptr
 	Offset       uint32
 	OffsetHigh   uint32
 	HEvent       Handle
@@ -388,53 +361,28 @@ const (
 	WSASYS_STATUS_LEN  = 128
 )
 
-type WSAData struct {
-	Version      uint16
-	HighVersion  uint16
-	Description  [WSADESCRIPTION_LEN + 1]byte
-	SystemStatus [WSASYS_STATUS_LEN + 1]byte
-	MaxSockets   uint16
-	MaxUdpDg     uint16
-	VendorInfo   *byte
-}
-
 type WSABuf struct {
 	Len uint32
 	Buf *byte
 }
 
-// TODO(brainman): fix all needed for os
-
+// Invented values to support what package os expects.
 const (
-	PROT_READ  = 0x1
-	PROT_WRITE = 0x2
-	MAP_SHARED = 0x1
-	SYS_FORK   = 0
-	SYS_PTRACE = 0
-	SYS_CHDIR  = 0
-	SYS_DUP2   = 0
-	SYS_FCNTL  = 0
-	SYS_EXECVE = 0
-	F_GETFD    = 0x1
-	F_SETFD    = 0x2
-	F_GETFL    = 0x3
-	F_SETFL    = 0x4
-	FD_CLOEXEC = 0
-	S_IFMT     = 0x1f000
-	S_IFIFO    = 0x1000
-	S_IFCHR    = 0x2000
-	S_IFDIR    = 0x4000
-	S_IFBLK    = 0x6000
-	S_IFREG    = 0x8000
-	S_IFLNK    = 0xa000
-	S_IFSOCK   = 0xc000
-	S_ISUID    = 0x800
-	S_ISGID    = 0x400
-	S_ISVTX    = 0x200
-	S_IRUSR    = 0x100
-	S_IWRITE   = 0x80
-	S_IWUSR    = 0x80
-	S_IXUSR    = 0x40
+	S_IFMT   = 0x1f000
+	S_IFIFO  = 0x1000
+	S_IFCHR  = 0x2000
+	S_IFDIR  = 0x4000
+	S_IFBLK  = 0x6000
+	S_IFREG  = 0x8000
+	S_IFLNK  = 0xa000
+	S_IFSOCK = 0xc000
+	S_ISUID  = 0x800
+	S_ISGID  = 0x400
+	S_ISVTX  = 0x200
+	S_IRUSR  = 0x100
+	S_IWRITE = 0x80
+	S_IWUSR  = 0x80
+	S_IXUSR  = 0x40
 )
 
 const (
@@ -453,13 +401,6 @@ type Hostent struct {
 	AddrList **byte
 }
 
-type Servent struct {
-	Name    *byte
-	Aliases **byte
-	Port    uint16
-	Proto   *byte
-}
-
 const (
 	DNS_TYPE_A       = 0x0001
 	DNS_TYPE_NS      = 0x0002
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index d1008bd..734ee6e 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -3,3 +3,20 @@
 // license that can be found in the LICENSE file.
 
 package syscall
+
+type WSAData struct {
+	Version      uint16
+	HighVersion  uint16
+	Description  [WSADESCRIPTION_LEN + 1]byte
+	SystemStatus [WSASYS_STATUS_LEN + 1]byte
+	MaxSockets   uint16
+	MaxUdpDg     uint16
+	VendorInfo   *byte
+}
+
+type Servent struct {
+	Name    *byte
+	Aliases **byte
+	Port    uint16
+	Proto   *byte
+}
diff --git a/src/pkg/syscall/ztypes_windows_amd64.go b/src/pkg/syscall/ztypes_windows_amd64.go
index d1008bd..78aa55b 100644
--- a/src/pkg/syscall/ztypes_windows_amd64.go
+++ b/src/pkg/syscall/ztypes_windows_amd64.go
@@ -3,3 +3,20 @@
 // license that can be found in the LICENSE file.
 
 package syscall
+
+type WSAData struct {
+	Version      uint16
+	HighVersion  uint16
+	MaxSockets   uint16
+	MaxUdpDg     uint16
+	VendorInfo   *byte
+	Description  [WSADESCRIPTION_LEN + 1]byte
+	SystemStatus [WSASYS_STATUS_LEN + 1]byte
+}
+
+type Servent struct {
+	Name    *byte
+	Aliases **byte
+	Proto   *byte
+	Port    uint16
+}
diff --git a/src/pkg/tabwriter/tabwriter.go b/src/pkg/tabwriter/tabwriter.go
index b84c6ec..2f35d96 100644
--- a/src/pkg/tabwriter/tabwriter.go
+++ b/src/pkg/tabwriter/tabwriter.go
@@ -17,7 +17,6 @@ import (
 	"utf8"
 )
 
-
 // ----------------------------------------------------------------------------
 // Filter implementation
 
@@ -32,7 +31,6 @@ type cell struct {
 	htab  bool // true if the cell is terminated by an htab ('\t')
 }
 
-
 // A Writer is a filter that inserts padding around tab-delimited
 // columns in its input to align them in the output.
 //
@@ -95,10 +93,8 @@ type Writer struct {
 	widths  []int        // list of column widths in runes - re-used during formatting
 }
 
-
 func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
 
-
 // Reset the current state.
 func (b *Writer) reset() {
 	b.buf.Reset()
@@ -110,7 +106,6 @@ func (b *Writer) reset() {
 	b.addLine()
 }
 
-
 // Internal representation (current state):
 //
 // - all text written is appended to buf; tabs and line breaks are stripped away
@@ -134,7 +129,6 @@ func (b *Writer) reset() {
 // |                  |                         |
 // buf                start of incomplete cell  pos
 
-
 // Formatting can be controlled with these flags.
 const (
 	// Ignore html tags and treat entities (starting with '&'
@@ -162,7 +156,6 @@ const (
 	Debug
 )
 
-
 // A Writer must be initialized with a call to Init. The first parameter (output)
 // specifies the filter output. The remaining parameters control the formatting:
 //
@@ -205,7 +198,6 @@ func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar
 	return b
 }
 
-
 // debugging support (keep code around)
 func (b *Writer) dump() {
 	pos := 0
@@ -220,14 +212,12 @@ func (b *Writer) dump() {
 	print("\n")
 }
 
-
 // local error wrapper so we can distinguish os.Errors we want to return
 // as errors from genuine panics (which we don't want to return as errors)
 type osError struct {
 	err os.Error
 }
 
-
 func (b *Writer) write0(buf []byte) {
 	n, err := b.output.Write(buf)
 	if n != len(buf) && err == nil {
@@ -238,7 +228,6 @@ func (b *Writer) write0(buf []byte) {
 	}
 }
 
-
 func (b *Writer) writeN(src []byte, n int) {
 	for n > len(src) {
 		b.write0(src)
@@ -247,13 +236,11 @@ func (b *Writer) writeN(src []byte, n int) {
 	b.write0(src[0:n])
 }
 
-
 var (
 	newline = []byte{'\n'}
 	tabs    = []byte("\t\t\t\t\t\t\t\t")
 )
 
-
 func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
 	if b.padbytes[0] == '\t' || useTabs {
 		// padding is done with tabs
@@ -274,7 +261,6 @@ func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
 	b.writeN(b.padbytes[0:], cellw-textw)
 }
 
-
 var vbar = []byte{'|'}
 
 func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
@@ -328,7 +314,6 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
 	return
 }
 
-
 // Format the text between line0 and line1 (excluding line1); pos
 // is the buffer position corresponding to the beginning of line0.
 // Returns the buffer position corresponding to the beginning of
@@ -392,21 +377,18 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
 	return b.writeLines(pos, line0, line1)
 }
 
-
 // Append text to current cell.
 func (b *Writer) append(text []byte) {
 	b.buf.Write(text)
 	b.cell.size += len(text)
 }
 
-
 // Update the cell width.
 func (b *Writer) updateWidth() {
 	b.cell.width += utf8.RuneCount(b.buf.Bytes()[b.pos:b.buf.Len()])
 	b.pos = b.buf.Len()
 }
 
-
 // To escape a text segment, bracket it with Escape characters.
 // For instance, the tab in this string "Ignore this tab: \xff\t\xff"
 // does not terminate a cell and constitutes a single character of
@@ -416,7 +398,6 @@ func (b *Writer) updateWidth() {
 //
 const Escape = '\xff'
 
-
 // Start escaped mode.
 func (b *Writer) startEscape(ch byte) {
 	switch ch {
@@ -429,7 +410,6 @@ func (b *Writer) startEscape(ch byte) {
 	}
 }
 
-
 // Terminate escaped mode. If the escaped text was an HTML tag, its width
 // is assumed to be zero for formatting purposes; if it was an HTML entity,
 // its width is assumed to be one. In all other cases, the width is the
@@ -450,7 +430,6 @@ func (b *Writer) endEscape() {
 	b.endChar = 0
 }
 
-
 // Terminate the current cell by adding it to the list of cells of the
 // current line. Returns the number of cells in that line.
 //
@@ -462,14 +441,12 @@ func (b *Writer) terminateCell(htab bool) int {
 	return len(*line)
 }
 
-
 func handlePanic(err *os.Error) {
 	if e := recover(); e != nil {
 		*err = e.(osError).err // re-panics if it's not a local osError
 	}
 }
 
-
 // Flush should be called after the last call to Write to ensure
 // that any data buffered in the Writer is written to output. Any
 // incomplete escape sequence at the end is simply considered
@@ -494,7 +471,6 @@ func (b *Writer) Flush() (err os.Error) {
 	return
 }
 
-
 var hbar = []byte("---\n")
 
 // Write writes buf to the writer b.
@@ -577,7 +553,6 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
 	return
 }
 
-
 // NewWriter allocates and initializes a new tabwriter.Writer.
 // The parameters are the same as for the the Init function.
 //
diff --git a/src/pkg/tabwriter/tabwriter_test.go b/src/pkg/tabwriter/tabwriter_test.go
index 043d915..6ef7e80 100644
--- a/src/pkg/tabwriter/tabwriter_test.go
+++ b/src/pkg/tabwriter/tabwriter_test.go
@@ -10,18 +10,14 @@ import (
 	"testing"
 )
 
-
 type buffer struct {
 	a []byte
 }
 
-
 func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
 
-
 func (b *buffer) clear() { b.a = b.a[0:0] }
 
-
 func (b *buffer) Write(buf []byte) (written int, err os.Error) {
 	n := len(b.a)
 	m := len(buf)
@@ -36,10 +32,8 @@ func (b *buffer) Write(buf []byte) (written int, err os.Error) {
 	return len(buf), nil
 }
 
-
 func (b *buffer) String() string { return string(b.a) }
 
-
 func write(t *testing.T, testname string, w *Writer, src string) {
 	written, err := io.WriteString(w, src)
 	if err != nil {
@@ -50,7 +44,6 @@ func write(t *testing.T, testname string, w *Writer, src string) {
 	}
 }
 
-
 func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
 	err := w.Flush()
 	if err != nil {
@@ -63,7 +56,6 @@ func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected s
 	}
 }
 
-
 func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
 	var b buffer
 	b.init(1000)
@@ -98,7 +90,6 @@ func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padch
 	verify(t, title, &w, &b, src, expected)
 }
 
-
 var tests = []struct {
 	testname                    string
 	minwidth, tabwidth, padding int
@@ -617,7 +608,6 @@ var tests = []struct {
 	},
 }
 
-
 func Test(t *testing.T) {
 	for _, e := range tests {
 		check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
diff --git a/src/pkg/template/template_test.go b/src/pkg/template/template_test.go
index 99b23c2..eae8011 100644
--- a/src/pkg/template/template_test.go
+++ b/src/pkg/template/template_test.go
@@ -259,7 +259,6 @@ var tests = []*Test{
 		out: "77",
 	},
 
-
 	// Repeated
 	&Test{
 		in: "{.section Pdata }\n" +
@@ -438,7 +437,6 @@ var tests = []*Test{
 			"pointedToString\n",
 	},
 
-
 	// Interface values
 
 	&Test{
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index 3b416ac..fd0bd86 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -214,12 +214,13 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
 		for _, procs := range cpuList {
 			runtime.GOMAXPROCS(procs)
 			b := &B{benchmark: Benchmark}
-			r := b.run()
 			benchName := Benchmark.Name
 			if procs != 1 {
 				benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
 			}
-			print(fmt.Sprintf("%s\t%v\n", benchName, r))
+			print(fmt.Sprintf("%s\t", benchName))
+			r := b.run()
+			print(fmt.Sprintf("%v\n", r))
 			if p := runtime.GOMAXPROCS(-1); p != procs {
 				print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
 			}
diff --git a/src/pkg/testing/iotest/reader.go b/src/pkg/testing/iotest/reader.go
index daa6ede..dcf5565 100644
--- a/src/pkg/testing/iotest/reader.go
+++ b/src/pkg/testing/iotest/reader.go
@@ -37,7 +37,6 @@ func (r *halfReader) Read(p []byte) (int, os.Error) {
 	return r.r.Read(p[0 : (len(p)+1)/2])
 }
 
-
 // DataErrReader returns a Reader that returns the final
 // error with the last data read, instead of by itself with
 // zero bytes of data.
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index ba72152..ec4a453 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -74,7 +74,6 @@ func Short() bool {
 	return *short
 }
 
-
 // Insert final newline if needed and tabs after internal newlines.
 func tabify(s string) string {
 	n := len(s)
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 26f40d1..d07e1ad 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -434,7 +434,7 @@ func skip(value, prefix string) (string, os.Error) {
 // structure.  Also, if the input string represents an inconsistent time
 // (such as having the wrong day of the week), the returned value will also
 // be inconsistent.  In any case, the elements of the returned time will be
-// sane: hours in 0..23, minutes in 0..59, day of month in 0..31, etc.
+// sane: hours in 0..23, minutes in 0..59, day of month in 1..31, etc.
 // Years must be in the range 0000..9999.
 func Parse(alayout, avalue string) (*Time, os.Error) {
 	var t Time
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index 2a83e0c..f3ea7b6 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_unix.go
@@ -24,7 +24,6 @@ type data struct {
 	error bool
 }
 
-
 func (d *data) read(n int) []byte {
 	if len(d.p) < n {
 		d.p = nil
@@ -54,7 +53,6 @@ func (d *data) byte() (n byte, ok bool) {
 	return p[0], true
 }
 
-
 // Make a string by stopping at the first NUL
 func byteString(p []byte) string {
 	for i := 0; i < len(p); i++ {
diff --git a/src/pkg/unicode/casetables.go b/src/pkg/unicode/casetables.go
index 6644070..86336b1 100644
--- a/src/pkg/unicode/casetables.go
+++ b/src/pkg/unicode/casetables.go
@@ -9,7 +9,6 @@
 
 package unicode
 
-
 var TurkishCase = _TurkishCase
 var _TurkishCase = SpecialCase{
 	CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index dbd8638..38a11c4 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -32,7 +32,7 @@ type Range16 struct {
 }
 
 // Range32 represents of a range of Unicode code points and is used when one or
-//  more of the values will not fit in 16 bits.  The range runs from Lo to Hi
+// more of the values will not fit in 16 bits.  The range runs from Lo to Hi
 // inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
 type Range32 struct {
 	Lo     uint32
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index c4e26df..8d2665a 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -212,6 +212,10 @@ var caseTest = []caseT{
 	{UpperCase, 0x10450, 0x10450},
 	{LowerCase, 0x10450, 0x10450},
 	{TitleCase, 0x10450, 0x10450},
+
+	// Non-letters with case.
+	{LowerCase, 0x2161, 0x2171},
+	{UpperCase, 0x0345, 0x0399},
 }
 
 func TestIsLetter(t *testing.T) {
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index 07b931d..b586bc6 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -14,6 +14,7 @@ import (
 	"http"
 	"log"
 	"os"
+	"path/filepath"
 	"sort"
 	"strconv"
 	"strings"
@@ -54,10 +55,47 @@ var cases = flag.Bool("cases",
 var test = flag.Bool("test",
 	false,
 	"test existing tables; can be used to compare web data with package data")
+var localFiles = flag.Bool("local",
+	false,
+	"data files have been copied to current directory; for debugging only")
 
 var scriptRe = regexp.MustCompile(`^([0-9A-F]+)(\.\.[0-9A-F]+)? *; ([A-Za-z_]+)$`)
 var logger = log.New(os.Stderr, "", log.Lshortfile)
 
+type reader struct {
+	*bufio.Reader
+	fd   *os.File
+	resp *http.Response
+}
+
+func open(url string) *reader {
+	file := filepath.Base(url)
+	if *localFiles {
+		fd, err := os.Open(file)
+		if err != nil {
+			logger.Fatal(err)
+		}
+		return &reader{bufio.NewReader(fd), fd, nil}
+	}
+	resp, err := http.Get(*dataURL)
+	if err != nil {
+		logger.Fatal(err)
+	}
+	if resp.StatusCode != 200 {
+		logger.Fatalf("bad GET status for %s: %d", file, resp.Status)
+	}
+	return &reader{bufio.NewReader(resp.Body), nil, resp}
+
+}
+
+func (r *reader) close() {
+	if r.fd != nil {
+		r.fd.Close()
+	} else {
+		r.resp.Body.Close()
+	}
+}
+
 var category = map[string]bool{
 	// Nd Lu etc.
 	// We use one-character names to identify merged categories
@@ -192,7 +230,7 @@ func parseCategory(line string) (state State) {
 		char.letter(field[FSimpleUppercaseMapping], field[FCodePoint], field[FSimpleTitlecaseMapping])
 	case "Lt":
 		char.letter(field[FSimpleUppercaseMapping], field[FSimpleLowercaseMapping], field[FCodePoint])
-	case "Lm", "Lo":
+	default:
 		char.letter(field[FSimpleUppercaseMapping], field[FSimpleLowercaseMapping], field[FSimpleTitlecaseMapping])
 	}
 	switch {
@@ -272,14 +310,7 @@ func loadChars() {
 	if *dataURL == "" {
 		flag.Set("data", *url+"UnicodeData.txt")
 	}
-	resp, err := http.Get(*dataURL)
-	if err != nil {
-		logger.Fatal(err)
-	}
-	if resp.StatusCode != 200 {
-		logger.Fatal("bad GET status for UnicodeData.txt", resp.Status)
-	}
-	input := bufio.NewReader(resp.Body)
+	input := open(*dataURL)
 	var first uint32 = 0
 	for {
 		line, err := input.ReadString('\n')
@@ -310,21 +341,14 @@ func loadChars() {
 			first = 0
 		}
 	}
-	resp.Body.Close()
+	input.close()
 }
 
 func loadCasefold() {
 	if *casefoldingURL == "" {
 		flag.Set("casefolding", *url+"CaseFolding.txt")
 	}
-	resp, err := http.Get(*casefoldingURL)
-	if err != nil {
-		logger.Fatal(err)
-	}
-	if resp.StatusCode != 200 {
-		logger.Fatal("bad GET status for CaseFolding.txt", resp.Status)
-	}
-	input := bufio.NewReader(resp.Body)
+	input := open(*casefoldingURL)
 	for {
 		line, err := input.ReadString('\n')
 		if err != nil {
@@ -355,7 +379,7 @@ func loadCasefold() {
 		}
 		chars[p1].foldCase = int(p2)
 	}
-	resp.Body.Close()
+	input.close()
 }
 
 const progHeader = `// Generated by running
@@ -366,7 +390,6 @@ package unicode
 
 `
 
-
 func printCategories() {
 	if *tablelist == "" {
 		return
@@ -663,15 +686,7 @@ func printScriptOrProperty(doProps bool) {
 	if flaglist == "" {
 		return
 	}
-	var err os.Error
-	resp, err := http.Get(*url + file)
-	if err != nil {
-		logger.Fatal(err)
-	}
-	if resp.StatusCode != 200 {
-		logger.Fatal("bad GET status for ", file, ":", resp.Status)
-	}
-	input := bufio.NewReader(resp.Body)
+	input := open(*url + file)
 	for {
 		line, err := input.ReadString('\n')
 		if err != nil {
@@ -682,7 +697,7 @@ func printScriptOrProperty(doProps bool) {
 		}
 		parseScript(line[0:len(line)-1], table)
 	}
-	resp.Body.Close()
+	input.close()
 
 	// Find out which scripts to dump
 	list := strings.Split(flaglist, ",")
@@ -865,6 +880,16 @@ func getCaseState(i int) (c *caseState) {
 	case ch.titleCase:
 		c._case = CaseTitle
 	}
+	// Some things such as roman numeral U+2161 don't describe themselves
+	// as upper case, but have a lower case.  Second-guess them.
+	if c._case == CaseNone && ch.lowerCase != 0 {
+		c._case = CaseUpper
+	}
+	// Same in the other direction.
+	if c._case == CaseNone && ch.upperCase != 0 {
+		c._case = CaseLower
+	}
+
 	if ch.upperCase != 0 {
 		c.deltaToUpper = ch.upperCase - i
 	}
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index a75011a..88b5c0f 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -5266,6 +5266,7 @@ var _CaseRanges = []CaseRange{
 	{0x028A, 0x028B, d{-217, 0, -217}},
 	{0x028C, 0x028C, d{-71, 0, -71}},
 	{0x0292, 0x0292, d{-219, 0, -219}},
+	{0x0345, 0x0345, d{84, 0, 84}},
 	{0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
 	{0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
 	{0x037B, 0x037D, d{130, 0, 130}},
@@ -5375,7 +5376,11 @@ var _CaseRanges = []CaseRange{
 	{0x212B, 0x212B, d{0, -8262, 0}},
 	{0x2132, 0x2132, d{0, 28, 0}},
 	{0x214E, 0x214E, d{-28, 0, -28}},
+	{0x2160, 0x216F, d{0, 16, 0}},
+	{0x2170, 0x217F, d{-16, 0, -16}},
 	{0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
+	{0x24B6, 0x24CF, d{0, 26, 0}},
+	{0x24D0, 0x24E9, d{-26, 0, -26}},
 	{0x2C00, 0x2C2E, d{0, 48, 0}},
 	{0x2C30, 0x2C5E, d{-48, 0, -48}},
 	{0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
@@ -5734,90 +5739,6 @@ var caseOrbit = []foldPair{
 	{0x2126, 0x03A9},
 	{0x212A, 0x004B},
 	{0x212B, 0x00C5},
-	{0x2160, 0x2170},
-	{0x2161, 0x2171},
-	{0x2162, 0x2172},
-	{0x2163, 0x2173},
-	{0x2164, 0x2174},
-	{0x2165, 0x2175},
-	{0x2166, 0x2176},
-	{0x2167, 0x2177},
-	{0x2168, 0x2178},
-	{0x2169, 0x2179},
-	{0x216A, 0x217A},
-	{0x216B, 0x217B},
-	{0x216C, 0x217C},
-	{0x216D, 0x217D},
-	{0x216E, 0x217E},
-	{0x216F, 0x217F},
-	{0x2170, 0x2160},
-	{0x2171, 0x2161},
-	{0x2172, 0x2162},
-	{0x2173, 0x2163},
-	{0x2174, 0x2164},
-	{0x2175, 0x2165},
-	{0x2176, 0x2166},
-	{0x2177, 0x2167},
-	{0x2178, 0x2168},
-	{0x2179, 0x2169},
-	{0x217A, 0x216A},
-	{0x217B, 0x216B},
-	{0x217C, 0x216C},
-	{0x217D, 0x216D},
-	{0x217E, 0x216E},
-	{0x217F, 0x216F},
-	{0x24B6, 0x24D0},
-	{0x24B7, 0x24D1},
-	{0x24B8, 0x24D2},
-	{0x24B9, 0x24D3},
-	{0x24BA, 0x24D4},
-	{0x24BB, 0x24D5},
-	{0x24BC, 0x24D6},
-	{0x24BD, 0x24D7},
-	{0x24BE, 0x24D8},
-	{0x24BF, 0x24D9},
-	{0x24C0, 0x24DA},
-	{0x24C1, 0x24DB},
-	{0x24C2, 0x24DC},
-	{0x24C3, 0x24DD},
-	{0x24C4, 0x24DE},
-	{0x24C5, 0x24DF},
-	{0x24C6, 0x24E0},
-	{0x24C7, 0x24E1},
-	{0x24C8, 0x24E2},
-	{0x24C9, 0x24E3},
-	{0x24CA, 0x24E4},
-	{0x24CB, 0x24E5},
-	{0x24CC, 0x24E6},
-	{0x24CD, 0x24E7},
-	{0x24CE, 0x24E8},
-	{0x24CF, 0x24E9},
-	{0x24D0, 0x24B6},
-	{0x24D1, 0x24B7},
-	{0x24D2, 0x24B8},
-	{0x24D3, 0x24B9},
-	{0x24D4, 0x24BA},
-	{0x24D5, 0x24BB},
-	{0x24D6, 0x24BC},
-	{0x24D7, 0x24BD},
-	{0x24D8, 0x24BE},
-	{0x24D9, 0x24BF},
-	{0x24DA, 0x24C0},
-	{0x24DB, 0x24C1},
-	{0x24DC, 0x24C2},
-	{0x24DD, 0x24C3},
-	{0x24DE, 0x24C4},
-	{0x24DF, 0x24C5},
-	{0x24E0, 0x24C6},
-	{0x24E1, 0x24C7},
-	{0x24E2, 0x24C8},
-	{0x24E3, 0x24C9},
-	{0x24E4, 0x24CA},
-	{0x24E5, 0x24CB},
-	{0x24E6, 0x24CC},
-	{0x24E7, 0x24CD},
-	{0x24E8, 0x24CE},
-	{0x24E9, 0x24CF},
 }
 
 // FoldCategory maps a category name to a table of
@@ -6099,8 +6020,7 @@ var foldLt = &RangeTable{
 // If there is no entry for a script name, there are no such points.
 var FoldScript = map[string]*RangeTable{}
 
-
 // Range entries: 3391 16-bit, 659 32-bit, 4050 total.
 // Range bytes: 20346 16-bit, 7908 32-bit, 28254 total.
 
-// Fold orbit bytes: 147 pairs, 588 bytes
+// Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/src/pkg/unsafe/unsafe.go b/src/pkg/unsafe/unsafe.go
index 8507bed..a125706 100644
--- a/src/pkg/unsafe/unsafe.go
+++ b/src/pkg/unsafe/unsafe.go
@@ -47,7 +47,7 @@ func Reflect(i interface{}) (typ interface{}, addr Pointer)
 // empty interface value with contents the type and the value (not the pointer to
 // the value).  The typ is assumed to contain a pointer to a runtime type; the type
 // information in the interface{} is ignored, so that, for example, both
-// *reflect.StructType and *runtime.StructType can be passed for typ.
+// *reflect.structType and *runtime.StructType can be passed for typ.
 func Unreflect(typ interface{}, addr Pointer) (ret interface{})
 
 // New allocates and returns a pointer to memory for a new value of the given type.
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
index f066a18..f24c463 100644
--- a/src/pkg/websocket/client.go
+++ b/src/pkg/websocket/client.go
@@ -7,7 +7,6 @@ package websocket
 import (
 	"bufio"
 	"bytes"
-	"container/vector"
 	"crypto/tls"
 	"fmt"
 	"http"
@@ -201,21 +200,21 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
 	bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
 
 	// Step 6-14. push request headers in fields.
-	var fields vector.StringVector
-	fields.Push("Upgrade: WebSocket\r\n")
-	fields.Push("Connection: Upgrade\r\n")
-	fields.Push("Host: " + host + "\r\n")
-	fields.Push("Origin: " + origin + "\r\n")
+	var fields []string
+	fields = append(fields, "Upgrade: WebSocket\r\n")
+	fields = append(fields, "Connection: Upgrade\r\n")
+	fields = append(fields, "Host: "+host+"\r\n")
+	fields = append(fields, "Origin: "+origin+"\r\n")
 	if protocol != "" {
-		fields.Push("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+		fields = append(fields, "Sec-WebSocket-Protocol: "+protocol+"\r\n")
 	}
 	// TODO(ukai): Step 15. send cookie if any.
 
 	// Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
 	key1, number1 := generateKeyNumber()
 	key2, number2 := generateKeyNumber()
-	fields.Push("Sec-WebSocket-Key1: " + key1 + "\r\n")
-	fields.Push("Sec-WebSocket-Key2: " + key2 + "\r\n")
+	fields = append(fields, "Sec-WebSocket-Key1: "+key1+"\r\n")
+	fields = append(fields, "Sec-WebSocket-Key2: "+key2+"\r\n")
 
 	// Step 24. shuffle fields and send them out.
 	for i := 1; i < len(fields); i++ {
diff --git a/src/pkg/websocket/server.go b/src/pkg/websocket/server.go
index 165cbff..e0e7c87 100644
--- a/src/pkg/websocket/server.go
+++ b/src/pkg/websocket/server.go
@@ -154,7 +154,6 @@ func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	f(ws)
 }
 
-
 /*
 Draft75Handler is an interface to a WebSocket based on the
 (soon obsolete) draft-hixie-thewebsocketprotocol-75.
diff --git a/src/pkg/xml/marshal.go b/src/pkg/xml/marshal.go
index 2ac03a9..f6e5bf5 100644
--- a/src/pkg/xml/marshal.go
+++ b/src/pkg/xml/marshal.go
@@ -14,10 +14,10 @@ import (
 )
 
 const (
-	// A generic XML header suitable for use with the output of Marshal and MarshalIndent.
-	// This is not automatically added to any output of this package, it is provided as a
-	// convenience.
-	Header = `<?xml version="1.0" encoding="UTF-8">\n`
+	// A generic XML header suitable for use with the output of Marshal and
+	// MarshalIndent.  This is not automatically added to any output of this
+	// package, it is provided as a convenience.
+	Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
 )
 
 // A Marshaler can produce well-formatted XML representing its internal state.
diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go
index e5d73dd..e7ba44e 100644
--- a/src/pkg/xml/xml.go
+++ b/src/pkg/xml/xml.go
@@ -416,7 +416,6 @@ func (p *Parser) autoClose(t Token) (Token, bool) {
 	return nil, false
 }
 
-
 // RawToken is like Token but does not verify that
 // start and end elements match and does not translate
 // name space prefixes to their corresponding URLs.
diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go
index aba21a2..6407624 100644
--- a/src/pkg/xml/xml_test.go
+++ b/src/pkg/xml/xml_test.go
@@ -546,7 +546,6 @@ func TestEntityInsideCDATA(t *testing.T) {
 	}
 }
 
-
 // The last three tests (respectively one for characters in attribute
 // names and two for character entities) pass not because of code
 // changed for issue 1259, but instead pass with the given messages
@@ -567,7 +566,6 @@ var characterTests = []struct {
 	{"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &;"},
 }
 
-
 func TestDisallowedCharacters(t *testing.T) {
 
 	for i, tt := range characterTests {
diff --git a/src/quietgcc.bash b/src/quietgcc.bash
index c99305e..759f6b4 100755
--- a/src/quietgcc.bash
+++ b/src/quietgcc.bash
@@ -32,13 +32,13 @@ case "$(uname -m -p)-$GOHOSTARCH" in
 esac
 
 # Run gcc, save error status, redisplay output without noise, exit with gcc status.
-tmp=${TMPDIR:-/tmp}/quietgcc.$$.$USER.out
+tmp="${TMPDIR:-/tmp}/quietgcc.$$.$USER.out"
 $gcc -Wall -Wno-sign-compare -Wno-missing-braces \
 	-Wno-parentheses -Wno-unknown-pragmas -Wno-switch -Wno-comment \
 	-Werror \
-	"$@" >$tmp 2>&1
+	"$@" >"$tmp" 2>&1
 status=$?
-egrep -v "$ignore" $tmp | uniq | tee $tmp.1
+egrep -v "$ignore" "$tmp" | uniq | tee "$tmp.1"
 
-rm -f $tmp $tmp.1
+rm -f "$tmp" "$tmp.1"
 exit $status
diff --git a/src/run.bash b/src/run.bash
index d125fd4..ae79a0c 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -69,11 +69,6 @@ gomake clean
 gotest
 ) || exit $?
 
-(xcd pkg/exp/ogle
-gomake clean
-time gomake ogle
-) || exit $?
-
 (xcd ../doc/progs
 time ./run
 ) || exit $?
diff --git a/test/chan/select6.go b/test/chan/select6.go
new file mode 100644
index 0000000..2ba6810
--- /dev/null
+++ b/test/chan/select6.go
@@ -0,0 +1,34 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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.
+
+// Issue 2075
+// A bug in select corrupts channel queues of failed cases
+// if there are multiple waiters on those channels and the
+// select is the last in the queue. If further waits are made
+// on the channel without draining it first then those waiters
+// will never wake up. In the code below c1 is such a channel.
+
+package main
+
+func main() {
+	c1 := make(chan bool)
+	c2 := make(chan bool)
+	c3 := make(chan bool)
+	go func() { <-c1 }()
+	go func() {
+		select {
+		case <-c1:
+			panic("dummy")
+		case <-c2:
+			c3 <- true
+		}
+		<-c1
+	}()
+	go func() { c2 <- true }()
+	<-c3
+	c1 <- true
+	c1 <- true
+}
diff --git a/test/chan/zerosize.go b/test/chan/zerosize.go
new file mode 100644
index 0000000..617c9da
--- /dev/null
+++ b/test/chan/zerosize.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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.
+
+// Making channels of a zero-sized type should not panic.
+
+package main
+
+func main() {
+	_ = make(chan [0]byte)
+	_ = make(chan [0]byte, 1)
+	_ = make(chan struct{})
+	_ = make(chan struct{}, 1)
+}
diff --git a/test/ddd1.go b/test/ddd1.go
index 96a358e..83e32de 100644
--- a/test/ddd1.go
+++ b/test/ddd1.go
@@ -44,4 +44,6 @@ func bad(args ...int) {
 	_ = unsafe.Pointer(&x...)	// ERROR "[.][.][.]"
 	_ = unsafe.Sizeof(x...)	// ERROR "[.][.][.]"
 	_ = [...]byte("foo") // ERROR "[.][.][.]"
+	_ = [...][...]int{{1,2,3},{4,5,6}}	// ERROR "[.][.][.]"
 }
+
diff --git a/test/divide.go b/test/divide.go
new file mode 100644
index 0000000..5c0f450
--- /dev/null
+++ b/test/divide.go
@@ -0,0 +1,54 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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.
+
+// divide corner cases
+
+package main
+
+import "fmt"
+
+func f8(x, y, q, r int8) {
+	if t := x / y; t != q {
+		fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+	}
+	if t := x % y; t != r {
+		fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+	}
+}
+
+func f16(x, y, q, r int16) {
+	if t := x / y; t != q {
+		fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+	}
+	if t := x % y; t != r {
+		fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+	}
+}
+
+func f32(x, y, q, r int32) {
+	if t := x / y; t != q {
+		fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+	}
+	if t := x % y; t != r {
+		fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+	}
+}
+
+func f64(x, y, q, r int64) {
+	if t := x / y; t != q {
+		fmt.Printf("%d/%d = %d, want %d\n", x, y, t, q)
+	}
+	if t := x % y; t != r {
+		fmt.Printf("%d%%%d = %d, want %d\n", x, y, t, r)
+	}
+}
+
+func main() {
+	f8(-1<<7, -1, -1<<7, 0)
+	f16(-1<<15, -1, -1<<15, 0)
+	f32(-1<<31, -1, -1<<31, 0)
+	f64(-1<<63, -1, -1<<63, 0)
+}
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
index 816f69e..dd5aaa7 100644
--- a/test/fixedbugs/bug273.go
+++ b/test/fixedbugs/bug273.go
@@ -47,15 +47,6 @@ func bigcap() {
 	g1 = make([]int, 10, big)
 }
 
-const (
-	addrBits = 8*uint(unsafe.Sizeof((*byte)(nil)))
-	sh = addrBits/2 - 2
-)
-var g2 [][1<<sh][1<<sh]byte
-func overflow() {
-	g2 = make([][1<<sh][1<<sh]byte, 64)
-}
-
 var g3 map[int]int
 func badmapcap() {
 	g3 = make(map[int]int, minus1)
@@ -74,6 +65,8 @@ func bigchancap() {
 	g4 = make(chan int, big)
 }
 
+const addrBits = unsafe.Sizeof((*byte)(nil))
+
 var g5 chan [1<<15]byte
 func overflowchan() {
 	if addrBits == 32 {
@@ -92,7 +85,6 @@ func main() {
 	shouldfail(badcap, "badcap")
 	shouldfail(badcap1, "badcap1")
 	shouldfail(bigcap, "bigcap")
-	shouldfail(overflow, "overflow")
 	shouldfail(badmapcap, "badmapcap")
 	shouldfail(bigmapcap, "bigmapcap")
 	shouldfail(badchancap, "badchancap")
diff --git a/test/fixedbugs/bug274.go b/test/fixedbugs/bug274.go
index 81ee9e5..198544c 100644
--- a/test/fixedbugs/bug274.go
+++ b/test/fixedbugs/bug274.go
@@ -25,6 +25,7 @@ func main() {
 		L1:  // ERROR "statement"
 	default:
 		     // correct since no semicolon is required before a '}'
-		L2:  // ERROR "not used"
+		goto L2
+		L2:
 	}
 }
diff --git a/test/fixedbugs/bug298.go b/test/fixedbugs/bug298.go
index fe4a99a..c16c3f9 100644
--- a/test/fixedbugs/bug298.go
+++ b/test/fixedbugs/bug298.go
@@ -7,5 +7,5 @@
 package ddd
 
 func Sum() int
-	for i := range []int{} { return i }  // ERROR "return outside function|expected"
+	for i := range []int{} { return i }  // ERROR "statement outside function|expected"
 
diff --git a/test/fixedbugs/bug346.go b/test/fixedbugs/bug346.go
new file mode 100644
index 0000000..31284c3
--- /dev/null
+++ b/test/fixedbugs/bug346.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: issue2056
+
+// 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 main
+
+import "os"
+
+func main() {
+	x := 4
+	a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
+
+	if a != 1 || b != 2 || c != 3 || d != 4 {
+		println("abcd: expected 1 2 3 4 got", a, b, c, d)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/bug347.go b/test/fixedbugs/bug347.go
new file mode 100644
index 0000000..5532cee
--- /dev/null
+++ b/test/fixedbugs/bug347.go
@@ -0,0 +1,49 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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 main
+
+import (
+	"runtime"
+	"strings"
+)
+
+var t *struct {
+	c chan int
+}
+
+var c chan int
+
+func f() {
+	select {
+	case <-t.c:  // THIS IS LINE 22
+		break
+	case <-c:
+		break
+	}
+}
+
+func main() {
+	defer func() {
+		recover()
+		for i := 0;; i++ {
+			pc, file, line, ok := runtime.Caller(i)
+			if !ok {
+				print("BUG: bug347: cannot find caller\n")
+				return
+			}
+			if !strings.Contains(file, "bug347.go") || runtime.FuncForPC(pc).Name() != "main.f" {
+				// walk past runtime frames
+				continue
+			}
+			if line != 22 {
+				print("BUG: bug347: panic at ", file, ":", line, " in ", runtime.FuncForPC(pc).Name(), "\n")
+			}
+			return
+		}
+	}()
+	f()
+}
diff --git a/test/fixedbugs/bug348.go b/test/fixedbugs/bug348.go
new file mode 100644
index 0000000..1a539aa
--- /dev/null
+++ b/test/fixedbugs/bug348.go
@@ -0,0 +1,46 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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 main
+
+import (
+	"runtime"
+	"strings"
+)
+
+func f() {
+	var x *string
+	
+	for _, i := range *x {  // THIS IS LINE 17
+		println(i)
+	}
+}
+
+func g() {
+}
+
+func main() {
+	defer func() {
+		for i := 0;; i++ {
+			pc, file, line, ok := runtime.Caller(i)
+			if !ok {
+				print("BUG: bug348: cannot find caller\n")
+				return
+			}
+			if !strings.Contains(file, "bug348.go") || runtime.FuncForPC(pc).Name() != "main.f" {
+				// walk past runtime frames
+				continue
+			}
+			if line != 17 {
+				print("BUG: bug348: panic at ", file, ":", line, " in ", runtime.FuncForPC(pc).Name(), "\n")
+				return
+			}
+			recover()
+			return
+		}
+	}()
+	f()
+}
diff --git a/test/fixedbugs/bug349.go b/test/fixedbugs/bug349.go
new file mode 100644
index 0000000..0700597
--- /dev/null
+++ b/test/fixedbugs/bug349.go
@@ -0,0 +1,13 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 1192 - detail in error
+
+package main
+
+func foo() (a, b, c int) {
+	return 0, 1 2.01  // ERROR "unexpected literal 2.01"
+}
diff --git a/test/fixedbugs/bug350.go b/test/fixedbugs/bug350.go
new file mode 100644
index 0000000..aac2949
--- /dev/null
+++ b/test/fixedbugs/bug350.go
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// 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 main
+
+type T int
+
+func (T) m() {}
+func (T) m() {} // ERROR "T[.]m redeclared"
+
+func (*T) p() {}
+func (*T) p() {} // ERROR "[(][*]T[)][.]p redeclared"
diff --git a/test/fixedbugs/bug351.go b/test/fixedbugs/bug351.go
new file mode 100644
index 0000000..c33e282
--- /dev/null
+++ b/test/fixedbugs/bug351.go
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// 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 main
+
+func main() {
+	(x) := 0  // ERROR "non-name [(]x[)]"
+}
diff --git a/test/fixedbugs/bug352.go b/test/fixedbugs/bug352.go
new file mode 100644
index 0000000..62fd006
--- /dev/null
+++ b/test/fixedbugs/bug352.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug352
+
+// 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 main
+
+var x [10][0]byte
+var y = make([]struct{}, 10)
+
+func main() {
+	if &x[1] != &x[2] {
+		println("BUG: bug352 [0]byte")
+	}
+	if &y[1] != &y[2] {
+		println("BUG: bug352 struct{}")
+	}
+}
diff --git a/test/fixedbugs/bug353.go b/test/fixedbugs/bug353.go
new file mode 100644
index 0000000..46f5c36
--- /dev/null
+++ b/test/fixedbugs/bug353.go
@@ -0,0 +1,30 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 2089 - internal compiler error
+
+package main
+
+import (
+	"io"
+	"os"
+)
+
+func echo(fd io.ReadWriterCloser) { // ERROR "undefined: io.ReadWriterCloser"
+	var buf [1024]byte
+	for {
+		n, err := fd.Read(buf)
+		if err != nil {
+			break
+		}
+		fd.Write(buf[0:n])
+	}
+}
+
+func main() {
+	fd, _ := os.Open("a.txt")
+	echo(fd)
+}
diff --git a/test/fixedbugs/bug354.go b/test/fixedbugs/bug354.go
new file mode 100644
index 0000000..1f6a6dc
--- /dev/null
+++ b/test/fixedbugs/bug354.go
@@ -0,0 +1,26 @@
+// $G $D/$F.go || echo BUG: bug354
+
+// 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.
+
+// issue 2086
+// was calling makeclosure twice on the closure
+
+package main
+
+import (
+	"os"
+)
+
+type Inner struct {
+	F func() os.Error
+}
+
+type Outer struct {
+	Inners []Inner
+}
+
+// calls makeclosure twice on same closure
+
+var Foo = Outer{[]Inner{Inner{func() os.Error{ return nil }}}}
diff --git a/test/fixedbugs/bug355.go b/test/fixedbugs/bug355.go
new file mode 100644
index 0000000..a9cf016
--- /dev/null
+++ b/test/fixedbugs/bug355.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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 main
+
+var f = func() int {
+	type S int
+	return 42
+}
+
+func main() {
+	if f() != 42 {
+		panic("BUG: bug355")
+	}
+}
diff --git a/test/fixedbugs/bug356.go b/test/fixedbugs/bug356.go
new file mode 100644
index 0000000..d21f0cf
--- /dev/null
+++ b/test/fixedbugs/bug356.go
@@ -0,0 +1,41 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug344
+
+// 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.
+
+// issue 1808
+
+package main
+
+func main() {
+	var i uint64
+	var x int = 12345
+
+	if y := x << (i&5); y != 12345<<0 {
+		println("BUG bug344", y)
+		return
+	}
+	
+	i++
+	if y := x << (i&5); y != 12345<<1 {
+		println("BUG bug344a", y)
+	}
+	
+	i = 70
+	if y := x << i; y != 0 {
+		println("BUG bug344b", y)
+	}
+	
+	i = 1<<32
+	if y := x << i; y != 0 {
+		println("BUG bug344c", y)
+	}
+}
+	
+
+/*
+typecheck [1008592b0]
+.   INDREG a(1) l(15) x(24) tc(2) runtime.ret G0 string
+bug343.go:15: internal compiler error: typecheck INDREG
+*/
diff --git a/test/fixedbugs/bug357.go b/test/fixedbugs/bug357.go
new file mode 100644
index 0000000..2220398
--- /dev/null
+++ b/test/fixedbugs/bug357.go
@@ -0,0 +1,25 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 1993.
+// error used to have last line number in file
+
+package main
+
+func bla1() bool {
+	return false
+}
+
+func bla5() bool {
+	_ = 1
+	false  // ERROR "false not used"
+	_ = 2
+}
+
+func main() {
+	x := bla1()
+	_ = x
+}
diff --git a/test/fixedbugs/bug358.go b/test/fixedbugs/bug358.go
new file mode 100644
index 0000000..cc622c0
--- /dev/null
+++ b/test/fixedbugs/bug358.go
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 1979
+// used to get internal compiler error too
+
+package main
+
+import (
+	"http"
+	"io/ioutil"
+	"os"
+)
+
+func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request)  // ERROR "syntax error"
+}
+
+type Page struct {
+	Title string
+	Body []byte
+}
+
diff --git a/test/fixedbugs/bug359.go b/test/fixedbugs/bug359.go
new file mode 100644
index 0000000..6ced608
--- /dev/null
+++ b/test/fixedbugs/bug359.go
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 1910
+// error on wrong line
+
+package main
+
+import "container/list"
+
+type Painting struct {
+	fragments list.List // private
+}
+
+func (p Painting) Foo() {
+	for e := p.fragments; e.Front() != nil; e = e.Next() {  // ERROR "unexported field"
+	}
+}
+
+// from comment 4 of issue 1910
+type Foo interface {
+	Run(a int) (a int)  // ERROR "a redeclared"
+}
diff --git a/test/fixedbugs/bug361.go b/test/fixedbugs/bug361.go
new file mode 100644
index 0000000..d2a64bc
--- /dev/null
+++ b/test/fixedbugs/bug361.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go || echo BUG: bug360
+
+// 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.
+
+// issue 1908
+// unreasonable width used to be internal fatal error
+
+package test
+
+func main() {
+	buf := [1<<30]byte{}
+	_ = buf[:]
+}
diff --git a/test/fixedbugs/bug362.go b/test/fixedbugs/bug362.go
new file mode 100644
index 0000000..7912091
--- /dev/null
+++ b/test/fixedbugs/bug362.go
@@ -0,0 +1,16 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 1662
+// iota inside var
+
+package main
+
+var (
+	a = iota  // ERROR "undefined: iota"
+	b = iota  // ERROR "undefined: iota"
+	c = iota  // ERROR "undefined: iota"
+)
diff --git a/test/fixedbugs/bug363.go b/test/fixedbugs/bug363.go
new file mode 100644
index 0000000..7e89749
--- /dev/null
+++ b/test/fixedbugs/bug363.go
@@ -0,0 +1,21 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// issue 1664
+
+package main
+
+func main() {
+	var i uint = 33
+	var a = (1<<i) + 4.5  // ERROR "shift of type float64"
+	println(a)
+	
+	var b = (1<<i) + 4.0  // ERROR "shift of type float64"
+	println(b)
+
+	var c int64 = (1<<i) + 4.0  // ok - it's all int64
+	println(b)
+}
diff --git a/test/fixedbugs/bug364.go b/test/fixedbugs/bug364.go
new file mode 100644
index 0000000..a174534
--- /dev/null
+++ b/test/fixedbugs/bug364.go
@@ -0,0 +1,25 @@
+package main
+
+import "fmt"
+
+var s string
+
+func accum(args ...interface{}) {
+	s += fmt.Sprintln(args...)
+}
+
+func f(){
+	v := 0.0
+	for i := 0; i < 3; i++ {
+		v += 0.1
+		defer accum(v)
+	}
+}
+
+func main() {
+	f()
+	if s != "0.30000000000000004\n0.2\n0.1\n" {
+		println("BUG: defer")
+		print(s)
+	}
+}
diff --git a/test/fixedbugs/bug365.go b/test/fixedbugs/bug365.go
new file mode 100644
index 0000000..7ec19b0
--- /dev/null
+++ b/test/fixedbugs/bug365.go
@@ -0,0 +1,22 @@
+// errchk $G $D/$F.go
+
+// 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.
+
+// check that compiler doesn't stop reading struct def
+// after first unknown type.
+
+// Fixes issue 2110.
+
+package main
+
+type S struct {
+	err os.Error  // ERROR "undefined"
+	Num int
+}
+
+func main() {
+	s := S{}
+	_ = s.Num  // no error here please
+}
diff --git a/test/gc2.go b/test/gc2.go
index c5c6cbe..c54d807 100644
--- a/test/gc2.go
+++ b/test/gc2.go
@@ -32,7 +32,8 @@ func main() {
 			}
 		}
 	}
-	
+
+	runtime.UpdateMemStats()
 	obj := runtime.MemStats.HeapObjects - st.HeapObjects
 	if obj > N/5 {
 		fmt.Println("too many objects left:", obj)
diff --git a/test/if.go b/test/if.go
index c1bb69d..18a6715 100644
--- a/test/if.go
+++ b/test/if.go
@@ -53,25 +53,28 @@ func main() {
 	count = 0
 	if true {
 		count = count + 1
-	} else
+	} else {
 		count = count - 1
+	}
 	assertequal(count, 1, "if else true")
 
 	count = 0
 	if false {
 		count = count + 1
-	} else
+	} else {
 		count = count - 1
+	}
 	assertequal(count, -1, "if else false")
 
 	count = 0
-	if t:=1; false {
+	if t := 1; false {
 		count = count + 1
 		_ = t
 		t := 7
 		_ = t
-	} else
+	} else {
 		count = count - t
+	}
 	assertequal(count, -1, "if else false var")
 
 	count = 0
@@ -80,8 +83,9 @@ func main() {
 		count = count + 1
 		t := 7
 		_ = t
-	} else
+	} else {
 		count = count - t
+	}
 	_ = t
 	assertequal(count, -1, "if else false var outside")
 }
diff --git a/test/malloc1.go b/test/malloc1.go
index 1469764..61f1797 100644
--- a/test/malloc1.go
+++ b/test/malloc1.go
@@ -18,6 +18,7 @@ var chatty = flag.Bool("v", false, "chatty")
 
 func main() {
 	runtime.Free(runtime.Alloc(1))
+	runtime.UpdateMemStats()
 	if *chatty {
 		fmt.Printf("%+v %v\n", runtime.MemStats, uint64(0))
 	}
diff --git a/test/mallocrand.go b/test/mallocrand.go
index e6b422e..f014b44 100644
--- a/test/mallocrand.go
+++ b/test/mallocrand.go
@@ -21,6 +21,7 @@ var footprint uint64
 var allocated uint64
 
 func bigger() {
+	runtime.UpdateMemStats()
 	if f := runtime.MemStats.Sys; footprint < f {
 		footprint = f
 		if *chatty {
diff --git a/test/mallocrep.go b/test/mallocrep.go
index 762f375..9f47e52 100644
--- a/test/mallocrep.go
+++ b/test/mallocrep.go
@@ -18,6 +18,7 @@ var chatty = flag.Bool("v", false, "chatty")
 var oldsys uint64
 
 func bigger() {
+	runtime.UpdateMemStats()
 	if st := runtime.MemStats; oldsys < st.Sys {
 		oldsys = st.Sys
 		if *chatty {
@@ -31,7 +32,7 @@ func bigger() {
 }
 
 func main() {
-	runtime.GC()		   // clean up garbage from init
+	runtime.GC()               // clean up garbage from init
 	runtime.MemProfileRate = 0 // disable profiler
 	runtime.MemStats.Alloc = 0 // ignore stacks
 	flag.Parse()
@@ -45,8 +46,10 @@ func main() {
 				panic("fail")
 			}
 			b := runtime.Alloc(uintptr(j))
+			runtime.UpdateMemStats()
 			during := runtime.MemStats.Alloc
 			runtime.Free(b)
+			runtime.UpdateMemStats()
 			if a := runtime.MemStats.Alloc; a != 0 {
 				println("allocated ", j, ": wrong stats: during=", during, " after=", a, " (want 0)")
 				panic("fail")
diff --git a/test/mallocrep1.go b/test/mallocrep1.go
index eb67bed..0b14799 100644
--- a/test/mallocrep1.go
+++ b/test/mallocrep1.go
@@ -42,6 +42,7 @@ func AllocAndFree(size, count int) {
 	if *chatty {
 		fmt.Printf("size=%d count=%d ...\n", size, count)
 	}
+	runtime.UpdateMemStats()
 	n1 := stats.Alloc
 	for i := 0; i < count; i++ {
 		b[i] = runtime.Alloc(uintptr(size))
@@ -50,11 +51,13 @@ func AllocAndFree(size, count int) {
 			println("lookup failed: got", base, n, "for", b[i])
 			panic("fail")
 		}
-		if runtime.MemStats.Sys > 1e9 {
+		runtime.UpdateMemStats()
+		if stats.Sys > 1e9 {
 			println("too much memory allocated")
 			panic("fail")
 		}
 	}
+	runtime.UpdateMemStats()
 	n2 := stats.Alloc
 	if *chatty {
 		fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
@@ -72,6 +75,7 @@ func AllocAndFree(size, count int) {
 			panic("fail")
 		}
 		runtime.Free(b[i])
+		runtime.UpdateMemStats()
 		if stats.Alloc != uint64(alloc-n) {
 			println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n)
 			panic("fail")
@@ -81,6 +85,7 @@ func AllocAndFree(size, count int) {
 			panic("fail")
 		}
 	}
+	runtime.UpdateMemStats()
 	n4 := stats.Alloc
 
 	if *chatty {
diff --git a/test/run b/test/run
index bb61198..bc31d2f 100755
--- a/test/run
+++ b/test/run
@@ -33,9 +33,9 @@ failed=0
 
 PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$GOROOT/bin}:`pwd`
 
-RUNFILE=/tmp/gorun-$$-$USER
-TMP1FILE=/tmp/gotest1-$$-$USER
-TMP2FILE=/tmp/gotest2-$$-$USER
+RUNFILE="/tmp/gorun-$$-$USER"
+TMP1FILE="/tmp/gotest1-$$-$USER"
+TMP2FILE="/tmp/gotest2-$$-$USER"
 
 # don't run the machine out of memory: limit individual processes to 4GB.
 # on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
@@ -64,20 +64,20 @@ do
 		fi
 		export F=$(basename $i .go)
 		export D=$dir
-		sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|g' >$RUNFILE
-		if ! { time -p bash -c "bash $RUNFILE >$TMP1FILE 2>&1" ; } 2>$TMP2FILE
+		sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|g' >"$RUNFILE"
+		if ! { time -p bash -c "bash '$RUNFILE' >'$TMP1FILE' 2>&1" ; } 2>"$TMP2FILE"
 		then
 			echo
 			echo "===========" $i
-			cat $TMP1FILE
+			cat "$TMP1FILE"
 			echo >&2 fail: $i
 			echo "# $i	# fail" >>pass.out
-		elif test -s $TMP1FILE
+		elif test -s "$TMP1FILE"
 		then
 			echo
 			echo "===========" $i
-			cat $TMP1FILE
-			if grep -q '^BUG' $TMP1FILE
+			cat "$TMP1FILE"
+			if grep -q '^BUG' "$TMP1FILE"
 			then
 				if [ $dir != bugs ]
 				then
@@ -93,13 +93,13 @@ do
 		else
 			echo $i >>pass.out
 		fi
-		echo $(awk 'NR==1{print $2}' $TMP2FILE) $D/$F >>times.out
+		echo $(awk 'NR==1{print $2}' "$TMP2FILE") $D/$F >>times.out
 		rm -f $F.$A $A.out
 	) done
 done | # clean up some stack noise
 	egrep -v '^(r[0-9a-z]+|[cfg]s)  +0x'  |
 	sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
-		s!'$RUNFILE'!$RUNFILE!g
+		s!'"$RUNFILE"'!$RUNFILE!g
 		s/^PC=0x[0-9a-f]*/pc: xxx/
 		s/^pc: 0x[0-9a-f]*/pc: xxx/
 		s/PC=0x[0-9a-f]*/PC=xxx/
@@ -110,7 +110,7 @@ done | # clean up some stack noise
 		/Segmentation fault/d
 		/^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
 
-rm -f $RUNFILE $TMP1FILE $TMP2FILE *.$A *.a $A.out
+rm -f "$RUNFILE" "$TMP1FILE" "$TMP2FILE" *.$A *.a $A.out
 diffmsg=""
 if ! diff $golden run.out
 then

-- 
Packaging for Google Go



More information about the Pkg-google-commits mailing list