public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: libgo patch committed: Update to current Go library
@ 2012-10-23 17:54 Uros Bizjak
  2012-10-23 18:09 ` Ian Lance Taylor
  2012-10-23 18:22 ` Ian Lance Taylor
  0 siblings, 2 replies; 25+ messages in thread
From: Uros Bizjak @ 2012-10-23 17:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Ian Lance Taylor, gofrontend-dev

Hello!

> I have committed a patch to update the mainline version of libgo to the
> current master Go library sources.  At this point I will only be
> updating the gcc 4.7 branch for bug fixes.
>
> This is a substantial patch that brings in several months of work.  As
> usual I am not posting the complete patch here, as it is mostly simply
> copies of changes to the upstream repository.  I have attached the
> changes to gccgo-specific files and files with lots of gccgo-specific
> changes.
>
> There is a decent change that this will break something on non-x86
> systems.  I will do what testing I am able to do after the commit.

On my x86_64-linux-gnu (Fedora 18) libgo testsuite fails following test:

--- FAIL: TestCgoCrashHandler (0.01 seconds)
testing.go:377:         program exited with error: exec: "go":
executable file not found in $PATH
--- FAIL: TestCrashHandler (0.00 seconds)
testing.go:377:         program exited with error: exec: "go":
executable file not found in $PATH
FAIL
FAIL: runtime

Probably some trivial test issue.

Additional test fails on alphaev68-linux-gnu:

--- FAIL: TestPassFD (0.15 seconds)
passfd_test.go:62:      FileConn: dup: Bad file descriptor
FAIL
FAIL: syscall

I didn't yet debug this one, will do soon.

Otherwise all other libgo tests pass on these two systems.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-23 17:54 libgo patch committed: Update to current Go library Uros Bizjak
@ 2012-10-23 18:09 ` Ian Lance Taylor
  2012-10-23 18:22 ` Ian Lance Taylor
  1 sibling, 0 replies; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-23 18:09 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 688 bytes --]

On Tue, Oct 23, 2012 at 10:47 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>
> On my x86_64-linux-gnu (Fedora 18) libgo testsuite fails following test:
>
> --- FAIL: TestCgoCrashHandler (0.01 seconds)
> testing.go:377:         program exited with error: exec: "go":
> executable file not found in $PATH
> --- FAIL: TestCrashHandler (0.00 seconds)
> testing.go:377:         program exited with error: exec: "go":
> executable file not found in $PATH
> FAIL
> FAIL: runtime

Thanks.  Turns out this test is currently meaningless with gccgo, and
was only working for me because I have the other Go compiler on my
PATH as well.  I committed this patch to mainline to disable it for
gccgo.

Ian

[-- Attachment #2: foo.patch --]
[-- Type: application/octet-stream, Size: 705 bytes --]

diff -r 29e06bafde95 libgo/go/runtime/crash_test.go
--- a/libgo/go/runtime/crash_test.go	Mon Oct 22 22:00:48 2012 -0700
+++ b/libgo/go/runtime/crash_test.go	Tue Oct 23 10:58:34 2012 -0700
@@ -7,7 +7,7 @@
 import (
 	"io/ioutil"
 	"os"
-	"os/exec"
+	// "os/exec"
 	"path/filepath"
 	"runtime"
 	"testing"
@@ -50,6 +50,9 @@
 	}
 	f.Close()
 
+	/*
+	 gccgo does not have a go command.
+
 	got, err := exec.Command("go", "run", src).CombinedOutput()
 	if err != nil {
 		t.Fatalf("program exited with error: %v\n%v", err, string(got))
@@ -58,6 +61,8 @@
 	if string(got) != string(want) {
 		t.Fatalf("expected %q, but got %q", string(want), string(got))
 	}
+
+	*/
 }
 
 func TestCrashHandler(t *testing.T) {

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-23 17:54 libgo patch committed: Update to current Go library Uros Bizjak
  2012-10-23 18:09 ` Ian Lance Taylor
@ 2012-10-23 18:22 ` Ian Lance Taylor
  2012-10-24  8:12   ` Uros Bizjak
  1 sibling, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-23 18:22 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches, gofrontend-dev

On Tue, Oct 23, 2012 at 10:47 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>
> Additional test fails on alphaev68-linux-gnu:
>
> --- FAIL: TestPassFD (0.15 seconds)
> passfd_test.go:62:      FileConn: dup: Bad file descriptor
> FAIL
> FAIL: syscall

As far as I can see this error message occurs when calling dup on the
second file descriptor returned by socketpair.  But I can't see why
that would fail on Alpha.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-23 18:22 ` Ian Lance Taylor
@ 2012-10-24  8:12   ` Uros Bizjak
  2012-10-24  8:22     ` Uros Bizjak
  2012-10-24  8:22     ` Uros Bizjak
  0 siblings, 2 replies; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24  8:12 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gofrontend-dev

On Tue, Oct 23, 2012 at 8:09 PM, Ian Lance Taylor <iant@google.com> wrote:
> On Tue, Oct 23, 2012 at 10:47 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>
>> Additional test fails on alphaev68-linux-gnu:
>>
>> --- FAIL: TestPassFD (0.15 seconds)
>> passfd_test.go:62:      FileConn: dup: Bad file descriptor
>> FAIL
>> FAIL: syscall
>
> As far as I can see this error message occurs when calling dup on the
> second file descriptor returned by socketpair.  But I can't see why
> that would fail on Alpha.

For some reason, the second dup on the same file descriptor fails.
Attached, please find strace dump, where:

...
gettimeofday({1351064744, 381316}, NULL) = 0
gettimeofday({1351064744, 381316}, NULL) = 0
gettimeofday({1351064744, 382293}, NULL) = 0
gettimeofday({1351064744, 382293}, NULL) = 0
gettimeofday({1351064744, 382293}, NULL) = 0
dup(4)                                  = 9
osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
mmap(NULL, 24704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x20003076000
mprotect(0x20003076000, 8192, PROT_NONE) = 0
clone(child_stack=0x2000307ab70,
flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
parent_tidptr=0x2000307b350, tls=0x2000307b970,
child_tidptr=0x2000307b350) = 21544
fcntl(9, F_SETFD, FD_CLOEXEC)           = 0
osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
sigreturn() (mask [SYS STOP TSTP IO USR2]) = 0
mmap(NULL, 24704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x2000307e000
mprotect(0x2000307e000, 8192, PROT_NONE) = 0
clone(child_stack=0x20003082b70,
flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
parent_tidptr=0x20003083350, tls=0x20003083970,
child_tidptr=0x20003083350) = 21545
futex(0x20000c4a450, FUTEX_WAIT, 0, NULL) = 0
sigreturn() (mask [ILL ABRT FPE KILL BUS ALRM URG CONT IO XCPU]) = 0
osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
futex(0xf84042b248, FUTEX_WAKE, 1)      = 1
wait4(21546, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, {ru_utime={0,
51757}, ru_stime={0, 21484}, ...}) = 21546
osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
close(9)                                = 0
dup(4)                                  = -1 EBADF (Bad file descriptor)
open("./a.out", O_RDONLY|O_CLOEXEC)     = 3
...

Is it OK to call dup on the same FD the second time?

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24  8:12   ` Uros Bizjak
  2012-10-24  8:22     ` Uros Bizjak
@ 2012-10-24  8:22     ` Uros Bizjak
  1 sibling, 0 replies; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24  8:22 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 740 bytes --]

On Wed, Oct 24, 2012 at 10:01 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Tue, Oct 23, 2012 at 8:09 PM, Ian Lance Taylor <iant@google.com> wrote:
>> On Tue, Oct 23, 2012 at 10:47 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>>
>>> Additional test fails on alphaev68-linux-gnu:
>>>
>>> --- FAIL: TestPassFD (0.15 seconds)
>>> passfd_test.go:62:      FileConn: dup: Bad file descriptor
>>> FAIL
>>> FAIL: syscall
>>
>> As far as I can see this error message occurs when calling dup on the
>> second file descriptor returned by socketpair.  But I can't see why
>> that would fail on Alpha.
>
> For some reason, the second dup on the same file descriptor fails.
> Attached, please find strace dump, where:

... Now attached for real.

Uros.

[-- Attachment #2: strace.txt.gz --]
[-- Type: application/x-gzip, Size: 4342 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24  8:12   ` Uros Bizjak
@ 2012-10-24  8:22     ` Uros Bizjak
  2012-10-24  8:31       ` Florian Weimer
  2012-10-24 12:31       ` Andreas Schwab
  2012-10-24  8:22     ` Uros Bizjak
  1 sibling, 2 replies; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24  8:22 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 10:01 AM, Uros Bizjak <ubizjak@gmail.com> wrote:

>>> Additional test fails on alphaev68-linux-gnu:
>>>
>>> --- FAIL: TestPassFD (0.15 seconds)
>>> passfd_test.go:62:      FileConn: dup: Bad file descriptor
>>> FAIL
>>> FAIL: syscall
>>
>> As far as I can see this error message occurs when calling dup on the
>> second file descriptor returned by socketpair.  But I can't see why
>> that would fail on Alpha.
>
> For some reason, the second dup on the same file descriptor fails.
> Attached, please find strace dump, where:
>
> ...
> gettimeofday({1351064744, 381316}, NULL) = 0
> gettimeofday({1351064744, 381316}, NULL) = 0
> gettimeofday({1351064744, 382293}, NULL) = 0
> gettimeofday({1351064744, 382293}, NULL) = 0
> gettimeofday({1351064744, 382293}, NULL) = 0
> dup(4)                                  = 9
> osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
> mmap(NULL, 24704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
> 0) = 0x20003076000
> mprotect(0x20003076000, 8192, PROT_NONE) = 0
> clone(child_stack=0x2000307ab70,
> flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
> parent_tidptr=0x2000307b350, tls=0x2000307b970,
> child_tidptr=0x2000307b350) = 21544
> fcntl(9, F_SETFD, FD_CLOEXEC)           = 0
> osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
> sigreturn() (mask [SYS STOP TSTP IO USR2]) = 0
> mmap(NULL, 24704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
> 0) = 0x2000307e000
> mprotect(0x2000307e000, 8192, PROT_NONE) = 0
> clone(child_stack=0x20003082b70,
> flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
> parent_tidptr=0x20003083350, tls=0x20003083970,
> child_tidptr=0x20003083350) = 21545
> futex(0x20000c4a450, FUTEX_WAIT, 0, NULL) = 0
> sigreturn() (mask [ILL ABRT FPE KILL BUS ALRM URG CONT IO XCPU]) = 0
> osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
> futex(0xf84042b248, FUTEX_WAKE, 1)      = 1
> wait4(21546, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, {ru_utime={0,
> 51757}, ru_stime={0, 21484}, ...}) = 21546
> osf_sigprocmask(SIG_BLOCK, [])          = 0 (old mask [])
> close(9)                                = 0
> dup(4)                                  = -1 EBADF (Bad file descriptor)
> open("./a.out", O_RDONLY|O_CLOEXEC)     = 3
> ...
>
> Is it OK to call dup on the same FD the second time?

To answer my own question:

dup(4)                                  = 9
...
close(9)                                = 0
dup(4)                                  = -1 EBADF (Bad file descriptor)

Test is calling dup on a closed file descriptor. FD 4 and 9 share file
status flags.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24  8:22     ` Uros Bizjak
@ 2012-10-24  8:31       ` Florian Weimer
  2012-10-24  8:44         ` Uros Bizjak
  2012-10-24 12:31       ` Andreas Schwab
  1 sibling, 1 reply; 25+ messages in thread
From: Florian Weimer @ 2012-10-24  8:31 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Ian Lance Taylor, gcc-patches, gofrontend-dev

On 10/24/2012 10:12 AM, Uros Bizjak wrote:

>> Is it OK to call dup on the same FD the second time?
>
> To answer my own question:
>
> dup(4)                                  = 9
> ...
> close(9)                                = 0
> dup(4)                                  = -1 EBADF (Bad file descriptor)
>
> Test is calling dup on a closed file descriptor. FD 4 and 9 share file
> status flags.

I suspect that this is something else because this works:

open("/dev/null", O_RDONLY)             = 3
dup(3)                                  = 4
close(4)                                = 0
dup(3)                                  = 4

#include <fcntl.h>
#include <unistd.h>

int
main(void)
{
   int fd1 = open("/dev/null", O_RDONLY);
   if (fd1 < 0) {
     perror("open");
     return 1;
   }
   int fd2 = dup(fd1);
   if (fd2 < 0) {
     perror("dup");
     return 1;
   }
   if (close(fd2) < 0) {
     perror("close");
     return 1;
   }
   int fd3 = dup(fd1);
   if (fd3 < 0) {
     perror("dup");
     return 1;
   }
   return 0;
}



-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24  8:31       ` Florian Weimer
@ 2012-10-24  8:44         ` Uros Bizjak
  0 siblings, 0 replies; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24  8:44 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Ian Lance Taylor, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 10:22 AM, Florian Weimer <fweimer@redhat.com> wrote:

>>> Is it OK to call dup on the same FD the second time?
>>
>>
>> To answer my own question:
>>
>> dup(4)                                  = 9
>> ...
>> close(9)                                = 0
>> dup(4)                                  = -1 EBADF (Bad file descriptor)
>>
>> Test is calling dup on a closed file descriptor. FD 4 and 9 share file
>> status flags.
>
>
> I suspect that this is something else because this works:

[...]

You are right, this example works on alpha, too.

Thanks,
Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24  8:22     ` Uros Bizjak
  2012-10-24  8:31       ` Florian Weimer
@ 2012-10-24 12:31       ` Andreas Schwab
  2012-10-24 13:06         ` Uros Bizjak
  1 sibling, 1 reply; 25+ messages in thread
From: Andreas Schwab @ 2012-10-24 12:31 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Ian Lance Taylor, gcc-patches, gofrontend-dev

Uros Bizjak <ubizjak@gmail.com> writes:

> To answer my own question:
>
> dup(4)                                  = 9
> ...
> close(9)                                = 0
> dup(4)                                  = -1 EBADF (Bad file descriptor)
>
> Test is calling dup on a closed file descriptor.

FD 4 is most likely closed by one of the cloned threads.  Use strace -f
to follow them.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 12:31       ` Andreas Schwab
@ 2012-10-24 13:06         ` Uros Bizjak
  2012-10-24 13:33           ` Ian Lance Taylor
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24 13:06 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Ian Lance Taylor, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 2:18 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
> Uros Bizjak <ubizjak@gmail.com> writes:
>
>> To answer my own question:
>>
>> dup(4)                                  = 9
>> ...
>> close(9)                                = 0
>> dup(4)                                  = -1 EBADF (Bad file descriptor)
>>
>> Test is calling dup on a closed file descriptor.
>
> FD 4 is most likely closed by one of the cloned threads.  Use strace -f
> to follow them.

Yes, indeed! Attached strace -f record confirms this on alpha.

The same happens on x86_64, but for some reason x86_64 doesn't
complain when executing dup(2) on closed FD.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 13:06         ` Uros Bizjak
@ 2012-10-24 13:33           ` Ian Lance Taylor
  2012-10-24 13:36             ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-24 13:33 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 5:31 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Oct 24, 2012 at 2:18 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
>> Uros Bizjak <ubizjak@gmail.com> writes:
>>
>>> To answer my own question:
>>>
>>> dup(4)                                  = 9
>>> ...
>>> close(9)                                = 0
>>> dup(4)                                  = -1 EBADF (Bad file descriptor)
>>>
>>> Test is calling dup on a closed file descriptor.
>>
>> FD 4 is most likely closed by one of the cloned threads.  Use strace -f
>> to follow them.
>
> Yes, indeed! Attached strace -f record confirms this on alpha.
>
> The same happens on x86_64, but for some reason x86_64 doesn't
> complain when executing dup(2) on closed FD.

The test execs itself by calling the fork and execve functions in
libc.  It is the child process that closes the FD after it forks.
From the point of view of the parent process, the FD should still be
open.  I don't think you attached the strace -f output so I can't
confirm this.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 13:33           ` Ian Lance Taylor
@ 2012-10-24 13:36             ` Uros Bizjak
  2012-10-24 14:50               ` Ian Lance Taylor
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24 13:36 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 1254 bytes --]

On Wed, Oct 24, 2012 at 3:10 PM, Ian Lance Taylor <iant@google.com> wrote:
> On Wed, Oct 24, 2012 at 5:31 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>> On Wed, Oct 24, 2012 at 2:18 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
>>> Uros Bizjak <ubizjak@gmail.com> writes:
>>>
>>>> To answer my own question:
>>>>
>>>> dup(4)                                  = 9
>>>> ...
>>>> close(9)                                = 0
>>>> dup(4)                                  = -1 EBADF (Bad file descriptor)
>>>>
>>>> Test is calling dup on a closed file descriptor.
>>>
>>> FD 4 is most likely closed by one of the cloned threads.  Use strace -f
>>> to follow them.
>>
>> Yes, indeed! Attached strace -f record confirms this on alpha.
>>
>> The same happens on x86_64, but for some reason x86_64 doesn't
>> complain when executing dup(2) on closed FD.
>
> The test execs itself by calling the fork and execve functions in
> libc.  It is the child process that closes the FD after it forks.
> From the point of view of the parent process, the FD should still be
> open.  I don't think you attached the strace -f output so I can't
> confirm this.

Eh, sorry, attached now.

After the second socketpair and before dup, there is a close in the same thread.

Uros.

[-- Attachment #2: strace.txt.gz --]
[-- Type: application/x-gzip, Size: 8524 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 13:36             ` Uros Bizjak
@ 2012-10-24 14:50               ` Ian Lance Taylor
  2012-10-24 16:47                 ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-24 14:50 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 6:19 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Oct 24, 2012 at 3:10 PM, Ian Lance Taylor <iant@google.com> wrote:
>> On Wed, Oct 24, 2012 at 5:31 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>> On Wed, Oct 24, 2012 at 2:18 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
>>>> Uros Bizjak <ubizjak@gmail.com> writes:
>>>>
>>>>> To answer my own question:
>>>>>
>>>>> dup(4)                                  = 9
>>>>> ...
>>>>> close(9)                                = 0
>>>>> dup(4)                                  = -1 EBADF (Bad file descriptor)
>>>>>
>>>>> Test is calling dup on a closed file descriptor.
>>>>
>>>> FD 4 is most likely closed by one of the cloned threads.  Use strace -f
>>>> to follow them.
>>>
>>> Yes, indeed! Attached strace -f record confirms this on alpha.
>>>
>>> The same happens on x86_64, but for some reason x86_64 doesn't
>>> complain when executing dup(2) on closed FD.
>>
>> The test execs itself by calling the fork and execve functions in
>> libc.  It is the child process that closes the FD after it forks.
>> From the point of view of the parent process, the FD should still be
>> open.  I don't think you attached the strace -f output so I can't
>> confirm this.
>
> Eh, sorry, attached now.
>
> After the second socketpair and before dup, there is a close in the same thread.

Thanks.  I agree.  Unfortunately, I can't figure out what is causing
it.  These seem to be the relevant calls.

16252 socketpair(PF_FILE, SOCK_STREAM, 0, [3, 4]) = 0

16252 clone(child_stack=0,
flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,
child_tidptr=0x20002f0ecd0) = 16259

16259 execve("./a.out", ["./a.out", "-test.run=^TestPassFD$", "--",
"/tmp/TestPassFD684357043"], [/* 33 vars */] <unfinished ...>

16252 clone( <unfinished ...>
16252 <... clone resumed> child_stack=0x200031e2b70,
flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
parent_tidptr=0x200031e3350, tls=0x200031e3970,
child_tidptr=0x200031e3350) = 16260

***** This is the bad call, but where does this come from?
16252 close(4 <unfinished ...>
16252 <... close resumed> )             = 0

16260 wait4(16259,  <unfinished ...>

16261 read(9,  <unfinished ...>

16259 sendmsg(5, {msg_name(0)=NULL, msg_iov(1)=[{"x", 1}],
msg_controllen=24, {cmsg_len=20, cmsg_level=SOL_SOCKET,
cmsg_type=SCM_RIGHTS, {9}}, msg_flags=0}, 0) = 1

16259 exit_group(0)                     = ?

16261 <... read resumed> "", 512)       = 0

16260 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0,
{ru_utime={0, 46875}, ru_stime={0, 26367}, ...}) = 16259

16261 dup(4)                            = -1 EBADF (Bad file descriptor)


Here is an approachj that might help.  Set a breakpoint on socketpair.
 The failure comes after the second call to socketpair, the one from
the function TestPassFD.  After that breakpoint is reached, set a
breakpoint on close.  Look for the call to close(4).  Get a backtrace
from there so we can see what is calling it.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 14:50               ` Ian Lance Taylor
@ 2012-10-24 16:47                 ` Uros Bizjak
  2012-10-24 17:55                   ` Ian Lance Taylor
  0 siblings, 1 reply; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24 16:47 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 4:30 PM, Ian Lance Taylor <iant@google.com> wrote:
> On Wed, Oct 24, 2012 at 6:19 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>> On Wed, Oct 24, 2012 at 3:10 PM, Ian Lance Taylor <iant@google.com> wrote:
>>> On Wed, Oct 24, 2012 at 5:31 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>>> On Wed, Oct 24, 2012 at 2:18 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
>>>>> Uros Bizjak <ubizjak@gmail.com> writes:
>>>>>
>>>>>> To answer my own question:
>>>>>>
>>>>>> dup(4)                                  = 9
>>>>>> ...
>>>>>> close(9)                                = 0
>>>>>> dup(4)                                  = -1 EBADF (Bad file descriptor)
>>>>>>
>>>>>> Test is calling dup on a closed file descriptor.
>>>>>
>>>>> FD 4 is most likely closed by one of the cloned threads.  Use strace -f
>>>>> to follow them.
>>>>
>>>> Yes, indeed! Attached strace -f record confirms this on alpha.
>>>>
>>>> The same happens on x86_64, but for some reason x86_64 doesn't
>>>> complain when executing dup(2) on closed FD.
>>>
>>> The test execs itself by calling the fork and execve functions in
>>> libc.  It is the child process that closes the FD after it forks.
>>> From the point of view of the parent process, the FD should still be
>>> open.  I don't think you attached the strace -f output so I can't
>>> confirm this.
>>
>> Eh, sorry, attached now.
>>
>> After the second socketpair and before dup, there is a close in the same thread.
>
> Thanks.  I agree.  Unfortunately, I can't figure out what is causing
> it.  These seem to be the relevant calls.
>
> 16252 socketpair(PF_FILE, SOCK_STREAM, 0, [3, 4]) = 0
>
> 16252 clone(child_stack=0,
> flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,
> child_tidptr=0x20002f0ecd0) = 16259
>
> 16259 execve("./a.out", ["./a.out", "-test.run=^TestPassFD$", "--",
> "/tmp/TestPassFD684357043"], [/* 33 vars */] <unfinished ...>
>
> 16252 clone( <unfinished ...>
> 16252 <... clone resumed> child_stack=0x200031e2b70,
> flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
> parent_tidptr=0x200031e3350, tls=0x200031e3970,
> child_tidptr=0x200031e3350) = 16260
>
> ***** This is the bad call, but where does this come from?
> 16252 close(4 <unfinished ...>
> 16252 <... close resumed> )             = 0
>
> 16260 wait4(16259,  <unfinished ...>
>
> 16261 read(9,  <unfinished ...>
>
> 16259 sendmsg(5, {msg_name(0)=NULL, msg_iov(1)=[{"x", 1}],
> msg_controllen=24, {cmsg_len=20, cmsg_level=SOL_SOCKET,
> cmsg_type=SCM_RIGHTS, {9}}, msg_flags=0}, 0) = 1
>
> 16259 exit_group(0)                     = ?
>
> 16261 <... read resumed> "", 512)       = 0
>
> 16260 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0,
> {ru_utime={0, 46875}, ru_stime={0, 26367}, ...}) = 16259
>
> 16261 dup(4)                            = -1 EBADF (Bad file descriptor)
>
>
> Here is an approachj that might help.  Set a breakpoint on socketpair.
>  The failure comes after the second call to socketpair, the one from
> the function TestPassFD.  After that breakpoint is reached, set a
> breakpoint on close.  Look for the call to close(4).  Get a backtrace
> from there so we can see what is calling it.

Continuing.
[New Thread 0x2000307b280 (LWP 8059)]

Breakpoint 18, 0x0000020002e378c0 in socketpair () from /lib/libc.so.6.1

Continuing.
[New Thread 0x20003083280 (LWP 8065)]
[Switching to Thread 0x20003083280 (LWP 8065)]

[...]

The first call with relevant FD is from:

Breakpoint 21, 0x0000020002e243f8 in close () from /lib/libc.so.6.1
(gdb) i r a0
a0             0x8      8
(gdb) bt
#0  0x0000020002e243f8 in close () from /lib/libc.so.6.1
#1  0x000000012003559c in syscall.Close (fd=<optimized out>) at libcalls.go:271
#2  0x00000200005d3cfc in os.close.pN7_os.file (file=0xf840414b70) at
../../../gcc-svn/trunk/libgo/go/os/file_unix.go:106
#3  0x0000020000888f18 in ffi_call_osf () at
../../../gcc-svn/trunk/libffi/src/alpha/osf.S:79
#4  0x00000200008889c4 in ffi_call (cif=<optimized out>, fn=<optimized
out>, rvalue=<optimized out>, avalue=0xf840c87fe8)
    at ../../../gcc-svn/trunk/libffi/src/alpha/ffi.c:169
#5  0x0000020000558204 in reflect.call (func_type=0x200009e9650
<__go_td_FppN7_os.fileerN5_erroree>,
    func_addr=0x200005d3c60 <os.close.pN7_os.file>,
is_interface=<optimized out>, is_method=<optimized out>,
    params=0xf840c87fe0, results=0x0) at
../../../gcc-svn/trunk/libgo/runtime/go-reflect-call.c:498
#6  0x00000200005620b8 in runfinq (dummy=<optimized out>) at
../../../gcc-svn/trunk/libgo/runtime/mgc0.c:1168
#7  0x0000020000566b20 in kickoff () at
../../../gcc-svn/trunk/libgo/runtime/proc.c:338
#8  0x0000020002d8d024 in ?? () from /lib/libc.so.6.1

[... dup call follows from the same thread ...]

Breakpoint 22, 0x0000020002e24e90 in dup () from /lib/libc.so.6.1
(gdb) i r a0
a0             0x8      8
(gdb) bt
#0  0x0000020002e24e90 in dup () from /lib/libc.so.6.1
#1  0x000000012003578c in syscall.Dup (oldfd=8) at libcalls.go:314
#2  0x00000200005b2794 in net.newFileFD (f=0xf8400004a0) at
../../../gcc-svn/trunk/libgo/go/net/file_unix.go:16
#3  0x00000200005c0dcc in net.FileConn (f=0x8) at
../../../gcc-svn/trunk/libgo/go/net/file_unix.go:78
#4  0x00000001200433e4 in syscall_test.TestPassFD (t.param=<optimized
out>) at passfd_test.go:60
#5  0x0000020000623920 in testing.tRunner (test=0xf840414978,
t.param=<optimized out>)
    at ../../../gcc-svn/trunk/libgo/go/testing/testing.go:301
