Joseph Poirier avatar Joseph Poirier committed 44627d9 Merge

Merged changes from golang.

Comments (0)

Files changed (62)

 Christoph Hack <christoph@tux21b.org>
 Christopher Nielsen <m4dh4tt3r@gmail.com>
 Christopher Redden <christopher.redden@gmail.com>
+Christopher Swenson <cswenson@google.com>
 Christopher Wedgwood <cw@f00f.org>
 Clement Skau <clementskau@gmail.com>
 Colby Ranger <cranger@google.com>
 pkg syscall (windows-386), const CREATE_NEW_PROCESS_GROUP ideal-int
 pkg syscall (windows-386), const CTRL_BREAK_EVENT ideal-int
 pkg syscall (windows-386), const CTRL_C_EVENT ideal-int
-pkg syscall (windows-386), func FindFirstFile1(*uint16, *Win32finddata1) (Handle, error)
-pkg syscall (windows-386), func FindNextFile1(Handle, *Win32finddata1) error
 pkg syscall (windows-386), func GetCurrentProcessId() uint32
 pkg syscall (windows-386), func Getsockopt(Handle, int32, int32, *byte, *int32) error
 pkg syscall (windows-386), type SysProcAttr struct, CreationFlags uint32
-pkg syscall (windows-386), type Win32finddata1 struct
-pkg syscall (windows-386), type Win32finddata1 struct, AlternateFileName [14]uint16
-pkg syscall (windows-386), type Win32finddata1 struct, CreationTime Filetime
-pkg syscall (windows-386), type Win32finddata1 struct, FileAttributes uint32
-pkg syscall (windows-386), type Win32finddata1 struct, FileName [MAX_PATH]uint16
-pkg syscall (windows-386), type Win32finddata1 struct, FileSizeHigh uint32
-pkg syscall (windows-386), type Win32finddata1 struct, FileSizeLow uint32
-pkg syscall (windows-386), type Win32finddata1 struct, LastAccessTime Filetime
-pkg syscall (windows-386), type Win32finddata1 struct, LastWriteTime Filetime
-pkg syscall (windows-386), type Win32finddata1 struct, Reserved0 uint32
-pkg syscall (windows-386), type Win32finddata1 struct, Reserved1 uint32
 pkg syscall (windows-amd64), const CREATE_NEW_PROCESS_GROUP ideal-int
 pkg syscall (windows-amd64), const CTRL_BREAK_EVENT ideal-int
 pkg syscall (windows-amd64), const CTRL_C_EVENT ideal-int
-pkg syscall (windows-amd64), func FindFirstFile1(*uint16, *Win32finddata1) (Handle, error)
-pkg syscall (windows-amd64), func FindNextFile1(Handle, *Win32finddata1) error
 pkg syscall (windows-amd64), func GetCurrentProcessId() uint32
 pkg syscall (windows-amd64), func Getsockopt(Handle, int32, int32, *byte, *int32) error
 pkg syscall (windows-amd64), type SysProcAttr struct, CreationFlags uint32
-pkg syscall (windows-amd64), type Win32finddata1 struct
-pkg syscall (windows-amd64), type Win32finddata1 struct, AlternateFileName [14]uint16
-pkg syscall (windows-amd64), type Win32finddata1 struct, CreationTime Filetime
-pkg syscall (windows-amd64), type Win32finddata1 struct, FileAttributes uint32
-pkg syscall (windows-amd64), type Win32finddata1 struct, FileName [MAX_PATH]uint16
-pkg syscall (windows-amd64), type Win32finddata1 struct, FileSizeHigh uint32
-pkg syscall (windows-amd64), type Win32finddata1 struct, FileSizeLow uint32
-pkg syscall (windows-amd64), type Win32finddata1 struct, LastAccessTime Filetime
-pkg syscall (windows-amd64), type Win32finddata1 struct, LastWriteTime Filetime
-pkg syscall (windows-amd64), type Win32finddata1 struct, Reserved0 uint32
-pkg syscall (windows-amd64), type Win32finddata1 struct, Reserved1 uint32

doc/install-source.html

 If you see the "hello, world" message then Go is installed correctly.
 </p>
 
+<h2 id="gopath">Set up your work environment</h2>
+
+<p>
+The document <a href="/doc/code.html">How to Write Go Code</a> explains how to
+set up a work environment in which to build and test Go code.
+</p>
 
 <h2 id="community">Community resources</h2>
 
 If you see the "hello, world" message then your Go installation is working.
 </p>
 
+<h2 id="gopath">Set up your work environment</h2>
+
+<p>
+The document <a href="/doc/code.html">How to Write Go Code</a> explains how to
+set up a work environment in which to build and test Go code.
+</p>
+
 <h2 id="next">What's next</h2>
 
 <p>
 </p>
 
 <p>
-For more detail about the process of building and testing Go programs
-read <a href="/doc/code.html">How to Write Go Code</a>.
-</p>
-
-<p>
 Build a web application by following the <a href="/doc/articles/wiki/">Wiki
 Tutorial</a>.
 </p>

misc/emacs/go-mode.el

             (save-restriction
               (let (deactivate-mark)
                 (widen)
-                (if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt -d"
-                                                  patchbuf nil errbuf))
-                    ; gofmt succeeded: apply patch hunks.
-                    (progn
-                      (kill-buffer errbuf)
-                      (gofmt-apply-patch filename srcbuf patchbuf)
-                      (set-window-configuration currconf))
+                ; If this is a new file, diff-mode can't apply a
+                ; patch to a non-exisiting file, so replace the buffer
+                ; completely with the output of 'gofmt'.
+                ; If the file exists, patch it to keep the 'undo' list happy.
+                (let* ((newfile (not (file-exists-p filename)))
+                      (flag (if newfile "" " -d")))
+                  (if (= 0 (shell-command-on-region (point-min) (point-max)
+                                                    (concat "gofmt" flag)
+                                                    patchbuf nil errbuf))
+                      ; gofmt succeeded: replace buffer or apply patch hunks.
+                      (let ((old-point (point))
+                            (old-mark (mark t)))
+                        (kill-buffer errbuf)
+                        (if newfile
+                            ; New file, replace it (diff-mode won't work)
+                            (gofmt-replace-buffer srcbuf patchbuf)
+                          ; Existing file, patch it
+                          (gofmt-apply-patch filename srcbuf patchbuf))
+                        (goto-char (min old-point (point-max)))
+                        ;; Restore the mark and point
+                        (if old-mark (push-mark (min old-mark (point-max)) t))
+                        (set-window-configuration currconf))
 
                   ;; gofmt failed: display the errors
-                  (gofmt-process-errors filename errbuf)))))
+                  (gofmt-process-errors filename errbuf))))))
 
           ;; Collapse any window opened on outbuf if shell-command-on-region
           ;; displayed it.
           (delete-windows-on patchbuf)))
       (kill-buffer patchbuf))))
 
