1. Joseph Poirier
  2. go

Commits

Joseph Poirier  committed 44627d9 Merge

Merged changes from golang.

  • Participants
  • Parent commits 0869ee8, 64b63f6
  • Branches default

Comments (0)

Files changed (62)

File CONTRIBUTORS

View file
 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>

File api/next.txt

View file
 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

File doc/install-source.html

View file
 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>
 

File doc/install.html

View file
 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>

File misc/emacs/go-mode.el

View file
             (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.

File src/cmd/5a/a.y

View file
 		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);
 	}

File src/cmd/5a/lex.c

View file
 	"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;
 

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

View file
       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);
 	}

File src/cmd/5c/list.c

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

File src/cmd/5g/cgen64.c

View file
 		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);

File src/cmd/5g/gobj.c

View file
 		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;

File src/cmd/5g/list.c

View file
 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)

File src/cmd/5g/peep.c

View file
 			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)

File src/cmd/5g/reg.c

View file
 		goto onereg;
 
 	case D_REGREG:
+	case D_REGREG2:
 		bit = zbits;
 		if(a->offset != NREG)
 			bit.b[0] |= RtoB(a->offset);

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

View file
 
 	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)

File src/cmd/5l/asm.c

View file
  		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);

File src/cmd/5l/l.h

View file
 	C_NONE		= 0,
 	C_REG,
 	C_REGREG,
+	C_REGREG2,
 	C_SHIFT,
 	C_FREG,
 	C_PSR,

File src/cmd/5l/list.c

View file
 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",

File src/cmd/5l/obj.c

View file
 		break;
 
 	case D_REGREG:
+	case D_REGREG2:
 		a->offset = BGETC(f);
 		break;
 

File src/cmd/5l/optab.c

View file
 	{ 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 },
 };

File src/cmd/5l/span.c

View file
 	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:

File src/cmd/6g/gobj.c

View file
 		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;

File src/cmd/8g/gobj.c

View file
 		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;

File src/cmd/api/goapi.go

View file
 	"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

File src/cmd/cgo/main.go

View file
 	"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.

File src/cmd/cgo/out.go

View file
 	}
 
 	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)
 		}

File src/cmd/gc/doc.go

View file
 	-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

File src/cmd/gc/esc.c

View file
 // 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;
 		}