#6  testing.$thunk7 (__go_thunk_parameter=<optimized out>) at
../../../gcc-svn/trunk/libgo/go/testing/testing.go:377
#7  0x0000020000566b20 in kickoff () at
../../../gcc-svn/trunk/libgo/runtime/proc.c:338
#8  0x0000020002d8d024 in ?? () from /lib/libc.so.6.1

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 16:47                 ` Uros Bizjak
@ 2012-10-24 17:55                   ` Ian Lance Taylor
  2012-10-24 17:58                     ` Uros Bizjak
  0 siblings, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-24 17:55 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 9:34 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>
> Continuing.
> [New Thread 0x2000307b280 (LWP 8059)]
>
> Breakpoint 18, 0x0000020002e378c0 in socketpair () from /lib/libc.so.6.1
>
> Continuing.
> [New Thread 0x20003083280 (LWP 8065)]
> [Switching to Thread 0x20003083280 (LWP 8065)]
>
> [...]
>
> The first call with relevant FD is from:
>
> Breakpoint 21, 0x0000020002e243f8 in close () from /lib/libc.so.6.1
> (gdb) i r a0
> a0             0x8      8

Does this mean that this is a call to close file descriptor 8?
According to the strace log, the file descriptor we care about is 4.
Although it is also true that I don't see a close of file descriptor 8
at all in the strace log.  Or is the change from 4 to 8 due somehow to
running the program under gdb?

> (gdb) bt
> #0  0x0000020002e243f8 in close () from /lib/libc.so.6.1
> #1  0x000000012003559c in syscall.Close (fd=<optimized out>) at libcalls.go:271
> #2  0x00000200005d3cfc in os.close.pN7_os.file (file=0xf840414b70) at
> ../../../gcc-svn/trunk/libgo/go/os/file_unix.go:106
> #3  0x0000020000888f18 in ffi_call_osf () at
> ../../../gcc-svn/trunk/libffi/src/alpha/osf.S:79
> #4  0x00000200008889c4 in ffi_call (cif=<optimized out>, fn=<optimized
> out>, rvalue=<optimized out>, avalue=0xf840c87fe8)
>     at ../../../gcc-svn/trunk/libffi/src/alpha/ffi.c:169
> #5  0x0000020000558204 in reflect.call (func_type=0x200009e9650
> <__go_td_FppN7_os.fileerN5_erroree>,
>     func_addr=0x200005d3c60 <os.close.pN7_os.file>,
> is_interface=<optimized out>, is_method=<optimized out>,
>     params=0xf840c87fe0, results=0x0) at
> ../../../gcc-svn/trunk/libgo/runtime/go-reflect-call.c:498
> #6  0x00000200005620b8 in runfinq (dummy=<optimized out>) at
> ../../../gcc-svn/trunk/libgo/runtime/mgc0.c:1168
> #7  0x0000020000566b20 in kickoff () at
> ../../../gcc-svn/trunk/libgo/runtime/proc.c:338
> #8  0x0000020002d8d024 in ?? () from /lib/libc.so.6.1

If this is indeed the file descriptor we care about, then this is
interesting, because it is being closed by a finalizer run by the
garbage collector.  That implies that the garbage collector collected
the local variable readFile in TestPassFD in passfd_test.go, which
would be clearly wrong.  Unfortunately this could be rather difficult
to debug.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 17:55                   ` Ian Lance Taylor
@ 2012-10-24 17:58                     ` Uros Bizjak
  2012-10-24 18:12                       ` Ian Lance Taylor
  2012-10-24 23:17                       ` Andreas Schwab
  0 siblings, 2 replies; 25+ messages in thread
From: Uros Bizjak @ 2012-10-24 17:58 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 7:46 PM, Ian Lance Taylor <iant@google.com> wrote:
> On Wed, Oct 24, 2012 at 9:34 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>
>> Continuing.
>> [New Thread 0x2000307b280 (LWP 8059)]
>>
>> Breakpoint 18, 0x0000020002e378c0 in socketpair () from /lib/libc.so.6.1
>>
>> Continuing.
>> [New Thread 0x20003083280 (LWP 8065)]
>> [Switching to Thread 0x20003083280 (LWP 8065)]
>>
>> [...]
>>
>> The first call with relevant FD is from:
>>
>> Breakpoint 21, 0x0000020002e243f8 in close () from /lib/libc.so.6.1
>> (gdb) i r a0
>> a0             0x8      8
>
> Does this mean that this is a call to close file descriptor 8?
> According to the strace log, the file descriptor we care about is 4.
> Although it is also true that I don't see a close of file descriptor 8
> at all in the strace log.  Or is the change from 4 to 8 due somehow to
> running the program under gdb?

Yes, I am running under gdb and all FDs are offset by +4 for some
reason. So, FD 8 corresponds to FD4 in the strace log.
>
>> (gdb) bt
>> #0  0x0000020002e243f8 in close () from /lib/libc.so.6.1
>> #1  0x000000012003559c in syscall.Close (fd=<optimized out>) at libcalls.go:271
>> #2  0x00000200005d3cfc in os.close.pN7_os.file (file=0xf840414b70) at
>> ../../../gcc-svn/trunk/libgo/go/os/file_unix.go:106
>> #3  0x0000020000888f18 in ffi_call_osf () at
>> ../../../gcc-svn/trunk/libffi/src/alpha/osf.S:79
>> #4  0x00000200008889c4 in ffi_call (cif=<optimized out>, fn=<optimized
>> out>, rvalue=<optimized out>, avalue=0xf840c87fe8)
>>     at ../../../gcc-svn/trunk/libffi/src/alpha/ffi.c:169
>> #5  0x0000020000558204 in reflect.call (func_type=0x200009e9650
>> <__go_td_FppN7_os.fileerN5_erroree>,
>>     func_addr=0x200005d3c60 <os.close.pN7_os.file>,
>> is_interface=<optimized out>, is_method=<optimized out>,
>>     params=0xf840c87fe0, results=0x0) at
>> ../../../gcc-svn/trunk/libgo/runtime/go-reflect-call.c:498
>> #6  0x00000200005620b8 in runfinq (dummy=<optimized out>) at
>> ../../../gcc-svn/trunk/libgo/runtime/mgc0.c:1168
>> #7  0x0000020000566b20 in kickoff () at
>> ../../../gcc-svn/trunk/libgo/runtime/proc.c:338
>> #8  0x0000020002d8d024 in ?? () from /lib/libc.so.6.1
>
> If this is indeed the file descriptor we care about, then this is
> interesting, because it is being closed by a finalizer run by the
> garbage collector.  That implies that the garbage collector collected
> the local variable readFile in TestPassFD in passfd_test.go, which
> would be clearly wrong.  Unfortunately this could be rather difficult
> to debug.

Yes, this is correct descriptor. For added fun, a descriptor that
corresponds to writeFile closes through the same mechanism.

Uros.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 17:58                     ` Uros Bizjak
@ 2012-10-24 18:12                       ` Ian Lance Taylor
  2012-10-24 21:12                         ` Ian Lance Taylor
  2012-10-24 23:17                       ` Andreas Schwab
  1 sibling, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-24 18:12 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Andreas Schwab, gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 10:52 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Oct 24, 2012 at 7:46 PM, Ian Lance Taylor <iant@google.com> wrote:
>> On Wed, Oct 24, 2012 at 9:34 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>>>
>>> Continuing.
>>> [New Thread 0x2000307b280 (LWP 8059)]
>>>
>>> Breakpoint 18, 0x0000020002e378c0 in socketpair () from /lib/libc.so.6.1
>>>
>>> Continuing.
>>> [New Thread 0x20003083280 (LWP 8065)]
>>> [Switching to Thread 0x20003083280 (LWP 8065)]
>>>
>>> [...]
>>>
>>> The first call with relevant FD is from:
>>>
>>> Breakpoint 21, 0x0000020002e243f8 in close () from /lib/libc.so.6.1
>>> (gdb) i r a0
>>> a0             0x8      8
>>
>> Does this mean that this is a call to close file descriptor 8?
>> According to the strace log, the file descriptor we care about is 4.
>> Although it is also true that I don't see a close of file descriptor 8
>> at all in the strace log.  Or is the change from 4 to 8 due somehow to
>> running the program under gdb?
>
> Yes, I am running under gdb and all FDs are offset by +4 for some
> reason. So, FD 8 corresponds to FD4 in the strace log.
>>
>>> (gdb) bt
>>> #0  0x0000020002e243f8 in close () from /lib/libc.so.6.1
>>> #1  0x000000012003559c in syscall.Close (fd=<optimized out>) at libcalls.go:271
>>> #2  0x00000200005d3cfc in os.close.pN7_os.file (file=0xf840414b70) at
>>> ../../../gcc-svn/trunk/libgo/go/os/file_unix.go:106
>>> #3  0x0000020000888f18 in ffi_call_osf () at
>>> ../../../gcc-svn/trunk/libffi/src/alpha/osf.S:79
>>> #4  0x00000200008889c4 in ffi_call (cif=<optimized out>, fn=<optimized
>>> out>, rvalue=<optimized out>, avalue=0xf840c87fe8)
>>>     at ../../../gcc-svn/trunk/libffi/src/alpha/ffi.c:169
>>> #5  0x0000020000558204 in reflect.call (func_type=0x200009e9650
>>> <__go_td_FppN7_os.fileerN5_erroree>,
>>>     func_addr=0x200005d3c60 <os.close.pN7_os.file>,
>>> is_interface=<optimized out>, is_method=<optimized out>,
>>>     params=0xf840c87fe0, results=0x0) at
>>> ../../../gcc-svn/trunk/libgo/runtime/go-reflect-call.c:498
>>> #6  0x00000200005620b8 in runfinq (dummy=<optimized out>) at
>>> ../../../gcc-svn/trunk/libgo/runtime/mgc0.c:1168
>>> #7  0x0000020000566b20 in kickoff () at
>>> ../../../gcc-svn/trunk/libgo/runtime/proc.c:338
>>> #8  0x0000020002d8d024 in ?? () from /lib/libc.so.6.1
>>
>> If this is indeed the file descriptor we care about, then this is
>> interesting, because it is being closed by a finalizer run by the
>> garbage collector.  That implies that the garbage collector collected
>> the local variable readFile in TestPassFD in passfd_test.go, which
>> would be clearly wrong.  Unfortunately this could be rather difficult
>> to debug.
>
> Yes, this is correct descriptor. For added fun, a descriptor that
> corresponds to writeFile closes through the same mechanism.

OK, so it's a garbage collector problem.  Can you e-mail me the test
binary offlist?  I will try to figure out where readFile lives.  The
fact that I'm not seeing any GC problems on x86 or x86_64 suggests
that this is something Alpha-specific.  Or, it could be something
specific to the non-split-stack code.  What's weird is that it's
unlikely to be a major error, since most of your tests pass.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 18:12                       ` Ian Lance Taylor
@ 2012-10-24 21:12                         ` Ian Lance Taylor
  0 siblings, 0 replies; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-24 21:12 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches, gofrontend-dev

On Wed, Oct 24, 2012 at 11:03 AM, Ian Lance Taylor <iant@google.com> wrote:
>
> OK, so it's a garbage collector problem.  Can you e-mail me the test
> binary offlist?  I will try to figure out where readFile lives.  The
> fact that I'm not seeing any GC problems on x86 or x86_64 suggests
> that this is something Alpha-specific.  Or, it could be something
> specific to the non-split-stack code.  What's weird is that it's
> unlikely to be a major error, since most of your tests pass.

Thanks for sending the binaries.  Unfortunately I don't see any
problems.  All the code looks reasonable, the registers should be on
the stack, and the garbage collector should see the stack.  I don't
see any way to make progress without doing some actual debugging.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-24 17:58                     ` Uros Bizjak
  2012-10-24 18:12                       ` Ian Lance Taylor
@ 2012-10-24 23:17                       ` Andreas Schwab
  1 sibling, 0 replies; 25+ messages in thread
From: Andreas Schwab @ 2012-10-24 23:17 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Ian Lance Taylor, gcc-patches, gofrontend-dev

Uros Bizjak <ubizjak@gmail.com> writes:

> Yes, I am running under gdb and all FDs are offset by +4 for some
> reason. So, FD 8 corresponds to FD4 in the strace log.

This is normal, gdb is leaking some fds to the inferior (which is a
bug).

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 25+ messages in thread

* libgo patch committed: Update to current Go library
@ 2013-11-27  7:17 Ian Lance Taylor
  0 siblings, 0 replies; 25+ messages in thread
From: Ian Lance Taylor @ 2013-11-27  7:17 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 230 bytes --]

This patch updates libgo to the current Go library sources, which will
almost certainly be the Go library included in the Go 1.2 release.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian


[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 23127 bytes --]

diff -r 827fb5004620 libgo/MERGE
--- a/libgo/MERGE	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/MERGE	Tue Nov 26 16:47:25 2013 -0800
@@ -1,4 +1,4 @@
-7ebbddd21330
+65bf677ab8d8
 
 The first line of this file holds the Mercurial revision number of the
 last merge done from the master library sources.
diff -r 827fb5004620 libgo/go/database/sql/driver/driver.go
--- a/libgo/go/database/sql/driver/driver.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/database/sql/driver/driver.go	Tue Nov 26 16:47:25 2013 -0800
@@ -140,8 +140,8 @@
 }
 
 // ColumnConverter may be optionally implemented by Stmt if the
-// the statement is aware of its own columns' types and can
-// convert from any type to a driver Value.
+// statement is aware of its own columns' types and can convert from
+// any type to a driver Value.
 type ColumnConverter interface {
 	// ColumnConverter returns a ValueConverter for the provided
 	// column index.  If the type of a specific column isn't known
diff -r 827fb5004620 libgo/go/database/sql/sql.go
--- a/libgo/go/database/sql/sql.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/database/sql/sql.go	Tue Nov 26 16:47:25 2013 -0800
@@ -201,7 +201,7 @@
 	connRequests *list.List // of connRequest
 	numOpen      int
 	pendingOpens int
-	// Used to sygnal the need for new connections
+	// Used to signal the need for new connections
 	// a goroutine running connectionOpener() reads on this chan and
 	// maybeOpenNewConnections sends on the chan (one send per needed connection)
 	// It is closed during db.Close(). The close tells the connectionOpener
@@ -1637,7 +1637,16 @@
 
 // A Result summarizes an executed SQL command.
 type Result interface {
+	// LastInsertId returns the integer generated by the database
+	// in response to a command. Typically this will be from an
+	// "auto increment" column when inserting a new row. Not all
+	// databases support this feature, and the syntax of such
+	// statements varies.
 	LastInsertId() (int64, error)
+
+	// RowsAffected returns the number of rows affected by an
+	// update, insert, or delete. Not every database or database
+	// driver may support this.
 	RowsAffected() (int64, error)
 }
 
diff -r 827fb5004620 libgo/go/debug/dwarf/const.go
--- a/libgo/go/debug/dwarf/const.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/debug/dwarf/const.go	Tue Nov 26 16:47:25 2013 -0800
@@ -207,9 +207,8 @@
 	formRef8        format = 0x14
 	formRefUdata    format = 0x15
 	formIndirect    format = 0x16
-	// following are defined in DWARF 4
 	formSecOffset   format = 0x17
-	formExprLoc     format = 0x18
+	formExprloc     format = 0x18
 	formFlagPresent format = 0x19
 	formRefSig8     format = 0x20
 )
diff -r 827fb5004620 libgo/go/debug/dwarf/entry.go
--- a/libgo/go/debug/dwarf/entry.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/debug/dwarf/entry.go	Tue Nov 26 16:47:25 2013 -0800
@@ -185,29 +185,15 @@
 		case formUdata:
 			val = int64(b.uint())
 
-		// exprloc
-		case formExprLoc:
-			val = b.bytes(int(b.uint()))
-
 		// flag
 		case formFlag:
 			val = b.uint8() == 1
+		// New in DWARF 4.
 		case formFlagPresent:
 			// The attribute is implicitly indicated as present, and no value is
 			// encoded in the debugging information entry itself.
 			val = true
 
-		// lineptr, loclistptr, macptr, rangelistptr
-		case formSecOffset:
-			is64, known := b.format.dwarf64()
-			if !known {
-				b.error("unknown size for DW_FORM_sec_offset")
-			} else if is64 {
-				val = Offset(b.uint64())
-			} else {
-				val = Offset(b.uint32())
-			}
-
 		// reference to other entry
 		case formRefAddr:
 			vers := b.format.version()
@@ -235,8 +221,6 @@
 			val = Offset(b.uint64()) + ubase
 		case formRefUdata:
 			val = Offset(b.uint()) + ubase
-		case formRefSig8:
-			val = b.uint64()
 
 		// string
 		case formString:
@@ -253,6 +237,30 @@
 				b.err = b1.err
 				return nil
 			}
+
+		// lineptr, loclistptr, macptr, rangelistptr
+		// New in DWARF 4, but clang can generate them with -gdwarf-2.
+		// Section reference, replacing use of formData4 and formData8.
+		case formSecOffset:
+			is64, known := b.format.dwarf64()
+			if !known {
+				b.error("unknown size for DW_FORM_sec_offset")
+			} else if is64 {
+				val = int64(b.uint64())
+			} else {
+				val = int64(b.uint32())
+			}
+
+		// exprloc
+		// New in DWARF 4.
+		case formExprloc:
+			val = b.bytes(int(b.uint()))
+
+		// reference
+		// New in DWARF 4.
+		case formRefSig8:
+			// 64-bit type signature.
+			val = b.uint64()
 		}
 		e.Field[i].Val = val
 	}
diff -r 827fb5004620 libgo/go/encoding/gob/doc.go
--- a/libgo/go/encoding/gob/doc.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/encoding/gob/doc.go	Tue Nov 26 16:47:25 2013 -0800
@@ -86,13 +86,13 @@
 at top the level will fail. A struct field of chan or func type is treated exactly
 like an unexported field and is ignored.
 
-Gob can encode a value of any type implementing the GobEncoder,
-encoding.BinaryMarshaler, or encoding.TextMarshaler interfaces by calling the
-corresponding method, in that order of preference.
+Gob can encode a value of any type implementing the GobEncoder or
+encoding.BinaryMarshaler interfaces by calling the corresponding method,
+in that order of preference.
 
-Gob can decode a value of any type implementing the GobDecoder,
-encoding.BinaryUnmarshaler, or encoding.TextUnmarshaler interfaces by calling
-the corresponding method, again in that order of preference.
+Gob can decode a value of any type implementing the GobDecoder or
+encoding.BinaryUnmarshaler interfaces by calling the corresponding method,
+again in that order of preference.
 
 Encoding Details
 
diff -r 827fb5004620 libgo/go/encoding/gob/gobencdec_test.go
--- a/libgo/go/encoding/gob/gobencdec_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/encoding/gob/gobencdec_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -11,6 +11,7 @@
 	"errors"
 	"fmt"
 	"io"
+	"net"
 	"strings"
 	"testing"
 	"time"
@@ -767,3 +768,17 @@
 		t.Fatalf("expected nil, got %v", err2)
 	}
 }
+
+func TestNetIP(t *testing.T) {
+	// Encoding of net.IP{1,2,3,4} in Go 1.1.
+	enc := []byte{0x07, 0x0a, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}
+
+	var ip net.IP
+	err := NewDecoder(bytes.NewReader(enc)).Decode(&ip)
+	if err != nil {
+		t.Fatalf("decode: %v", err)
+	}
+	if ip.String() != "1.2.3.4" {
+		t.Errorf("decoded to %v, want 1.2.3.4", ip.String())
+	}
+}
diff -r 827fb5004620 libgo/go/encoding/gob/type.go
--- a/libgo/go/encoding/gob/type.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/encoding/gob/type.go	Tue Nov 26 16:47:25 2013 -0800
@@ -88,18 +88,25 @@
 		ut.externalEnc, ut.encIndir = xGob, indir
 	} else if ok, indir := implementsInterface(ut.user, binaryMarshalerInterfaceType); ok {
 		ut.externalEnc, ut.encIndir = xBinary, indir
-	} else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok {
-		ut.externalEnc, ut.encIndir = xText, indir
 	}
 
+	// NOTE(rsc): Would like to allow MarshalText here, but results in incompatibility
+	// with older encodings for net.IP. See golang.org/issue/6760.
+	// } else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok {
+	// 	ut.externalEnc, ut.encIndir = xText, indir
+	// }
+
 	if ok, indir := implementsInterface(ut.user, gobDecoderInterfaceType); ok {
 		ut.externalDec, ut.decIndir = xGob, indir
 	} else if ok, indir := implementsInterface(ut.user, binaryUnmarshalerInterfaceType); ok {
 		ut.externalDec, ut.decIndir = xBinary, indir
-	} else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok {
-		ut.externalDec, ut.decIndir = xText, indir
 	}
 
+	// See note above.
+	// } else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok {
+	// 	ut.externalDec, ut.decIndir = xText, indir
+	// }
+
 	userTypeCache[rt] = ut
 	return
 }
diff -r 827fb5004620 libgo/go/encoding/xml/read.go
--- a/libgo/go/encoding/xml/read.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/encoding/xml/read.go	Tue Nov 26 16:47:25 2013 -0800
@@ -53,7 +53,7 @@
 //      Unmarshal records the attribute value in that field.
 //
 //   * If the XML element contains character data, that data is
-//      accumulated in the first struct field that has tag "chardata".
+//      accumulated in the first struct field that has tag ",chardata".
 //      The struct field may have type []byte or string.
 //      If there is no such field, the character data is discarded.
 //
diff -r 827fb5004620 libgo/go/go/doc/synopsis.go
--- a/libgo/go/go/doc/synopsis.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/go/doc/synopsis.go	Tue Nov 26 16:47:25 2013 -0800
@@ -22,6 +22,9 @@
 		if q == ' ' && p == '.' && (!unicode.IsUpper(pp) || unicode.IsUpper(ppp)) {
 			return i
 		}
+		if p == '。' || p == '.' {
+			return i
+		}
 		ppp, pp, p = pp, p, q
 	}
 	return len(s)
diff -r 827fb5004620 libgo/go/go/doc/synopsis_test.go
--- a/libgo/go/go/doc/synopsis_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/go/doc/synopsis_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -28,6 +28,8 @@
 	{"P. Q.   ", 8, "P. Q."},
 	{"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."},
 	{"Package こんにちは 世界\n", 31, "Package こんにちは 世界"},
+	{"Package こんにちは。世界", 26, "Package こんにちは。"},
+	{"Package 안녕.世界", 17, "Package 안녕."},
 	{"Package foo does bar.", 21, "Package foo does bar."},
 	{"Copyright 2012 Google, Inc. Package foo does bar.", 27, ""},
 	{"All Rights reserved. Package foo does bar.", 20, ""},
diff -r 827fb5004620 libgo/go/net/hosts_test.go
--- a/libgo/go/net/hosts_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/hosts_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -53,6 +53,19 @@
 	hostsPath = p
 }
 