+(defun gofmt-replace-buffer (srcbuf patchbuf)
+  (with-current-buffer srcbuf
+    (erase-buffer)
+    (insert-buffer-substring patchbuf)))
+
 (defconst gofmt-stdin-tag "<standard input>")
 
 (defun gofmt-apply-patch (filename srcbuf patchbuf)
   (require 'diff-mode)
   ;; apply all the patch hunks and restore the mark and point
-  (let ((old-point (point))
-        (old-mark (mark t)))
-    (with-current-buffer patchbuf
-      (let ((filename (file-name-nondirectory filename))
-            (min (point-min)))
-        (replace-string gofmt-stdin-tag  filename nil min (point-max))
-        (replace-regexp "^--- /tmp/gofmt[0-9]*" (concat "--- /tmp/" filename)
-                        nil min (point-max)))
-      (condition-case nil
-          (while t
-            (diff-hunk-next)
-            (diff-apply-hunk))
-        ;; When there's no more hunks, diff-hunk-next signals an error, ignore it
-        (error nil)))
-    (goto-char (min old-point (point-max)))
-    (if old-mark (push-mark (min old-mark (point-max)) t))))
+  (with-current-buffer patchbuf
+    (let ((filename (file-name-nondirectory filename))
+          (min (point-min)))
+      (replace-string gofmt-stdin-tag  filename nil min (point-max))
+      (replace-regexp "^--- /tmp/gofmt[0-9]*" (concat "--- /tmp/" filename)
+                      nil min (point-max)))
+    (condition-case nil
+        (while t
+          (diff-hunk-next)
+          (diff-apply-hunk))
+      ;; When there's no more hunks, diff-hunk-next signals an error, ignore it
+      (error nil))))
 
 (defun gofmt-process-errors (filename errbuf)
   ;; Convert the gofmt stderr to something understood by the compilation mode.
 		outcode(AWORD, Always, &nullgen, NREG, &g);
 	}
 /*
- * MULL hi,lo,r1,r2
+ * MULL r1,r2,(hi,lo)
  */
 |	LTYPEM cond reg ',' reg ',' regreg
 	{
 		outcode($1, $2, &$3, $5.reg, &$7);
 	}
 /*
- * MULA hi,lo,r1,r2
+ * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff -> r4
+ * MULAW{T,B} r1,r2,r3,r4
  */
 |	LTYPEN cond reg ',' reg ',' reg ',' spreg
 	{
-		$7.type = D_REGREG;
+		$7.type = D_REGREG2;
 		$7.offset = $9;
 		outcode($1, $2, &$3, $5.reg, &$7);
 	}
 	"UNDEF",	LTYPEE,	AUNDEF,
 	"CLZ",		LTYPE2, ACLZ,
 
+	"MULWT",	LTYPE1, AMULWT,
+	"MULWB",	LTYPE1, AMULWB,
+	"MULAWT",	LTYPEN, AMULAWT,
+	"MULAWB",	LTYPEN, AMULAWB,
+
 	0
 };
 
 		break;
 
 	case D_REGREG:
+	case D_REGREG2:
 		Bputc(&obuf, a->offset);
 		break;
 

src/cmd/5a/y.tab.c

       93,    99,   100,   101,   107,   111,   115,   122,   129,   136,
      140,   147,   154,   161,   168,   175,   184,   196,   200,   204,
      211,   218,   222,   229,   236,   243,   250,   254,   258,   262,
-     269,   291,   298,   307,   314,   320,   323,   327,   332,   333,
-     336,   342,   351,   359,   365,   370,   375,   381,   384,   390,
-     398,   402,   411,   417,   418,   419,   420,   425,   431,   437,
-     443,   444,   447,   448,   456,   465,   466,   475,   476,   482,
-     485,   486,   487,   489,   497,   505,   514,   520,   526,   532,
-     540,   546,   554,   555,   559,   567,   568,   574,   575,   583,
-     584,   587,   593,   601,   609,   617,   627,   630,   634,   640,
-     641,   642,   645,   646,   650,   654,   658,   662,   668,   671,
-     677,   678,   682,   686,   690,   694,   698,   702,   706,   710,
-     714
+     269,   291,   299,   308,   315,   321,   324,   328,   333,   334,
+     337,   343,   352,   360,   366,   371,   376,   382,   385,   391,
+     399,   403,   412,   418,   419,   420,   421,   426,   432,   438,
+     444,   445,   448,   449,   457,   466,   467,   476,   477,   483,
+     486,   487,   488,   490,   498,   506,   515,   521,   527,   533,
+     541,   547,   555,   556,   560,   568,   569,   575,   576,   584,
+     585,   588,   594,   602,   610,   618,   628,   631,   635,   641,
+     642,   643,   646,   647,   651,   655,   659,   663,   669,   672,
+     678,   679,   683,   687,   691,   695,   699,   703,   707,   711,
+     715
 };
 #endif
 
   case 42:
 
 /* Line 1455 of yacc.c  */
-#line 299 "a.y"
+#line 300 "a.y"
     {
-		(yyvsp[(7) - (9)].gen).type = D_REGREG;
+		(yyvsp[(7) - (9)].gen).type = D_REGREG2;
 		(yyvsp[(7) - (9)].gen).offset = (yyvsp[(9) - (9)].lval);
 		outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].gen), (yyvsp[(5) - (9)].gen).reg, &(yyvsp[(7) - (9)].gen));
 	}
   case 43:
 
 /* Line 1455 of yacc.c  */
-#line 308 "a.y"
+#line 309 "a.y"
     {
 		outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].gen), NREG, &nullgen);
 	}
   case 44:
 
 /* Line 1455 of yacc.c  */
-#line 315 "a.y"
+#line 316 "a.y"
     {
 		outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
 	}
   case 45:
 
 /* Line 1455 of yacc.c  */
-#line 320 "a.y"
+#line 321 "a.y"
     {
 		(yyval.lval) = Always;
 	}
   case 46:
 
 /* Line 1455 of yacc.c  */
-#line 324 "a.y"
+#line 325 "a.y"
     {
 		(yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
 	}
   case 47:
 
 /* Line 1455 of yacc.c  */
-#line 328 "a.y"
+#line 329 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
 	}
   case 50:
 
 /* Line 1455 of yacc.c  */
-#line 337 "a.y"
+#line 338 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_BRANCH;
   case 51:
 
 /* Line 1455 of yacc.c  */
-#line 343 "a.y"
+#line 344 "a.y"
     {
 		(yyval.gen) = nullgen;
 		if(pass == 2)
   case 52:
 
 /* Line 1455 of yacc.c  */
-#line 352 "a.y"
+#line 353 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_BRANCH;
   case 53:
 
 /* Line 1455 of yacc.c  */
-#line 360 "a.y"
+#line 361 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_CONST;
   case 54:
 
 /* Line 1455 of yacc.c  */
-#line 366 "a.y"
+#line 367 "a.y"
     {
 		(yyval.gen) = (yyvsp[(2) - (2)].gen);
 		(yyval.gen).type = D_CONST;
   case 55:
 
 /* Line 1455 of yacc.c  */
-#line 371 "a.y"
+#line 372 "a.y"
     {
 		(yyval.gen) = (yyvsp[(4) - (4)].gen);
 		(yyval.gen).type = D_OCONST;
   case 56:
 
 /* Line 1455 of yacc.c  */
-#line 376 "a.y"
+#line 377 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_SCONST;
   case 58:
 
 /* Line 1455 of yacc.c  */
-#line 385 "a.y"
+#line 386 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_FCONST;
   case 59:
 
 /* Line 1455 of yacc.c  */
-#line 391 "a.y"
+#line 392 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_FCONST;
   case 60:
 
 /* Line 1455 of yacc.c  */
-#line 399 "a.y"
+#line 400 "a.y"
     {
 		(yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
 	}
   case 61:
 
 /* Line 1455 of yacc.c  */
-#line 403 "a.y"
+#line 404 "a.y"
     {
 		int i;
 		(yyval.lval)=0;
   case 62:
 
 /* Line 1455 of yacc.c  */
-#line 412 "a.y"
+#line 413 "a.y"
     {
 		(yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
 	}
   case 66:
 
 /* Line 1455 of yacc.c  */
-#line 421 "a.y"
+#line 422 "a.y"
     {
 		(yyval.gen) = (yyvsp[(1) - (4)].gen);
 		(yyval.gen).reg = (yyvsp[(3) - (4)].lval);
   case 67:
 
 /* Line 1455 of yacc.c  */
-#line 426 "a.y"
+#line 427 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_PSR;
   case 68:
 
 /* Line 1455 of yacc.c  */
-#line 432 "a.y"
+#line 433 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_FPCR;
   case 69:
 
 /* Line 1455 of yacc.c  */
-#line 438 "a.y"
+#line 439 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_OREG;
   case 73:
 
 /* Line 1455 of yacc.c  */
-#line 449 "a.y"
+#line 450 "a.y"
     {
 		(yyval.gen) = (yyvsp[(1) - (1)].gen);
 		if((yyvsp[(1) - (1)].gen).name != D_EXTERN && (yyvsp[(1) - (1)].gen).name != D_STATIC) {
   case 74:
 
 /* Line 1455 of yacc.c  */
-#line 457 "a.y"
+#line 458 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_OREG;
   case 76:
 
 /* Line 1455 of yacc.c  */
-#line 467 "a.y"
+#line 468 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_OREG;
   case 78:
 
 /* Line 1455 of yacc.c  */
-#line 477 "a.y"
+#line 478 "a.y"
     {
 		(yyval.gen) = (yyvsp[(1) - (4)].gen);
 		(yyval.gen).type = D_OREG;
   case 83:
 
 /* Line 1455 of yacc.c  */
-#line 490 "a.y"
+#line 491 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_CONST;
   case 84:
 
 /* Line 1455 of yacc.c  */
-#line 498 "a.y"
+#line 499 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_REG;
   case 85:
 
 /* Line 1455 of yacc.c  */
-#line 506 "a.y"
+#line 507 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_REGREG;
   case 86:
 
 /* Line 1455 of yacc.c  */
-#line 515 "a.y"
+#line 516 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_SHIFT;
   case 87:
 
 /* Line 1455 of yacc.c  */
-#line 521 "a.y"
+#line 522 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_SHIFT;
   case 88:
 
 /* Line 1455 of yacc.c  */
-#line 527 "a.y"
+#line 528 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_SHIFT;
   case 89:
 
 /* Line 1455 of yacc.c  */
-#line 533 "a.y"
+#line 534 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_SHIFT;
   case 90:
 
 /* Line 1455 of yacc.c  */
-#line 541 "a.y"
+#line 542 "a.y"
     {
 		if((yyval.lval) < 0 || (yyval.lval) >= 16)
 			print("register value out of range\n");
   case 91:
 
 /* Line 1455 of yacc.c  */
-#line 547 "a.y"
+#line 548 "a.y"
     {
 		if((yyval.lval) < 0 || (yyval.lval) >= 32)
 			print("shift value out of range\n");
   case 93:
 
 /* Line 1455 of yacc.c  */
-#line 556 "a.y"
+#line 557 "a.y"
     {
 		(yyval.lval) = REGPC;
 	}
   case 94:
 
 /* Line 1455 of yacc.c  */
-#line 560 "a.y"
+#line 561 "a.y"
     {
 		if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
 			print("register value out of range\n");
   case 96:
 
 /* Line 1455 of yacc.c  */
-#line 569 "a.y"
+#line 570 "a.y"
     {
 		(yyval.lval) = REGSP;
 	}
   case 98:
 
 /* Line 1455 of yacc.c  */
-#line 576 "a.y"
+#line 577 "a.y"
     {
 		if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
 			print("register value out of range\n");
   case 101:
 
 /* Line 1455 of yacc.c  */
-#line 588 "a.y"
+#line 589 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_FREG;
   case 102:
 
 /* Line 1455 of yacc.c  */
-#line 594 "a.y"
+#line 595 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_FREG;
   case 103:
 
 /* Line 1455 of yacc.c  */
-#line 602 "a.y"
+#line 603 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_OREG;
   case 104:
 
 /* Line 1455 of yacc.c  */
-#line 610 "a.y"
+#line 611 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_OREG;
   case 105:
 
 /* Line 1455 of yacc.c  */
-#line 618 "a.y"
+#line 619 "a.y"
     {
 		(yyval.gen) = nullgen;
 		(yyval.gen).type = D_OREG;
   case 106:
 
 /* Line 1455 of yacc.c  */
-#line 627 "a.y"
+#line 628 "a.y"
     {
 		(yyval.lval) = 0;
 	}
   case 107:
 
 /* Line 1455 of yacc.c  */
-#line 631 "a.y"
+#line 632 "a.y"
     {
 		(yyval.lval) = (yyvsp[(2) - (2)].lval);
 	}
   case 108:
 
 /* Line 1455 of yacc.c  */
-#line 635 "a.y"
+#line 636 "a.y"
     {
 		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
 	}
   case 113:
 
 /* Line 1455 of yacc.c  */
-#line 647 "a.y"
+#line 648 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
 	}
   case 114:
 
 /* Line 1455 of yacc.c  */
-#line 651 "a.y"
+#line 652 "a.y"
     {
 		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
 	}
   case 115:
 
 /* Line 1455 of yacc.c  */
-#line 655 "a.y"
+#line 656 "a.y"
     {
 		(yyval.lval) = (yyvsp[(2) - (2)].lval);
 	}
   case 116:
 
 /* Line 1455 of yacc.c  */
-#line 659 "a.y"
+#line 660 "a.y"
     {
 		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
 	}
   case 117:
 
 /* Line 1455 of yacc.c  */
-#line 663 "a.y"
+#line 664 "a.y"
     {
 		(yyval.lval) = (yyvsp[(2) - (3)].lval);
 	}
   case 118:
 
 /* Line 1455 of yacc.c  */
-#line 668 "a.y"
+#line 669 "a.y"
     {
 		(yyval.lval) = 0;
 	}
   case 119:
 
 /* Line 1455 of yacc.c  */
-#line 672 "a.y"
+#line 673 "a.y"
     {
 		(yyval.lval) = (yyvsp[(2) - (2)].lval);
 	}
   case 121:
 
 /* Line 1455 of yacc.c  */
-#line 679 "a.y"
+#line 680 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
 	}
   case 122:
 
 /* Line 1455 of yacc.c  */
-#line 683 "a.y"
+#line 684 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
 	}
   case 123:
 
 /* Line 1455 of yacc.c  */
-#line 687 "a.y"
+#line 688 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
 	}
   case 124:
 
 /* Line 1455 of yacc.c  */
-#line 691 "a.y"
+#line 692 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
 	}
   case 125:
 
 /* Line 1455 of yacc.c  */
-#line 695 "a.y"
+#line 696 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
 	}
   case 126:
 
 /* Line 1455 of yacc.c  */
-#line 699 "a.y"
+#line 700 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
 	}
   case 127:
 
 /* Line 1455 of yacc.c  */
-#line 703 "a.y"
+#line 704 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
 	}
   case 128:
 
 /* Line 1455 of yacc.c  */
-#line 707 "a.y"
+#line 708 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
 	}
   case 129:
 
 /* Line 1455 of yacc.c  */
-#line 711 "a.y"
+#line 712 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
 	}
   case 130:
 
 /* Line 1455 of yacc.c  */
-#line 715 "a.y"
+#line 716 "a.y"
     {
 		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
 	}

src/cmd/5c/list.c

 {
 	char str[STRINGSZ];
 	Adr *a;
-	char *op;
+	const char *op;
 	int v;
 
 	a = va_arg(fp->args, Adr*);

src/cmd/5g/cgen64.c

 		p1->from.type = D_REG;
 		p1->from.reg = bl.val.u.reg;
 		p1->reg = ch.val.u.reg;
-		p1->to.type = D_REGREG;
+		p1->to.type = D_REGREG2;
 		p1->to.reg = ah.val.u.reg;
 		p1->to.offset = ah.val.u.reg;
 //print("%P\n", p1);
 		p1->from.type = D_REG;
 		p1->from.reg = bh.val.u.reg;
 		p1->reg = cl.val.u.reg;
-		p1->to.type = D_REGREG;
+		p1->to.type = D_REGREG2;
 		p1->to.reg = ah.val.u.reg;
 		p1->to.offset = ah.val.u.reg;
 //print("%P\n", p1);

src/cmd/5g/gobj.c

 		break;
 
 	case D_REGREG:
+	case D_REGREG2:
 		Bputc(b, a->offset);
 		break;
 
 		if(isblank(pl->name))
 			continue;
 
-		if(debug['S']) {
+		// -S prints code; -SS prints code and data
+		if(debug['S'] && (pl->name || debug['S']>1)) {
 			s = S;
 			if(pl->name != N)
 				s = pl->name->sym;

src/cmd/5g/list.c

 Dconv(Fmt *fp)
 {
 	char str[STRINGSZ];
-	char *op;
+	const char *op;
 	Addr *a;
 	int i;
 	int32 v;
 			sprint(str, "%M(R%d)(REG)", a, a->reg);
 		break;
 
+	case D_REGREG2:
+		sprint(str, "R%d,R%d", a->reg, (int)a->offset);
+		if(a->name != D_NONE || a->sym != S)
+			sprint(str, "%M(R%d)(REG)", a, a->reg);
+		break;
+
 	case D_FREG:
 		sprint(str, "F%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)

src/cmd/5g/peep.c

 			if(a->reg == v->reg)
 				return 1;
 		} else
-		if(a->type == D_REGREG) {
+		if(a->type == D_REGREG || a->type == D_REGREG2) {
 			if(a->reg == v->reg)
 				return 1;
 			if(a->offset == v->reg)
 			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
 				a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
 		} else
-		if(a->type == D_REGREG) {
+		if(a->type == D_REGREG || a->type == D_REGREG2) {
 			if(a->offset == v->reg)
 				a->offset = s->reg;
 			if(a->reg == v->reg)
 		goto onereg;
 
 	case D_REGREG:
+	case D_REGREG2:
 		bit = zbits;
 		if(a->offset != NREG)
 			bit.b[0] |= RtoB(a->offset);

src/cmd/5l/5.out.h

 
 	ACLZ,
 
+	AMULWT,
+	AMULWB,
+	AMULAWT,
+	AMULAWB,
+
 	ALAST,
 };
 
 
 #define	D_SHIFT		(D_NONE+19)
 #define	D_FPCR		(D_NONE+20)
-#define	D_REGREG	(D_NONE+21)
+#define	D_REGREG	(D_NONE+21) // (reg, reg)
 #define	D_ADDR		(D_NONE+22)
 
 #define	D_SBIG		(D_NONE+23)
 #define	D_CONST2	(D_NONE+24)
 
+#define	D_REGREG2	(D_NONE+25) // reg, reg
+
 /* name */
 #define	D_EXTERN	(D_NONE+3)
 #define	D_STATIC	(D_NONE+4)
  		o1 |= p->to.reg << 12;
  		o1 |= p->from.reg;
 		break;
+	case 98:	/* MULW{T,B} Rs, Rm, Rd */
+		o1 = oprrr(p->as, p->scond);
+		o1 |= p->to.reg << 16;
+		o1 |= p->from.reg << 8;
+		o1 |= p->reg;
+		break;
+	case 99:	/* MULAW{T,B} Rs, Rm, Rn, Rd */
+		o1 = oprrr(p->as, p->scond);
+		o1 |= p->to.reg << 12;
+		o1 |= p->from.reg << 8;
+		o1 |= p->reg;
+		o1 |= p->to.offset << 16;
+		break;
 	}
 	
 	out[0] = o1;
 	case ACLZ:
 		// CLZ doesn't support .S
 		return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
+
+	case AMULWT:
+		return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
+	case AMULWB:
+		return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
+	case AMULAWT:
+		return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
+	case AMULAWB:
+		return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
 	}
 	diag("bad rrr %d", a);
 	prasm(curp);
 	C_NONE		= 0,
 	C_REG,
 	C_REGREG,
+	C_REGREG2,
 	C_SHIFT,
 	C_FREG,
 	C_PSR,

src/cmd/5l/list.c

 Dconv(Fmt *fp)
 {
 	char str[STRINGSZ];
-	char *op;
+	const char *op;
 	Adr *a;
 	int32 v;
 
 			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
 		break;
 
+	case D_REGREG2:
+		snprint(str, sizeof str, "R%d,R%d", a->reg, (int)a->offset);
+		if(a->name != D_NONE || a->sym != S)
+			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
+		break;
+
 	case D_FREG:
 		snprint(str, sizeof str, "F%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
 	[C_RCON]	= "C_RCON",
 	[C_REG]		= "C_REG",
 	[C_REGREG]	= "C_REGREG",
+	[C_REGREG2]	= "C_REGREG2",
 	[C_ROREG]	= "C_ROREG",
 	[C_SAUTO]	= "C_SAUTO",
 	[C_SBRA]	= "C_SBRA",
 		break;
 
 	case D_REGREG:
+	case D_REGREG2:
 		a->offset = BGETC(f);
 		break;
 

src/cmd/5l/optab.c

 	{ ADIV,		C_REG,	C_NONE,	C_REG,		16, 4, 0 },
 
 	{ AMULL,	C_REG,	C_REG,	C_REGREG,	17, 4, 0 },
+	{ AMULA,	C_REG,	C_REG,	C_REGREG2,	17, 4, 0 },
 
 	{ AMOVW,	C_REG,	C_NONE,	C_SAUTO,	20, 4, REGSP },
 	{ AMOVW,	C_REG,	C_NONE,	C_SOREG,	20, 4, 0 },
 
 	{ ACLZ,		C_REG,	C_NONE,	C_REG,		97, 4, 0 },
 
+	{ AMULWT,	C_REG,	C_REG,	C_REG,		98, 4, 0 },
+	{ AMULAWT,	C_REG,	C_REG,	C_REGREG2,		99, 4, 0 },
+
 	{ AXXX,		C_NONE,	C_NONE,	C_NONE,		 0, 4, 0 },
 };

src/cmd/5l/span.c

 	case D_REGREG:
 		return C_REGREG;
 
+	case D_REGREG2:
+		return C_REGREG2;
+
 	case D_SHIFT:
 		return C_SHIFT;
 
 			break;
 
 		case AMULL:
-			oprange[AMULA] = oprange[r];
 			oprange[AMULAL] = oprange[r];
 			oprange[AMULLU] = oprange[r];
 			oprange[AMULALU] = oprange[r];
 			break;
 
+		case AMULWT:
+			oprange[AMULWB] = oprange[r];
+			break;
+
+		case AMULAWT:
+			oprange[AMULAWB] = oprange[r];
+			break;
+
+		case AMULA:
 		case ALDREX:
 		case ASTREX:
 		case ALDREXD:

src/cmd/6g/gobj.c

 		if(isblank(pl->name))
 			continue;
 
-		if(debug['S']) {
+		// -S prints code; -SS prints code and data
+		if(debug['S'] && (pl->name || debug['S']>1)) {
 			s = S;
 			if(pl->name != N)
 				s = pl->name->sym;

src/cmd/8g/gobj.c

 		if(isblank(pl->name))
 			continue;
 
-		if(debug['S']) {
+		// -S prints code; -SS prints code and data
+		if(debug['S'] && (pl->name || debug['S']>1)) {
 			s = S;
 			if(pl->name != N)
 				s = pl->name->sym;

src/cmd/api/goapi.go

 	"os/exec"
 	"path"
 	"path/filepath"
+	"runtime"
 	"sort"
 	"strconv"
 	"strings"
 func main() {
 	flag.Parse()
 
+	if !strings.Contains(runtime.Version(), "weekly") {
+		if *nextFile != "" {
+			fmt.Printf("Go version is %q, ignoring -next %s\n", runtime.Version(), *nextFile)
+			*nextFile = ""
+		}
+	}
+
 	if *forceCtx != "" {
 		setContexts()
 	}
 	if err != nil {
 		log.Fatalf("Error reading file %s: %v", filename, err)
 	}
-	return strings.Split(strings.TrimSpace(string(bs)), "\n")
+	text := strings.TrimSpace(string(bs))
+	if text == "" {
+		return nil
+	}
+	return strings.Split(text, "\n")
 }
 
 // pkgSymbol represents a symbol in a package

src/cmd/cgo/main.go

 	"path/filepath"
 	"reflect"
 	"runtime"
+	"sort"
 	"strings"
 )
 
 	GccOptions  []string
 	CgoFlags    map[string]string // #cgo flags (CFLAGS, LDFLAGS)
 	Written     map[string]bool
-	Name        map[string]*Name    // accumulated Name from Files
-	Typedef     map[string]ast.Expr // accumulated Typedef from Files
-	ExpFunc     []*ExpFunc          // accumulated ExpFunc from Files
+	Name        map[string]*Name // accumulated Name from Files
+	ExpFunc     []*ExpFunc       // accumulated ExpFunc from Files
 	Decl        []ast.Decl
 	GoFiles     []string // list of Go files
 	GccFiles    []string // list of gcc output files
 	Ref      []*Ref              // all references to C.xxx in AST
 	ExpFunc  []*ExpFunc          // exported functions for this file
 	Name     map[string]*Name    // map from Go name to Name
-	Typedef  map[string]ast.Expr // translations of all necessary types from C
+}
+
+func nameKeys(m map[string]*Name) []string {
+	var ks []string
+	for k := range m {
+		ks = append(ks, k)
+	}
+	sort.Strings(ks)
+	return ks
 }
 
 // A Ref refers to an expression of the form C.xxx in the AST.

src/cmd/cgo/out.go

 	}
 
 	cVars := make(map[string]bool)
-	for _, n := range p.Name {
+	for _, key := range nameKeys(p.Name) {
+		n := p.Name[key]
 		if n.Kind != "var" {
 			continue
 		}
 	}
 	fmt.Fprintf(fc, "\n")
 
-	for _, n := range p.Name {
+	for _, key := range nameKeys(p.Name) {
+		n := p.Name[key]
 		if n.Const != "" {
 			fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
 		}
 	}
 	fmt.Fprintf(fgo2, "\n")
 
-	for _, n := range p.Name {
+	for _, key := range nameKeys(p.Name) {
+		n := p.Name[key]
 		if n.FuncType != nil {
 			p.writeDefsFunc(fc, fgo2, n)
 		}
 	fmt.Fprintf(fgcc, "%s\n", f.Preamble)
 	fmt.Fprintf(fgcc, "%s\n", gccProlog)
 
-	for _, n := range f.Name {
+	for _, key := range nameKeys(f.Name) {
+		n := f.Name[key]
 		if n.FuncType != nil {
 			p.writeOutputFunc(fgcc, n)
 		}

src/cmd/gc/doc.go

 	-N
 		disable optimizations
 	-S
-		write assembly language text to standard output
+		write assembly language text to standard output (code only)
+	-SS
+		write assembly language text to standard output (code and data)
 	-u
 		disallow importing packages not marked as safe
 	-V
 // 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.
+
+// Escape analysis.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+// Run analysis on minimal sets of mutually recursive functions
+// or single non-recursive functions, bottom up.
 //
-// Escape analysis.
+// Finding these sets is finding strongly connected components
+// in the static call graph.  The algorithm for doing that is taken
+// from Sedgewick, Algorithms, Second Edition, p. 482, with two
+// adaptations.
+//
+// First, a hidden closure function (n->curfn != N) cannot be the
+// root of a connected component. Refusing to use it as a root
+// forces it into the component of the function in which it appears.
+// The analysis assumes that closures and the functions in which they
+// appear are analyzed together, so that the aliasing between their
+// variables can be modeled more precisely.
+//
+// Second, each function becomes two virtual nodes in the graph,
+// with numbers n and n+1. We record the function's node number as n
+// but search from node n+1. If the search tells us that the component
+// number (min) is n+1, we know that this is a trivial component: one function
+// plus its closures. If the search tells us that the component number is
+// n, then there was a path from node n+1 back to node n, meaning that
+// the function set is mutually recursive. The escape analysis can be
+// more precise when analyzing a single non-recursive function than
+// when analyzing a set of mutually recursive functions.
+
+static NodeList *stack;
+static uint32 visitgen;
+static uint32 visit(Node*);
+static uint32 visitcode(Node*, uint32);
+static uint32 visitcodelist(NodeList*, uint32);
+
+static void analyze(NodeList*, int);
+
+enum
+{
+	EscFuncUnknown = 0,
+	EscFuncPlanned,
+	EscFuncStarted,
+	EscFuncTagged,
+};
+
+void
+escapes(NodeList *all)
+{
+	NodeList *l;
+
+	for(l=all; l; l=l->next)
+		l->n->walkgen = 0;
+
+	visitgen = 0;
+	for(l=all; l; l=l->next)
+		if(l->n->op == ODCLFUNC && l->n->curfn == N)
+			visit(l->n);
+
+	for(l=all; l; l=l->next)
+		l->n->walkgen = 0;
+}
+
+static uint32
+visit(Node *n)
+{
+	uint32 min, recursive;
+	NodeList *l, *block;
+
+	if(n->walkgen > 0) {
+		// already visited
+		return n->walkgen;
+	}
+	
+	visitgen++;
+	n->walkgen = visitgen;
+	visitgen++;
+	min = visitgen;
+
+	l = mal(sizeof *l);
+	l->next = stack;
+	l->n = n;
+	stack = l;
+	min = visitcodelist(n->nbody, min);
+	if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) {
+		// This node is the root of a strongly connected component.
+
+		// The original min passed to visitcodelist was n->walkgen+1.
+		// If visitcodelist found its way back to n->walkgen, then this
+		// block is a set of mutually recursive functions.
+		// Otherwise it's just a lone function that does not recurse.
+		recursive = min == n->walkgen;
+
+		// Remove connected component from stack.
+		// Mark walkgen so that future visits return a large number
+		// so as not to affect the caller's min.
+		block = stack;
+		for(l=stack; l->n != n; l=l->next)
+			l->n->walkgen = (uint32)~0U;
+		n->walkgen = (uint32)~0U;
+		stack = l->next;
+		l->next = nil;
+
+		// Run escape analysis on this set of functions.
+		analyze(block, recursive);
+	}
+
+	return min;
+}
+
+static uint32
+visitcodelist(NodeList *l, uint32 min)
+{
+	for(; l; l=l->next)
+		min = visitcode(l->n, min);
+	return min;
+}
+
+static uint32
+visitcode(Node *n, uint32 min)
+{
+	Node *fn;
+	uint32 m;
+
+	if(n == N)
+		return min;
+
+	min = visitcodelist(n->ninit, min);
+	min = visitcode(n->left, min);
+	min = visitcode(n->right, min);
+	min = visitcodelist(n->list, min);
+	min = visitcode(n->ntest, min);
+	min = visitcode(n->nincr, min);
+	min = visitcodelist(n->nbody, min);
+	min = visitcodelist(n->nelse, min);
+	min = visitcodelist(n->rlist, min);
+	
+	if(n->op == OCALLFUNC || n->op == OCALLMETH) {
+		fn = n->left;
+		if(n->op == OCALLMETH)
+			fn = n->left->right->sym->def;
+		if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody)
+			if((m = visit(fn->defn)) < min)
+				min = m;
+	}
+	
+	if(n->op == OCLOSURE)
+		if((m = visit(n->closure)) < min)
+			min = m;
+
+	return min;
+}
+
+// An escape analysis pass for a set of functions.
 //
 // First escfunc, esc and escassign recurse over the ast of each
 // function to dig out flow(dst,src) edges between any
 // not escape, then new(T) can be rewritten into a stack allocation.
 // The same is true of slice literals.
 //
-// If escape analysis is disabled (-s), this code is not used.
+// If optimizations are disabled (-N), this code is not used.
 // Instead, the compiler assumes that any value whose address
 // is taken without being immediately dereferenced
 // needs to be moved to the heap, and new(T) and slice
 // literals are always real allocations.
 
-#include <u.h>
-#include <libc.h>
-#include "go.h"
+typedef struct EscState EscState;
 
-static void escfunc(Node *func);
-static void esclist(NodeList *l);
-static void esc(Node *n);
-static void escloopdepthlist(NodeList *l);
-static void escloopdepth(Node *n);
-static void escassign(Node *dst, Node *src);
-static void esccall(Node*);
-static void escflows(Node *dst, Node *src);
-static void escflood(Node *dst);
-static void escwalk(int level, Node *dst, Node *src);
-static void esctag(Node *func);
+static void escfunc(EscState*, Node *func);
+static void esclist(EscState*, NodeList *l);
+static void esc(EscState*, Node *n);
+static void escloopdepthlist(EscState*, NodeList *l);
+static void escloopdepth(EscState*, Node *n);
+static void escassign(EscState*, Node *dst, Node *src);
+static void esccall(EscState*, Node*);
+static void escflows(EscState*, Node *dst, Node *src);
+static void escflood(EscState*, Node *dst);
+static void escwalk(EscState*, int level, Node *dst, Node *src);
+static void esctag(EscState*, Node *func);
 
-// Fake node that all
-//   - return values and output variables
-//   - parameters on imported functions not marked 'safe'
-//   - assignments to global variables
-// flow to.
-static Node	theSink;
+struct EscState {
+	// Fake node that all
+	//   - return values and output variables
+	//   - parameters on imported functions not marked 'safe'
+	//   - assignments to global variables
+	// flow to.
+	Node	theSink;
+	
+	NodeList*	dsts;		// all dst nodes
+	int	loopdepth;	// for detecting nested loop scopes
+	int	pdepth;		// for debug printing in recursions.
+	int	dstcount, edgecount;	// diagnostic
+	NodeList*	noesc;	// list of possible non-escaping nodes, for printing
+};
 
-static NodeList*	dsts;		// all dst nodes
-static int	loopdepth;	// for detecting nested loop scopes
-static int	pdepth;		// for debug printing in recursions.
 static Strlit*	safetag;	// gets slapped on safe parameters' field types for export
-static int	dstcount, edgecount;	// diagnostic
-static NodeList*	noesc;	// list of possible non-escaping nodes, for printing
 
-void
-escapes(NodeList *all)
+static void
+analyze(NodeList *all, int recursive)
 {
 	NodeList *l;
+	EscState es, *e;
+	
+	USED(recursive);
 
-	theSink.op = ONAME;
-	theSink.orig = &theSink;
-	theSink.class = PEXTERN;
-	theSink.sym = lookup(".sink");
-	theSink.escloopdepth = -1;
+	memset(&es, 0, sizeof es);
+	e = &es;
+	e->theSink.op = ONAME;
+	e->theSink.orig = &e->theSink;
+	e->theSink.class = PEXTERN;
+	e->theSink.sym = lookup(".sink");
+	e->theSink.escloopdepth = -1;
 
-	safetag = strlit("noescape");
-	noesc = nil;
+	if(safetag == nil)
+		safetag = strlit("noescape");
+
+	for(l=all; l; l=l->next)
+		if(l->n->op == ODCLFUNC)
+			l->n->esc = EscFuncPlanned;
 
 	// flow-analyze functions
 	for(l=all; l; l=l->next)
 		if(l->n->op == ODCLFUNC)
-			escfunc(l->n);
+			escfunc(e, l->n);
 
-	// print("escapes: %d dsts, %d edges\n", dstcount, edgecount);
+	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
 
 	// visit the updstream of each dst, mark address nodes with
 	// addrescapes, mark parameters unsafe
-	for(l = dsts; l; l=l->next)
-		escflood(l->n);
+	for(l = e->dsts; l; l=l->next)
+		escflood(e, l->n);
 
 	// for all top level functions, tag the typenodes corresponding to the param nodes
 	for(l=all; l; l=l->next)
 		if(l->n->op == ODCLFUNC)
-			esctag(l->n);
+			esctag(e, l->n);
 
 	if(debug['m']) {
-		for(l=noesc; l; l=l->next)
+		for(l=e->noesc; l; l=l->next)
 			if(l->n->esc == EscNone)
 				warnl(l->n->lineno, "%S %hN does not escape",
 					(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
 
 
 static void
-escfunc(Node *func)
+escfunc(EscState *e, Node *func)
 {
 	Node *savefn;
 	NodeList *ll;
 	int saveld;
 
-	saveld = loopdepth;
-	loopdepth = 1;
+	if(func->esc != 1)
+		fatal("repeat escfunc %N", func->nname);
+	func->esc = EscFuncStarted;
+
+	saveld = e->loopdepth;
+	e->loopdepth = 1;
 	savefn = curfn;
 	curfn = func;
 
 		switch (ll->n->class) {
 		case PPARAMOUT:
 			// output parameters flow to the sink
-			escflows(&theSink, ll->n);
-			ll->n->escloopdepth = loopdepth;
+			escflows(e, &e->theSink, ll->n);
+			ll->n->escloopdepth = e->loopdepth;
 			break;
 		case PPARAM:
 			if(ll->n->type && !haspointers(ll->n->type))
 				break;
 			ll->n->esc = EscNone;	// prime for escflood later
-			noesc = list(noesc, ll->n);
-			ll->n->escloopdepth = loopdepth;
+			e->noesc = list(e->noesc, ll->n);
+			ll->n->escloopdepth = e->loopdepth;
 			break;
 		}
 	}
 
-	escloopdepthlist(curfn->nbody);
-	esclist(curfn->nbody);
+	escloopdepthlist(e, curfn->nbody);
+	esclist(e, curfn->nbody);
 	curfn = savefn;
-	loopdepth = saveld;
+	e->loopdepth = saveld;
 }
 
-// Mark labels that have no backjumps to them as not increasing loopdepth.
+// Mark labels that have no backjumps to them as not increasing e->loopdepth.
 // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
 // and set it to one of the following two.  Then in esc we'll clear it again.
 static Label looping;
 static Label nonlooping;
 
 static void
-escloopdepthlist(NodeList *l)
+escloopdepthlist(EscState *e, NodeList *l)
 {
 	for(; l; l=l->next)
-		escloopdepth(l->n);
+		escloopdepth(e, l->n);
 }
 
 static void
-escloopdepth(Node *n)
+escloopdepth(EscState *e, Node *n)
 {
 	if(n == N)
 		return;
 
-	escloopdepthlist(n->ninit);
+	escloopdepthlist(e, n->ninit);
 
 	switch(n->op) {
 	case OLABEL:
 		break;
 	}
 
-	escloopdepth(n->left);
-	escloopdepth(n->right);
-	escloopdepthlist(n->list);
-	escloopdepth(n->ntest);
-	escloopdepth(n->nincr);
-	escloopdepthlist(n->nbody);
-	escloopdepthlist(n->nelse);
-	escloopdepthlist(n->rlist);
+	escloopdepth(e, n->left);
+	escloopdepth(e, n->right);
+	escloopdepthlist(e, n->list);
+	escloopdepth(e, n->ntest);
+	escloopdepth(e, n->nincr);
+	escloopdepthlist(e, n->nbody);
+	escloopdepthlist(e, n->nelse);
+	escloopdepthlist(e, n->rlist);
 
 }
 
 static void
-esclist(NodeList *l)
+esclist(EscState *e, NodeList *l)
 {
 	for(; l; l=l->next)
-		esc(l->n);
+		esc(e, l->n);
 }
 
 static void
-esc(Node *n)
+esc(EscState *e, Node *n)
 {
 	int lno;
 	NodeList *ll, *lr;
 	lno = setlineno(n);
 
 	if(n->op == OFOR || n->op == ORANGE)
-		loopdepth++;
+		e->loopdepth++;
 
-	esc(n->left);
-	esc(n->right);
-	esc(n->ntest);
-	esc(n->nincr);
-	esclist(n->ninit);
-	esclist(n->nbody);
-	esclist(n->nelse);
-	esclist(n->list);
-	esclist(n->rlist);
+	esc(e, n->left);
+	esc(e, n->right);
+	esc(e, n->ntest);
+	esc(e, n->nincr);
+	esclist(e, n->ninit);
+	esclist(e, n->nbody);
+	esclist(e, n->nelse);
+	esclist(e, n->list);
+	esclist(e, n->rlist);
 
 	if(n->op == OFOR || n->op == ORANGE)
-		loopdepth--;
+		e->loopdepth--;
 
 	if(debug['m'] > 1)
-		print("%L:[%d] %S esc: %N\n", lineno, loopdepth,
+		print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth,
 		      (curfn && curfn->nname) ? curfn->nname->sym : S, n);
 
 	switch(n->op) {
 	case ODCL:
 		// Record loop depth at declaration.
 		if(n->left)
-			n->left->escloopdepth = loopdepth;
+			n->left->escloopdepth = e->loopdepth;
 		break;
 
 	case OLABEL:
 		} else if(n->left->sym->label == &looping) {
 			if(debug['m'] > 1)
 				print("%L: %N looping label\n", lineno, n);
-			loopdepth++;
+			e->loopdepth++;
 		}
 		// See case OLABEL in escloopdepth above
 		// else if(n->left->sym->label == nil)
 	case ORANGE:
 		// Everything but fixed array is a dereference.
 		if(isfixedarray(n->type) && n->list->next)
-			escassign(n->list->next->n, n->right);
+			escassign(e, n->list->next->n, n->right);
 		break;
 
 	case OSWITCH:
 			for(ll=n->list; ll; ll=ll->next) {  // cases
 				// ntest->right is the argument of the .(type),
 				// ll->n->nname is the variable per case
-				escassign(ll->n->nname, n->ntest->right);
+				escassign(e, ll->n->nname, n->ntest->right);
 			}
 		}
 		break;
 
 	case OAS:
 	case OASOP:
-		escassign(n->left, n->right);
+		escassign(e, n->left, n->right);
 		break;
 
 	case OAS2:	// x,y = a,b
 		if(count(n->list) == count(n->rlist))
 			for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
-				escassign(ll->n, lr->n);
+				escassign(e, ll->n, lr->n);
 		break;
 
 	case OAS2RECV:		// v, ok = <-ch
 	case OAS2MAPR:		// v, ok = m[k]
 	case OAS2DOTTYPE:	// v, ok = x.(type)
-		escassign(n->list->n, n->rlist->n);
+		escassign(e, n->list->n, n->rlist->n);
 		break;
 
 	case OSEND:		// ch <- x
-		escassign(&theSink, n->right);
+		escassign(e, &e->theSink, n->right);
 		break;
 
 	case ODEFER:
-		if(loopdepth == 1)  // top level
+		if(e->loopdepth == 1)  // top level
 			break;
 		// arguments leak out of scope
 		// TODO: leak to a dummy node instead
 		// fallthrough
 	case OPROC:
 		// go f(x) - f and x escape
-		escassign(&theSink, n->left->left);
-		escassign(&theSink, n->left->right);  // ODDDARG for call
+		escassign(e, &e->theSink, n->left->left);
+		escassign(e, &e->theSink, n->left->right);  // ODDDARG for call
 		for(ll=n->left->list; ll; ll=ll->next)
-			escassign(&theSink, ll->n);
+			escassign(e, &e->theSink, ll->n);
 		break;
 
 	case ORETURN:
 		for(ll=n->list; ll; ll=ll->next)
-			escassign(&theSink, ll->n);
+			escassign(e, &e->theSink, ll->n);
 		break;
 
 	case OPANIC:
 		// Argument could leak through recover.
-		escassign(&theSink, n->left);
+		escassign(e, &e->theSink, n->left);
 		break;
 
 	case OAPPEND:
 		if(!n->isddd)
 			for(ll=n->list->next; ll; ll=ll->next)
-				escassign(&theSink, ll->n);  // lose track of assign to dereference
+				escassign(e, &e->theSink, ll->n);  // lose track of assign to dereference
 		break;
 
 	case OCALLMETH:
 	case OCALLFUNC:
 	case OCALLINTER:
-		esccall(n);
+		esccall(e, n);
 		break;
 
 	case OCONV:
 	case OCONVNOP:
 	case OCONVIFACE:
-		escassign(n, n->left);
+		escassign(e, n, n->left);
 		break;
 
 	case OARRAYLIT:
 		if(isslice(n->type)) {
 			n->esc = EscNone;  // until proven otherwise
-			noesc = list(noesc, n);
-			n->escloopdepth = loopdepth;
+			e->noesc = list(e->noesc, n);
+			n->escloopdepth = e->loopdepth;
 			// Values make it to memory, lose track.
 			for(ll=n->list; ll; ll=ll->next)
-				escassign(&theSink, ll->n->right);
+				escassign(e, &e->theSink, ll->n->right);
 		} else {
 			// Link values to array.
 			for(ll=n->list; ll; ll=ll->next)
-				escassign(n, ll->n->right);
+				escassign(e, n, ll->n->right);
 		}
 		break;
 
 	case OSTRUCTLIT:
 		// Link values to struct.
 		for(ll=n->list; ll; ll=ll->next)
-			escassign(n, ll->n->right);
+			escassign(e, n, ll->n->right);
 		break;
 	
 	case OPTRLIT:
 		n->esc = EscNone;  // until proven otherwise
-		noesc = list(noesc, n);
-		n->escloopdepth = loopdepth;
+		e->noesc = list(e->noesc, n);
+		n->escloopdepth = e->loopdepth;
 		// Contents make it to memory, lose track.
-		escassign(&theSink, n->left);
+		escassign(e, &e->theSink, n->left);
 		break;
 
 	case OMAPLIT:
 		n->esc = EscNone;  // until proven otherwise
-		noesc = list(noesc, n);
-		n->escloopdepth = loopdepth;
+		e->noesc = list(e->noesc, n);
+		n->escloopdepth = e->loopdepth;
 		// Keys and values make it to memory, lose track.
 		for(ll=n->list; ll; ll=ll->next) {
-			escassign(&theSink, ll->n->left);
-			escassign(&theSink, ll->n->right);
+			escassign(e, &e->theSink, ll->n->left);
+			escassign(e, &e->theSink, ll->n->right);
 		}
 		break;
 	
 			a = nod(OADDR, ll->n->closure, N);
 			a->lineno = ll->n->lineno;
 			typecheck(&a, Erv);
-			escassign(n, a);
+			escassign(e, n, a);
 		}
 		// fallthrough
 	case OADDR:
 	case OMAKEMAP:
 	case OMAKESLICE:
 	case ONEW:
-		n->escloopdepth = loopdepth;
+		n->escloopdepth = e->loopdepth;
 		n->esc = EscNone;  // until proven otherwise
-		noesc = list(noesc, n);
+		e->noesc = list(e->noesc, n);
 		break;
 	}
 
 // evaluated in curfn.	For expr==nil, dst must still be examined for
 // evaluations inside it (e.g *f(x) = y)
 static void
-escassign(Node *dst, Node *src)
+escassign(EscState *e, Node *dst, Node *src)
 {
 	int lno;
 
 		return;
 
 	if(debug['m'] > 1)
-		print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, loopdepth,
+		print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth,
 		      (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src);
 
 	setlineno(dst);
 	
 	// Analyze lhs of assignment.
-	// Replace dst with theSink if we can't track it.
+	// Replace dst with e->theSink if we can't track it.
 	switch(dst->op) {
 	default:
 		dump("dst", dst);
 
 	case ONAME:
 		if(dst->class == PEXTERN)
-			dst = &theSink;
+			dst = &e->theSink;
 		break;
 	case ODOT:	      // treat "dst.x  = src" as "dst = src"
-		escassign(dst->left, src);
+		escassign(e, dst->left, src);
 		return;
 	case OINDEX:
 		if(isfixedarray(dst->left->type)) {
-			escassign(dst->left, src);
+			escassign(e, dst->left, src);
 			return;
 		}
-		dst = &theSink;  // lose track of dereference
+		dst = &e->theSink;  // lose track of dereference
 		break;
 	case OIND:
 	case ODOTPTR:
-		dst = &theSink;  // lose track of dereference
+		dst = &e->theSink;  // lose track of dereference
 		break;
 	case OINDEXMAP:
 		// lose track of key and value
-		escassign(&theSink, dst->right);
-		dst = &theSink;
+		escassign(e, &e->theSink, dst->right);
+		dst = &e->theSink;
 		break;
 	}
 
 	lno = setlineno(src);
-	pdepth++;
+	e->pdepth++;
 
 	switch(src->op) {
 	case OADDR:	// dst = &x
 	case OMAKESLICE:
 	case ONEW:
 	case OCLOSURE:
-		escflows(dst, src);
+		escflows(e, dst, src);
 		break;
 
 	case ODOT:
 	case OSLICE:
 	case OSLICEARR:
 		// Conversions, field access, slice all preserve the input value.
-		escassign(dst, src->left);
+		escassign(e, dst, src->left);
 		break;
 
 	case OAPPEND:
 		// Append returns first argument.
-		escassign(dst, src->list->n);
+		escassign(e, dst, src->list->n);
 		break;
 	
 	case OINDEX:
 		// Index of array preserves input value.
 		if(isfixedarray(src->left->type))
-			escassign(dst, src->left);
+			escassign(e, dst, src->left);
 		break;
 
 	case OADD:
 		// Might be pointer arithmetic, in which case
 		// the operands flow into the result.
 		// TODO(rsc): Decide what the story is here.  This is unsettling.
-		escassign(dst, src->left);
-		escassign(dst, src->right);
+		escassign(e, dst, src->left);
+		escassign(e, dst, src->right);
 		break;
-
 	}
 
-	pdepth--;
+	e->pdepth--;
 	lineno = lno;
 }
 
 // different for methods vs plain functions and for imported vs
 // this-package
 static void
-esccall(Node *n)
+esccall(EscState *e, Node *n)
 {
 	NodeList *ll, *lr;
 	Node *a, *fn, *src;
 		}
 	}
 			
-	if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype) {
-		// Local function.  Incorporate into flow graph.
+	if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
+		// Local function in this round.  Incorporate into flow graph.
+		if(fn->defn->esc == EscFuncUnknown)
+			fatal("graph inconsistency");
 
 		// Receiver.
 		if(n->op != OCALLFUNC)
-			escassign(fn->ntype->left->left, n->left->left);
+			escassign(e, fn->ntype->left->left, n->left->left);
 
 		for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
 			src = ll->n;
 			if(lr->n->isddd && !n->isddd) {
 				// Introduce ODDDARG node to represent ... allocation.
 				src = nod(ODDDARG, N, N);
-				src->escloopdepth = loopdepth;
+				src->escloopdepth = e->loopdepth;
 				src->lineno = n->lineno;
 				src->esc = EscNone;  // until we find otherwise
-				noesc = list(noesc, src);
+				e->noesc = list(e->noesc, src);
 				n->right = src;
 			}
 			if(lr->n->left != N)
-				escassign(lr->n->left, src);
+				escassign(e, lr->n->left, src);
 			if(src != ll->n)
 				break;
 		}
 		// "..." arguments are untracked
 		for(; ll; ll=ll->next)
-			escassign(&theSink, ll->n);
+			escassign(e, &e->theSink, ll->n);
 		return;
 	}
 
-	// Imported function.  Use the escape tags.
+	// Imported or completely analyzed function.  Use the escape tags.
 	if(n->op != OCALLFUNC) {
 		t = getthisx(fntype)->type;
 		if(!t->note || strcmp(t->note->s, safetag->s) != 0)
-			escassign(&theSink, n->left->left);
+			escassign(e, &e->theSink, n->left->left);
 	}
 	for(t=getinargx(fntype)->type; ll; ll=ll->next) {
 		src = ll->n;
 		if(t->isddd && !n->isddd) {
 			// Introduce ODDDARG node to represent ... allocation.
 			src = nod(ODDDARG, N, N);
-			src->escloopdepth = loopdepth;
+			src->escloopdepth = e->loopdepth;
 			src->lineno = n->lineno;
 			src->esc = EscNone;  // until we find otherwise
-			noesc = list(noesc, src);
+			e->noesc = list(e->noesc, src);
 			n->right = src;
 		}
 		if(!t->note || strcmp(t->note->s, safetag->s) != 0)
-			escassign(&theSink, src);
+			escassign(e, &e->theSink, src);
 		if(src != ll->n)
 			break;
 		t = t->down;
 	}
 	// "..." arguments are untracked
 	for(; ll; ll=ll->next)
-		escassign(&theSink, ll->n);
+		escassign(e, &e->theSink, ll->n);
 }
 
 // Store the link src->dst in dst, throwing out some quick wins.
 static void
-escflows(Node *dst, Node *src)
+escflows(EscState *e, Node *dst, Node *src)
 {
 	if(dst == nil || src == nil || dst == src)
 		return;
 		print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
 
 	if(dst->escflowsrc == nil) {
-		dsts = list(dsts, dst);
-		dstcount++;
+		e->dsts = list(e->dsts, dst);
+		e->dstcount++;
 	}
-	edgecount++;
+	e->edgecount++;
 
 	dst->escflowsrc = list(dst->escflowsrc, src);
 }
 // so this address doesn't leak (yet).
 // If level == 0, it means the /value/ of this node can reach the root of this flood.
 // so if this node is an OADDR, it's argument should be marked as escaping iff
-// it's currfn/loopdepth are different from the flood's root.
+// it's currfn/e->loopdepth are different from the flood's root.
 // Once an object has been moved to the heap, all of it's upstream should be considered
 // escaping to the global scope.
 static void
-escflood(Node *dst)
+escflood(EscState *e, Node *dst)
 {
 	NodeList *l;
 
 
 	for(l = dst->escflowsrc; l; l=l->next) {
 		walkgen++;
-		escwalk(0, dst, l->n);
+		escwalk(e, 0, dst, l->n);
 	}
 }
 
 static void
-escwalk(int level, Node *dst, Node *src)
+escwalk(EscState *e, int level, Node *dst, Node *src)
 {
 	NodeList *ll;
 	int leaks;
 
 	if(debug['m']>1)
 		print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
-		      level, pdepth, pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
+		      level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
 		      (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
 
-	pdepth++;
+	e->pdepth++;
 
 	leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth);
 
 		if(src->class == PPARAMREF) {
 			if(leaks && debug['m'])
 				warnl(src->lineno, "leaking closure reference %hN", src);
-			escwalk(level, dst, src->closure);
+			escwalk(e, level, dst, src->closure);
 		}
 		break;
 
 			if(debug['m'])
 				warnl(src->lineno, "%hN escapes to heap", src);
 		}