+// https://code.google.com/p/go/issues/detail?id=6646
+func TestSingleLineHostsFile(t *testing.T) {
+	p := hostsPath
+	hostsPath = "testdata/hosts_singleline"
+
+	ips := lookupStaticHost("odin")
+	if len(ips) != 1 || ips[0] != "127.0.0.2" {
+		t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"})
+	}
+
+	hostsPath = p
+}
+
 func TestLookupHost(t *testing.T) {
 	// Can't depend on this to return anything in particular,
 	// but if it does return something, make sure it doesn't
diff -r 827fb5004620 libgo/go/net/http/httputil/dump.go
--- a/libgo/go/net/http/httputil/dump.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/http/httputil/dump.go	Tue Nov 26 16:47:25 2013 -0800
@@ -45,13 +45,27 @@
 func (c *dumpConn) SetReadDeadline(t time.Time) error  { return nil }
 func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
 
+type neverEnding byte
+
+func (b neverEnding) Read(p []byte) (n int, err error) {
+	for i := range p {
+		p[i] = byte(b)
+	}
+	return len(p), nil
+}
+
 // DumpRequestOut is like DumpRequest but includes
 // headers that the standard http.Transport adds,
 // such as User-Agent.
 func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 	save := req.Body
+	dummyBody := false
 	if !body || req.Body == nil {
 		req.Body = nil
+		if req.ContentLength != 0 {
+			req.Body = ioutil.NopCloser(io.LimitReader(neverEnding('x'), req.ContentLength))
+			dummyBody = true
+		}
 	} else {
 		var err error
 		save, req.Body, err = drainBody(req.Body)
@@ -99,7 +113,19 @@
 	if err != nil {
 		return nil, err
 	}
-	return buf.Bytes(), nil
+	dump := buf.Bytes()
+
+	// If we used a dummy body above, remove it now.
+	// TODO: if the req.ContentLength is large, we allocate memory
+	// unnecessarily just to slice it off here.  But this is just
+	// a debug function, so this is acceptable for now. We could
+	// discard the body earlier if this matters.
+	if dummyBody {
+		if i := bytes.Index(dump, []byte("\r\n\r\n")); i >= 0 {
+			dump = dump[:i+4]
+		}
+	}
+	return dump, nil
 }
 
 // delegateReader is a reader that delegates to another reader,
diff -r 827fb5004620 libgo/go/net/http/httputil/dump_test.go
--- a/libgo/go/net/http/httputil/dump_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/http/httputil/dump_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -20,6 +20,7 @@
 
 	WantDump    string
 	WantDumpOut string
+	NoBody      bool // if true, set DumpRequest{,Out} body to false
 }
 
 var dumpTests = []dumpTest{
@@ -83,6 +84,31 @@
 			"User-Agent: Go 1.1 package http\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 	},
+
+	// Request with Body, but Dump requested without it.
+	{
+		Req: http.Request{
+			Method: "POST",
+			URL: &url.URL{
+				Scheme: "http",
+				Host:   "post.tld",
+				Path:   "/",
+			},
+			ContentLength: 6,
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+		},
+
+		Body: []byte("abcdef"),
+
+		WantDumpOut: "POST / HTTP/1.1\r\n" +
+			"Host: post.tld\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
+			"Content-Length: 6\r\n" +
+			"Accept-Encoding: gzip\r\n\r\n",
+
+		NoBody: true,
+	},
 }
 
 func TestDumpRequest(t *testing.T) {
@@ -105,7 +131,7 @@
 
 		if tt.WantDump != "" {
 			setBody()
-			dump, err := DumpRequest(&tt.Req, true)
+			dump, err := DumpRequest(&tt.Req, !tt.NoBody)
 			if err != nil {
 				t.Errorf("DumpRequest #%d: %s", i, err)
 				continue
@@ -118,7 +144,7 @@
 
 		if tt.WantDumpOut != "" {
 			setBody()
-			dump, err := DumpRequestOut(&tt.Req, true)
+			dump, err := DumpRequestOut(&tt.Req, !tt.NoBody)
 			if err != nil {
 				t.Errorf("DumpRequestOut #%d: %s", i, err)
 				continue
diff -r 827fb5004620 libgo/go/net/parse.go
--- a/libgo/go/net/parse.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/parse.go	Tue Nov 26 16:47:25 2013 -0800
@@ -54,7 +54,7 @@
 		if n >= 0 {
 			f.data = f.data[0 : ln+n]
 		}
-		if err == io.EOF {
+		if err == io.EOF || err == io.ErrUnexpectedEOF {
 			f.atEOF = true
 		}
 	}
diff -r 827fb5004620 libgo/go/net/testdata/hosts_singleline
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/net/testdata/hosts_singleline	Tue Nov 26 16:47:25 2013 -0800
@@ -0,0 +1,1 @@
+127.0.0.2	odin
\ No newline at end of file
diff -r 827fb5004620 libgo/go/net/textproto/reader.go
--- a/libgo/go/net/textproto/reader.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/textproto/reader.go	Tue Nov 26 16:47:25 2013 -0800
@@ -574,13 +574,10 @@
 		// and upper case after each dash.
 		// (Host, User-Agent, If-Modified-Since).
 		// MIME headers are ASCII only, so no Unicode issues.
-		if a[i] == ' ' {
-			a[i] = '-'
-			upper = true
-			continue
-		}
 		c := a[i]
-		if upper && 'a' <= c && c <= 'z' {
+		if c == ' ' {
+			c = '-'
+		} else if upper && 'a' <= c && c <= 'z' {
 			c -= toLower
 		} else if !upper && 'A' <= c && c <= 'Z' {
 			c += toLower
diff -r 827fb5004620 libgo/go/net/textproto/reader_test.go
--- a/libgo/go/net/textproto/reader_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/textproto/reader_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -25,6 +25,10 @@
 	{"user-agent", "User-Agent"},
 	{"USER-AGENT", "User-Agent"},
 	{"üser-agenT", "üser-Agent"}, // non-ASCII unchanged
+
+	// This caused a panic due to mishandling of a space:
+	{"C Ontent-Transfer-Encoding", "C-Ontent-Transfer-Encoding"},
+	{"foo bar", "Foo-Bar"},
 }
 
 func TestCanonicalMIMEHeaderKey(t *testing.T) {
diff -r 827fb5004620 libgo/go/net/url/url.go
--- a/libgo/go/net/url/url.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/net/url/url.go	Tue Nov 26 16:47:25 2013 -0800
@@ -558,8 +558,8 @@
 	return err
 }
 
-// Encode encodes the values into ``URL encoded'' form.
-// e.g. "foo=bar&bar=baz"
+// Encode encodes the values into ``URL encoded'' form
+// ("bar=baz&foo=quux") sorted by key.
 func (v Values) Encode() string {
 	if v == nil {
 		return ""
diff -r 827fb5004620 libgo/go/os/file_unix.go
--- a/libgo/go/os/file_unix.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/os/file_unix.go	Tue Nov 26 16:47:25 2013 -0800
@@ -176,14 +176,11 @@
 	fi = make([]FileInfo, len(names))
 	for i, filename := range names {
 		fip, lerr := lstat(dirname + filename)
-		if lerr == nil {
-			fi[i] = fip
-		} else {
+		if lerr != nil {
 			fi[i] = &fileStat{name: filename}
-			if err == nil {
-				err = lerr
-			}
+			continue
 		}
+		fi[i] = fip
 	}
 	return fi, err
 }
diff -r 827fb5004620 libgo/go/os/os_unix_test.go
--- a/libgo/go/os/os_unix_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/os/os_unix_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -92,8 +92,8 @@
 	defer func() { *LstatP = Lstat }()
 
 	dirs, err := handle.Readdir(-1)
-	if err != ErrInvalid {
-		t.Fatalf("Expected Readdir to return ErrInvalid, got %v", err)
+	if err != nil {
+		t.Fatalf("Expected Readdir to return no error, got %v", err)
 	}
 	foundfail := false
 	for _, dir := range dirs {
diff -r 827fb5004620 libgo/go/runtime/pprof/pprof_test.go
--- a/libgo/go/runtime/pprof/pprof_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/runtime/pprof/pprof_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -8,6 +8,7 @@
 	"bytes"
 	"fmt"
 	"hash/crc32"
+	"math/big"
 	"os/exec"
 	"regexp"
 	"runtime"
@@ -123,6 +124,10 @@
 		}
 	})
 
+	if len(need) == 0 {
+		return
+	}
+
 	var total uintptr
 	for i, name := range need {
 		total += have[i]
@@ -237,6 +242,26 @@
 	}
 }
 
+// Test that profiling of division operations is okay, especially on ARM. See issue 6681.
+func TestMathBigDivide(t *testing.T) {
+	testCPUProfile(t, nil, func() {
+		t := time.After(5 * time.Second)
+		pi := new(big.Int)
+		for {
+			for i := 0; i < 100; i++ {
+				n := big.NewInt(2646693125139304345)
+				d := big.NewInt(842468587426513207)
+				pi.Div(n, d)
+			}
+			select {
+			case <-t:
+				return
+			default:
+			}
+		}
+	})
+}
+
 // Operating systems that are expected to fail the tests. See issue 6047.
 var badOS = map[string]bool{
 	"darwin":  true,
diff -r 827fb5004620 libgo/go/strings/replace.go
--- a/libgo/go/strings/replace.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/strings/replace.go	Tue Nov 26 16:47:25 2013 -0800
@@ -364,17 +364,18 @@
 
 func (r *singleStringReplacer) Replace(s string) string {
 	var buf []byte
-	i := 0
+	i, matched := 0, false
 	for {
 		match := r.finder.next(s[i:])
 		if match == -1 {
 			break
 		}
+		matched = true
 		buf = append(buf, s[i:i+match]...)
 		buf = append(buf, r.value...)
 		i += match + len(r.finder.pattern)
 	}
-	if buf == nil {
+	if !matched {
 		return s
 	}
 	buf = append(buf, s[i:]...)
diff -r 827fb5004620 libgo/go/strings/replace_test.go
--- a/libgo/go/strings/replace_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/strings/replace_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -261,10 +261,21 @@
 	testCases = append(testCases,
 		testCase{abcMatcher, "", ""},
 		testCase{abcMatcher, "ab", "ab"},
+		testCase{abcMatcher, "abc", "[match]"},
 		testCase{abcMatcher, "abcd", "[match]d"},
 		testCase{abcMatcher, "cabcabcdabca", "c[match][match]d[match]a"},
 	)
 
+	// Issue 6659 cases (more single string replacer)
+
+	noHello := NewReplacer("Hello", "")
+	testCases = append(testCases,
+		testCase{noHello, "Hello", ""},
+		testCase{noHello, "Hellox", "x"},
+		testCase{noHello, "xHello", "x"},
+		testCase{noHello, "xHellox", "xx"},
+	)
+
 	// No-arg test cases.
 
 	nop := NewReplacer()
diff -r 827fb5004620 libgo/go/testing/testing.go
--- a/libgo/go/testing/testing.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/testing/testing.go	Tue Nov 26 16:47:25 2013 -0800
@@ -73,17 +73,19 @@
 //
 // Example functions without output comments are compiled but not executed.
 //
-// The naming convention to declare examples for a function F, a type T and
+// The naming convention to declare examples for the package, a function F, a type T and
 // method M on type T are:
 //
+//     func Example() { ... }
 //     func ExampleF() { ... }
 //     func ExampleT() { ... }
 //     func ExampleT_M() { ... }
 //
-// Multiple example functions for a type/function/method may be provided by
+// Multiple example functions for a package/type/function/method may be provided by
 // appending a distinct suffix to the name. The suffix must start with a
 // lower-case letter.
 //
+//     func Example_suffix() { ... }
 //     func ExampleF_suffix() { ... }
 //     func ExampleT_suffix() { ... }
 //     func ExampleT_M_suffix() { ... }
diff -r 827fb5004620 libgo/go/time/export_test.go
--- a/libgo/go/time/export_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/time/export_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -18,4 +18,7 @@
 	localOnce.Do(initTestingZone)
 }
 
-var ParseTimeZone = parseTimeZone
+var (
+	ForceZipFileForTesting = forceZipFileForTesting
+	ParseTimeZone          = parseTimeZone
+)
diff -r 827fb5004620 libgo/go/time/time_test.go
--- a/libgo/go/time/time_test.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/time/time_test.go	Tue Nov 26 16:47:25 2013 -0800
@@ -578,6 +578,18 @@
 	}
 }
 
+func TestLoadLocationZipFile(t *testing.T) {
+	t.Skip("gccgo does not use the zip file")
+
+	ForceZipFileForTesting(true)
+	defer ForceZipFileForTesting(false)
+
+	_, err := LoadLocation("Australia/Sydney")
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 var rubyTests = []ParseTest{
 	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
 	// Ignore the time zone in the test. If it parses, it'll be OK.
diff -r 827fb5004620 libgo/go/time/zoneinfo_plan9.go
--- a/libgo/go/time/zoneinfo_plan9.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/time/zoneinfo_plan9.go	Tue Nov 26 16:47:25 2013 -0800
@@ -154,3 +154,7 @@
 	}
 	return nil, errors.New("unknown time zone " + name)
 }
+
+func forceZipFileForTesting(zipOnly bool) {
+	// We only use the zip file anyway.
+}
diff -r 827fb5004620 libgo/go/time/zoneinfo_unix.go
--- a/libgo/go/time/zoneinfo_unix.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/time/zoneinfo_unix.go	Tue Nov 26 16:47:25 2013 -0800
@@ -28,7 +28,19 @@
 	"/usr/share/zoneinfo/",
 	"/usr/share/lib/zoneinfo/",
 	"/usr/lib/locale/TZ/",
-	runtime.GOROOT() + "/lib/time/zoneinfo/",
+	runtime.GOROOT() + "/lib/time/zoneinfo.zip",
+}
+
+var origZoneDirs = zoneDirs
+
+func forceZipFileForTesting(zipOnly bool) {
+	zoneDirs = make([]string, len(origZoneDirs))
+	copy(zoneDirs, origZoneDirs)
+	if zipOnly {
+		for i := 0; i < len(zoneDirs)-1; i++ {
+			zoneDirs[i] = "/XXXNOEXIST"
+		}
+	}
 }
 
 func initLocal() {
diff -r 827fb5004620 libgo/go/time/zoneinfo_windows.go
--- a/libgo/go/time/zoneinfo_windows.go	Tue Nov 26 15:22:17 2013 -0800
+++ b/libgo/go/time/zoneinfo_windows.go	Tue Nov 26 16:47:25 2013 -0800
@@ -264,3 +264,7 @@
 	}
 	return nil, errors.New("unknown time zone " + name)
 }
+
+func forceZipFileForTesting(zipOnly bool) {
+	// We only use the zip file anyway.
+}

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-25  9:50 ` Rainer Orth
@ 2012-10-25 18:31   ` Ian Lance Taylor
  0 siblings, 0 replies; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-25 18:31 UTC (permalink / raw)
  To: Rainer Orth; +Cc: gcc-patches, gofrontend-dev

On Thu, Oct 25, 2012 at 2:36 AM, Rainer Orth
<ro@cebitec.uni-bielefeld.de> wrote:
> Ian Lance Taylor <iant@google.com> writes:
>
>> There is a decent change that this will break something on non-x86
>> systems.  I will do what testing I am able to do after the commit.
>
> As expected, it did break the Solaris libgo build:
>
> * udpsock_posix.go lacked definitions of joinIPv4Group, joinIPv6Group,
>   setIPv6MulticastInterface, setIPv6MulticastLoopback.  It turned out
>   that sockoptip_solaris.go isn't needed any longer, but
>   sockoptip_posix.go can be used instead.
>
> * Solaris lacked some stat_atim*.go in go/archive/tar initially.  With
>   stat_atim.go used, it didn't build initially.  Since Stat_t.[AC]tim
>   are Timestruc, we need a corresponding Unix(), now provided in
>   syscall_solaris.go.
>
> With those changes, libgo builds again, and Solaris/x86 testsuite
> results are reasonable:

Thanks.  I committed your patch to mainline.

Ian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: libgo patch committed: Update to current Go library
  2012-10-23  5:14 Ian Lance Taylor
@ 2012-10-25  9:50 ` Rainer Orth
  2012-10-25 18:31   ` Ian Lance Taylor
  0 siblings, 1 reply; 25+ messages in thread
From: Rainer Orth @ 2012-10-25  9:50 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 3348 bytes --]

Ian Lance Taylor <iant@google.com> writes:

> There is a decent change that this will break something on non-x86
> systems.  I will do what testing I am able to do after the commit.

As expected, it did break the Solaris libgo build:

* udpsock_posix.go lacked definitions of joinIPv4Group, joinIPv6Group,
  setIPv6MulticastInterface, setIPv6MulticastLoopback.  It turned out
  that sockoptip_solaris.go isn't needed any longer, but
  sockoptip_posix.go can be used instead.

* Solaris lacked some stat_atim*.go in go/archive/tar initially.  With
  stat_atim.go used, it didn't build initially.  Since Stat_t.[AC]tim
  are Timestruc, we need a corresponding Unix(), now provided in
  syscall_solaris.go.

With those changes, libgo builds again, and Solaris/x86 testsuite
results are reasonable:

FAIL: net

--- FAIL: TestMulticastListener (0.03 seconds)
multicast_posix_test.go:72:     "224.0.0.254:12345" not found in RIB

FAIL: syscall

creds_test.go:22:41: error: reference to undefined identifier 'syscall.AF_LOCAL'
  fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
                                         ^
creds_test.go:29:66: error: reference to undefined identifier 'syscall.SO_PASSCRED'
  err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1)
                                                                  ^
creds_test.go:48:12: error: reference to undefined identifier 'syscall.Ucred'
  var ucred syscall.Ucred
            ^
creds_test.go:53:18: error: reference to undefined identifier 'syscall.UnixCredentials'
   oob := syscall.UnixCredentials(&ucred)
                  ^
creds_test.go:63:17: error: reference to undefined identifier 'syscall.UnixCredentials'
  oob := syscall.UnixCredentials(&ucred)
                 ^
creds_test.go:102:27: error: reference to undefined identifier 'syscall.ParseUnixCredentials'
  newUcred, err := syscall.ParseUnixCredentials(&scm[0])
                           ^
passfd_test.go:40:41: error: reference to undefined identifier 'syscall.AF_LOCAL'
  fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
                                         ^

Needs some porting work, it seems.

FAIL: net/http

unexpected fault address unexpected fault address 0x7f079d14be59unexpected fault address 0x7ffffd140410
0x7f079bb4bed9unexpected fault address unexpected fault address Illegal Instruction

0x7ffffd140410
0x7f079d54be59



goroutine 1 [chan receive]:
main.main
        /var/gcc/regression/trunk/10-gcc/build/i386-pc-solaris2.10/amd64/libgo/gotest29238/test/_testmain.go:159

and many more goroutine stacks...

FAIL: runtime/pprof

Reported as PR go/54873 already.

On the other hand, many Solaris/SPARC tests are failing:

unexpected fault address 0xfcb70dec
throw: fault
[signal 0xa code=0x1 addr=0xfcb70dec]

goroutine 4 [running]:
unexpected fault address 0xfcb71864
panic during panic
FAIL: log

Still have to investigate what's going on.

	Rainer


2012-10-23  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	* Makefile.am [LIBGO_IS_SOLARIS] (go_net_sockoptip_file): Replace
	go/net/sockoptip_solaris.go by go/net/sockoptip_posix.go.
	[LIBGO_IS_SOLARIS] (archive_tar_atim_file): Use
	go/archive/tar/stat_atim.go.
	* Makefile.in: Regenerate.
	* go/net/sockoptip_solaris.go: Remove.
	* go/syscall/syscall_solaris.go: New file.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sol2-libgo-bootstrap.patch --]
[-- Type: text/x-patch, Size: 1400 bytes --]

# HG changeset patch
# Parent e8a7c94c7461ab7d5fc572468b69feddbb338069
Restore Solaris bootstrap

diff --git a/libgo/Makefile.am b/libgo/Makefile.am
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -704,7 +704,7 @@ if LIBGO_IS_SOLARIS
 go_net_cgo_file = go/net/cgo_linux.go
 go_net_sock_file = go/net/sock_solaris.go
 go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_solaris.go
+go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
 else
 if LIBGO_IS_FREEBSD
 go_net_cgo_file = go/net/cgo_bsd.go
@@ -968,6 +968,9 @@ endif
 if LIBGO_IS_OPENBSD
 archive_tar_atim_file = go/archive/tar/stat_atim.go
 endif
+if LIBGO_IS_SOLARIS
+archive_tar_atim_file = go/archive/tar/stat_atim.go
+endif
 if LIBGO_IS_DARWIN
 archive_tar_atim_file = go/archive/tar/stat_atimespec.go
 endif
diff --git a/libgo/go/syscall/syscall_solaris.go b/libgo/go/syscall/syscall_solaris.go
new file mode 100644
--- /dev/null
+++ b/libgo/go/syscall/syscall_solaris.go
@@ -0,0 +1,13 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func (ts *Timestruc) Unix() (sec int64, nsec int64) {
+	return int64(ts.Sec), int64(ts.Nsec)
+}
+
+func (ts *Timestruc) Nano() int64 {
+	return int64(ts.Sec)*1e9 + int64(ts.Nsec)
+}

[-- Attachment #3: Type: text/plain, Size: 144 bytes --]



-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

^ permalink raw reply	[flat|nested] 25+ messages in thread

* libgo patch committed: Update to current Go library
@ 2012-10-23  5:14 Ian Lance Taylor
  2012-10-25  9:50 ` Rainer Orth
  0 siblings, 1 reply; 25+ messages in thread
From: Ian Lance Taylor @ 2012-10-23  5:14 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 697 bytes --]

I have committed a patch to update the mainline version of libgo to the
current master Go library sources.  At this point I will only be
updating the gcc 4.7 branch for bug fixes.

This is a substantial patch that brings in several months of work.  As
usual I am not posting the complete patch here, as it is mostly simply
copies of changes to the upstream repository.  I have attached the
changes to gccgo-specific files and files with lots of gccgo-specific
changes.

There is a decent change that this will break something on non-x86
systems.  I will do what testing I am able to do after the commit.

Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 138257 bytes --]

diff -r bf12a7f41b67 go/gogo.cc
--- a/go/gogo.cc	Sun Oct 07 21:29:09 2012 -0700
+++ b/go/gogo.cc	Mon Oct 22 17:36:23 2012 -0700
@@ -1251,6 +1251,7 @@
   this->package_->bindings()->clear_file_scope();
 
   // Warn about packages which were imported but not used.
+  bool quiet = saw_errors();
   for (Packages::iterator p = this->packages_.begin();
        p != this->packages_.end();
        ++p)
@@ -1260,7 +1261,7 @@
 	  && package->is_imported()
 	  && !package->used()
 	  && !package->uses_sink_alias()
-	  && !saw_errors())
+	  && !quiet)
 	error_at(package->location(), "imported and not used: %s",
 		 Gogo::message_name(package->package_name()).c_str());
       package->clear_is_imported();
diff -r bf12a7f41b67 go/runtime.cc
--- a/go/runtime.cc	Sun Oct 07 21:29:09 2012 -0700
+++ b/go/runtime.cc	Mon Oct 22 17:36:23 2012 -0700
@@ -32,6 +32,8 @@
   RFT_BOOLPTR,
   // Go type int, C type int.
   RFT_INT,
+  // Go type int32, C type int32_t.
+  RFT_INT32,
   // Go type int64, C type int64_t.
   RFT_INT64,
   // Go type uint64, C type uint64_t.
@@ -102,6 +104,10 @@
 	  t = Type::lookup_integer_type("int");
 	  break;
 
+	case RFT_INT32:
+	  t = Type::lookup_integer_type("int32");
+	  break;
+
 	case RFT_INT64:
 	  t = Type::lookup_integer_type("int64");
 	  break;
@@ -206,6 +212,7 @@
     case RFT_BOOL:
     case RFT_BOOLPTR:
     case RFT_INT:
+    case RFT_INT32:
     case RFT_INT64:
     case RFT_UINT64:
     case RFT_UINTPTR:
diff -r bf12a7f41b67 go/runtime.def
--- a/go/runtime.def	Sun Oct 07 21:29:09 2012 -0700
+++ b/go/runtime.def	Mon Oct 22 17:36:23 2012 -0700
@@ -148,27 +148,28 @@
 
 
 // Start building a select statement.
-DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT), R1(POINTER))
+DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT32), R1(POINTER))
 
 // Add a default clause to a select statement.
-DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P2(POINTER, INT), R0())
+DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault",
+	       P2(POINTER, INT32), R0())
 
 // Add a send clause to a select statement.
 DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend",
-	       P4(POINTER, CHAN, POINTER, INT), R0())
+	       P4(POINTER, CHAN, POINTER, INT32), R0())
 
 // Add a receive clause to a select statement, for a clause which does
 // not check whether the channel is closed.
 DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv",
-	       P4(POINTER, CHAN, POINTER, INT), R0())
+	       P4(POINTER, CHAN, POINTER, INT32), R0())
 
 // Add a receive clause to a select statement, for a clause which does
 // check whether the channel is closed.
 DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2",
-	       P5(POINTER, CHAN, POINTER, BOOLPTR, INT), R0())
+	       P5(POINTER, CHAN, POINTER, BOOLPTR, INT32), R0())
 
 // Run a select, returning the index of the selected clause.
-DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT))
+DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT32))
 
 
 // Panic.
diff -r bf12a7f41b67 go/statements.cc
--- a/go/statements.cc	Sun Oct 07 21:29:09 2012 -0700
+++ b/go/statements.cc	Mon Oct 22 17:36:23 2012 -0700
@@ -4841,6 +4841,8 @@
   std::vector<std::vector<Bexpression*> > cases(count);
   std::vector<Bstatement*> clauses(count);
 
+  Type* int32_type = Type::lookup_integer_type("int32");
+
   int i = 0;
   for (Clauses::iterator p = this->clauses_.begin();
        p != this->clauses_.end();
@@ -4849,7 +4851,8 @@
       int index = p->index();
       mpz_t ival;
       mpz_init_set_ui(ival, index);
-      Expression* index_expr = Expression::make_integer(&ival, NULL, location);
+      Expression* index_expr = Expression::make_integer(&ival, int32_type,
+							location);
       mpz_clear(ival);
       cases[i].push_back(tree_to_expr(index_expr->get_tree(context)));
 
diff -r bf12a7f41b67 libgo/MERGE
--- a/libgo/MERGE	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/MERGE	Mon Oct 22 17:36:23 2012 -0700
@@ -1,4 +1,4 @@
-2d8bc3c94ecb
+291d9f1baf75
 
 The first line of this file holds the Mercurial revision number of the
 last merge done from the master library sources.
diff -r bf12a7f41b67 libgo/Makefile.am
--- a/libgo/Makefile.am	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/Makefile.am	Mon Oct 22 17:36:23 2012 -0700
@@ -230,6 +230,21 @@
 	exp/types.gox \
 	exp/utf8string.gox
 
+toolexeclibgoexphtmldir = $(toolexeclibgoexpdir)/html
+
+toolexeclibgoexphtml_DATA = \
+	exp/html/atom.gox
+
+toolexeclibgoexplocaledir = $(toolexeclibgoexpdir)/locale
+
+toolexeclibgoexplocale_DATA = \
+	exp/locale/collate.gox
+
+toolexeclibgoexplocalecollatedir = $(toolexeclibgoexplocaledir)/collate
+
+toolexeclibgoexplocalecollate_DATA = \
+	exp/locale/collate/build.gox
+
 toolexeclibgogodir = $(toolexeclibgodir)/go
 
 toolexeclibgogo_DATA = \
@@ -483,6 +498,7 @@
 	runtime/go-unwind.c \
 	runtime/chan.c \
 	runtime/cpuprof.c \
+	runtime/lfstack.c \
 	$(runtime_lock_files) \
 	runtime/mcache.c \
 	runtime/mcentral.c \
@@ -492,6 +508,8 @@
 	runtime/mgc0.c \
 	runtime/mheap.c \
 	runtime/msize.c \
+	runtime/panic.c \
+	runtime/parfor.c \
 	runtime/print.c \
 	runtime/proc.c \
 	runtime/runtime.c \
@@ -656,16 +674,16 @@
 else # !LIBGO_IS_RTEMS
 if LIBGO_IS_LINUX
 go_net_fd_os_file = go/net/fd_linux.go
-go_net_newpollserver_file = go/net/newpollserver.go
+go_net_newpollserver_file = go/net/newpollserver_unix.go
 else # !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
 if LIBGO_IS_NETBSD
 go_net_fd_os_file = go/net/fd_netbsd.go
-go_net_newpollserver_file = go/net/newpollserver.go
+go_net_newpollserver_file = go/net/newpollserver_unix.go
 else # !LIBGO_IS_NETBSD && !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
 # By default use select with pipes.  Most systems should have
 # something better.
 go_net_fd_os_file = go/net/fd_select.go
-go_net_newpollserver_file = go/net/newpollserver.go
+go_net_newpollserver_file = go/net/newpollserver_unix.go
 endif # !LIBGO_IS_NETBSD
 endif # !LIBGO_IS_LINUX
 endif # !LIBGO_IS_RTEMS
@@ -674,13 +692,13 @@
 go_net_cgo_file = go/net/cgo_linux.go
 go_net_sock_file = go/net/sock_linux.go
 go_net_sockopt_file = go/net/sockopt_linux.go
-go_net_sockoptip_file = go/net/sockoptip_linux.go
+go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
 else
 if LIBGO_IS_IRIX
 go_net_cgo_file = go/net/cgo_linux.go
 go_net_sock_file = go/net/sock_linux.go
 go_net_sockopt_file = go/net/sockopt_linux.go
-go_net_sockoptip_file = go/net/sockoptip_linux.go
+go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
 else
 if LIBGO_IS_SOLARIS
 go_net_cgo_file = go/net/cgo_linux.go
@@ -692,12 +710,19 @@
 go_net_cgo_file = go/net/cgo_bsd.go
 go_net_sock_file = go/net/sock_bsd.go
 go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_freebsd.go
+go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
+else
+if LIBGO_IS_NETBSD
+go_net_cgo_file = go/net/cgo_netbsd.go
+go_net_sock_file = go/net/sock_bsd.go
+go_net_sockopt_file = go/net/sockopt_bsd.go
+go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
 else
 go_net_cgo_file = go/net/cgo_bsd.go
 go_net_sock_file = go/net/sock_bsd.go
 go_net_sockopt_file = go/net/sockopt_bsd.go
-go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_netbsd.go
+go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go
+endif
 endif
 endif
 endif
@@ -706,8 +731,12 @@
 if LIBGO_IS_LINUX
 go_net_sendfile_file = go/net/sendfile_linux.go
 else
+if LIBGO_IS_FREEBSD
+go_net_sendfile_file = go/net/sendfile_freebsd.go
+else
 go_net_sendfile_file = go/net/sendfile_stub.go
 endif
+endif
 
 if LIBGO_IS_LINUX
 go_net_interface_file = go/net/interface_linux.go
@@ -725,13 +754,12 @@
 	go/net/dial.go \
 	go/net/dnsclient.go \
 	go/net/dnsclient_unix.go \
-	go/net/dnsconfig.go \
+	go/net/dnsconfig_unix.go \
 	go/net/dnsmsg.go \
-	go/net/doc.go \
 	$(go_net_newpollserver_file) \
-	go/net/fd.go \
+	go/net/fd_unix.go \
 	$(go_net_fd_os_file) \
-	go/net/file.go \
+	go/net/file_unix.go \
 	go/net/hosts.go \
 	go/net/interface.go \
 	$(go_net_interface_file) \
@@ -740,6 +768,7 @@
 	go/net/iprawsock_posix.go \
 	go/net/ipsock.go \
 	go/net/ipsock_posix.go \
+	go/net/lookup.go \
 	go/net/lookup_unix.go \
 	go/net/mac.go \
 	go/net/net.go \
@@ -747,12 +776,12 @@
 	go/net/parse.go \
 	go/net/pipe.go \
 	go/net/port.go \
+	go/net/port_unix.go \
 	$(go_net_sendfile_file) \
-	go/net/sock.go \
+	go/net/sock_posix.go \
 	$(go_net_sock_file) \
-	go/net/sockopt.go \
+	go/net/sockopt_posix.go \
 	$(go_net_sockopt_file) \
-	go/net/sockoptip.go \
 	$(go_net_sockoptip_file) \
 	go/net/tcpsock.go \
 	go/net/tcpsock_posix.go \
@@ -831,6 +860,7 @@
 
 go_reflect_files = \
 	go/reflect/deepequal.go \
+	go/reflect/makefunc.go \
 	go/reflect/type.go \
 	go/reflect/value.go
 
@@ -882,12 +912,14 @@
 go_strings_files = \
 	go/strings/reader.go \
 	go/strings/replace.go \
+	go/strings/search.go \
 	go/strings/strings.go
 
 go_sync_files = \
 	go/sync/cond.go \
 	go/sync/mutex.go \
 	go/sync/once.go \
+	go/sync/race0.go \
 	go/sync/runtime.go \
 	go/sync/rwmutex.go \
 	go/sync/waitgroup.go
@@ -930,11 +962,28 @@
 	go/unicode/letter.go \
 	go/unicode/tables.go
 
+if LIBGO_IS_LINUX
+archive_tar_atim_file = go/archive/tar/stat_atim.go
+endif
+if LIBGO_IS_OPENBSD
+archive_tar_atim_file = go/archive/tar/stat_atim.go
+endif
+if LIBGO_IS_DARWIN
+archive_tar_atim_file = go/archive/tar/stat_atimespec.go
+endif
+if LIBGO_IS_FREEBSD
+archive_tar_atim_file = go/archive/tar/stat_atimespec.go
+endif
+if LIBGO_IS_NETBSD
+archive_tar_atim_file = go/archive/tar/stat_atimespec.go
+endif
 
 go_archive_tar_files = \
 	go/archive/tar/common.go \
 	go/archive/tar/reader.go \
-	go/archive/tar/writer.go
+	go/archive/tar/stat_unix.go \
+	go/archive/tar/writer.go \
+	$(archive_tar_atim_file)
 
 go_archive_zip_files = \
 	go/archive/zip/reader.go \
@@ -948,6 +997,7 @@
 	go/compress/bzip2/move_to_front.go
 
 go_compress_flate_files = \
+	go/compress/flate/copy.go \
 	go/compress/flate/deflate.go \
 	go/compress/flate/huffman_bit_writer.go \
 	go/compress/flate/huffman_code.go \
@@ -979,6 +1029,7 @@
 go_crypto_aes_files = \
 	go/crypto/aes/block.go \
 	go/crypto/aes/cipher.go \
+	go/crypto/aes/cipher_generic.go \
 	go/crypto/aes/const.go
 go_crypto_cipher_files = \
 	go/crypto/cipher/cbc.go \
@@ -1033,9 +1084,11 @@
 	go/crypto/tls/handshake_server.go \
 	go/crypto/tls/key_agreement.go \
 	go/crypto/tls/prf.go \
+	go/crypto/tls/ticket.go \
 	go/crypto/tls/tls.go
 go_crypto_x509_files = \
 	go/crypto/x509/cert_pool.go \
+	go/crypto/x509/pem_decrypt.go \
 	go/crypto/x509/pkcs1.go \
 	go/crypto/x509/pkcs8.go \
 	go/crypto/x509/root.go \
@@ -1130,8 +1183,26 @@
 	go/exp/html/parse.go \
 	go/exp/html/render.go \
 	go/exp/html/token.go
+go_exp_html_atom_files = \
+	go/exp/html/atom/atom.go \
+	go/exp/html/atom/table.go
 go_exp_inotify_files = \
 	go/exp/inotify/inotify_linux.go
+go_exp_locale_collate_files = \
+	go/exp/locale/collate/colelem.go \
+	go/exp/locale/collate/collate.go \
+	go/exp/locale/collate/contract.go \
+	go/exp/locale/collate/export.go \
+	go/exp/locale/collate/table.go \
+	go/exp/locale/collate/tables.go \
+	go/exp/locale/collate/trie.go
+go_exp_locale_collate_build_files = \
+	go/exp/locale/collate/build/builder.go \
+	go/exp/locale/collate/build/colelem.go \
+	go/exp/locale/collate/build/contract.go \
+	go/exp/locale/collate/build/order.go \
+	go/exp/locale/collate/build/table.go \
+	go/exp/locale/collate/build/trie.go
 go_exp_norm_files = \
 	go/exp/norm/composition.go \
 	go/exp/norm/forminfo.go \
@@ -1161,6 +1232,7 @@
 
 go_go_ast_files = \
 	go/go/ast/ast.go \
+	go/go/ast/commentmap.go \
 	go/go/ast/filter.go \
 	go/go/ast/import.go \
 	go/go/ast/print.go \
@@ -1170,6 +1242,7 @@
 go_go_build_files = \
 	go/go/build/build.go \
 	go/go/build/doc.go \
+	go/go/build/read.go \
 	syslist.go
 go_go_doc_files = \
 	go/go/doc/comment.go \
@@ -1235,6 +1308,7 @@
 	go/image/jpeg/writer.go
 
 go_image_png_files = \
+	go/image/png/paeth.go \
 	go/image/png/reader.go \
 	go/image/png/writer.go
 
@@ -1243,6 +1317,7 @@
 	go/index/suffixarray/suffixarray.go
 
 go_io_ioutil_files = \
+	go/io/ioutil/blackhole.go \
 	go/io/ioutil/ioutil.go \
 	go/io/ioutil/tempfile.go
 
@@ -1358,6 +1433,7 @@
 
 go_regexp_syntax_files = \
 	go/regexp/syntax/compile.go \
+	go/regexp/syntax/doc.go \
 	go/regexp/syntax/parse.go \
 	go/regexp/syntax/perl_groups.go \
 	go/regexp/syntax/prog.go \
@@ -1544,6 +1620,7 @@
 	go/syscall/syscall_errno.go \
 	go/syscall/libcall_support.go \
 	go/syscall/libcall_posix.go \
+	go/syscall/race0.go \
 	go/syscall/socket.go \
 	go/syscall/sockcmsg_unix.go \
 	go/syscall/str.go \
@@ -1714,6 +1791,9 @@
 	encoding/xml.lo \
 	exp/ebnf.lo \
 	exp/html.lo \
+	exp/html/atom.lo \
+	exp/locale/collate.lo \
+	exp/locale/collate/build.lo \
 	exp/norm.lo \
 	exp/proxy.lo \
 	exp/terminal.lo \
@@ -2562,6 +2642,33 @@
 	@$(CHECK)
 .PHONY: exp/html/check
 
+@go_include@ exp/html/atom.lo.dep
+exp/html/atom.lo.dep: $(go_exp_html_atom_files)
+	$(BUILDDEPS)
+exp/html/atom.lo: $(go_exp_html_atom_files)
+	$(BUILDPACKAGE)
+exp/html/atom/check: $(CHECK_DEPS)
+	@$(CHECK)
+.PHONY: exp/html/atom/check
+
+@go_include@ exp/locale/collate.lo.dep
+exp/locale/collate.lo.dep: $(go_exp_locale_collate_files)
+	$(BUILDDEPS)
+exp/locale/collate.lo: $(go_exp_locale_collate_files)
+	$(BUILDPACKAGE)
+exp/locale/collate/check: $(CHECK_DEPS)
+	@$(CHECK)
+.PHONY: exp/locale/collate/check
+
+@go_include@ exp/locale/collate/build.lo.dep
+exp/locale/collate/build.lo.dep: $(go_exp_locale_collate_build_files)
+	$(BUILDDEPS)
+exp/locale/collate/build.lo: $(go_exp_locale_collate_build_files)
+	$(BUILDPACKAGE)
+exp/locale/collate/build/check: $(CHECK_DEPS)
+	@$(CHECK)
+.PHONY: exp/locale/collate/build/check
+
 @go_include@ exp/norm.lo.dep
 exp/norm.lo.dep: $(go_exp_norm_files)
 	$(BUILDDEPS)
@@ -3142,6 +3249,9 @@
 syscall/wait.lo: go/syscall/wait.c
 	@$(MKDIR_P) syscall
 	$(LTCOMPILE) -c -o $@ $<
+syscall/check: $(CHECK_DEPS)
+	@$(CHECK)
+.PHONY: syscall/check
 
 # How to build a .gox file from a .lo file.
 BUILDGOX = \
@@ -3310,8 +3420,14 @@
 	$(BUILDGOX)
 exp/html.gox: exp/html.lo
 	$(BUILDGOX)
+exp/html/atom.gox: exp/html/atom.lo
+	$(BUILDGOX)
 exp/inotify.gox: exp/inotify.lo
 	$(BUILDGOX)
+exp/locale/collate.gox: exp/locale/collate.lo
+	$(BUILDGOX)
+exp/locale/collate/build.gox: exp/locale/collate/build.lo
+	$(BUILDGOX)
 exp/norm.gox: exp/norm.lo
 	$(BUILDGOX)
 exp/proxy.gox: exp/proxy.lo
@@ -3484,6 +3600,7 @@
 	strconv/check \
 	strings/check \
 	sync/check \
+	syscall/check \
 	time/check \
 	unicode/check \
 	archive/tar/check \
@@ -3532,10 +3649,14 @@
 	encoding/xml/check \
 	exp/ebnf/check \
 	exp/html/check \
+	exp/html/atom/check \
 	$(exp_inotify_check) \
+	exp/locale/collate/check \
+	exp/locale/collate/build/check \
 	exp/norm/check \
 	exp/proxy/check \
 	exp/terminal/check \
+	exp/types/check \
 	exp/utf8string/check \
 	html/template/check \
 	go/ast/check \
diff -r bf12a7f41b67 libgo/configure.ac
--- a/libgo/configure.ac	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/configure.ac	Mon Oct 22 17:36:23 2012 -0700
@@ -129,6 +129,7 @@
 is_irix=no
 is_linux=no
 is_netbsd=no
+is_openbsd=no
 is_rtems=no
 is_solaris=no
 GOOS=unknown
@@ -138,6 +139,7 @@
   *-*-irix6*)    is_irix=yes;    GOOS=irix ;;
   *-*-linux*)    is_linux=yes;   GOOS=linux ;;
   *-*-netbsd*)	 is_netbsd=yes;  GOOS=netbsd ;;
+  *-*-openbsd*)  is_openbsd=yes; GOOS=openbsd ;;
   *-*-rtems*)    is_rtems=yes;   GOOS=rtems ;;
   *-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
 esac
@@ -146,6 +148,7 @@
 AM_CONDITIONAL(LIBGO_IS_IRIX, test $is_irix = yes)
 AM_CONDITIONAL(LIBGO_IS_LINUX, test $is_linux = yes)
 AM_CONDITIONAL(LIBGO_IS_NETBSD, test $is_netbsd = yes)
+AM_CONDITIONAL(LIBGO_IS_OPENBSD, test $is_openbsd = yes)
 AM_CONDITIONAL(LIBGO_IS_RTEMS, test $is_rtems = yes)
 AM_CONDITIONAL(LIBGO_IS_SOLARIS, test $is_solaris = yes)
 AC_SUBST(GOOS)
diff -r bf12a7f41b67 libgo/runtime/chan.c
--- a/libgo/runtime/chan.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/chan.c	Mon Oct 22 17:36:23 2012 -0700
@@ -4,8 +4,9 @@
 
 #include "runtime.h"
 #include "arch.h"
+#include "go-type.h"
+#include "race.h"
 #include "malloc.h"
-#include "go-type.h"
 
 #define	NOSELGEN	1
 
@@ -24,6 +25,7 @@
 	G*	g;		// g and selgen constitute
 	uint32	selgen;		// a weak pointer to g
 	SudoG*	link;
+	int64	releasetime;
 	byte*	elem;		// data element
 };
 
@@ -35,13 +37,13 @@
 
 struct	Hchan
 {
-	uint32	qcount;			// total data in the q
-	uint32	dataqsiz;		// size of the circular q
+	uintgo	qcount;			// total data in the q
+	uintgo	dataqsiz;		// size of the circular q
 	uint16	elemsize;
 	bool	closed;
 	uint8	elemalign;
-	uint32	sendx;			// send index
-	uint32	recvx;			// receive index
+	uintgo	sendx;			// send index
+	uintgo	recvx;			// receive index
 	WaitQ	recvq;			// list of recv waiters
 	WaitQ	sendq;			// list of send waiters
 	Lock;
@@ -80,17 +82,22 @@
 static	void	dequeueg(WaitQ*);
 static	SudoG*	dequeue(WaitQ*);
 static	void	enqueue(WaitQ*, SudoG*);
+static	void	racesync(Hchan*, SudoG*);
 
 Hchan*
 runtime_makechan_c(ChanType *t, int64 hint)
 {
 	Hchan *c;
-	int32 n;
+	uintptr n;
 	const Type *elem;
 
 	elem = t->__element_type;
 
-	if(hint < 0 || (int32)hint != hint || (elem->__size > 0 && (uintptr)hint > MaxMem / elem->__size))
+	// compiler checks this but be safe.
+	if(elem->__size >= (1<<16))
+		runtime_throw("makechan: invalid channel element type");
+
+	if(hint < 0 || (intgo)hint != hint || (elem->__size > 0 && (uintptr)hint > MaxMem / elem->__size))
 		runtime_panicstring("makechan: size out of range");
 
 	n = sizeof(*c);
@@ -102,19 +109,19 @@
 	c->dataqsiz = hint;
 
 	if(debug)
-		runtime_printf("makechan: chan=%p; elemsize=%D; elemalign=%d; dataqsiz=%d\n",
-			c, (int64)elem->__size, elem->__align, c->dataqsiz);
+		runtime_printf("makechan: chan=%p; elemsize=%D; elemalign=%d; dataqsiz=%D\n",
+			c, (int64)elem->__size, elem->__align, (int64)c->dataqsiz);
 
 	return c;
 }
 
 // For reflect
-//	func makechan(typ *ChanType, size uint32) (chan)
-uintptr reflect_makechan(ChanType *, uint32)
+//	func makechan(typ *ChanType, size uint64) (chan)
+uintptr reflect_makechan(ChanType *, uint64)
   asm ("reflect.makechan");
 
 uintptr
-reflect_makechan(ChanType *t, uint32 size)
+reflect_makechan(ChanType *t, uint64 size)
 {
 	void *ret;
 	Hchan *c;
@@ -153,11 +160,12 @@
  * the operation; we'll see that it's now closed.
  */
 void
-runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres)
+runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
 {
 	SudoG *sg;
 	SudoG mysg;
 	G* gp;
+	int64 t0;
 	G* g;
 
 	g = runtime_g();
@@ -168,9 +176,7 @@
 			*pres = false;
 			return;
 		}
-		g->status = Gwaiting;
-		g->waitreason = "chan send (nil chan)";
-		runtime_gosched();
+		runtime_park(nil, nil, "chan send (nil chan)");
 		return;  // not reached
 	}
 
@@ -181,7 +187,17 @@
 		runtime_printf("chansend: chan=%p\n", c);
 	}
 
+	t0 = 0;
+	mysg.releasetime = 0;
+	if(runtime_blockprofilerate > 0) {
+		t0 = runtime_cputicks();
+		mysg.releasetime = -1;
+	}
+
 	runtime_lock(c);
+	// TODO(dvyukov): add similar instrumentation to select.
+	if(raceenabled)
+		runtime_racereadpc(c, pc);
 	if(c->closed)
 		goto closed;
 
@@ -190,12 +206,16 @@
 
 	sg = dequeue(&c->recvq);
 	if(sg != nil) {
+		if(raceenabled)
+			racesync(c, sg);
 		runtime_unlock(c);
 
 		gp = sg->g;
 		gp->param = sg;
 		if(sg->elem != nil)
 			runtime_memmove(sg->elem, ep, c->elemsize);
+		if(sg->releasetime)
+			sg->releasetime = runtime_cputicks();
 		runtime_ready(gp);
 
 		if(pres != nil)
@@ -213,11 +233,8 @@
 	mysg.g = g;
 	mysg.selgen = NOSELGEN;
 	g->param = nil;
-	g->status = Gwaiting;
-	g->waitreason = "chan send";
 	enqueue(&c->sendq, &mysg);
-	runtime_unlock(c);
-	runtime_gosched();
+	runtime_park(runtime_unlock, c, "chan send");
 
 	if(g->param == nil) {
 		runtime_lock(c);
@@ -226,6 +243,9 @@
 		goto closed;
 	}
 
+	if(mysg.releasetime > 0)
+		runtime_blockevent(mysg.releasetime - t0, 2);
+
 	return;
 
 asynch:
@@ -241,15 +261,16 @@
 		mysg.g = g;
 		mysg.elem = nil;
 		mysg.selgen = NOSELGEN;
-		g->status = Gwaiting;
-		g->waitreason = "chan send";
 		enqueue(&c->sendq, &mysg);
-		runtime_unlock(c);
-		runtime_gosched();
+		runtime_park(runtime_unlock, c, "chan send");
 
 		runtime_lock(c);
 		goto asynch;
 	}
+
+	if(raceenabled)
+		runtime_racerelease(chanbuf(c, c->sendx));
+
 	runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize);
 	if(++c->sendx == c->dataqsiz)
 		c->sendx = 0;
@@ -259,11 +280,15 @@
 	if(sg != nil) {
 		gp = sg->g;
 		runtime_unlock(c);
+		if(sg->releasetime)
+			sg->releasetime = runtime_cputicks();
 		runtime_ready(gp);
 	} else
 		runtime_unlock(c);
 	if(pres != nil)
 		*pres = true;
+	if(mysg.releasetime > 0)
+		runtime_blockevent(mysg.releasetime - t0, 2);
 	return;
 
 closed:
@@ -278,6 +303,7 @@
 	SudoG *sg;
 	SudoG mysg;
 	G *gp;
+	int64 t0;
 	G *g;
 
 	if(runtime_gcwaiting)
@@ -294,12 +320,17 @@
 			*selected = false;
 			return;
 		}
-		g->status = Gwaiting;
-		g->waitreason = "chan receive (nil chan)";
-		runtime_gosched();
+		runtime_park(nil, nil, "chan receive (nil chan)");
 		return;  // not reached
 	}
 
+	t0 = 0;
+	mysg.releasetime = 0;
+	if(runtime_blockprofilerate > 0) {
+		t0 = runtime_cputicks();
+		mysg.releasetime = -1;
+	}
+
 	runtime_lock(c);
 	if(c->dataqsiz > 0)
 		goto asynch;
@@ -309,12 +340,16 @@
 
 	sg = dequeue(&c->sendq);
 	if(sg != nil) {
+		if(raceenabled)
+			racesync(c, sg);
 		runtime_unlock(c);
 
 		if(ep != nil)
 			runtime_memmove(ep, sg->elem, c->elemsize);
 		gp = sg->g;
 		gp->param = sg;
+		if(sg->releasetime)
+			sg->releasetime = runtime_cputicks();
 		runtime_ready(gp);
 
 		if(selected != nil)
@@ -334,11 +369,8 @@
 	mysg.g = g;
 	mysg.selgen = NOSELGEN;
 	g->param = nil;
-	g->status = Gwaiting;
-	g->waitreason = "chan receive";
 	enqueue(&c->recvq, &mysg);
-	runtime_unlock(c);
-	runtime_gosched();
+	runtime_park(runtime_unlock, c, "chan receive");
 
 	if(g->param == nil) {
 		runtime_lock(c);
@@ -349,6 +381,8 @@
 
 	if(received != nil)
 		*received = true;
+	if(mysg.releasetime > 0)
+		runtime_blockevent(mysg.releasetime - t0, 2);
 	return;
 
 asynch:
@@ -366,15 +400,16 @@
 		mysg.g = g;
 		mysg.elem = nil;
 		mysg.selgen = NOSELGEN;
-		g->status = Gwaiting;
-		g->waitreason = "chan receive";
 		enqueue(&c->recvq, &mysg);
-		runtime_unlock(c);
-		runtime_gosched();
+		runtime_park(runtime_unlock, c, "chan receive");
 
 		runtime_lock(c);
 		goto asynch;
 	}
+
+	if(raceenabled)
+		runtime_raceacquire(chanbuf(c, c->recvx));
+
 	if(ep != nil)
 		runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize);
 	runtime_memclr(chanbuf(c, c->recvx), c->elemsize);
@@ -386,6 +421,8 @@
 	if(sg != nil) {
 		gp = sg->g;
 		runtime_unlock(c);
+		if(sg->releasetime)
+			sg->releasetime = runtime_cputicks();
 		runtime_ready(gp);
 	} else
 		runtime_unlock(c);
@@ -394,6 +431,8 @@
 		*selected = true;
 	if(received != nil)
 		*received = true;
+	if(mysg.releasetime > 0)
+		runtime_blockevent(mysg.releasetime - t0, 2);
 	return;
 
 closed:
@@ -403,7 +442,11 @@
 		*selected = true;
 	if(received != nil)
 		*received = false;
+	if(raceenabled)
+		runtime_raceacquire(c);
 	runtime_unlock(c);
+	if(mysg.releasetime > 0)
+		runtime_blockevent(mysg.releasetime - t0, 2);
 }
 
 // The compiler generates a call to __go_send_small to send a value 8
@@ -424,7 +467,7 @@
 #else
 	p = u.b + sizeof(uint64) - t->__element_type->__size;
 #endif
-	runtime_chansend(t, c, p, nil);
+	runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
 }
 
 // The compiler generates a call to __go_send_big to send a value
@@ -432,7 +475,7 @@
 void
 __go_send_big(ChanType *t, Hchan* c, byte* p)
 {
-	runtime_chansend(t, c, p, nil);
+	runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
 }
 
 // The compiler generates a call to __go_receive_small to receive a
@@ -500,7 +543,7 @@
 {
 	bool res;
 
-	runtime_chansend(t, c, p, &res);
+	runtime_chansend(t, c, p, &res, runtime_getcallerpc(&t));
 	return res;
 }
 
@@ -590,7 +633,7 @@
 		vp = (byte*)&val;
 	else
 		vp = (byte*)val;
-	runtime_chansend(t, c, vp, sp);
+	runtime_chansend(t, c, vp, sp, runtime_getcallerpc(&t));
 	return selected;
 }
 
@@ -643,10 +686,10 @@
 
 // newselect(size uint32) (sel *byte);
 
-void* runtime_newselect(int) __asm__("runtime.newselect");
+void* runtime_newselect(int32) __asm__("runtime.newselect");
 
 void*
-runtime_newselect(int size)
+runtime_newselect(int32 size)
 {
 	Select *sel;
 
@@ -688,11 +731,11 @@
 
 // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
 
-void runtime_selectsend(Select *, Hchan *, void *, int)
+void runtime_selectsend(Select *, Hchan *, void *, int32)
   __asm__("runtime.selectsend");
 
 void
-runtime_selectsend(Select *sel, Hchan *c, void *elem, int index)
+runtime_selectsend(Select *sel, Hchan *c, void *elem, int32 index)
 {
 	// nil cases do not compete
 	if(c == nil)
@@ -728,11 +771,11 @@
 
 // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
 
-void runtime_selectrecv(Select *, Hchan *, void *, int)
+void runtime_selectrecv(Select *, Hchan *, void *, int32)
   __asm__("runtime.selectrecv");
 
 void
-runtime_selectrecv(Select *sel, Hchan *c, void *elem, int index)
+runtime_selectrecv(Select *sel, Hchan *c, void *elem, int32 index)
 {
 	// nil cases do not compete
 	if(c == nil)
@@ -743,11 +786,11 @@
 
 // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
 
-void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int)
+void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int32)
   __asm__("runtime.selectrecv2");
 
 void
-runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int index)
+runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int32 index)
 {
 	// nil cases do not compete
 	if(c == nil)
@@ -784,16 +827,16 @@
 
 // selectdefault(sel *byte) (selected bool);
 
-void runtime_selectdefault(Select *, int) __asm__("runtime.selectdefault");
+void runtime_selectdefault(Select *, int32) __asm__("runtime.selectdefault");
 
 void
-runtime_selectdefault(Select *sel, int index)
+runtime_selectdefault(Select *sel, int32 index)
 {
 	selectdefault(sel, index);
 }
 
 static void
-selectdefault(Select *sel, int index)
+selectdefault(Select *sel, int32 index)
 {
 	int32 i;
 	Scase *cas;
@@ -848,12 +891,7 @@
 void
 runtime_block(void)
 {
-	G *g;
-
-	g = runtime_g();
-	g->status = Gwaiting;	// forever
-	g->waitreason = "select (no cases)";
-	runtime_gosched();
+	runtime_park(nil, nil, "select (no cases)");	// forever
 }
 
 static int selectgo(Select**);
@@ -985,10 +1023,7 @@
 	}
 
 	g->param = nil;
-	g->status = Gwaiting;
-	g->waitreason = "select";
-	selunlock(sel);
-	runtime_gosched();
+	runtime_park((void(*)(Lock*))selunlock, (Lock*)sel, "select");
 
 	sellock(sel);
 	sg = g->param;
@@ -1029,6 +1064,8 @@
 
 asyncrecv:
 	// can receive from buffer
+	if(raceenabled)
+		runtime_raceacquire(chanbuf(c, c->recvx));
 	if(cas->receivedp != nil)
 		*cas->receivedp = true;
 	if(cas->sg.elem != nil)
@@ -1049,6 +1086,8 @@
 
 asyncsend:
 	// can send to buffer
+	if(raceenabled)
+		runtime_racerelease(chanbuf(c, c->sendx));
 	runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize);
 	if(++c->sendx == c->dataqsiz)
 		c->sendx = 0;
@@ -1065,6 +1104,8 @@
 
 syncrecv:
 	// can receive from sleeping sender (sg)
+	if(raceenabled)
+		racesync(c, sg);
 	selunlock(sel);
 	if(debug)
 		runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
@@ -1084,10 +1125,14 @@
 		*cas->receivedp = false;
 	if(cas->sg.elem != nil)
 		runtime_memclr(cas->sg.elem, c->elemsize);
+	if(raceenabled)
+		runtime_raceacquire(c);
 	goto retc;
 
 syncsend:
 	// can send to sleeping receiver (sg)
+	if(raceenabled)
+		racesync(c, sg);
 	selunlock(sel);
 	if(debug)
 		runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
@@ -1110,6 +1155,102 @@
 	return 0;  // not reached
 }
 
+// This struct must match ../reflect/value.go:/runtimeSelect.
+typedef struct runtimeSelect runtimeSelect;
+struct runtimeSelect
+{
+	uintptr dir;
+	ChanType *typ;
+	Hchan *ch;
+	uintptr val;
+};
+
+// This enum must match ../reflect/value.go:/SelectDir.
+enum SelectDir {
+	SelectSend = 1,
+	SelectRecv,
+	SelectDefault,
+};
+
+struct rselect_ret {
+	intgo chosen;
+	uintptr word;
+	bool recvOK;
+};
+
+// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
+
+struct rselect_ret reflect_rselect(Slice)
+     asm("reflect.rselect");
+
+struct rselect_ret
+reflect_rselect(Slice cases)
+{
+	struct rselect_ret ret;
+	int32 i;
+	Select *sel;
+	runtimeSelect* rcase, *rc;
+	void *elem;
+	void *recvptr;
+	uintptr maxsize;
+	bool onlyptr;
+
+	ret.chosen = -1;
+	ret.word = 0;
+	ret.recvOK = false;
+
+	maxsize = 0;
+	onlyptr = true;
+	rcase = (runtimeSelect*)cases.__values;
+	for(i=0; i<cases.__count; i++) {
+		rc = &rcase[i];
+		if(rc->dir == SelectRecv && rc->ch != nil) {
+			if(maxsize < rc->typ->__element_type->__size)
+				maxsize = rc->typ->__element_type->__size;
+			if(!__go_is_pointer_type(rc->typ->__element_type))
+				onlyptr = false;
+		}
+	}
+
+	recvptr = nil;
+	if(!onlyptr)
+		recvptr = runtime_mal(maxsize);
+
+	newselect(cases.__count, &sel);
+	for(i=0; i<cases.__count; i++) {
+		rc = &rcase[i];
+		switch(rc->dir) {
+		case SelectDefault:
+			selectdefault(sel, i);
+			break;
+		case SelectSend:
+			if(rc->ch == nil)
+				break;
+			if(!__go_is_pointer_type(rc->typ->__element_type))
+				elem = (void*)rc->val;
+			else
+				elem = (void*)&rc->val;
+			selectsend(sel, rc->ch, i, elem);
+			break;
+		case SelectRecv:
+			if(rc->ch == nil)
+				break;
+			if(!__go_is_pointer_type(rc->typ->__element_type))
+				elem = recvptr;
+			else
+				elem = &ret.word;
+			selectrecv(sel, rc->ch, i, elem, &ret.recvOK);
+			break;
+		}
+	}
+
+	ret.chosen = (intgo)(uintptr)selectgo(&sel);
+	if(rcase[ret.chosen].dir == SelectRecv && !__go_is_pointer_type(rcase[ret.chosen].typ->__element_type))
+		ret.word = (uintptr)recvptr;
+
+	return ret;
+}
+
 // closechan(sel *byte);
 void
 runtime_closechan(Hchan *c)
@@ -1129,6 +1270,11 @@
 		runtime_panicstring("close of closed channel");
 	}
 
+	if(raceenabled) {
+		runtime_racewritepc(c, runtime_getcallerpc(&c));
+		runtime_racerelease(c);
+	}
+
 	c->closed = true;
 
 	// release all readers
@@ -1172,15 +1318,15 @@
 }
 
 // For reflect
-//	func chanlen(c chan) (len int32)
+//	func chanlen(c chan) (len int)
 
-int32 reflect_chanlen(uintptr) __asm__("reflect.chanlen");
+intgo reflect_chanlen(uintptr) __asm__("reflect.chanlen");
 
-int32
+intgo
 reflect_chanlen(uintptr ca)
 {
 	Hchan *c;
-	int32 len;
+	intgo len;
 
 	c = (Hchan*)ca;
 	if(c == nil)
@@ -1190,22 +1336,22 @@
 	return len;
 }
 
-int
+intgo
 __go_chan_len(Hchan *c)
 {
 	return reflect_chanlen((uintptr)c);
 }
 
 // For reflect
-//	func chancap(c chan) (cap int32)
+//	func chancap(c chan) (cap intgo)
 
-int32 reflect_chancap(uintptr) __asm__("reflect.chancap");
+intgo reflect_chancap(uintptr) __asm__("reflect.chancap");
 
-int32
+intgo
 reflect_chancap(uintptr ca)
 {
 	Hchan *c;
-	int32 cap;
+	intgo cap;
 
 	c = (Hchan*)ca;
 	if(c == nil)
@@ -1215,7 +1361,7 @@
 	return cap;
 }
 
-int
+intgo
 __go_chan_cap(Hchan *c)
 {
 	return reflect_chancap((uintptr)c);
@@ -1273,3 +1419,12 @@
 	q->last->link = sgp;
 	q->last = sgp;
 }
+
+static void
+racesync(Hchan *c, SudoG *sg)
+{
+	runtime_racerelease(chanbuf(c, 0));
+	runtime_raceacquireg(sg->g, chanbuf(c, 0));
+	runtime_racereleaseg(sg->g, chanbuf(c, 0));
+	runtime_raceacquire(chanbuf(c, 0));
+}
diff -r bf12a7f41b67 libgo/runtime/cpuprof.c
--- a/libgo/runtime/cpuprof.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/cpuprof.c	Mon Oct 22 17:36:23 2012 -0700
@@ -130,7 +130,7 @@
 // SetCPUProfileRate sets the CPU profiling rate.
 // The user documentation is in debug.go.
 void
-runtime_SetCPUProfileRate(int32 hz)
+runtime_SetCPUProfileRate(intgo hz)
 {
 	uintptr *p;
 	uintptr n;
diff -r bf12a7f41b67 libgo/runtime/go-rune.c
--- a/libgo/runtime/go-rune.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/go-rune.c	Mon Oct 22 17:36:23 2012 -0700
@@ -15,7 +15,7 @@
 int
 __go_get_rune (const unsigned char *str, size_t len, int *rune)
 {
-  int c, c1, c2, c3;
+  int c, c1, c2, c3, l;
 
   /* Default to the "replacement character".  */
   *rune = 0xfffd;
@@ -37,8 +37,10 @@
   if ((c & 0xe0) == 0xc0
       && (c1 & 0xc0) == 0x80)
     {
-      *rune = (((c & 0x1f) << 6)
-	       + (c1 & 0x3f));
+      l = (((c & 0x1f) << 6) + (c1 & 0x3f));
+      if (l <= 0x7f)
+	return 1;
+      *rune = l;
       return 2;
     }
 
@@ -50,17 +52,21 @@
       && (c1 & 0xc0) == 0x80
       && (c2 & 0xc0) == 0x80)
     {
-      *rune = (((c & 0xf) << 12)
-	       + ((c1 & 0x3f) << 6)
-	       + (c2 & 0x3f));
+      l = (((c & 0xf) << 12)
+	   + ((c1 & 0x3f) << 6)
+	   + (c2 & 0x3f));
 
-      if (*rune >= 0xd800 && *rune < 0xe000)
+      if (l <= 0x7ff)
+	return 1;
+
+      if (l >= 0xd800 && l < 0xe000)
 	{
 	  /* Invalid surrogate half; return replace character.  */
-	  *rune = 0xfffd;
 	  return 1;
 	}
 
+      *rune = l;
+
       return 3;
     }
 
@@ -73,10 +79,15 @@
       && (c2 & 0xc0) == 0x80
       && (c3 & 0xc0) == 0x80)
     {
-      *rune = (((c & 0x7) << 18)
-	       + ((c1 & 0x3f) << 12)
-	       + ((c2 & 0x3f) << 6)
-	       + (c3 & 0x3f));
+      l = (((c & 0x7) << 18)
+	   + ((c1 & 0x3f) << 12)
+	   + ((c2 & 0x3f) << 6)
+	   + (c3 & 0x3f));
+
+      if (l <= 0xffff || l > 0x10ffff)
+	return 1;
+
+      *rune = l;
       return 4;
     }
 
diff -r bf12a7f41b67 libgo/runtime/go-signal.c
--- a/libgo/runtime/go-signal.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/go-signal.c	Mon Oct 22 17:36:23 2012 -0700
@@ -138,6 +138,19 @@
 #undef P
 #undef D
 
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+static void
+runtime_badsignal(int32 sig)
+{
+	if (sig == SIGPROF) {
+		return;  // Ignore SIGPROFs intended for a non-Go thread.
+	}
+	runtime_write(2, badsignal, sizeof badsignal - 1);
+	runtime_exit(1);
+}
+
 /* Handle a signal, for cases where we don't panic.  We can split the
    stack here.  */
 
@@ -146,6 +159,12 @@
 {
   int i;
 
+  if (runtime_m () == NULL)
+    {
+      runtime_badsignal (sig);
+      return;
+    }
+
 #ifdef SIGPROF
   if (sig == SIGPROF)
     {
diff -r bf12a7f41b67 libgo/runtime/go-trampoline.c
--- a/libgo/runtime/go-trampoline.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/go-trampoline.c	Mon Oct 22 17:36:23 2012 -0700
@@ -106,8 +106,8 @@
    no other references to it.  */
 
 void
-runtime_trampoline_scan (void (*scan) (byte *, int64))
+runtime_trampoline_scan (void (*addroot) (byte *, uintptr))
 {
   if (trampoline_page != NULL)
-    scan ((byte *) &trampoline_page, sizeof trampoline_page);
+    addroot ((byte *) &trampoline_page, sizeof trampoline_page);
 }
diff -r bf12a7f41b67 libgo/runtime/lfstack.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/lfstack.c	Mon Oct 22 17:36:23 2012 -0700
@@ -0,0 +1,66 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Lock-free stack.
+
+#include "runtime.h"
+#include "arch.h"
+
+#if __SIZEOF_POINTER__ == 8
+// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
+// So we use 17msb of pointers as ABA counter.
+# define PTR_BITS 47
+#else
+# define PTR_BITS 32
+#endif
+#define PTR_MASK ((1ull<<PTR_BITS)-1)
+
+void
+runtime_lfstackpush(uint64 *head, LFNode *node)
+{
+	uint64 old, new;
+
+	if((uintptr)node != ((uintptr)node&PTR_MASK)) {
+		runtime_printf("p=%p\n", node);
+		runtime_throw("runtime_lfstackpush: invalid pointer");
+	}
+
+	node->pushcnt++;
+	new = (uint64)(uintptr)node|(((uint64)node->pushcnt)<<PTR_BITS);
+	old = runtime_atomicload64(head);
+	for(;;) {
+		node->next = (LFNode*)(uintptr)(old&PTR_MASK);
+		if(runtime_cas64(head, &old, new))
+			break;
+	}
+}
+
+LFNode*
+runtime_lfstackpop(uint64 *head)
+{
+	LFNode *node, *node2;
+	uint64 old, new;
+
+	old = runtime_atomicload64(head);
+	for(;;) {
+		if(old == 0)
+			return nil;
+		node = (LFNode*)(uintptr)(old&PTR_MASK);
+		node2 = runtime_atomicloadp(&node->next);
+		new = 0;
+		if(node2 != nil)
+			new = (uint64)(uintptr)node2|(((uint64)node2->pushcnt)<<PTR_BITS);
+		if(runtime_cas64(head, &old, new))
+			return node;
+	}
+}
+
+LFNode* runtime_lfstackpop2(uint64*)
+  asm("runtime.lfstackpop2");
+
+LFNode*
+runtime_lfstackpop2(uint64 *head)
+{
+	return runtime_lfstackpop(head);
+}
diff -r bf12a7f41b67 libgo/runtime/malloc.goc
--- a/libgo/runtime/malloc.goc	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/malloc.goc	Mon Oct 22 17:36:23 2012 -0700
@@ -17,12 +17,13 @@
 #include "go-string.h"
 #include "interface.h"
 #include "go-type.h"
+#include "race.h"
 
 MHeap runtime_mheap;
 
 extern MStats mstats;	// defined in extern.go
 
-extern volatile int32 runtime_MemProfileRate
+extern volatile intgo runtime_MemProfileRate
   __asm__ ("runtime.MemProfileRate");
 
 // Allocate an object of at least size bytes.
@@ -33,7 +34,8 @@
 {
 	M *m;
 	G *g;
-	int32 sizeclass, rate;
+	int32 sizeclass;
+	intgo rate;
 	MCache *c;
 	uintptr npages;
 	MSpan *s;
@@ -53,6 +55,9 @@
 	if(size == 0)
 		size = 1;
 
+	if(DebugTypeAtBlockEnd)
+		size += sizeof(uintptr);
+
 	c = m->mcache;
 	c->local_nmalloc++;
 	if(size <= MaxSmallSize) {
@@ -72,7 +77,7 @@
 		npages = size >> PageShift;
 		if((size & PageMask) != 0)
 			npages++;
-		s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1);
+		s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1, zeroed);
 		if(s == nil)
 			runtime_throw("out of memory");
 		size = npages<<PageShift;
@@ -83,9 +88,20 @@
 		// setup for mark sweep
 		runtime_markspan(v, 0, 0, true);
 	}
+
+	if (sizeof(void*) == 4 && c->local_total_alloc >= (1<<30)) {
+		// purge cache stats to prevent overflow
+		runtime_lock(&runtime_mheap);
+		runtime_purgecachedstats(c);
+		runtime_unlock(&runtime_mheap);
+	}
+
 	if(!(flag & FlagNoGC))
 		runtime_markallocated(v, size, (flag&FlagNoPointers) != 0);
 
+	if(DebugTypeAtBlockEnd)
+		*(uintptr*)((uintptr)v+size-sizeof(uintptr)) = 0;
+
 	m->mallocing = 0;
 
 	if(!(flag & FlagNoProfiling) && (rate = runtime_MemProfileRate) > 0) {
@@ -107,6 +123,11 @@
 
 	if(dogc && mstats.heap_alloc >= mstats.next_gc)
 		runtime_gc(0);
+
+	if(raceenabled) {
+		runtime_racemalloc(v, size, m->racepc);
+		m->racepc = nil;
+	}
 	return v;
 }
 
@@ -144,6 +165,9 @@
 	}
 	prof = runtime_blockspecial(v);
 
+	if(raceenabled)
+		runtime_racefree(v);
+
 	// Find size class for v.
 	sizeclass = s->sizeclass;
 	c = m->mcache;
@@ -178,11 +202,21 @@
 int32
 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
 {
+	M *m;
 	uintptr n, i;
 	byte *p;
 	MSpan *s;
 
-	runtime_m()->mcache->local_nlookup++;
+	m = runtime_m();
+
+	m->mcache->local_nlookup++;
+	if (sizeof(void*) == 4 && m->mcache->local_nlookup >= (1<<30)) {
+		// purge cache stats to prevent overflow
+		runtime_lock(&runtime_mheap);
+		runtime_purgecachedstats(m->mcache);
+		runtime_unlock(&runtime_mheap);
+	}
+
 	s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
 	if(sp)
 		*sp = s;
@@ -210,7 +244,7 @@
 		return 0;
 	}
 
-	n = runtime_class_to_size[s->sizeclass];
+	n = s->elemsize;
 	if(base) {
 		i = ((byte*)v - p)/n;
 		*base = p + i*n;
@@ -224,7 +258,7 @@
 MCache*
 runtime_allocmcache(void)
 {
-	int32 rate;
+	intgo rate;
 	MCache *c;
 
 	runtime_lock(&runtime_mheap);
@@ -232,6 +266,7 @@
 	mstats.mcache_inuse = runtime_mheap.cachealloc.inuse;
 	mstats.mcache_sys = runtime_mheap.cachealloc.sys;
 	runtime_unlock(&runtime_mheap);
+	runtime_memclr((byte*)c, sizeof(*c));
 
 	// Set first allocation sample size.
 	rate = runtime_MemProfileRate;
@@ -244,12 +279,19 @@
 }
 
 void
-runtime_purgecachedstats(M* m)
+runtime_freemcache(MCache *c)
 {
-	MCache *c;
+	runtime_MCache_ReleaseAll(c);
+	runtime_lock(&runtime_mheap);
+	runtime_purgecachedstats(c);
+	runtime_FixAlloc_Free(&runtime_mheap.cachealloc, c);
+	runtime_unlock(&runtime_mheap);
+}
 
+void
+runtime_purgecachedstats(MCache *c)
+{
 	// Protected by either heap or GC lock.
-	c = m->mcache;
 	mstats.heap_alloc += c->local_cachealloc;
 	c->local_cachealloc = 0;
 	mstats.heap_objects += c->local_objects;
@@ -445,6 +487,220 @@
 	return p;
 }
 
+static Lock settype_lock;
+
+void
+runtime_settype_flush(M *m, bool sysalloc)
+{
+	uintptr *buf, *endbuf;
+	uintptr size, ofs, j, t;
+	uintptr ntypes, nbytes2, nbytes3;
+	uintptr *data2;
+	byte *data3;
+	bool sysalloc3;
+	void *v;
+	uintptr typ, p;
+	MSpan *s;
+
+	buf = m->settype_buf;
+	endbuf = buf + m->settype_bufsize;
+
+	runtime_lock(&settype_lock);
+	while(buf < endbuf) {
+		v = (void*)*buf;
+		*buf = 0;
+		buf++;
+		typ = *buf;
+		buf++;
+
+		// (Manually inlined copy of runtime_MHeap_Lookup)
+		p = (uintptr)v>>PageShift;
+		if(sizeof(void*) == 8)
+			p -= (uintptr)runtime_mheap.arena_start >> PageShift;
+		s = runtime_mheap.map[p];
+
+		if(s->sizeclass == 0) {
+			s->types.compression = MTypes_Single;
+			s->types.data = typ;
+			continue;
+		}
+
+		size = s->elemsize;
+		ofs = ((uintptr)v - (s->start<<PageShift)) / size;
+
+		switch(s->types.compression) {
+		case MTypes_Empty:
+			ntypes = (s->npages << PageShift) / size;
+			nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
+
+			if(!sysalloc) {
+				data3 = runtime_mallocgc(nbytes3, FlagNoPointers, 0, 1);
+			} else {
+				data3 = runtime_SysAlloc(nbytes3);
+				if(0) runtime_printf("settype(0->3): SysAlloc(%x) --> %p\n", (uint32)nbytes3, data3);
+			}
+
+			s->types.compression = MTypes_Bytes;
+			s->types.sysalloc = sysalloc;
+			s->types.data = (uintptr)data3;
+
+			((uintptr*)data3)[1] = typ;
+			data3[8*sizeof(uintptr) + ofs] = 1;
+			break;
+
+		case MTypes_Words:
+			((uintptr*)s->types.data)[ofs] = typ;
+			break;
+
+		case MTypes_Bytes:
+			data3 = (byte*)s->types.data;
+			for(j=1; j<8; j++) {
+				if(((uintptr*)data3)[j] == typ) {
+					break;
+				}
+				if(((uintptr*)data3)[j] == 0) {
+					((uintptr*)data3)[j] = typ;
+					break;
+				}
+			}
+			if(j < 8) {
+				data3[8*sizeof(uintptr) + ofs] = j;
+			} else {
+				ntypes = (s->npages << PageShift) / size;
+				nbytes2 = ntypes * sizeof(uintptr);
+
+				if(!sysalloc) {
+					data2 = runtime_mallocgc(nbytes2, FlagNoPointers, 0, 1);
+				} else {
+					data2 = runtime_SysAlloc(nbytes2);
+					if(0) runtime_printf("settype.(3->2): SysAlloc(%x) --> %p\n", (uint32)nbytes2, data2);
+				}
+
+				sysalloc3 = s->types.sysalloc;
+
+				s->types.compression = MTypes_Words;
+				s->types.sysalloc = sysalloc;
+				s->types.data = (uintptr)data2;
+
+				// Move the contents of data3 to data2. Then deallocate data3.
+				for(j=0; j<ntypes; j++) {
+					t = data3[8*sizeof(uintptr) + j];
+					t = ((uintptr*)data3)[t];
+					data2[j] = t;
+				}
+				if(sysalloc3) {
+					nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
+					if(0) runtime_printf("settype.(3->2): SysFree(%p,%x)\n", data3, (uint32)nbytes3);
+					runtime_SysFree(data3, nbytes3);
+				}
+
+				data2[ofs] = typ;
+			}
+			break;
+		}
+	}
+	runtime_unlock(&settype_lock);
+
+	m->settype_bufsize = 0;
+}
+
+// It is forbidden to use this function if it is possible that
+// explicit deallocation via calling runtime_free(v) may happen.
+void
+runtime_settype(void *v, uintptr t)
+{
+	M *m1;
+	uintptr *buf;
+	uintptr i;
+	MSpan *s;
+
+	if(t == 0)
+		runtime_throw("settype: zero type");
+
+	m1 = runtime_m();
+	buf = m1->settype_buf;
+	i = m1->settype_bufsize;
+	buf[i+0] = (uintptr)v;
+	buf[i+1] = t;
+	i += 2;
+	m1->settype_bufsize = i;
+
+	if(i == nelem(m1->settype_buf)) {
+		runtime_settype_flush(m1, false);
+	}
+
+	if(DebugTypeAtBlockEnd) {
+		s = runtime_MHeap_Lookup(&runtime_mheap, v);
+		*(uintptr*)((uintptr)v+s->elemsize-sizeof(uintptr)) = t;
+	}
+}
+
+void
+runtime_settype_sysfree(MSpan *s)
+{
+	uintptr ntypes, nbytes;
+
+	if(!s->types.sysalloc)
+		return;
+
+	nbytes = (uintptr)-1;
+
+	switch (s->types.compression) {
+	case MTypes_Words:
+		ntypes = (s->npages << PageShift) / s->elemsize;
+		nbytes = ntypes * sizeof(uintptr);
+		break;
+	case MTypes_Bytes:
+		ntypes = (s->npages << PageShift) / s->elemsize;
+		nbytes = 8*sizeof(uintptr) + 1*ntypes;
+		break;
+	}
+
+	if(nbytes != (uintptr)-1) {
+		if(0) runtime_printf("settype: SysFree(%p,%x)\n", (void*)s->types.data, (uint32)nbytes);
+		runtime_SysFree((void*)s->types.data, nbytes);
+	}
+}
+
+uintptr
+runtime_gettype(void *v)
+{
+	MSpan *s;
+	uintptr t, ofs;
+	byte *data;
+
+	s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
+	if(s != nil) {
+		t = 0;
+		switch(s->types.compression) {
+		case MTypes_Empty:
+			break;
+		case MTypes_Single:
+			t = s->types.data;
+			break;
+		case MTypes_Words:
+			ofs = (uintptr)v - (s->start<<PageShift);
+			t = ((uintptr*)s->types.data)[ofs/s->elemsize];
+			break;
+		case MTypes_Bytes:
+			ofs = (uintptr)v - (s->start<<PageShift);
+			data = (byte*)s->types.data;
+			t = data[8*sizeof(uintptr) + ofs/s->elemsize];
+			t = ((uintptr*)data)[t];
+			break;
+		default:
+			runtime_throw("runtime_gettype: invalid compression kind");
+		}
+		if(0) {
+			runtime_lock(&settype_lock);
+			runtime_printf("%p -> %d,%X\n", v, (int32)s->types.compression, (int64)t);
+			runtime_unlock(&settype_lock);
+		}
+		return t;
+	}
+	return 0;
+}
+
 // Runtime stubs.
 
 void*
@@ -453,9 +709,24 @@
 	return runtime_mallocgc(n, 0, 1, 1);
 }
 
-func new(typ *Type) (ret *uint8) {
-	uint32 flag = typ->__code&GO_NO_POINTERS ? FlagNoPointers : 0;
+void *
+runtime_new(Type *typ)
+{
+	void *ret;
+	uint32 flag;
+
+	runtime_m()->racepc = runtime_getcallerpc(&typ);
+	flag = typ->__code&GO_NO_POINTERS ? FlagNoPointers : 0;
 	ret = runtime_mallocgc(typ->__size, flag, 1, 1);
+
+	if(UseSpanType && !flag) {
+		if(false) {
+			runtime_printf("new %S: %p\n", *typ->__reflection, ret);
+		}
+		runtime_settype(ret, (uintptr)typ | TypeInfo_SingleObject);
+	}
+
+	return ret;
 }
 
 func GC() {
diff -r bf12a7f41b67 libgo/runtime/malloc.h
--- a/libgo/runtime/malloc.h	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/malloc.h	Mon Oct 22 17:36:23 2012 -0700
@@ -85,6 +85,7 @@
 typedef struct MSpan	MSpan;
 typedef struct MStats	MStats;
 typedef struct MLink	MLink;
+typedef struct MTypes	MTypes;
 
 enum
 {
@@ -124,8 +125,8 @@
 	// Max number of threads to run garbage collection.
 	// 2, 3, and 4 are all plausible maximums depending
 	// on the hardware details of the machine.  The garbage
-	// collector scales well to 4 cpus.
-	MaxGcproc = 4,
+	// collector scales well to 8 cpus.
+	MaxGcproc = 8,
 };
 
 // Maximum memory allocation size, a hint for callers.
@@ -282,19 +283,19 @@
 struct MCache
 {
 	MCacheList list[NumSizeClasses];
-	uint64 size;
-	int64 local_cachealloc;	// bytes allocated (or freed) from cache since last lock of heap
-	int64 local_objects;	// objects allocated (or freed) from cache since last lock of heap
-	int64 local_alloc;	// bytes allocated (or freed) since last lock of heap
-	int64 local_total_alloc;	// bytes allocated (even if freed) since last lock of heap
-	int64 local_nmalloc;	// number of mallocs since last lock of heap
-	int64 local_nfree;	// number of frees since last lock of heap
-	int64 local_nlookup;	// number of pointer lookups since last lock of heap
+	uintptr size;
+	intptr local_cachealloc;	// bytes allocated (or freed) from cache since last lock of heap
+	intptr local_objects;	// objects allocated (or freed) from cache since last lock of heap
+	intptr local_alloc;	// bytes allocated (or freed) since last lock of heap
+	uintptr local_total_alloc;	// bytes allocated (even if freed) since last lock of heap
+	uintptr local_nmalloc;	// number of mallocs since last lock of heap
+	uintptr local_nfree;	// number of frees since last lock of heap
+	uintptr local_nlookup;	// number of pointer lookups since last lock of heap
 	int32 next_sample;	// trigger heap sample after allocating this many bytes
 	// Statistics about allocation size classes since last lock of heap
 	struct {
-		int64 nmalloc;
-		int64 nfree;
+		uintptr nmalloc;
+		uintptr nfree;
 	} local_by_size[NumSizeClasses];
 
 };
@@ -303,6 +304,44 @@
 void	runtime_MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
 void	runtime_MCache_ReleaseAll(MCache *c);
 
+// MTypes describes the types of blocks allocated within a span.
+// The compression field describes the layout of the data.
+//
+// MTypes_Empty:
+//     All blocks are free, or no type information is available for
+//     allocated blocks.
+//     The data field has no meaning.
+// MTypes_Single:
+//     The span contains just one block.
+//     The data field holds the type information.
+//     The sysalloc field has no meaning.
+// MTypes_Words:
+//     The span contains multiple blocks.
+//     The data field points to an array of type [NumBlocks]uintptr,
+//     and each element of the array holds the type of the corresponding
+//     block.
+// MTypes_Bytes:
+//     The span contains at most seven different types of blocks.
+//     The data field points to the following structure:
+//         struct {
+//             type  [8]uintptr       // type[0] is always 0
+//             index [NumBlocks]byte
+//         }
+//     The type of the i-th block is: data.type[data.index[i]]
+enum
+{
+	MTypes_Empty = 0,
+	MTypes_Single = 1,
+	MTypes_Words = 2,
+	MTypes_Bytes = 3,
+};
+struct MTypes
+{
+	byte	compression;	// one of MTypes_*
+	bool	sysalloc;	// whether (void*)data is from runtime_SysAlloc
+	uintptr	data;
+};
+
 // An MSpan is a run of pages.
 enum
 {
@@ -315,16 +354,17 @@
 {
 	MSpan	*next;		// in a span linked list
 	MSpan	*prev;		// in a span linked list
-	MSpan	*allnext;	// in the list of all spans
 	PageID	start;		// starting page number
 	uintptr	npages;		// number of pages in span
 	MLink	*freelist;	// list of free objects
 	uint32	ref;		// number of allocated objects in this span
 	uint32	sizeclass;	// size class
+	uintptr	elemsize;	// computed from sizeclass or from npages
 	uint32	state;		// MSpanInUse etc
 	int64   unusedsince;	// First time spotted by GC in MSpanFree state
 	uintptr npreleased;	// number of pages released to the OS
 	byte	*limit;		// end of data in span
+	MTypes	types;		// types of allocated objects in this span
 };
 
 void	runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
@@ -351,6 +391,7 @@
 void	runtime_MCentral_Init(MCentral *c, int32 sizeclass);
 int32	runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **first);
 void	runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *first);
+void	runtime_MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
 
 // Main malloc heap.
 // The heap itself is the "free[]" and "large" arrays,
@@ -360,7 +401,9 @@
 	Lock;
 	MSpan free[MaxMHeapList];	// free lists of given length
 	MSpan large;			// free lists length >= MaxMHeapList
-	MSpan *allspans;
+	MSpan **allspans;
+	uint32	nspan;
+	uint32	nspancap;
 
 	// span lookup
 	MSpan *map[1<<MHeapMap_Bits];
@@ -387,7 +430,7 @@
 extern MHeap runtime_mheap;
 
 void	runtime_MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
-MSpan*	runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
+MSpan*	runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed);
 void	runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct);
 MSpan*	runtime_MHeap_Lookup(MHeap *h, void *v);
 MSpan*	runtime_MHeap_LookupMaybe(MHeap *h, void *v);
@@ -408,7 +451,12 @@
 void	runtime_unmarkspan(void *v, uintptr size);
 bool	runtime_blockspecial(void*);
 void	runtime_setblockspecial(void*, bool);
-void	runtime_purgecachedstats(M*);
+void	runtime_purgecachedstats(MCache*);
+
+void	runtime_settype(void*, uintptr);
+void	runtime_settype_flush(M*, bool);
+void	runtime_settype_sysfree(MSpan*);
+uintptr	runtime_gettype(void*);
 
 enum
 {
@@ -421,10 +469,21 @@
 void	runtime_MProf_Malloc(void*, uintptr);
 void	runtime_MProf_Free(void*, uintptr);
 void	runtime_MProf_GC(void);
-void	runtime_MProf_Mark(void (*scan)(byte *, int64));
-int32	runtime_helpgc(bool*);
+void	runtime_MProf_Mark(void (*addroot)(byte *, uintptr));
+int32	runtime_gcprocs(void);
+void	runtime_helpgc(int32 nproc);
 void	runtime_gchelper(void);
 
 struct __go_func_type;
 bool	runtime_getfinalizer(void *p, bool del, void (**fn)(void*), const struct __go_func_type **ft);
-void	runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64));
+void	runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, uintptr));
+
+enum
+{
+	TypeInfo_SingleObject = 0,
+	TypeInfo_Array = 1,
+	TypeInfo_Map = 2,
+
+	// Enables type information at the end of blocks allocated from heap	
+	DebugTypeAtBlockEnd = 0,
+};
diff -r bf12a7f41b67 libgo/runtime/mcache.c
--- a/libgo/runtime/mcache.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/mcache.c	Mon Oct 22 17:36:23 2012 -0700
@@ -43,11 +43,6 @@
 		// block is zeroed iff second word is zero ...
 		if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
 			runtime_memclr((byte*)v, size);
-		else {
-			// ... except for the link pointer
-			// that we used above; zero that.
-			v->next = nil;
-		}
 	}
 	c->local_cachealloc += size;
 	c->local_objects++;
diff -r bf12a7f41b67 libgo/runtime/mcentral.c
--- a/libgo/runtime/mcentral.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/mcentral.c	Mon Oct 22 17:36:23 2012 -0700
@@ -88,9 +88,6 @@
 }
 
 // Free n objects back into the central free list.
-// Return the number of objects allocated.
-// The objects are linked together by their first words.
-// On return, *pstart points at the first object and *pend at the last.
 void
 runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *start)
 {
@@ -148,6 +145,42 @@
 	}
 }
 
+// Free n objects from a span s back into the central free list c.
+// Called from GC.
+void
+runtime_MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end)
+{
+	int32 size;
+
+	runtime_lock(c);
+
+	// Move to nonempty if necessary.
+	if(s->freelist == nil) {
+		runtime_MSpanList_Remove(s);
+		runtime_MSpanList_Insert(&c->nonempty, s);
+	}
+
+	// Add the objects back to s's free list.
+	end->next = s->freelist;
+	s->freelist = start;
+	s->ref -= n;
+	c->nfree += n;
+
+	// If s is completely freed, return it to the heap.
+	if(s->ref == 0) {
+		size = runtime_class_to_size[c->sizeclass];
+		runtime_MSpanList_Remove(s);
+		*(uintptr*)(s->start<<PageShift) = 1;  // needs zeroing
+		s->freelist = nil;
+		c->nfree -= (s->npages << PageShift) / size;
+		runtime_unlock(c);
+		runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+		runtime_MHeap_Free(&runtime_mheap, s, 0);
+	} else {
+		runtime_unlock(c);
+	}
+}
+
 void
 runtime_MGetSizeClassInfo(int32 sizeclass, uintptr *sizep, int32 *npagesp, int32 *nobj)
 {
@@ -174,7 +207,7 @@
 
 	runtime_unlock(c);
 	runtime_MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
-	s = runtime_MHeap_Alloc(&runtime_mheap, npages, c->sizeclass, 0);
+	s = runtime_MHeap_Alloc(&runtime_mheap, npages, c->sizeclass, 0, 1);
 	if(s == nil) {
 		// TODO(rsc): Log out of memory
 		runtime_lock(c);
diff -r bf12a7f41b67 libgo/runtime/mfinal.c
--- a/libgo/runtime/mfinal.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/mfinal.c	Mon Oct 22 17:36:23 2012 -0700
@@ -193,7 +193,7 @@
 }
 
 void
-runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64))
+runtime_walkfintab(void (*fn)(void*), void (*addroot)(byte *, uintptr))
 {
 	void **key;
 	void **ekey;
@@ -206,8 +206,8 @@
 		for(; key < ekey; key++)
 			if(*key != nil && *key != ((void*)-1))
 				fn(*key);
-		scan((byte*)&fintab[i].fkey, sizeof(void*));
-		scan((byte*)&fintab[i].val, sizeof(void*));
+		addroot((byte*)&fintab[i].fkey, sizeof(void*));
+		addroot((byte*)&fintab[i].val, sizeof(void*));
 		runtime_unlock(&fintab[i]);
 	}
 }
diff -r bf12a7f41b67 libgo/runtime/mgc0.c
--- a/libgo/runtime/mgc0.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/mgc0.c	Mon Oct 22 17:36:23 2012 -0700
@@ -9,6 +9,7 @@
 #include "runtime.h"
 #include "arch.h"
 #include "malloc.h"
+#include "race.h"
 
 #ifdef USING_SPLIT_STACK
 
@@ -22,8 +23,8 @@
 
 enum {
 	Debug = 0,
-	PtrSize = sizeof(void*),
 	DebugMark = 0,  // run second pass to check mark
+	DataBlock = 8*1024,
 
 	// Four bits per word (see #defines below).
 	wordsPerBitmapWord = sizeof(void*)*8/4,
@@ -78,17 +79,14 @@
 //
 uint32 runtime_worldsema = 1;
 
-// TODO: Make these per-M.
-static uint64 nhandoff;
-
 static int32 gctrace;
 
 typedef struct Workbuf Workbuf;
 struct Workbuf
 {
-	Workbuf *next;
+	LFNode node; // must be first
 	uintptr nobj;
-	byte *obj[512-2];
+	byte *obj[512-(sizeof(LFNode)+sizeof(uintptr))/sizeof(byte*)];
 };
 
 typedef struct Finalizer Finalizer;
@@ -122,22 +120,32 @@
 static void	putempty(Workbuf*);
 static Workbuf* handoff(Workbuf*);
 
+typedef struct GcRoot GcRoot;
+struct GcRoot
+{
+	byte *p;
+	uintptr n;
+};
+
 static struct {
-	Lock fmu;
-	Workbuf	*full;
-	Lock emu;
-	Workbuf	*empty;
+	uint64	full;  // lock-free list of full blocks
+	uint64	empty; // lock-free list of empty blocks
+	byte	pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
 	uint32	nproc;
 	volatile uint32	nwait;
 	volatile uint32	ndone;
+	volatile uint32 debugmarkdone;
 	Note	alldone;
-	Lock	markgate;
-	Lock	sweepgate;
-	MSpan	*spans;
+	ParFor	*markfor;
+	ParFor	*sweepfor;
 
 	Lock;
 	byte	*chunk;
 	uintptr	nchunk;
+
+	GcRoot	*roots;
+	uint32	nroot;
+	uint32	rootcap;
 } work;
 
 // scanblock scans a block of n bytes starting at pointer b for references
@@ -147,7 +155,7 @@
 // body.  Keeping an explicit work list is easier on the stack allocator and
 // more efficient.
 static void
-scanblock(byte *b, int64 n)
+scanblock(byte *b, uintptr n)
 {
 	byte *obj, *arena_start, *arena_used, *p;
 	void **vp;
@@ -158,8 +166,8 @@
 	Workbuf *wbuf;
 	bool keepworking;
 
-	if((int64)(uintptr)n != n || n < 0) {
-		runtime_printf("scanblock %p %D\n", b, n);
+	if((intptr)n < 0) {
+		runtime_printf("scanblock %p %D\n", b, (int64)n);
 		runtime_throw("scanblock");
 	}
 
@@ -173,7 +181,7 @@
 	nobj = 0;  // number of queued objects
 
 	// Scanblock helpers pass b==nil.
-	// The main proc needs to return to make more
+	// Procs needs to return to make more
 	// calls to scanblock.  But if work.nproc==1 then
 	// might as well process blocks as soon as we
 	// have them.
@@ -190,7 +198,7 @@
 		// Each iteration scans the block b of length n, queueing pointers in
 		// the work buffer.
 		if(Debug > 1)
-			runtime_printf("scanblock %p %D\n", b, n);
+			runtime_printf("scanblock %p %D\n", b, (int64)n);
 
 		vp = (void**)b;
 		n >>= (2+PtrSize/8);  /* n /= PtrSize (4 or 8) */
@@ -257,6 +265,14 @@
 			bits = xbits >> shift;
 
 		found:
+			// If another proc wants a pointer, give it some.
+			if(work.nwait > 0 && nobj > 4 && work.full == 0) {
+				wbuf->nobj = nobj;
+				wbuf = handoff(wbuf);
+				nobj = wbuf->nobj;
+				wp = (void**)(wbuf->obj + nobj);
+			}
+
 			// Now we have bits, bitp, and shift correct for
 			// obj pointing at the base of the object.
 			// Only care about allocated and not marked.
@@ -278,13 +294,7 @@
 			if((bits & bitNoPointers) != 0)
 				continue;
 
-			// If another proc wants a pointer, give it some.
-			if(nobj > 4 && work.nwait > 0 && work.full == nil) {
-				wbuf->nobj = nobj;
-				wbuf = handoff(wbuf);
-				nobj = wbuf->nobj;
-				wp = (void**)(wbuf->obj + nobj);
-			}
+			PREFETCH(obj);
 
 			// If buffer is full, get a new one.
 			if(wbuf == nil || nobj >= nelem(wbuf->obj)) {
@@ -305,7 +315,8 @@
 		// Fetch b from the work buffer.
 		if(nobj == 0) {
 			if(!keepworking) {
-				putempty(wbuf);
+				if(wbuf)
+					putempty(wbuf);
 				return;
 			}
 			// Emptied our buffer: refill.
@@ -335,7 +346,7 @@
 // it is simpler, slower, single-threaded, recursive,
 // and uses bitSpecial as the mark bit.
 static void
-debug_scanblock(byte *b, int64 n)
+debug_scanblock(byte *b, uintptr n)
 {
 	byte *obj, *p;
 	void **vp;
@@ -345,8 +356,8 @@
 	if(!DebugMark)
 		runtime_throw("debug_scanblock without DebugMark");
 
-	if((int64)(uintptr)n != n || n < 0) {
-		runtime_printf("debug_scanblock %p %D\n", b, n);
+	if((intptr)n < 0) {
+		runtime_printf("debug_scanblock %p %D\n", b, (int64)n);
 		runtime_throw("debug_scanblock");
 	}
 
@@ -374,7 +385,6 @@
 		if(s == nil)
 			continue;
 
-
 		p =  (byte*)((uintptr)s->start<<PageShift);
 		if(s->sizeclass == 0) {
 			obj = p;
@@ -411,53 +421,33 @@
 	}
 }
 
+static void
+markroot(ParFor *desc, uint32 i)
+{
+	USED(&desc);
+	scanblock(work.roots[i].p, work.roots[i].n);
+}
+
 // Get an empty work buffer off the work.empty list,
 // allocating new buffers as needed.
 static Workbuf*
 getempty(Workbuf *b)
 {
-	if(work.nproc == 1) {
-		// Put b on full list.
-		if(b != nil) {
-			b->next = work.full;
-			work.full = b;
+	if(b != nil)
+		runtime_lfstackpush(&work.full, &b->node);
+	b = (Workbuf*)runtime_lfstackpop(&work.empty);
+	if(b == nil) {
+		// Need to allocate.
+		runtime_lock(&work);
+		if(work.nchunk < sizeof *b) {
+			work.nchunk = 1<<20;
+			work.chunk = runtime_SysAlloc(work.nchunk);
 		}
-		// Grab from empty list if possible.
-		b = work.empty;
-		if(b != nil) {
-			work.empty = b->next;
-			goto haveb;
-		}
-	} else {
-		// Put b on full list.
-		if(b != nil) {
-			runtime_lock(&work.fmu);
-			b->next = work.full;
-			work.full = b;
-			runtime_unlock(&work.fmu);
-		}
-		// Grab from empty list if possible.
-		runtime_lock(&work.emu);
-		b = work.empty;
-		if(b != nil)
-			work.empty = b->next;
-		runtime_unlock(&work.emu);
-		if(b != nil)
-			goto haveb;
+		b = (Workbuf*)work.chunk;
+		work.chunk += sizeof *b;
+		work.nchunk -= sizeof *b;
+		runtime_unlock(&work);
 	}
-
-	// Need to allocate.
-	runtime_lock(&work);
-	if(work.nchunk < sizeof *b) {
-		work.nchunk = 1<<20;
-		work.chunk = runtime_SysAlloc(work.nchunk);
-	}
-	b = (Workbuf*)work.chunk;
-	work.chunk += sizeof *b;
-	work.nchunk -= sizeof *b;
-	runtime_unlock(&work);
-
-haveb:
 	b->nobj = 0;
 	return b;
 }
@@ -465,112 +455,95 @@
 static void
 putempty(Workbuf *b)
 {
-	if(b == nil)
-		return;
-
-	if(work.nproc == 1) {
-		b->next = work.empty;
-		work.empty = b;
-		return;
-	}
-
-	runtime_lock(&work.emu);
-	b->next = work.empty;
-	work.empty = b;
-	runtime_unlock(&work.emu);
+	runtime_lfstackpush(&work.empty, &b->node);
 }
 
 // Get a full work buffer off the work.full list, or return nil.
 static Workbuf*
 getfull(Workbuf *b)
 {
+	M *m;
 	int32 i;
-	Workbuf *b1;
 
-	if(work.nproc == 1) {
-		// Put b on empty list.
-		if(b != nil) {
-			b->next = work.empty;
-			work.empty = b;
-		}
-		// Grab from full list if possible.
-		// Since work.nproc==1, no one else is
-		// going to give us work.
-		b = work.full;
-		if(b != nil)
-			work.full = b->next;
+	if(b != nil)
+		runtime_lfstackpush(&work.empty, &b->node);
+	b = (Workbuf*)runtime_lfstackpop(&work.full);
+	if(b != nil || work.nproc == 1)
 		return b;
-	}
 
-	putempty(b);
-
-	// Grab buffer from full list if possible.
-	for(;;) {
-		b1 = work.full;
-		if(b1 == nil)
-			break;
-		runtime_lock(&work.fmu);
-		if(work.full != nil) {
-			b1 = work.full;
-			work.full = b1->next;
-			runtime_unlock(&work.fmu);
-			return b1;
-		}
-		runtime_unlock(&work.fmu);
-	}
-
+	m = runtime_m();
 	runtime_xadd(&work.nwait, +1);
 	for(i=0;; i++) {
-		b1 = work.full;
-		if(b1 != nil) {
-			runtime_lock(&work.fmu);
-			if(work.full != nil) {
-				runtime_xadd(&work.nwait, -1);
-				b1 = work.full;
-				work.full = b1->next;
-				runtime_unlock(&work.fmu);
-				return b1;
-			}
-			runtime_unlock(&work.fmu);
-			continue;
+		if(work.full != 0) {
+			runtime_xadd(&work.nwait, -1);
+			b = (Workbuf*)runtime_lfstackpop(&work.full);
+			if(b != nil)
+				return b;
+			runtime_xadd(&work.nwait, +1);
 		}
 		if(work.nwait == work.nproc)
 			return nil;
-		if(i < 10)
+		if(i < 10) {
+			m->gcstats.nprocyield++;
 			runtime_procyield(20);
-		else if(i < 20)
+		} else if(i < 20) {
+			m->gcstats.nosyield++;
 			runtime_osyield();
-		else
+		} else {
+			m->gcstats.nsleep++;
 			runtime_usleep(100);
+		}
 	}
 }
 
 static Workbuf*
 handoff(Workbuf *b)
 {
+	M *m;
 	int32 n;
 	Workbuf *b1;
 
+	m = runtime_m();
+
 	// Make new buffer with half of b's pointers.
 	b1 = getempty(nil);
 	n = b->nobj/2;
 	b->nobj -= n;
 	b1->nobj = n;
 	runtime_memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]);
-	nhandoff += n;
+	m->gcstats.nhandoff++;
+	m->gcstats.nhandoffcnt += n;
 
 	// Put b on full list - let first half of b get stolen.
-	runtime_lock(&work.fmu);
-	b->next = work.full;
-	work.full = b;
-	runtime_unlock(&work.fmu);
-
+	runtime_lfstackpush(&work.full, &b->node);
 	return b1;
 }
 
-// Scanstack calls scanblock on each of gp's stack segments.
 static void
-scanstack(void (*scanblock)(byte*, int64), G *gp)
+addroot(byte *p, uintptr n)
+{
+	uint32 cap;
+	GcRoot *new;
+
+	if(work.nroot >= work.rootcap) {
+		cap = PageSize/sizeof(GcRoot);
+		if(cap < 2*work.rootcap)
+			cap = 2*work.rootcap;
+		new = (GcRoot*)runtime_SysAlloc(cap*sizeof(GcRoot));
+		if(work.roots != nil) {
+			runtime_memmove(new, work.roots, work.rootcap*sizeof(GcRoot));
+			runtime_SysFree(work.roots, work.rootcap*sizeof(GcRoot));
+		}
+		work.roots = new;
+		work.rootcap = cap;
+	}
+	work.roots[work.nroot].p = p;
+	work.roots[work.nroot].n = n;
+	work.nroot++;
+}
+
+static void
+addstackroots(G *gp)
 {
 #ifdef USING_SPLIT_STACK
 	M *mp;
@@ -609,11 +582,11 @@
 		}
 	}
 	if(sp != nil) {
-		scanblock(sp, spsize);
+		addroot(sp, spsize);
 		while((sp = __splitstack_find(next_segment, next_sp,
 					      &spsize, &next_segment,
 					      &next_sp, &initial_sp)) != nil)
-			scanblock(sp, spsize);
+			addroot(sp, spsize);
 	}
 #else
 	M *mp;
@@ -635,16 +608,14 @@
 	}
 	top = (byte*)gp->gcinitial_sp + gp->gcstack_size;
 	if(top > bottom)
-		scanblock(bottom, top - bottom);
+		addroot(bottom, top - bottom);
 	else
-		scanblock(top, bottom - top);
+		addroot(top, bottom - top);
 #endif
 }
 
-// Markfin calls scanblock on the blocks that have finalizers:
-// the things pointed at cannot be freed until the finalizers have run.
 static void
-markfin(void *v)
+addfinroots(void *v)
 {
 	uintptr size;
 
@@ -653,7 +624,7 @@
 		runtime_throw("mark - finalizer inconsistency");
 
 	// do not mark the finalizer block itself.  just mark the things it points at.
-	scanblock(v, size);
+	addroot(v, size);
 }
 
 static struct root_list* roots;
@@ -668,22 +639,15 @@
 }
 
 static void
-debug_markfin(void *v)
-{
-	uintptr size;
-
-	if(!runtime_mlookup(v, (byte**)&v, &size, nil))
-		runtime_throw("debug_mark - finalizer inconsistency");
-	debug_scanblock(v, size);
-}
-
-// Mark
-static void
-mark(void (*scan)(byte*, int64))
+addroots(void)
 {
 	struct root_list *pl;
 	G *gp;
 	FinBlock *fb;
+	MSpan *s, **allspans;
+	uint32 spanidx;
+
+	work.nroot = 0;
 
 	// mark data+bss.
 	for(pl = roots; pl != nil; pl = pl->next) {
@@ -692,20 +656,36 @@
 			void *decl = pr->decl;
 			if(decl == nil)
 				break;
-			scanblock(decl, pr->size);
+			addroot(decl, pr->size);
 			pr++;
 		}
 	}
 
-	scan((byte*)&runtime_m0, sizeof runtime_m0);
-	scan((byte*)&runtime_g0, sizeof runtime_g0);
-	scan((byte*)&runtime_allg, sizeof runtime_allg);
-	scan((byte*)&runtime_allm, sizeof runtime_allm);
-	runtime_MProf_Mark(scan);
-	runtime_time_scan(scan);
-	runtime_trampoline_scan(scan);
+	addroot((byte*)&runtime_m0, sizeof runtime_m0);
+	addroot((byte*)&runtime_g0, sizeof runtime_g0);
+	addroot((byte*)&runtime_allg, sizeof runtime_allg);
+	addroot((byte*)&runtime_allm, sizeof runtime_allm);
+	runtime_MProf_Mark(addroot);
+	runtime_time_scan(addroot);
+	runtime_trampoline_scan(addroot);
 
-	// mark stacks
+	// MSpan.types
+	allspans = runtime_mheap.allspans;
+	for(spanidx=0; spanidx<runtime_mheap.nspan; spanidx++) {
+		s = allspans[spanidx];
+		if(s->state == MSpanInUse) {
+			switch(s->types.compression) {
+			case MTypes_Empty:
+			case MTypes_Single:
+				break;
+			case MTypes_Words:
+			case MTypes_Bytes:
+				addroot((byte*)&s->types.data, sizeof(void*));
+				break;
+			}
+		}
+	}
+
 	for(gp=runtime_allg; gp!=nil; gp=gp->alllink) {
 		switch(gp->status){
 		default:
@@ -716,27 +696,22 @@
 		case Grunning:
 			if(gp != runtime_g())
 				runtime_throw("mark - world not stopped");
-			scanstack(scan, gp);
+			addstackroots(gp);
 			break;
 		case Grunnable:
 		case Gsyscall:
 		case Gwaiting:
-			scanstack(scan, gp);
+			addstackroots(gp);
 			break;
 		}
 	}
 
-	// mark things pointed at by objects with finalizers
-	if(scan == debug_scanblock)
-		runtime_walkfintab(debug_markfin, scan);
-	else
-		runtime_walkfintab(markfin, scan);
+	runtime_walkfintab(addfinroots, addroot);
 
 	for(fb=allfin; fb; fb=fb->alllink)
-		scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]));
+		addroot((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]));
 
-	// in multiproc mode, join in the queued work.
-	scan(nil, 0);
+	addroot((byte*)&work, sizeof work);
 }
 
 static bool
@@ -771,122 +746,149 @@
 	f->fn = fn;
 	f->ft = ft;
 	f->arg = p;
-	runtime_unlock(&finlock); 
+	runtime_unlock(&finlock);
 	return true;
 }
 
 // Sweep frees or collects finalizers for blocks not marked in the mark phase.
 // It clears the mark bits in preparation for the next GC round.
 static void
-sweep(void)
+sweepspan(ParFor *desc, uint32 idx)
 {
 	M *m;
-	MSpan *s;
 	int32 cl, n, npages;
 	uintptr size;
 	byte *p;
 	MCache *c;
 	byte *arena_start;
-	int64 now;
+	MLink head, *end;
+	int32 nfree;
+	byte *type_data;
+	byte compression;
+	uintptr type_data_inc;
+	MSpan *s;
 
 	m = runtime_m();
+
+	USED(&desc);
+	s = runtime_mheap.allspans[idx];
+	// Stamp newly unused spans. The scavenger will use that
+	// info to potentially give back some pages to the OS.
+	if(s->state == MSpanFree && s->unusedsince == 0)
+		s->unusedsince = runtime_nanotime();
+	if(s->state != MSpanInUse)
+		return;
 	arena_start = runtime_mheap.arena_start;
-	now = runtime_nanotime();
+	p = (byte*)(s->start << PageShift);
+	cl = s->sizeclass;
+	size = s->elemsize;
+	if(cl == 0) {
+		n = 1;
+	} else {
+		// Chunk full of small blocks.
+		npages = runtime_class_to_allocnpages[cl];
+		n = (npages << PageShift) / size;
+	}
+	nfree = 0;
+	end = &head;
+	c = m->mcache;
+	
+	type_data = (byte*)s->types.data;
+	type_data_inc = sizeof(uintptr);
+	compression = s->types.compression;
+	switch(compression) {
+	case MTypes_Bytes:
+		type_data += 8*sizeof(uintptr);
+		type_data_inc = 1;
+		break;
+	}
 
-	for(;;) {
-		s = work.spans;
-		if(s == nil)
-			break;
-		if(!runtime_casp(&work.spans, s, s->allnext))
+	// Sweep through n objects of given size starting at p.
+	// This thread owns the span now, so it can manipulate
+	// the block bitmap without atomic operations.
+	for(; n > 0; n--, p += size, type_data+=type_data_inc) {
+		uintptr off, *bitp, shift, bits;
+
+		off = (uintptr*)p - (uintptr*)arena_start;
+		bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		bits = *bitp>>shift;
+
+		if((bits & bitAllocated) == 0)
 			continue;
 
-		// Stamp newly unused spans. The scavenger will use that
-		// info to potentially give back some pages to the OS.
-		if(s->state == MSpanFree && s->unusedsince == 0)
-			s->unusedsince = now;
-
-		if(s->state != MSpanInUse)
+		if((bits & bitMarked) != 0) {
+			if(DebugMark) {
+				if(!(bits & bitSpecial))
+					runtime_printf("found spurious mark on %p\n", p);
+				*bitp &= ~(bitSpecial<<shift);
+			}
+			*bitp &= ~(bitMarked<<shift);
 			continue;
-
-		p = (byte*)(s->start << PageShift);
-		cl = s->sizeclass;
-		if(cl == 0) {
-			size = s->npages<<PageShift;
-			n = 1;
-		} else {
-			// Chunk full of small blocks.
-			size = runtime_class_to_size[cl];
-			npages = runtime_class_to_allocnpages[cl];
-			n = (npages << PageShift) / size;
 		}
 
-		// Sweep through n objects of given size starting at p.
-		// This thread owns the span now, so it can manipulate
-		// the block bitmap without atomic operations.
-		for(; n > 0; n--, p += size) {
-			uintptr off, *bitp, shift, bits;
+		// Special means it has a finalizer or is being profiled.
+		// In DebugMark mode, the bit has been coopted so
+		// we have to assume all blocks are special.
+		if(DebugMark || (bits & bitSpecial) != 0) {
+			if(handlespecial(p, size))
+				continue;
+		}
 
-			off = (uintptr*)p - (uintptr*)arena_start;
-			bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
-			shift = off % wordsPerBitmapWord;
-			bits = *bitp>>shift;
+		// Mark freed; restore block boundary bit.
+		*bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
 
-			if((bits & bitAllocated) == 0)
-				continue;
-
-			if((bits & bitMarked) != 0) {
-				if(DebugMark) {
-					if(!(bits & bitSpecial))
-						runtime_printf("found spurious mark on %p\n", p);
-					*bitp &= ~(bitSpecial<<shift);
-				}
-				*bitp &= ~(bitMarked<<shift);
-				continue;
-			}
-
-			// Special means it has a finalizer or is being profiled.
-			// In DebugMark mode, the bit has been coopted so
-			// we have to assume all blocks are special.
-			if(DebugMark || (bits & bitSpecial) != 0) {
-				if(handlespecial(p, size))
-					continue;
-			}
-
-			// Mark freed; restore block boundary bit.
-			*bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
-
-			c = m->mcache;
-			if(s->sizeclass == 0) {
-				// Free large span.
-				runtime_unmarkspan(p, 1<<PageShift);
-				*(uintptr*)p = 1;	// needs zeroing
-				runtime_MHeap_Free(&runtime_mheap, s, 1);
-			} else {
-				// Free small object.
-				if(size > sizeof(uintptr))
-					((uintptr*)p)[1] = 1;	// mark as "needs to be zeroed"
-				c->local_by_size[s->sizeclass].nfree++;
-				runtime_MCache_Free(c, p, s->sizeclass, size);
-			}
+		if(cl == 0) {
+			// Free large span.
+			runtime_unmarkspan(p, 1<<PageShift);
+			*(uintptr*)p = 1;	// needs zeroing
+			runtime_MHeap_Free(&runtime_mheap, s, 1);
 			c->local_alloc -= size;
 			c->local_nfree++;
+		} else {
+			// Free small object.
+			switch(compression) {
+			case MTypes_Words:
+				*(uintptr*)type_data = 0;
+				break;
+			case MTypes_Bytes:
+				*(byte*)type_data = 0;
+				break;
+			}
+			if(size > sizeof(uintptr))
+				((uintptr*)p)[1] = 1;	// mark as "needs to be zeroed"
+			
+			end->next = (MLink*)p;
+			end = (MLink*)p;
+			nfree++;
 		}
 	}
+
+	if(nfree) {
+		c->local_by_size[cl].nfree += nfree;
+		c->local_alloc -= size * nfree;
+		c->local_nfree += nfree;
+		c->local_cachealloc -= nfree * size;
+		c->local_objects -= nfree;
+		runtime_MCentral_FreeSpan(&runtime_mheap.central[cl], s, nfree, head.next, end);
+	}
 }
 
 void
 runtime_gchelper(void)
 {
-	// Wait until main proc is ready for mark help.
-	runtime_lock(&work.markgate);
-	runtime_unlock(&work.markgate);
+	// parallel mark for over gc roots
+	runtime_parfordo(work.markfor);
+	// help other threads scan secondary blocks
 	scanblock(nil, 0);
 
-	// Wait until main proc is ready for sweep help.
-	runtime_lock(&work.sweepgate);
-	runtime_unlock(&work.sweepgate);
-	sweep();
+	if(DebugMark) {
+		// wait while the main thread executes mark(debug_scanblock)
+		while(runtime_atomicload(&work.debugmarkdone) == 0)
+			runtime_usleep(10);
+	}
 
+	runtime_parfordo(work.sweepfor);
 	if(runtime_xadd(&work.ndone, +1) == work.nproc-1)
 		runtime_notewakeup(&work.alldone);
 }
@@ -912,21 +914,31 @@
 }
 
 static void
-cachestats(void)
+cachestats(GCStats *stats)
 {
 	M *m;
 	MCache *c;
 	uint32 i;
 	uint64 stacks_inuse;
 	uint64 stacks_sys;
+	uint64 *src, *dst;
 
+	if(stats)
+		runtime_memclr((byte*)stats, sizeof(*stats));
 	stacks_inuse = 0;
 	stacks_sys = runtime_stacks_sys;
 	for(m=runtime_allm; m; m=m->alllink) {
-		runtime_purgecachedstats(m);
+		c = m->mcache;
+		runtime_purgecachedstats(c);
 		// stacks_inuse += m->stackalloc->inuse;
 		// stacks_sys += m->stackalloc->sys;
-		c = m->mcache;
+		if(stats) {
+			src = (uint64*)&m->gcstats;
+			dst = (uint64*)stats;
+			for(i=0; i<sizeof(*stats)/sizeof(uint64); i++)
+				dst[i] += src[i];
+			runtime_memclr((byte*)&m->gcstats, sizeof(m->gcstats));
+		}
 		for(i=0; i<nelem(c->local_by_size); i++) {
 			mstats.by_size[i].nmalloc += c->local_by_size[i].nmalloc;
 			c->local_by_size[i].nmalloc = 0;
@@ -945,7 +957,15 @@
 	int64 t0, t1, t2, t3;
 	uint64 heap0, heap1, obj0, obj1;
 	const byte *p;
-	bool extra;
+	GCStats stats;
+	M *m1;
+	uint32 i;
+
+	// The atomic operations are not atomic if the uint64s
+	// are not aligned on uint64 boundaries. This has been
+	// a problem in the past.
+	if((((uintptr)&work.empty) & 7) != 0)
+		runtime_throw("runtime: gc work buffer is misaligned");
 
 	// Make sure all registers are saved on stack so that
 	// scanstack sees them.
@@ -986,48 +1006,67 @@
 	}
 
 	t0 = runtime_nanotime();
-	nhandoff = 0;
 
 	m->gcing = 1;
 	runtime_stoptheworld();
 
-	cachestats();
-	heap0 = mstats.heap_alloc;
-	obj0 = mstats.nmalloc - mstats.nfree;
+	for(m1=runtime_allm; m1; m1=m1->alllink)
+		runtime_settype_flush(m1, false);
 
-	runtime_lock(&work.markgate);
-	runtime_lock(&work.sweepgate);
+	heap0 = 0;
+	obj0 = 0;
+	if(gctrace) {
+		cachestats(nil);
+		heap0 = mstats.heap_alloc;
+		obj0 = mstats.nmalloc - mstats.nfree;
+	}
 
-	extra = false;
-	work.nproc = 1;
-	if(runtime_gomaxprocs > 1 && runtime_ncpu > 1) {
-		runtime_noteclear(&work.alldone);
-		work.nproc += runtime_helpgc(&extra);
-	}
 	work.nwait = 0;
 	work.ndone = 0;
+	work.debugmarkdone = 0;
+	work.nproc = runtime_gcprocs();
+	addroots();
+	m->locks++;	// disable gc during mallocs in parforalloc
+	if(work.markfor == nil)
+		work.markfor = runtime_parforalloc(MaxGcproc);
+	runtime_parforsetup(work.markfor, work.nproc, work.nroot, nil, false, markroot);
+	if(work.sweepfor == nil)
+		work.sweepfor = runtime_parforalloc(MaxGcproc);
+	runtime_parforsetup(work.sweepfor, work.nproc, runtime_mheap.nspan, nil, true, sweepspan);
+	m->locks--;
+	if(work.nproc > 1) {
+		runtime_noteclear(&work.alldone);
+		runtime_helpgc(work.nproc);
+	}
 
-	runtime_unlock(&work.markgate);  // let the helpers in
-	mark(scanblock);
-	if(DebugMark)
-		mark(debug_scanblock);
+	runtime_parfordo(work.markfor);
+	scanblock(nil, 0);
+
+	if(DebugMark) {
+		for(i=0; i<work.nroot; i++)
+			debug_scanblock(work.roots[i].p, work.roots[i].n);
+		runtime_atomicstore(&work.debugmarkdone, 1);
+	}
 	t1 = runtime_nanotime();
 
-	work.spans = runtime_mheap.allspans;
-	runtime_unlock(&work.sweepgate);  // let the helpers in
-	sweep();
-	if(work.nproc > 1)
-		runtime_notesleep(&work.alldone);
+	runtime_parfordo(work.sweepfor);
 	t2 = runtime_nanotime();
 
 	stealcache();
-	cachestats();
+	cachestats(&stats);
+
+	if(work.nproc > 1)
+		runtime_notesleep(&work.alldone);
+
+	stats.nprocyield += work.sweepfor->nprocyield;
+	stats.nosyield += work.sweepfor->nosyield;
+	stats.nsleep += work.sweepfor->nsleep;
 
 	mstats.next_gc = mstats.heap_alloc+(mstats.heap_alloc-runtime_stacks_sys)*gcpercent/100;
 	m->gcing = 0;
 
-	m->locks++;	// disable gc during the mallocs in newproc
 	if(finq != nil) {
+		m->locks++;	// disable gc during the mallocs in newproc
 		// kick off or wake up goroutine to run queued finalizers
 		if(fing == nil)
 			fing = __go_go(runfinq, nil);
@@ -1035,10 +1074,9 @@
 			fingwait = 0;
 			runtime_ready(fing);
 		}
+		m->locks--;
 	}
-	m->locks--;
 
-	cachestats();
 	heap1 = mstats.heap_alloc;
 	obj1 = mstats.nmalloc - mstats.nfree;
 
@@ -1051,26 +1089,22 @@
 		runtime_printf("pause %D\n", t3-t0);
 
 	if(gctrace) {
-		runtime_printf("gc%d(%d): %D+%D+%D ms, %D -> %D MB %D -> %D (%D-%D) objects\n",
+		runtime_printf("gc%d(%d): %D+%D+%D ms, %D -> %D MB %D -> %D (%D-%D) objects,"
+				" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
 			mstats.numgc, work.nproc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000,
 			heap0>>20, heap1>>20, obj0, obj1,
-			mstats.nmalloc, mstats.nfree);
+			mstats.nmalloc, mstats.nfree,
+			stats.nhandoff, stats.nhandoffcnt,
+			work.sweepfor->nsteal, work.sweepfor->nstealcnt,
+			stats.nprocyield, stats.nosyield, stats.nsleep);
 	}
-	
+
 	runtime_MProf_GC();
 	runtime_semrelease(&runtime_worldsema);
+	runtime_starttheworld();
 
-	// If we could have used another helper proc, start one now,
-	// in the hope that it will be available next time.
-	// It would have been even better to start it before the collection,
-	// but doing so requires allocating memory, so it's tricky to
-	// coordinate.  This lazy approach works out in practice:
-	// we don't mind if the first couple gc rounds don't have quite
-	// the maximum number of procs.
-	runtime_starttheworld(extra);
-
-	// give the queued finalizers, if any, a chance to run	
-	if(finq != nil)	
+	// give the queued finalizers, if any, a chance to run
+	if(finq != nil)
 		runtime_gosched();
 
 	if(gctrace > 1 && !force)
@@ -1093,22 +1127,23 @@
 	m = runtime_m();
 	m->gcing = 1;
 	runtime_stoptheworld();
-	cachestats();
+	cachestats(nil);
 	*stats = mstats;
 	m->gcing = 0;
 	runtime_semrelease(&runtime_worldsema);
-	runtime_starttheworld(false);
+	runtime_starttheworld();
 }
 
 static void
 runfinq(void* dummy __attribute__ ((unused)))
 {
-	G* gp;
 	Finalizer *f;
 	FinBlock *fb, *next;
 	uint32 i;
 
-	gp = runtime_g();
+	if(raceenabled)
+		runtime_racefingo();
+
 	for(;;) {
 		// There's no need for a lock in this section
 		// because it only conflicts with the garbage
@@ -1120,9 +1155,7 @@
 		finq = nil;
 		if(fb == nil) {
 			fingwait = 1;
-			gp->status = Gwaiting;
-			gp->waitreason = "finalizer wait";
-			runtime_gosched();
+			runtime_park(nil, nil, "finalizer wait");
 			continue;
 		}
 		for(; fb; fb=next) {
diff -r bf12a7f41b67 libgo/runtime/mheap.c
--- a/libgo/runtime/mheap.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/mheap.c	Mon Oct 22 17:36:23 2012 -0700
@@ -27,11 +27,24 @@
 {
 	MHeap *h;
 	MSpan *s;
+	MSpan **all;
+	uint32 cap;
 
 	h = vh;
 	s = (MSpan*)p;
-	s->allnext = h->allspans;
-	h->allspans = s;
+	if(h->nspan >= h->nspancap) {
+		cap = 64*1024/sizeof(all[0]);
+		if(cap < h->nspancap*3/2)
+			cap = h->nspancap*3/2;
+		all = (MSpan**)runtime_SysAlloc(cap*sizeof(all[0]));
+		if(h->allspans) {
+			runtime_memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
+			runtime_SysFree(h->allspans, h->nspancap*sizeof(all[0]));
+		}
+		h->allspans = all;
+		h->nspancap = cap;
+	}
+	h->allspans[h->nspan++] = s;
 }
 
 // Initialize the heap; fetch memory using alloc.
@@ -53,12 +66,12 @@
 // Allocate a new span of npage pages from the heap
 // and record its size class in the HeapMap and HeapMapCache.
 MSpan*
-runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
+runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed)
 {
 	MSpan *s;
 
 	runtime_lock(h);
-	runtime_purgecachedstats(runtime_m());
+	runtime_purgecachedstats(runtime_m()->mcache);
 	s = MHeap_AllocLocked(h, npage, sizeclass);
 	if(s != nil) {
 		mstats.heap_inuse += npage<<PageShift;
@@ -68,6 +81,8 @@
 		}
 	}
 	runtime_unlock(h);
+	if(s != nil && *(uintptr*)(s->start<<PageShift) != 0 && zeroed)
+		runtime_memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
 	return s;
 }
 
@@ -125,12 +140,11 @@
 		MHeap_FreeLocked(h, t);
 	}
 
-	if(*(uintptr*)(s->start<<PageShift) != 0)
-		runtime_memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
-
 	// Record span info, because gc needs to be
 	// able to map interior pointer to containing span.
 	s->sizeclass = sizeclass;
+	s->elemsize = (sizeclass==0 ? s->npages<<PageShift : (uintptr)runtime_class_to_size[sizeclass]);
+	s->types.compression = MTypes_Empty;
 	p = s->start;
 	if(sizeof(void*) == 8)
 		p -= ((uintptr)h->arena_start>>PageShift);
@@ -259,7 +273,7 @@
 runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct)
 {
 	runtime_lock(h);
-	runtime_purgecachedstats(runtime_m());
+	runtime_purgecachedstats(runtime_m()->mcache);
 	mstats.heap_inuse -= s->npages<<PageShift;
 	if(acct) {
 		mstats.heap_alloc -= s->npages<<PageShift;
@@ -276,6 +290,10 @@
 	MSpan *t;
 	PageID p;
 
+	if(s->types.sysalloc)
+		runtime_settype_sysfree(s);
+	s->types.compression = MTypes_Empty;
+
 	if(s->state != MSpanInUse || s->ref != 0) {
 		runtime_printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
 		runtime_throw("MHeap_FreeLocked - invalid free");
@@ -416,9 +434,11 @@
 	span->freelist = nil;
 	span->ref = 0;
 	span->sizeclass = 0;
+	span->elemsize = 0;
 	span->state = 0;
 	span->unusedsince = 0;
 	span->npreleased = 0;
+	span->types.compression = MTypes_Empty;
 }
 
 // Initialize an empty doubly-linked list.
diff -r bf12a7f41b67 libgo/runtime/mprof.goc
--- a/libgo/runtime/mprof.goc	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/mprof.goc	Mon Oct 22 17:36:23 2012 -0700
@@ -15,21 +15,35 @@
 // NOTE(rsc): Everything here could use cas if contention became an issue.
 static Lock proflock;
 
-// Per-call-stack allocation information.
+enum { MProf, BProf };  // profile types
+
+// Per-call-stack profiling information.
 // Lookup by hashing call stack into a linked-list hash table.
 typedef struct Bucket Bucket;
 struct Bucket
 {
 	Bucket	*next;	// next in hash list
-	Bucket	*allnext;	// next in list of all buckets
-	uintptr	allocs;
-	uintptr	frees;
-	uintptr	alloc_bytes;
-	uintptr	free_bytes;
-	uintptr	recent_allocs;  // since last gc
-	uintptr	recent_frees;
-	uintptr	recent_alloc_bytes;
-	uintptr	recent_free_bytes;
+	Bucket	*allnext;	// next in list of all mbuckets/bbuckets
+	int32	typ;
+	union
+	{
+		struct  // typ == MProf
+		{
+			uintptr	allocs;
+			uintptr	frees;
+			uintptr	alloc_bytes;
+			uintptr	free_bytes;
+			uintptr	recent_allocs;  // since last gc
+			uintptr	recent_frees;
+			uintptr	recent_alloc_bytes;
+			uintptr	recent_free_bytes;
+		};
+		struct  // typ == BProf
+		{
+			int64	count;
+			int64	cycles;
+		};
+	};
 	uintptr	hash;
 	uintptr	nstk;
 	uintptr	stk[1];
@@ -38,12 +52,13 @@
 	BuckHashSize = 179999,
 };
 static Bucket **buckhash;
-static Bucket *buckets;
+static Bucket *mbuckets;  // memory profile buckets
+static Bucket *bbuckets;  // blocking profile buckets
 static uintptr bucketmem;
 
 // Return the bucket for stk[0:nstk], allocating new bucket if needed.
 static Bucket*
-stkbucket(uintptr *stk, int32 nstk, bool alloc)
+stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
 {
 	int32 i;
 	uintptr h;
@@ -66,7 +81,7 @@
 
 	i = h%BuckHashSize;
 	for(b = buckhash[i]; b; b=b->next)
-		if(b->hash == h && b->nstk == (uintptr)nstk &&
+		if(b->typ == typ && b->hash == h && b->nstk == (uintptr)nstk &&
 		   runtime_mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
 			return b;
 
@@ -76,12 +91,18 @@
 	b = runtime_mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
 	bucketmem += sizeof *b + nstk*sizeof stk[0];
 	runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
+	b->typ = typ;
 	b->hash = h;
 	b->nstk = nstk;
 	b->next = buckhash[i];
 	buckhash[i] = b;
-	b->allnext = buckets;
-	buckets = b;
+	if(typ == MProf) {
+		b->allnext = mbuckets;
+		mbuckets = b;
+	} else {
+		b->allnext = bbuckets;
+		bbuckets = b;
+	}
 	return b;
 }
 
@@ -92,7 +113,7 @@
 	Bucket *b;
 	
 	runtime_lock(&proflock);
-	for(b=buckets; b; b=b->allnext) {
+	for(b=mbuckets; b; b=b->allnext) {
 		b->allocs += b->recent_allocs;
 		b->frees += b->recent_frees;
 		b->alloc_bytes += b->recent_alloc_bytes;
@@ -107,20 +128,26 @@
 
 // Map from pointer to Bucket* that allocated it.
 // Three levels:
-//	Linked-list hash table for top N-20 bits.
-//	Array index for next 13 bits.
-//	Linked list for next 7 bits.
+//	Linked-list hash table for top N-AddrHashShift bits.
+//	Array index for next AddrDenseBits bits.
+//	Linked list for next AddrHashShift-AddrDenseBits bits.
 // This is more efficient than using a general map,
 // because of the typical clustering of the pointer keys.
 
 typedef struct AddrHash AddrHash;
 typedef struct AddrEntry AddrEntry;
 
+enum {
+	AddrHashBits = 12,	// good for 4GB of used address space
+	AddrHashShift = 20,	// each AddrHash knows about 1MB of address space
+	AddrDenseBits = 8,	// good for a profiling rate of 4096 bytes
+};
+
 struct AddrHash
 {
 	AddrHash *next;	// next in top-level hash table linked list
 	uintptr addr;	// addr>>20
-	AddrEntry *dense[1<<13];
+	AddrEntry *dense[1<<AddrDenseBits];
 };
 
 struct AddrEntry
@@ -130,9 +157,6 @@
 	Bucket *b;
 };
 
-enum {
-	AddrHashBits = 12	// 1MB per entry, so good for 4GB of used address space
-};
 static AddrHash *addrhash[1<<AddrHashBits];
 static AddrEntry *addrfree;
 static uintptr addrmem;
@@ -155,15 +179,15 @@
 	AddrHash *ah;
 	AddrEntry *e;
 
-	h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+	h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
 	for(ah=addrhash[h]; ah; ah=ah->next)
-		if(ah->addr == (addr>>20))
+		if(ah->addr == (addr>>AddrHashShift))
 			goto found;
 
 	ah = runtime_mallocgc(sizeof *ah, FlagNoProfiling, 0, 1);
 	addrmem += sizeof *ah;
 	ah->next = addrhash[h];
-	ah->addr = addr>>20;
+	ah->addr = addr>>AddrHashShift;
 	addrhash[h] = ah;
 
 found:
@@ -175,9 +199,9 @@
 		e[63].next = nil;
 	}
 	addrfree = e->next;
-	e->addr = (uint32)~(addr & ((1<<20)-1));
+	e->addr = (uint32)~(addr & ((1<<AddrHashShift)-1));
 	e->b = b;
-	h = (addr>>7)&(nelem(ah->dense)-1);	// entry in dense is top 13 bits of low 20.
+	h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1);	// entry in dense is top 8 bits of low 20.
 	e->next = ah->dense[h];
 	ah->dense[h] = e;
 }
@@ -191,16 +215,16 @@
 	AddrEntry *e, **l;
 	Bucket *b;
 
-	h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+	h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
 	for(ah=addrhash[h]; ah; ah=ah->next)
-		if(ah->addr == (addr>>20))
+		if(ah->addr == (addr>>AddrHashShift))
 			goto found;
 	return nil;
 
 found:
-	h = (addr>>7)&(nelem(ah->dense)-1);	// entry in dense is top 13 bits of low 20.
+	h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1);	// entry in dense is top 8 bits of low 20.
 	for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
-		if(e->addr == (uint32)~(addr & ((1<<20)-1))) {
+		if(e->addr == (uint32)~(addr & ((1<<AddrHashShift)-1))) {
 			*l = e->next;
 			b = e->b;
 			e->next = addrfree;
@@ -227,7 +251,7 @@
 	m->nomemprof++;
 	nstk = runtime_callers(1, stk, 32);
 	runtime_lock(&proflock);
-	b = stkbucket(stk, nstk, true);
+	b = stkbucket(MProf, stk, nstk, true);
 	b->recent_allocs++;
 	b->recent_alloc_bytes += size;
 	setaddrbucket((uintptr)p, b);
@@ -259,6 +283,37 @@
 	m->nomemprof--;
 }
 
+int64 runtime_blockprofilerate;  // in CPU ticks
+
+void runtime_SetBlockProfileRate(intgo) asm("runtime.SetBlockProfileRate");
+
+void
+runtime_SetBlockProfileRate(intgo rate)
+{
+	runtime_atomicstore64((uint64*)&runtime_blockprofilerate, rate * runtime_tickspersecond() / (1000*1000*1000));
+}
+
+void
+runtime_blockevent(int64 cycles, int32 skip)
+{
+	int32 nstk;
+	int64 rate;
+	uintptr stk[32];
+	Bucket *b;
+
+	if(cycles <= 0)
+		return;
+	rate = runtime_atomicload64((uint64*)&runtime_blockprofilerate);
+	if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
+		return;
+
+	nstk = runtime_callers(skip, stk, 32);
+	runtime_lock(&proflock);
+	b = stkbucket(BProf, stk, nstk, true);
+	b->count++;
+	b->cycles += cycles;
+	runtime_unlock(&proflock);
+}
 
 // Go interface to profile data.  (Declared in extern.go)
 // Assumes Go sizeof(int) == sizeof(int32)
@@ -287,20 +342,20 @@
 		r->stk[i] = 0;
 }
 
-func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
+func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
 	Bucket *b;
 	Record *r;
 
 	runtime_lock(&proflock);
 	n = 0;
-	for(b=buckets; b; b=b->allnext)
+	for(b=mbuckets; b; b=b->allnext)
 		if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
 			n++;
 	ok = false;
 	if(n <= p.__count) {
 		ok = true;
 		r = (Record*)p.__values;
-		for(b=buckets; b; b=b->allnext)
+		for(b=mbuckets; b; b=b->allnext)
 			if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
 				record(r++, b);
 	}
@@ -308,12 +363,46 @@
 }
 
 void
-runtime_MProf_Mark(void (*scan)(byte *, int64))
+runtime_MProf_Mark(void (*addroot)(byte *, uintptr))
 {
 	// buckhash is not allocated via mallocgc.
-	scan((byte*)&buckets, sizeof buckets);
-	scan((byte*)&addrhash, sizeof addrhash);
-	scan((byte*)&addrfree, sizeof addrfree);
+	addroot((byte*)&mbuckets, sizeof mbuckets);
+	addroot((byte*)&bbuckets, sizeof bbuckets);
+	addroot((byte*)&addrhash, sizeof addrhash);
+	addroot((byte*)&addrfree, sizeof addrfree);
+}
+
+// Must match BlockProfileRecord in debug.go.
+typedef struct BRecord BRecord;
+struct BRecord {
+	int64 count;
+	int64 cycles;
+	uintptr stk[32];
+};
+
+func BlockProfile(p Slice) (n int, ok bool) {
+	Bucket *b;
+	BRecord *r;
+	int32 i;
+
+	runtime_lock(&proflock);
+	n = 0;
+	for(b=bbuckets; b; b=b->allnext)
+		n++;
+	ok = false;
+	if(n <= p.__count) {
+		ok = true;
+		r = (BRecord*)p.__values;
+		for(b=bbuckets; b; b=b->allnext, r++) {
+			r->count = b->count;
+			r->cycles = b->cycles;
+			for(i=0; (uintptr)i<b->nstk && (uintptr)i<nelem(r->stk); i++)
+				r->stk[i] = b->stk[i];
+			for(; (uintptr)i<nelem(r->stk); i++)
+				r->stk[i] = 0;			
+		}
+	}
+	runtime_unlock(&proflock);
 }
 
 // Must match StackRecord in debug.go.
@@ -322,7 +411,7 @@
 	uintptr stk[32];
 };
 
-func ThreadCreateProfile(p Slice) (n int32, ok bool) {
+func ThreadCreateProfile(p Slice) (n int, ok bool) {
 	TRecord *r;
 	M *first, *m;
 	
@@ -341,7 +430,7 @@
 	}
 }
 
-func Stack(b Slice, all bool) (n int32) {
+func Stack(b Slice, all bool) (n int) {
 	byte *pc, *sp;
 	bool enablegc;
 	
@@ -378,7 +467,7 @@
 		runtime_m()->gcing = 0;
 		mstats.enablegc = enablegc;
 		runtime_semrelease(&runtime_worldsema);
-		runtime_starttheworld(false);
+		runtime_starttheworld();
 	}
 }
 
@@ -397,7 +486,7 @@
 		r->stk[n] = 0;
 }
 
-func GoroutineProfile(b Slice) (n int32, ok bool) {
+func GoroutineProfile(b Slice) (n int, ok bool) {
 	TRecord *r;
 	G *gp;
 	
@@ -423,7 +512,7 @@
 	
 		runtime_m()->gcing = 0;
 		runtime_semrelease(&runtime_worldsema);
-		runtime_starttheworld(false);
+		runtime_starttheworld();
 	}
 }
 
diff -r bf12a7f41b67 libgo/runtime/panic.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/panic.c	Mon Oct 22 17:36:23 2012 -0700
@@ -0,0 +1,115 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "go-defer.h"
+
+// Code related to defer, panic and recover.
+
+uint32 runtime_panicking;
+static Lock paniclk;
+
+// Run all deferred functions for the current goroutine.
+static void
+rundefer(void)
+{
+	G *g;
+	Defer *d;
+
+	g = runtime_g();
+	while((d = g->defer) != nil) {
+		void (*pfn)(void*);
+
+		g->defer = d->__next;
+		pfn = d->__pfn;
+		d->__pfn = nil;
+		if (pfn != nil)
+			(*pfn)(d->__arg);
+		runtime_free(d);
+	}
+}
+
+void
+runtime_startpanic(void)
+{
+	M *m;
+
+	m = runtime_m();
+	if(m->dying) {
+		runtime_printf("panic during panic\n");
+		runtime_exit(3);
+	}
+	m->dying = 1;
+	runtime_xadd(&runtime_panicking, 1);
+	runtime_lock(&paniclk);
+}
+
+void
+runtime_dopanic(int32 unused __attribute__ ((unused)))
+{
+	G *g;
+	static bool didothers;
+
+	g = runtime_g();
+	if(g->sig != 0)
+		runtime_printf("[signal %x code=%p addr=%p]\n",
+			       g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
+
+	if(runtime_gotraceback()){
+		if(g != runtime_m()->g0) {
+			runtime_printf("\n");
+			runtime_goroutineheader(g);
+			runtime_traceback();
+			runtime_goroutinetrailer(g);
+		}
+		if(!didothers) {
+			didothers = true;
+			runtime_tracebackothers(g);
+		}
+	}
+	runtime_unlock(&paniclk);
+	if(runtime_xadd(&runtime_panicking, -1) != 0) {
+		// Some other m is panicking too.
+		// Let it print what it needs to print.
+		// Wait forever without chewing up cpu.
+		// It will exit when it's done.
+		static Lock deadlock;
+		runtime_lock(&deadlock);
+		runtime_lock(&deadlock);
+	}
+
+	runtime_exit(2);
+}
+
+void
+runtime_throw(const char *s)
+{
+	runtime_startpanic();
+	runtime_printf("throw: %s\n", s);
+	runtime_dopanic(0);
+	*(int32*)0 = 0;	// not reached
+	runtime_exit(1);	// even more not reached
+}
+
+void
+runtime_panicstring(const char *s)
+{
+	Eface err;
+
+	if(runtime_m()->gcing) {
+		runtime_printf("panic: %s\n", s);
+		runtime_throw("panic during gc");
+	}
+	runtime_newErrorString(runtime_gostringnocopy((const byte*)s), &err);
+	runtime_panic(err);
+}
+
+void runtime_Goexit (void) asm ("runtime.Goexit");
+
+void
+runtime_Goexit(void)
+{
+	rundefer();
+	runtime_goexit();
+}
diff -r bf12a7f41b67 libgo/runtime/parfor.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/parfor.c	Mon Oct 22 17:36:23 2012 -0700
@@ -0,0 +1,232 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parallel for algorithm.
+
+#include "runtime.h"
+#include "arch.h"
+
+struct ParForThread
+{
+	// the thread's iteration space [32lsb, 32msb)
+	uint64 pos;
+	// stats
+	uint64 nsteal;
+	uint64 nstealcnt;
+	uint64 nprocyield;
+	uint64 nosyield;
+	uint64 nsleep;
+	byte pad[CacheLineSize];
+};
+
+ParFor*
+runtime_parforalloc(uint32 nthrmax)
+{
+	ParFor *desc;
+
+	// The ParFor object is followed by CacheLineSize padding
+	// and then nthrmax ParForThread.
+	desc = (ParFor*)runtime_malloc(sizeof(ParFor) + CacheLineSize + nthrmax * sizeof(ParForThread));
+	desc->thr = (ParForThread*)((byte*)(desc+1) + CacheLineSize);
+	desc->nthrmax = nthrmax;
+	return desc;
+}
+
+// For testing from Go
+// func parforalloc2(nthrmax uint32) *ParFor
+
+ParFor *runtime_parforalloc2(uint32)
+   asm("runtime.parforalloc2");
+
+ParFor *
+runtime_parforalloc2(uint32 nthrmax)
+{
+	return runtime_parforalloc(nthrmax);
+}
+
+void
+runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
+{
+	uint32 i, begin, end;
+
+	if(desc == nil || nthr == 0 || nthr > desc->nthrmax || body == nil) {
+		runtime_printf("desc=%p nthr=%d count=%d body=%p\n", desc, nthr, n, body);
+		runtime_throw("parfor: invalid args");
+	}
+
+	desc->body = body;
+	desc->done = 0;
+	desc->nthr = nthr;
+	desc->thrseq = 0;
+	desc->cnt = n;
+	desc->ctx = ctx;
+	desc->wait = wait;
+	desc->nsteal = 0;
+	desc->nstealcnt = 0;
+	desc->nprocyield = 0;
+	desc->nosyield = 0;
+	desc->nsleep = 0;
+	for(i=0; i<nthr; i++) {
+		begin = (uint64)n*i / nthr;
+		end = (uint64)n*(i+1) / nthr;
+		desc->thr[i].pos = (uint64)begin | (((uint64)end)<<32);
+	}
+}
+
+// For testing from Go
+// func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
+
+void runtime_parforsetup2(ParFor *, uint32, uint32, void *, bool, void *)
+  asm("runtime.parforsetup2");
+
+void
+runtime_parforsetup2(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void *body)
+{
+	runtime_parforsetup(desc, nthr, n, ctx, wait, (void(*)(ParFor*, uint32))body);
+}
+
+void
+runtime_parfordo(ParFor *desc)
+{
+	ParForThread *me;
+	uint32 tid, begin, end, begin2, try, victim, i;
+	uint64 *mypos, *victimpos, pos, newpos;
+	void (*body)(ParFor*, uint32);
+	bool idle;
+
+	// Obtain 0-based thread index.
+	tid = runtime_xadd(&desc->thrseq, 1) - 1;
+	if(tid >= desc->nthr) {
+		runtime_printf("tid=%d nthr=%d\n", tid, desc->nthr);
+		runtime_throw("parfor: invalid tid");
+	}
+
+	// If single-threaded, just execute the for serially.
+	if(desc->nthr==1) {
+		for(i=0; i<desc->cnt; i++)
+			desc->body(desc, i);
+		return;
+	}
+
+	body = desc->body;
+	me = &desc->thr[tid];
+	mypos = &me->pos;
+	for(;;) {
+		for(;;) {
+			// While there is local work,
+			// bump low index and execute the iteration.
+			pos = runtime_xadd64(mypos, 1);
+			begin = (uint32)pos-1;
+			end = (uint32)(pos>>32);
+			if(begin < end) {
+				body(desc, begin);
+				continue;
+			}
+			break;
+		}
+
+		// Out of work, need to steal something.
+		idle = false;
+		for(try=0;; try++) {
+			// If we don't see any work for long enough,
+			// increment the done counter...
+			if(try > desc->nthr*4 && !idle) {
+				idle = true;
+				runtime_xadd(&desc->done, 1);
+			}
+			// ...if all threads have incremented the counter,
+			// we are done.
+			if(desc->done + !idle == desc->nthr) {
+				if(!idle)
+					runtime_xadd(&desc->done, 1);
+				goto exit;
+			}
+			// Choose a random victim for stealing.
+			victim = runtime_fastrand1() % (desc->nthr-1);
+			if(victim >= tid)
+				victim++;
+			victimpos = &desc->thr[victim].pos;
+			pos = runtime_atomicload64(victimpos);
+			for(;;) {
+				// See if it has any work.
+				begin = (uint32)pos;
+				end = (uint32)(pos>>32);
+				if(begin >= end-1) {
+					begin = end = 0;
+					break;
+				}
+				if(idle) {
+					runtime_xadd(&desc->done, -1);
+					idle = false;
+				}
+				begin2 = begin + (end-begin)/2;
+				newpos = (uint64)begin | (uint64)begin2<<32;
+				if(runtime_cas64(victimpos, &pos, newpos)) {
+					begin = begin2;
+					break;
+				}
+			}
+			if(begin < end) {
+				// Has successfully stolen some work.
+				if(idle)
+					runtime_throw("parfor: should not be idle");
+				runtime_atomicstore64(mypos, (uint64)begin | (uint64)end<<32);
+				me->nsteal++;
+				me->nstealcnt += end-begin;
+				break;
+			}
+			// Backoff.
+			if(try < desc->nthr) {
+				// nothing
+			} else if (try < 4*desc->nthr) {
+				me->nprocyield++;
+				runtime_procyield(20);
+			// If a caller asked not to wait for the others, exit now
+			// (assume that most work is already done at this point).
+			} else if (!desc->wait) {
+				if(!idle)
+					runtime_xadd(&desc->done, 1);
+				goto exit;
+			} else if (try < 6*desc->nthr) {
+				me->nosyield++;
+				runtime_osyield();
+			} else {
+				me->nsleep++;
+				runtime_usleep(1);
+			}
+		}
+	}
+exit:
+	runtime_xadd64(&desc->nsteal, me->nsteal);
+	runtime_xadd64(&desc->nstealcnt, me->nstealcnt);
+	runtime_xadd64(&desc->nprocyield, me->nprocyield);
+	runtime_xadd64(&desc->nosyield, me->nosyield);
+	runtime_xadd64(&desc->nsleep, me->nsleep);
+	me->nsteal = 0;
+	me->nstealcnt = 0;
+	me->nprocyield = 0;
+	me->nosyield = 0;
+	me->nsleep = 0;
+}
+
+// For testing from Go
+// func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+
+struct parforiters_ret {
+  uintptr start;
+  uintptr end;
+};
+
+struct parforiters_ret runtime_parforiters(ParFor *, uintptr)
+  asm("runtime.parforiters");
+
+struct parforiters_ret
+runtime_parforiters(ParFor *desc, uintptr tid)
+{
+	struct parforiters_ret ret;
+
+	ret.start = (uint32)desc->thr[tid].pos;
+	ret.end = (uint32)(desc->thr[tid].pos>>32);
+	return ret;
+}
diff -r bf12a7f41b67 libgo/runtime/print.c
--- a/libgo/runtime/print.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/print.c	Mon Oct 22 17:36:23 2012 -0700
@@ -156,15 +156,16 @@
 	int32 e, s, i, n;
 	float64 h;
 
-	if(runtime_isNaN(v)) {
+	if(ISNAN(v)) {
 		gwrite("NaN", 3);
 		return;
 	}
-	if(runtime_isInf(v, 1)) {
+	i = __builtin_isinf_sign(v);
+	if(i > 0) {
 		gwrite("+Inf", 4);
 		return;
 	}
-	if(runtime_isInf(v, -1)) {
+	if(i < 0) {
 		gwrite("-Inf", 4);
 		return;
 	}
@@ -290,8 +291,8 @@
 	// extern uint32 runtime_maxstring;
 
 	// if(v.len > runtime_maxstring) {
-	// 	gwrite("[invalid string]", 16);
-	// 	return;
+	//	gwrite("[string too long]", 17);
+	//	return;
 	// }
 	if(v.__length > 0)
 		gwrite(v.__data, v.__length);
diff -r bf12a7f41b67 libgo/runtime/proc.c
--- a/libgo/runtime/proc.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/proc.c	Mon Oct 22 17:36:23 2012 -0700
@@ -17,6 +17,7 @@
 #include "arch.h"
 #include "defs.h"
 #include "malloc.h"
+#include "race.h"
 #include "go-defer.h"
 
 #ifdef USING_SPLIT_STACK
@@ -330,6 +331,9 @@
 {
 	void (*fn)(void*);
 
+	if(g->traceback != nil)
+		gtraceback(g);
+
 	fn = (void (*)(void*))(g->entry);
 	fn(g->param);
 	runtime_goexit();
@@ -471,6 +475,9 @@
 	// Can not enable GC until all roots are registered.
 	// mstats.enablegc = 1;
 	m->nomemprof--;
+
+	if(raceenabled)
+		runtime_raceinit();
 }
 
 extern void main_init(void) __asm__ ("__go_init_main");
@@ -507,6 +514,8 @@
 	runtime_gosched();
 
 	main_main();
+	if(raceenabled)
+		runtime_racefini();
 	runtime_exit(0);
 	for(;;)
 		*(int32*)0 = 0;
@@ -540,11 +549,11 @@
 }
 
 void
-runtime_goroutineheader(G *g)
+runtime_goroutineheader(G *gp)
 {
 	const char *status;
 
-	switch(g->status) {
+	switch(gp->status) {
 	case Gidle:
 		status = "idle";
 		break;
@@ -558,8 +567,8 @@
 		status = "syscall";
 		break;
 	case Gwaiting:
-		if(g->waitreason)
-			status = g->waitreason;
+		if(gp->waitreason)
+			status = gp->waitreason;
 		else
 			status = "waiting";
 		break;
@@ -570,7 +579,7 @@
 		status = "???";
 		break;
 	}
-	runtime_printf("goroutine %d [%s]:\n", g->goid, status);
+	runtime_printf("goroutine %d [%s]:\n", gp->goid, status);
 }
 
 void
@@ -598,15 +607,15 @@
 void
 runtime_tracebackothers(G * volatile me)
 {
-	G * volatile g;
+	G * volatile gp;
 	Traceback traceback;
 
 	traceback.gp = me;
-	for(g = runtime_allg; g != nil; g = g->alllink) {
-		if(g == me || g->status == Gdead)
+	for(gp = runtime_allg; gp != nil; gp = gp->alllink) {
+		if(gp == me || gp->status == Gdead)
 			continue;
 		runtime_printf("\n");
-		runtime_goroutineheader(g);
+		runtime_goroutineheader(gp);
 
 		// Our only mechanism for doing a stack trace is
 		// _Unwind_Backtrace.  And that only works for the
@@ -616,25 +625,25 @@
 
 		// This means that if g is running or in a syscall, we
 		// can't reliably print a stack trace.  FIXME.
-		if(g->status == Gsyscall || g->status == Grunning) {
+		if(gp->status == Gsyscall || gp->status == Grunning) {
 			runtime_printf("no stack trace available\n");
-			runtime_goroutinetrailer(g);
+			runtime_goroutinetrailer(gp);
 			continue;
 		}
 
-		g->traceback = &traceback;
+		gp->traceback = &traceback;
 
 #ifdef USING_SPLIT_STACK
 		__splitstack_getcontext(&me->stack_context[0]);
 #endif
 		getcontext(&me->context);
 
-		if(g->traceback != nil) {
-			runtime_gogo(g);
+		if(gp->traceback != nil) {
+			runtime_gogo(gp);
 		}
 
 		runtime_printtrace(traceback.pcbuf, traceback.c);
-		runtime_goroutinetrailer(g);
+		runtime_goroutinetrailer(gp);
 	}
 }
 
@@ -666,22 +675,22 @@
 }
 
 static void
-mcommoninit(M *m)
+mcommoninit(M *mp)
 {
-	m->id = runtime_sched.mcount++;
-	m->fastrand = 0x49f6428aUL + m->id + runtime_cputicks();
+	mp->id = runtime_sched.mcount++;
+	mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks();
 
-	if(m->mcache == nil)
-		m->mcache = runtime_allocmcache();
+	if(mp->mcache == nil)
+		mp->mcache = runtime_allocmcache();
 
-	runtime_callers(1, m->createstack, nelem(m->createstack));
+	runtime_callers(1, mp->createstack, nelem(mp->createstack));
 
 	// Add to runtime_allm so garbage collector doesn't free m
 	// when it is just in a register or thread-local storage.
-	m->alllink = runtime_allm;
+	mp->alllink = runtime_allm;
 	// runtime_NumCgoCall() iterates over allm w/o schedlock,
 	// so we need to publish it safely.
-	runtime_atomicstorep(&runtime_allm, m);
+	runtime_atomicstorep(&runtime_allm, mp);
 }
 
 // Try to increment mcpu.  Report whether succeeded.
@@ -701,34 +710,34 @@
 
 // Put on `g' queue.  Sched must be locked.
 static void
-gput(G *g)
+gput(G *gp)
 {
-	M *m;
+	M *mp;
 
 	// If g is wired, hand it off directly.
-	if((m = g->lockedm) != nil && canaddmcpu()) {
-		mnextg(m, g);
+	if((mp = gp->lockedm) != nil && canaddmcpu()) {
+		mnextg(mp, gp);
 		return;
 	}
 
 	// If g is the idle goroutine for an m, hand it off.
-	if(g->idlem != nil) {
-		if(g->idlem->idleg != nil) {
+	if(gp->idlem != nil) {
+		if(gp->idlem->idleg != nil) {
 			runtime_printf("m%d idle out of sync: g%d g%d\n",
-				g->idlem->id,
-				g->idlem->idleg->goid, g->goid);
+				gp->idlem->id,
+				gp->idlem->idleg->goid, gp->goid);
 			runtime_throw("runtime: double idle");
 		}
-		g->idlem->idleg = g;
+		gp->idlem->idleg = gp;
 		return;
 	}
 
-	g->schedlink = nil;
+	gp->schedlink = nil;
 	if(runtime_sched.ghead == nil)
-		runtime_sched.ghead = g;
+		runtime_sched.ghead = gp;
 	else
-		runtime_sched.gtail->schedlink = g;
-	runtime_sched.gtail = g;
+		runtime_sched.gtail->schedlink = gp;
+	runtime_sched.gtail = gp;
 
 	// increment gwait.
 	// if it transitions to nonzero, set atomic gwaiting bit.
@@ -747,11 +756,11 @@
 static G*
 gget(void)
 {
-	G *g;
+	G *gp;
 
-	g = runtime_sched.ghead;
-	if(g){
-		runtime_sched.ghead = g->schedlink;
+	gp = runtime_sched.ghead;
+	if(gp) {
+		runtime_sched.ghead = gp->schedlink;
 		if(runtime_sched.ghead == nil)
 			runtime_sched.gtail = nil;
 		// decrement gwait.
@@ -759,45 +768,45 @@
 		if(--runtime_sched.gwait == 0)
 			runtime_xadd(&runtime_sched.atomic, -1<<gwaitingShift);
 	} else if(m->idleg != nil) {
-		g = m->idleg;
+		gp = m->idleg;
 		m->idleg = nil;
 	}
-	return g;
+	return gp;
 }
 
 // Put on `m' list.  Sched must be locked.
 static void
-mput(M *m)
+mput(M *mp)
 {
-	m->schedlink = runtime_sched.mhead;
-	runtime_sched.mhead = m;
+	mp->schedlink = runtime_sched.mhead;
+	runtime_sched.mhead = mp;
 	runtime_sched.mwait++;
 }
 
 // Get an `m' to run `g'.  Sched must be locked.
 static M*
-mget(G *g)
+mget(G *gp)
 {
-	M *m;
+	M *mp;
 
 	// if g has its own m, use it.
-	if(g && (m = g->lockedm) != nil)
-		return m;
+	if(gp && (mp = gp->lockedm) != nil)
+		return mp;
 
 	// otherwise use general m pool.
-	if((m = runtime_sched.mhead) != nil){
-		runtime_sched.mhead = m->schedlink;
+	if((mp = runtime_sched.mhead) != nil) {
+		runtime_sched.mhead = mp->schedlink;
 		runtime_sched.mwait--;
 	}
-	return m;
+	return mp;
 }
 
 // Mark g ready to run.
 void
-runtime_ready(G *g)
+runtime_ready(G *gp)
 {
 	schedlock();
-	readylocked(g);
+	readylocked(gp);
 	schedunlock();
 }
 
@@ -805,23 +814,23 @@
 // G might be running already and about to stop.
 // The sched lock protects g->status from changing underfoot.
 static void
-readylocked(G *g)
+readylocked(G *gp)
 {
-	if(g->m){
+	if(gp->m) {
 		// Running on another machine.
 		// Ready it when it stops.
-		g->readyonstop = 1;
+		gp->readyonstop = 1;
 		return;
 	}
 
 	// Mark runnable.
-	if(g->status == Grunnable || g->status == Grunning) {
-		runtime_printf("goroutine %d has status %d\n", g->goid, g->status);
+	if(gp->status == Grunnable || gp->status == Grunning) {
+		runtime_printf("goroutine %d has status %d\n", gp->goid, gp->status);
 		runtime_throw("bad g->status in ready");
 	}
-	g->status = Grunnable;
+	gp->status = Grunnable;
 
-	gput(g);
+	gput(gp);
 	matchmg();
 }
 
@@ -829,23 +838,23 @@
 // debuggers can set a breakpoint here and catch all
 // new goroutines.
 static void
-newprocreadylocked(G *g)
+newprocreadylocked(G *gp)
 {
-	readylocked(g);
+	readylocked(gp);
 }
 
 // Pass g to m for running.
 // Caller has already incremented mcpu.
 static void
-mnextg(M *m, G *g)
+mnextg(M *mp, G *gp)
 {
 	runtime_sched.grunning++;
-	m->nextg = g;
-	if(m->waitnextg) {
-		m->waitnextg = 0;
+	mp->nextg = gp;
+	if(mp->waitnextg) {
+		mp->waitnextg = 0;
 		if(mwakeup != nil)
 			runtime_notewakeup(&mwakeup->havenextg);
-		mwakeup = m;
+		mwakeup = mp;
 	}
 }
 
@@ -969,35 +978,38 @@
 }
 
 int32
-runtime_helpgc(bool *extra)
+runtime_gcprocs(void)
+{
+	int32 n;
+	
+	// Figure out how many CPUs to use during GC.
+	// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
+	n = runtime_gomaxprocs;
+	if(n > runtime_ncpu)
+		n = runtime_ncpu > 0 ? runtime_ncpu : 1;
+	if(n > MaxGcproc)
+		n = MaxGcproc;
+	if(n > runtime_sched.mwait+1) // one M is currently running
+		n = runtime_sched.mwait+1;
+	return n;
+}
+
+void
+runtime_helpgc(int32 nproc)
 {
 	M *mp;
-	int32 n, max;
-
-	// Figure out how many CPUs to use.
-	// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
-	max = runtime_gomaxprocs;
-	if(max > runtime_ncpu)
-		max = runtime_ncpu > 0 ? runtime_ncpu : 1;
-	if(max > MaxGcproc)
-		max = MaxGcproc;
-
-	// We're going to use one CPU no matter what.
-	// Figure out the max number of additional CPUs.
-	max--;
+	int32 n;
 
 	runtime_lock(&runtime_sched);
-	n = 0;
-	while(n < max && (mp = mget(nil)) != nil) {
-		n++;
+	for(n = 1; n < nproc; n++) { // one M is currently running
+		mp = mget(nil);
+		if(mp == nil)
+			runtime_throw("runtime_gcprocs inconsistency");
 		mp->helpgc = 1;
 		mp->waitnextg = 0;
 		runtime_notewakeup(&mp->havenextg);
 	}
 	runtime_unlock(&runtime_sched);
-	if(extra)
-		*extra = n != max;
-	return n;
 }
 
 void
@@ -1037,26 +1049,38 @@
 }
 
 void
-runtime_starttheworld(bool extra)
+runtime_starttheworld(void)
 {
-	M *m;
+	M *mp;
+	int32 max;
+	
+	// Figure out how many CPUs GC could possibly use.
+	max = runtime_gomaxprocs;
+	if(max > runtime_ncpu)
+		max = runtime_ncpu > 0 ? runtime_ncpu : 1;
+	if(max > MaxGcproc)
+		max = MaxGcproc;
 
 	schedlock();
 	runtime_gcwaiting = 0;
 	setmcpumax(runtime_gomaxprocs);
 	matchmg();
-	if(extra && canaddmcpu()) {
-		// Start a new m that will (we hope) be idle
-		// and so available to help when the next
-		// garbage collection happens.
+	if(runtime_gcprocs() < max && canaddmcpu()) {
+		// If GC could have used another helper proc, start one now,
+		// in the hope that it will be available next time.
+		// It would have been even better to start it before the collection,
+		// but doing so requires allocating memory, so it's tricky to
+		// coordinate.  This lazy approach works out in practice:
+		// we don't mind if the first couple gc rounds don't have quite
+		// the maximum number of procs.
 		// canaddmcpu above did mcpu++
 		// (necessary, because m will be doing various
 		// initialization work so is definitely running),
 		// but m is not running a specific goroutine,
 		// so set the helpgc flag as a signal to m's
 		// first schedule(nil) to mcpu-- and grunning--.
-		m = runtime_newm();
-		m->helpgc = 1;
+		mp = runtime_newm();
+		mp->helpgc = 1;
 		runtime_sched.grunning++;
 	}
 	schedunlock();
@@ -1110,6 +1134,11 @@
 		runtime_initsig();
 
 	schedule(nil);
+
+	// TODO(brainman): This point is never reached, because scheduler
+	// does not release os threads at the moment. But once this path
+	// is enabled, we must remove our seh here.
+
 	return nil;
 }
 
@@ -1148,14 +1177,14 @@
 M*
 runtime_newm(void)
 {
-	M *m;
+	M *mp;
 	pthread_attr_t attr;
 	pthread_t tid;
 	size_t stacksize;
 
-	m = runtime_malloc(sizeof(M));
-	mcommoninit(m);
-	m->g0 = runtime_malg(-1, nil, nil);
+	mp = runtime_malloc(sizeof(M));
+	mcommoninit(mp);
+	mp->g0 = runtime_malg(-1, nil, nil);
 
 	if(pthread_attr_init(&attr) != 0)
 		runtime_throw("pthread_attr_init");
@@ -1175,10 +1204,10 @@
 	if(pthread_attr_setstacksize(&attr, stacksize) != 0)
 		runtime_throw("pthread_attr_setstacksize");
 
-	if(pthread_create(&tid, &attr, runtime_mstart, m) != 0)
+	if(pthread_create(&tid, &attr, runtime_mstart, mp) != 0)
 		runtime_throw("pthread_create");
 
-	return m;
+	return mp;
 }
 
 // One round of scheduler: find a goroutine and run it.
@@ -1202,7 +1231,7 @@
 		if(atomic_mcpu(v) > maxgomaxprocs)
 			runtime_throw("negative mcpu in scheduler");
 
-		switch(gp->status){
+		switch(gp->status) {
 		case Grunnable:
 		case Gdead:
 			// Shouldn't have been running!
@@ -1212,6 +1241,8 @@
 			gput(gp);
 			break;
 		case Gmoribund:
+			if(raceenabled)
+				runtime_racegoend(gp->goid);
 			gp->status = Gdead;
 			if(gp->lockedm) {
 				gp->lockedm = nil;
@@ -1224,7 +1255,7 @@
 				runtime_exit(0);
 			break;
 		}
-		if(gp->readyonstop){
+		if(gp->readyonstop) {
 			gp->readyonstop = 0;
 			readylocked(gp);
 		}
@@ -1272,6 +1303,18 @@
 	runtime_mcall(schedule);
 }
 
+// Puts the current goroutine into a waiting state and unlocks the lock.
+// The goroutine can be made runnable again by calling runtime_ready(gp).
+void
+runtime_park(void (*unlockf)(Lock*), Lock *lock, const char *reason)
+{
+	g->status = Gwaiting;
+	g->waitreason = reason;
+	if(unlockf)
+		unlockf(lock);
+	runtime_gosched();
+}
+
 // The goroutine g is about to enter a system call.
 // Record that it's not using the cpu anymore.
 // This is called only from the go syscall library and cgocall,
@@ -1448,10 +1491,15 @@
 	byte *sp;
 	size_t spsize;
 	G *newg;
+	int32 goid;
+
+	goid = runtime_xadd((uint32*)&runtime_sched.goidgen, 1);
+	if(raceenabled)
+		runtime_racegostart(goid, runtime_getcallerpc(&fn));
 
 	schedlock();
 
-	if((newg = gfget()) != nil){
+	if((newg = gfget()) != nil) {
 #ifdef USING_SPLIT_STACK
 		int dont_block_signals = 0;
 
@@ -1482,8 +1530,7 @@
 	newg->gopc = (uintptr)__builtin_return_address(0);
 
 	runtime_sched.gcount++;
-	runtime_sched.goidgen++;
-	newg->goid = runtime_sched.goidgen;
+	newg->goid = goid;
 
 	if(sp == nil)
 		runtime_throw("nil g->stack0");
@@ -1512,49 +1559,22 @@
 
 // Put on gfree list.  Sched must be locked.
 static void
-gfput(G *g)
+gfput(G *gp)
 {
-	g->schedlink = runtime_sched.gfree;
-	runtime_sched.gfree = g;
+	gp->schedlink = runtime_sched.gfree;
+	runtime_sched.gfree = gp;
 }
 
 // Get from gfree list.  Sched must be locked.
 static G*
 gfget(void)
 {
-	G *g;
+	G *gp;
 
-	g = runtime_sched.gfree;
-	if(g)
-		runtime_sched.gfree = g->schedlink;
-	return g;
-}
-
-// Run all deferred functions for the current goroutine.
-static void
-rundefer(void)
-{
-	Defer *d;
-
-	while((d = g->defer) != nil) {
-		void (*pfn)(void*);
-
-		pfn = d->__pfn;
-		d->__pfn = nil;
-		if (pfn != nil)
-			(*pfn)(d->__arg);
-		g->defer = d->__next;
-		runtime_free(d);
-	}
-}
-
-void runtime_Goexit (void) asm ("runtime.Goexit");
-
-void
-runtime_Goexit(void)
-{
-	rundefer();
-	runtime_goexit();
+	gp = runtime_sched.gfree;
+	if(gp)
+		runtime_sched.gfree = gp->schedlink;
+	return gp;
 }
 
 void runtime_Gosched (void) asm ("runtime.Gosched");
@@ -1651,10 +1671,10 @@
 	return m->id;
 }
 
-int32 runtime_NumGoroutine (void)
+intgo runtime_NumGoroutine (void)
   __asm__ ("runtime.NumGoroutine");
 
-int32
+intgo
 runtime_NumGoroutine()
 {
 	return runtime_sched.gcount;
diff -r bf12a7f41b67 libgo/runtime/race.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/race.h	Mon Oct 22 17:36:23 2012 -0700
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Definitions related to data race detection.
+
+#ifdef RACE
+enum { raceenabled = 1 };
+#else
+enum { raceenabled = 0 };
+#endif
+
+// Initialize race detection subsystem.
+void	runtime_raceinit(void);
+// Finalize race detection subsystem, does not return.
+void	runtime_racefini(void);
+
+void	runtime_racemalloc(void *p, uintptr sz, void *pc);
+void	runtime_racefree(void *p);
+void	runtime_racegostart(int32 goid, void *pc);
+void	runtime_racegoend(int32 goid);
+void	runtime_racewritepc(void *addr, void *pc);
+void	runtime_racereadpc(void *addr, void *pc);
+void	runtime_racefingo(void);
+void	runtime_raceacquire(void *addr);
+void	runtime_raceacquireg(G *gp, void *addr);
+void	runtime_racerelease(void *addr);
+void	runtime_racereleaseg(G *gp, void *addr);
+void	runtime_racereleasemerge(void *addr);
+void	runtime_racereleasemergeg(G *gp, void *addr);
diff -r bf12a7f41b67 libgo/runtime/runtime.c
--- a/libgo/runtime/runtime.c	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/runtime.c	Mon Oct 22 17:36:23 2012 -0700
@@ -4,13 +4,13 @@
 
 #include <unistd.h>
 
+#include "config.h"
+
 #include "runtime.h"
 #include "array.h"
 #include "go-panic.h"
 #include "go-string.h"
 
-uint32	runtime_panicking;
-
 int32
 runtime_gotraceback(void)
 {
@@ -22,84 +22,6 @@
 	return runtime_atoi(p);
 }
 
-static Lock paniclk;
-
-void
-runtime_startpanic(void)
-{
-	M *m;
-
-	m = runtime_m();
-	if(m->dying) {
-		runtime_printf("panic during panic\n");
-		runtime_exit(3);
-	}
-	m->dying = 1;
-	runtime_xadd(&runtime_panicking, 1);
-	runtime_lock(&paniclk);
-}
-
-void
-runtime_dopanic(int32 unused __attribute__ ((unused)))
-{
-	G* g;
-	static bool didothers;
-
-	g = runtime_g();
-	if(g->sig != 0)
-		runtime_printf("[signal %x code=%p addr=%p]\n",
-			g->sig, (void*)(g->sigcode0), (void*)(g->sigcode1));
-
-	if(runtime_gotraceback()){
-		if(g != runtime_m()->g0) {
-			runtime_printf("\n");
-			runtime_goroutineheader(g);
-			runtime_traceback();
-			runtime_goroutinetrailer(g);
-		}
-		if(!didothers) {
-			didothers = true;
-			runtime_tracebackothers(g);
-		}
-	}
-
-	runtime_unlock(&paniclk);
-	if(runtime_xadd(&runtime_panicking, -1) != 0) {
-		// Some other m is panicking too.
-		// Let it print what it needs to print.
-		// Wait forever without chewing up cpu.
-		// It will exit when it's done.
-		static Lock deadlock;
-		runtime_lock(&deadlock);
-		runtime_lock(&deadlock);
-	}
-
-	runtime_exit(2);
-}
-
-void
-runtime_throw(const char *s)
-{
-	runtime_startpanic();
-	runtime_printf("throw: %s\n", s);
-	runtime_dopanic(0);
-	*(int32*)0 = 0;	// not reached
-	runtime_exit(1);	// even more not reached
-}
-
-void
-runtime_panicstring(const char *s)
-{
-	Eface err;
-
-	if(runtime_m()->gcing) {
-		runtime_printf("panic: %s\n", s);
-		runtime_throw("panic during gc");
-	}
-	runtime_newErrorString(runtime_gostringnocopy((const byte*)s), &err);
-	runtime_panic(err);
-}
-
 static int32	argc;
 static byte**	argv;
 
@@ -247,14 +169,41 @@
 	return traceback > 1 || (s != nil && __builtin_strchr((const char*)s, '.') != nil && __builtin_memcmp(s, "runtime.", 7) != 0);
 }
 
-bool
-runtime_isInf(float64 f, int32 sign)
+static Lock ticksLock;
+static int64 ticks;
+
+int64
+runtime_tickspersecond(void)
 {
-	if(!__builtin_isinf(f))
-		return false;
-	if(sign == 0)
-		return true;
-	if(sign > 0)
-		return f > 0;
-	return f < 0;
+	int64 res, t0, t1, c0, c1;
+
+	res = (int64)runtime_atomicload64((uint64*)&ticks);
+	if(res != 0)
+		return ticks;
+	runtime_lock(&ticksLock);
+	res = ticks;
+	if(res == 0) {
+		t0 = runtime_nanotime();
+		c0 = runtime_cputicks();
+		runtime_usleep(100*1000);
+		t1 = runtime_nanotime();
+		c1 = runtime_cputicks();
+		if(t1 == t0)
+			t1++;
+		res = (c1-c0)*1000*1000*1000/(t1-t0);
+		if(res == 0)
+			res++;
+		runtime_atomicstore64((uint64*)&ticks, res);
+	}
+	runtime_unlock(&ticksLock);
+	return res;
 }
+
+int64 runtime_pprof_runtime_cyclesPerSecond(void)
+     asm("runtime_pprof.runtime_cyclesPerSecond");
+
+int64
+runtime_pprof_runtime_cyclesPerSecond(void)
+{
+	return runtime_tickspersecond();
+}
diff -r bf12a7f41b67 libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/runtime.h	Mon Oct 22 17:36:23 2012 -0700
@@ -1,8 +1,6 @@
-/* runtime.h -- runtime support for Go.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
 
 #include "config.h"
 
@@ -42,8 +40,12 @@
 typedef unsigned int uint64  __attribute__ ((mode (DI)));
 typedef float        float32 __attribute__ ((mode (SF)));
 typedef double       float64 __attribute__ ((mode (DF)));
+typedef signed int   intptr __attribute__ ((mode (pointer)));
 typedef unsigned int uintptr __attribute__ ((mode (pointer)));
 
+typedef int		intgo; // Go's int
+typedef unsigned int	uintgo; // Go's uint
+
 /* Defined types.  */
 
 typedef	uint8			bool;
@@ -59,6 +61,10 @@
 typedef	struct	Hchan		Hchan;
 typedef	struct	Timers		Timers;
 typedef	struct	Timer		Timer;
+typedef struct	GCStats		GCStats;
+typedef struct	LFNode		LFNode;
+typedef struct	ParFor		ParFor;
+typedef struct	ParForThread	ParForThread;
 
 typedef	struct	__go_open_array		Slice;
 typedef	struct	__go_string		String;
@@ -105,6 +111,10 @@
 	true	= 1,
 	false	= 0,
 };
+enum
+{
+	PtrSize = sizeof(void*),
+};
 
 /*
  * structures
@@ -119,6 +129,16 @@
 	uint32	key;	// futex-based impl
 	M*	waitm;	// waiting M (sema-based impl)
 };
+struct	GCStats
+{
+	// the struct must consist of only uint64's,
+	// because it is casted to uint64[].
+	uint64	nhandoff;
+	uint64	nhandoffcnt;
+	uint64	nprocyield;
+	uint64	nosyield;
+	uint64	nsleep;
+};
 struct	G
 {
 	Defer*	defer;
@@ -142,6 +162,7 @@
 	G*	schedlink;
 	bool	readyonstop;
 	bool	ispanic;
+	int8	raceignore; // ignore race detection events
 	M*	m;		// for debuggers, but offset not hard-coded
 	M*	lockedm;
 	M*	idlem;
@@ -190,6 +211,14 @@
 	uintptr	waitsema;	// semaphore for parking on locks
 	uint32	waitsemacount;
 	uint32	waitsemalock;
+	GCStats	gcstats;
+	bool	racecall;
+	void*	racepc;
+
+	uintptr	settype_buf[1024];
+	uintptr	settype_bufsize;
+
+	uintptr	end[];
 };
 
 struct	SigTab
@@ -218,7 +247,6 @@
 	uintptr	entry;	// entry pc
 };
 
-/* Macros.  */
 
 #ifdef GOOS_windows
 enum {
@@ -257,6 +285,34 @@
 	Eface	arg;
 };
 
+// Lock-free stack node.
+struct LFNode
+{
+	LFNode	*next;
+	uintptr	pushcnt;
+};
+
+// Parallel for descriptor.
+struct ParFor
+{
+	void (*body)(ParFor*, uint32);	// executed for each element
+	uint32 done;			// number of idle threads
+	uint32 nthr;			// total number of threads
+	uint32 nthrmax;			// maximum number of threads
+	uint32 thrseq;			// thread id sequencer
+	uint32 cnt;			// iteration space [0, cnt)
+	void *ctx;			// arbitrary user context
+	bool wait;			// if true, wait while all threads finish processing,
+					// otherwise parfor may return while other threads are still working
+	ParForThread *thr;		// array of thread descriptors
+	// stats
+	uint64 nsteal;
+	uint64 nstealcnt;
+	uint64 nprocyield;
+	uint64 nosyield;
+	uint64 nsleep;
+};
+
 /*
  * defined macros
  *    you need super-gopher-guru privilege
@@ -265,6 +321,7 @@
 #define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
 #define	nil		((void*)0)
 #define USED(v)		((void) v)
+#define	ROUND(x, n)	(((x)+(n)-1)&~((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
 
 /*
  * external data
@@ -312,7 +369,8 @@
 void	runtime_minit(void);
 void	runtime_mallocinit(void);
 void	runtime_gosched(void);
-void	runtime_tsleep(int64);
+void	runtime_park(void(*)(Lock*), Lock*, const char*);
+void	runtime_tsleep(int64, const char*);
 M*	runtime_newm(void);
 void	runtime_goexit(void);
 void	runtime_entersyscall(void) __asm__("syscall.Entersyscall");
@@ -322,9 +380,12 @@
 int32	runtime_callers(int32, uintptr*, int32);
 int64	runtime_nanotime(void);
 int64	runtime_cputicks(void);
+int64	runtime_tickspersecond(void);
+void	runtime_blockevent(int64, int32);
+extern int64 runtime_blockprofilerate;
 
 void	runtime_stoptheworld(void);
-void	runtime_starttheworld(bool);
+void	runtime_starttheworld(void);
 extern uint32 runtime_worldsema;
 G*	__go_go(void (*pfn)(void*), void*);
 
@@ -372,6 +433,28 @@
 void	runtime_futexwakeup(uint32*, uint32);
 
 /*
+ * Lock-free stack.
+ * Initialize uint64 head to 0, compare with 0 to test for emptiness.
+ * The stack does not keep pointers to nodes,
+ * so they can be garbage collected if there are no other pointers to nodes.
+ */
+void	runtime_lfstackpush(uint64 *head, LFNode *node)
+  asm("runtime.lfstackpush");
+LFNode*	runtime_lfstackpop(uint64 *head);
+
+/*
+ * Parallel for over [0, n).
+ * body() is executed for each iteration.
+ * nthr - total number of worker threads.
+ * ctx - arbitrary user context.
+ * if wait=true, threads return from parfor() when all work is done;
+ * otherwise, threads can return while other threads are still finishing processing.
+ */
+ParFor*	runtime_parforalloc(uint32 nthrmax);
+void	runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
+void	runtime_parfordo(ParFor *desc) asm("runtime.parfordo");
+
+/*
  * low level C-called
  */
 #define runtime_mmap mmap
@@ -432,12 +515,17 @@
 void	free(void *v);
 #define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
 #define runtime_casp(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+#define runtime_cas64(pval, pold, new) __atomic_compare_exchange_n (pval, pold, new, 1, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED)
 #define runtime_xadd(p, v) __sync_add_and_fetch (p, v)
+#define runtime_xadd64(p, v) __sync_add_and_fetch (p, v)
 #define runtime_xchg(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
 #define runtime_atomicload(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
 #define runtime_atomicstore(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
 #define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
 #define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_atomicload64(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
+#define runtime_atomicstore64(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
+#define PREFETCH(p) __builtin_prefetch(p)
 
 struct __go_func_type;
 bool	runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
@@ -469,8 +557,7 @@
 /*
  * wrapped for go users
  */
-bool	runtime_isInf(float64 f, int32 sign);
-#define runtime_isNaN(f) __builtin_isnan(f)
+#define ISNAN(f) __builtin_isnan(f)
 void	runtime_semacquire(uint32 volatile *);
 void	runtime_semrelease(uint32 volatile *);
 int32	runtime_gomaxprocsfunc(int32 n);
@@ -493,8 +580,13 @@
 // This is a no-op on other systems.
 void	runtime_setprof(bool);
 
-void	runtime_time_scan(void (*)(byte*, int64));
-void	runtime_trampoline_scan(void (*)(byte *, int64));
+enum
+{
+	UseSpanType = 1,
+};
+
+void	runtime_time_scan(void (*)(byte*, uintptr));
+void	runtime_trampoline_scan(void (*)(byte *, uintptr));
 
 void	runtime_setsig(int32, bool, bool);
 #define runtime_setitimer setitimer
diff -r bf12a7f41b67 libgo/runtime/runtime1.goc
--- a/libgo/runtime/runtime1.goc	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/runtime1.goc	Mon Oct 22 17:36:23 2012 -0700
@@ -5,10 +5,10 @@
 package runtime
 #include "runtime.h"
 
-func GOMAXPROCS(n int32) (ret int32) {
+func GOMAXPROCS(n int) (ret int) {
 	ret = runtime_gomaxprocsfunc(n);
 }
 
-func NumCPU() (ret int32) {
+func NumCPU() (ret int) {
 	ret = runtime_ncpu;
 }
diff -r bf12a7f41b67 libgo/runtime/sema.goc
--- a/libgo/runtime/sema.goc	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/sema.goc	Mon Oct 22 17:36:23 2012 -0700
@@ -24,30 +24,32 @@
 typedef struct Sema Sema;
 struct Sema
 {
-	uint32 volatile *addr;
-	G *g;
-	Sema *prev;
-	Sema *next;
+	uint32 volatile*	addr;
+	G*	g;
+	int64	releasetime;
+	Sema*	prev;
+	Sema*	next;
 };
 
 typedef struct SemaRoot SemaRoot;
 struct SemaRoot
 {
-        Lock;
-	Sema *head;
-	Sema *tail;
+	Lock;
+	Sema*	head;
+	Sema*	tail;
 	// Number of waiters. Read w/o the lock.
-	uint32 volatile nwait;
+	uint32 volatile	nwait;
 };
 
 // Prime to not correlate with any user patterns.
 #define SEMTABLESZ 251
 
-static union
+union semtable
 {
 	SemaRoot;
 	uint8 pad[CacheLineSize];
-} semtable[SEMTABLESZ];
+};
+static union semtable semtable[SEMTABLESZ];
 
 static SemaRoot*
 semroot(uint32 volatile *addr)
@@ -95,13 +97,13 @@
 	return 0;
 }
 
-void
-runtime_semacquire(uint32 volatile *addr)
+static void
+semacquireimpl(uint32 volatile *addr, int32 profile)
 {
-	G *g;
-	Sema s;
+	Sema s;	// Needs to be allocated on stack, otherwise garbage collector could deallocate it
 	SemaRoot *root;
-
+	int64 t0;
+	
 	// Easy case.
 	if(cansemacquire(addr))
 		return;
@@ -112,8 +114,13 @@
 	//	enqueue itself as a waiter
 	//	sleep
 	//	(waiter descriptor is dequeued by signaler)
-	g = runtime_g();
 	root = semroot(addr);
+	t0 = 0;
+	s.releasetime = 0;
+	if(profile && runtime_blockprofilerate > 0) {
+		t0 = runtime_cputicks();
+		s.releasetime = -1;
+	}
 	for(;;) {
 
 		runtime_lock(root);
@@ -128,16 +135,22 @@
 		// Any semrelease after the cansemacquire knows we're waiting
 		// (we set nwait above), so go to sleep.
 		semqueue(root, addr, &s);
-		g->status = Gwaiting;
-		g->waitreason = "semacquire";
-		runtime_unlock(root);
-		runtime_gosched();
-		if(cansemacquire(addr))
+		runtime_park(runtime_unlock, root, "semacquire");
+		if(cansemacquire(addr)) {
+			if(t0)
+				runtime_blockevent(s.releasetime - t0, 3);
 			return;
+		}
 	}
 }
 
 void
+runtime_semacquire(uint32 volatile *addr)
+{
+	semacquireimpl(addr, 0);
+}
+
+void
 runtime_semrelease(uint32 volatile *addr)
 {
 	Sema *s;
@@ -168,12 +181,15 @@
 		}
 	}
 	runtime_unlock(root);
-	if(s)
+	if(s) {
+		if(s->releasetime)
+			s->releasetime = runtime_cputicks();
 		runtime_ready(s->g);
+	}
 }
 
 func runtime_Semacquire(addr *uint32) {
-	runtime_semacquire(addr);
+	semacquireimpl(addr, 1);
 }
 
 func runtime_Semrelease(addr *uint32) {
diff -r bf12a7f41b67 libgo/runtime/string.goc
--- a/libgo/runtime/string.goc	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/string.goc	Mon Oct 22 17:36:23 2012 -0700
@@ -32,8 +32,8 @@
 	Runeself	= 0x80,
 };
 
-func stringiter(s String, k int32) (retk int32) {
-	int32 l, n;
+func stringiter(s String, k int) (retk int) {
+	int32 l;
 
 	if(k >= s.__length) {
 		// retk=0 is end of iteration
@@ -48,15 +48,12 @@
 	}
 
 	// multi-char rune
-	n = charntorune(&l, s.__data+k, s.__length-k);
-	retk = k + (n ? n : 1);
+	retk = k + charntorune(&l, s.__data+k, s.__length-k);
 
 out:
 }
 
-func stringiter2(s String, k int32) (retk int32, retv int32) {
-	int32 n;
-
+func stringiter2(s String, k int) (retk int, retv int) {
 	if(k >= s.__length) {
 		// retk=0 is end of iteration
 		retk = 0;
@@ -71,8 +68,7 @@
 	}
 
 	// multi-char rune
-	n = charntorune(&retv, s.__data+k, s.__length-k);
-	retk = k + (n ? n : 1);
+	retk = k + charntorune(&retv, s.__data+k, s.__length-k);
 
 out:
 }
diff -r bf12a7f41b67 libgo/runtime/time.goc
--- a/libgo/runtime/time.goc	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/runtime/time.goc	Mon Oct 22 17:36:23 2012 -0700
@@ -10,6 +10,7 @@
 #include "defs.h"
 #include "arch.h"
 #include "malloc.h"
+#include "race.h"
 
 static Timers timers;
 static void addtimer(Timer*);
@@ -22,17 +23,16 @@
 
 // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
 func Sleep(ns int64) {
-	G *g;
-
-	g = runtime_g();
-	g->status = Gwaiting;
-	g->waitreason = "sleep";
-	runtime_tsleep(ns);
+	runtime_tsleep(ns, "sleep");
 }
 
 // startTimer adds t to the timer heap.
 func startTimer(t *Timer) {
+	if(raceenabled)
+		runtime_racerelease(t);
+	runtime_lock(&timers);
 	addtimer(t);
+	runtime_unlock(&timers);
 }
 
 // stopTimer removes t from the timer heap if it is there.
@@ -57,27 +57,24 @@
 }
 
 // Put the current goroutine to sleep for ns nanoseconds.
-// The caller must have set g->status and g->waitreason.
 void
-runtime_tsleep(int64 ns)
+runtime_tsleep(int64 ns, const char *reason)
 {
 	G* g;
 	Timer t;
 
 	g = runtime_g();
 
-	if(ns <= 0) {
-		g->status = Grunning;
-		g->waitreason = nil;
+	if(ns <= 0)
 		return;
-	}
 
 	t.when = runtime_nanotime() + ns;
 	t.period = 0;
 	t.f = ready;
 	t.arg.__object = g;
+	runtime_lock(&timers);
 	addtimer(&t);
-	runtime_gosched();
+	runtime_park(runtime_unlock, &timers, reason);
 }
 
 // Add a timer to the heap and start or kick the timer proc
@@ -88,7 +85,6 @@
 	int32 n;
 	Timer **nt;
 
-	runtime_lock(&timers);
 	if(timers.len >= timers.cap) {
 		// Grow slice.
 		n = 16;
@@ -116,7 +112,6 @@
 	}
 	if(timers.timerproc == nil)
 		timers.timerproc = __go_go(timerproc, nil);
-	runtime_unlock(&timers);
 }
 
 // Delete timer t from the heap.
@@ -159,13 +154,11 @@
 static void
 timerproc(void* dummy __attribute__ ((unused)))
 {
-	G *g;
 	int64 delta, now;
 	Timer *t;
 	void (*f)(int64, Eface);
 	Eface arg;
 
-	g = runtime_g();
 	for(;;) {
 		runtime_lock(&timers);
 		now = runtime_nanotime();
@@ -192,16 +185,15 @@
 			f = t->f;
 			arg = t->arg;
 			runtime_unlock(&timers);
+			if(raceenabled)
+				runtime_raceacquire(t);
 			f(now, arg);
 			runtime_lock(&timers);
 		}
 		if(delta < 0) {
 			// No timers left - put goroutine to sleep.
 			timers.rescheduling = true;
-			g->status = Gwaiting;
-			g->waitreason = "timer goroutine (idle)";
-			runtime_unlock(&timers);
-			runtime_gosched();
+			runtime_park(runtime_unlock, &timers, "timer goroutine (idle)");
 			continue;
 		}
 		// At least one timer pending.  Sleep until then.
@@ -263,7 +255,7 @@
 }
 
 void
-runtime_time_scan(void (*scan)(byte*, int64))
+runtime_time_scan(void (*addroot)(byte*, uintptr))
 {
-	scan((byte*)&timers, sizeof timers);
+	addroot((byte*)&timers, sizeof timers);
 }
diff -r bf12a7f41b67 libgo/testsuite/gotest
--- a/libgo/testsuite/gotest	Sun Oct 07 21:29:09 2012 -0700
+++ b/libgo/testsuite/gotest	Mon Oct 22 17:36:23 2012 -0700
@@ -346,6 +346,11 @@
 
 # They all compile; now generate the code to call them.
 
+testname() {
+	# Remove the package from the name used with the -test option.
+	echo $1 | sed 's/^.*\.//'
+}
+
 localname() {
 	# The package main has been renamed to __main__ when imported.
 	# Adjust its uses.
@@ -373,7 +378,7 @@
 	fi
 	# benchmarks are named BenchmarkFoo.
 	pattern='Benchmark([^a-z].*)?'
-	benchmarks=$($NM -p -v _gotest_.o $xofile | egrep " $test .*\."$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | fgrep -v ' __go_' | sed 's/.* //' | $symtogo)
+	benchmarks=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | fgrep -v ' __go_' | sed 's/.* //' | $symtogo)
 
 	# examples are named ExampleFoo
 	pattern='Example([^a-z].*)?'
@@ -396,8 +401,9 @@
 	echo 'var tests = []testing.InternalTest {'
 	for i in $tests
 	do
+		n=$(testname $i)
 		j=$(localname $i)
-		echo '	{"'$i'", '$j'},'
+		echo '	{"'$n'", '$j'},'
 	done
 	echo '}'
 
@@ -407,8 +413,9 @@
 	echo 'var benchmarks = []testing.InternalBenchmark{ //'
 	for i in $benchmarks
 	do
+		n=$(testname $i)
 		j=$(localname $i)
-		echo '	{"'$i'", '$j'},'
+		echo '	{"'$n'", '$j'},'
 	done
 	echo '}'
 
@@ -417,8 +424,9 @@
 	# This doesn't work because we don't pick up the output.
 	#for i in $examples
 	#do
+	#	n=$(testname $i)
 	#	j=$(localname $i)
-	#	echo '	{"'$i'", '$j', ""},'
+	#	echo '	{"'$n'", '$j', ""},'
 	#done
 	echo '}'
 
Index: test/fixedbugs/bug358.go
===================================================================
--- test/fixedbugs/bug358.go	(revision 192508)
+++ test/fixedbugs/bug358.go	(working copy)
@@ -12,7 +12,7 @@ package main
 import (
 	"io/ioutil"	// GCCGO_ERROR "imported and not used"
 	"net/http"
-	"os"
+	"os"		// GCCGO_ERROR "imported and not used"
 )
 
 func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
Index: test/fixedbugs/bug369.go
===================================================================
--- test/fixedbugs/bug369.go	(revision 192508)
+++ test/fixedbugs/bug369.go	(working copy)
@@ -38,9 +38,9 @@ func BenchmarkSlowNonASCII(b *testing.B)
 }
 
 func main() {
-	os.Args = []string{os.Args[0], "-test.benchtime=0.1"}
+	os.Args = []string{os.Args[0], "-test.benchtime=100ms"}
 	flag.Parse()
-	
+
 	rslow := testing.Benchmark(BenchmarkSlowNonASCII)
 	rfast := testing.Benchmark(BenchmarkFastNonASCII)
 	tslow := rslow.NsPerOp()

^ permalink raw reply	[flat|nested] 25+ messages in thread

* libgo patch committed: Update to current Go library
@ 2011-04-07 17:09 Ian Lance Taylor
  0 siblings, 0 replies; 25+ messages in thread
From: Ian Lance Taylor @ 2011-04-07 17:09 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 211 bytes --]

I committed this patch to update libgo to the current Go library.  This
brings in a change to the way os.Open works.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


[-- Attachment #2: patch --]
[-- Type: application/x-bzip, Size: 61447 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* libgo patch committed: Update to current Go library
@ 2011-03-30 16:06 Ian Lance Taylor
  0 siblings, 0 replies; 25+ messages in thread
From: Ian Lance Taylor @ 2011-03-30 16:06 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 234 bytes --]

I have updated libgo to the current master Go library.  The main reason
for this is to bring in some new code which uses nonblocking connect.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian


[-- Attachment #2: patch --]
[-- Type: application/x-bzip, Size: 38752 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2013-11-27  1:05 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-23 17:54 libgo patch committed: Update to current Go library Uros Bizjak
2012-10-23 18:09 ` Ian Lance Taylor
2012-10-23 18:22 ` Ian Lance Taylor
2012-10-24  8:12   ` Uros Bizjak
2012-10-24  8:22     ` Uros Bizjak
2012-10-24  8:31       ` Florian Weimer
2012-10-24  8:44         ` Uros Bizjak
2012-10-24 12:31       ` Andreas Schwab
2012-10-24 13:06         ` Uros Bizjak
2012-10-24 13:33           ` Ian Lance Taylor
2012-10-24 13:36             ` Uros Bizjak
2012-10-24 14:50               ` Ian Lance Taylor
2012-10-24 16:47                 ` Uros Bizjak
2012-10-24 17:55                   ` Ian Lance Taylor
2012-10-24 17:58                     ` Uros Bizjak
2012-10-24 18:12                       ` Ian Lance Taylor
2012-10-24 21:12                         ` Ian Lance Taylor
2012-10-24 23:17                       ` Andreas Schwab
2012-10-24  8:22     ` Uros Bizjak
  -- strict thread matches above, loose matches on Subject: below --
2013-11-27  7:17 Ian Lance Taylor
2012-10-23  5:14 Ian Lance Taylor
2012-10-25  9:50 ` Rainer Orth
2012-10-25 18:31   ` Ian Lance Taylor
2011-04-07 17:09 Ian Lance Taylor
2011-03-30 16:06 Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).