summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-10-16 15:00:08 -0400
committerRuss Cox <rsc@golang.org>2014-10-16 15:00:08 -0400
commit78db2eb9c66d478bee0d56edcc55d4f865f8c6c7 (patch)
treed08da7ddd82570422ae87dc9d3ac061f8ce3b648
parentaf64ab79c0ad72decf083d78cf54257d009741b5 (diff)
parent25c63c2c30f4807b073f849d248144d97893ce70 (diff)
downloadgo-78db2eb9c66d478bee0d56edcc55d4f865f8c6c7.tar.gz
all: merge default branch into dev.garbage
hg was unable to create a CL on the code review server for this, so I am submitting the merge by hand. The only manual edits are in mgc0.c, to reapply the removal of cached/ncached to the new code.
-rw-r--r--AUTHORS1
-rw-r--r--CONTRIBUTORS2
-rw-r--r--doc/go1.4.txt4
-rw-r--r--doc/go1compat.html10
-rw-r--r--include/link.h2
-rw-r--r--misc/cgo/test/callback_c_gc.c10
-rw-r--r--misc/cgo/test/callback_c_gccgo.c7
-rw-r--r--misc/cgo/test/cgo_test.go2
-rw-r--r--misc/cgo/test/issue8517.go13
-rw-r--r--misc/cgo/test/issue8517_windows.c24
-rw-r--r--misc/cgo/test/issue8517_windows.go45
-rw-r--r--misc/cgo/test/issue8811.c8
-rw-r--r--misc/cgo/test/issue8811.go22
-rw-r--r--misc/cgo/test/issue8828.go16
-rw-r--r--misc/cgo/test/issue8828/issue8828.c7
-rw-r--r--misc/cgo/test/issue8828/trivial.go8
-rw-r--r--src/cmd/5a/lex.c1
-rw-r--r--src/cmd/5c/reg.c9
-rw-r--r--src/cmd/6a/lex.c1
-rw-r--r--src/cmd/6c/reg.c14
-rw-r--r--src/cmd/8a/lex.c1
-rw-r--r--src/cmd/8c/reg.c9
-rw-r--r--src/cmd/cc/godefs.c6
-rw-r--r--src/cmd/gc/builtin.c5
-rw-r--r--src/cmd/gc/dcl.c14
-rw-r--r--src/cmd/gc/order.c6
-rw-r--r--src/cmd/gc/pgen.c2
-rw-r--r--src/cmd/gc/racewalk.c7
-rw-r--r--src/cmd/gc/reflect.c25
-rw-r--r--src/cmd/gc/runtime.go7
-rw-r--r--src/cmd/gc/sinit.c2
-rw-r--r--src/cmd/gc/walk.c32
-rw-r--r--src/cmd/go/build.go2
-rw-r--r--src/cmd/go/doc.go39
-rw-r--r--src/cmd/go/list.go39
-rw-r--r--src/cmd/go/pkg.go22
-rwxr-xr-xsrc/cmd/go/test.bash14
-rw-r--r--src/cmd/go/testdata/src/vetpkg/a_test.go1
-rw-r--r--src/cmd/go/testdata/src/vetpkg/b.go7
-rw-r--r--src/cmd/go/vet.go23
-rw-r--r--src/cmd/ld/decodesym.c5
-rw-r--r--src/cmd/ld/dwarf.c14
-rw-r--r--src/cmd/ld/ldelf.c2
-rw-r--r--src/cmd/ld/ldpe.c26
-rw-r--r--src/cmd/ld/macho.c3
-rw-r--r--src/crypto/x509/x509.go17
-rw-r--r--src/crypto/x509/x509_test.go63
-rw-r--r--src/database/sql/fakedb_test.go22
-rw-r--r--src/database/sql/sql.go11
-rw-r--r--src/debug/elf/file.go8
-rw-r--r--src/encoding/asn1/asn1.go4
-rw-r--r--src/encoding/asn1/asn1_test.go48
-rw-r--r--src/encoding/gob/encode.go10
-rw-r--r--src/encoding/json/decode.go40
-rw-r--r--src/encoding/json/decode_test.go21
-rw-r--r--src/encoding/json/encode.go2
-rw-r--r--src/go/build/build.go27
-rw-r--r--src/go/build/build_test.go18
-rw-r--r--src/go/build/doc.go10
-rw-r--r--src/go/build/testdata/empty/dummy0
-rw-r--r--src/go/build/testdata/multi/file.go5
-rw-r--r--src/go/build/testdata/multi/file_appengine.go5
-rw-r--r--src/liblink/data.c2
-rw-r--r--src/math/big/int.go19
-rw-r--r--src/math/big/int_test.go36
-rw-r--r--src/math/big/rat.go7
-rw-r--r--src/math/big/rat_test.go1
-rw-r--r--src/net/fd_windows.go12
-rw-r--r--src/net/http/client.go28
-rw-r--r--src/net/http/client_test.go37
-rw-r--r--src/net/http/export_test.go5
-rw-r--r--src/net/http/response_test.go28
-rw-r--r--src/net/http/serve_test.go97
-rw-r--r--src/net/http/server.go32
-rw-r--r--src/net/http/transport.go11
-rw-r--r--src/net/http/transport_test.go33
-rw-r--r--src/net/rpc/client.go12
-rw-r--r--src/net/rpc/client_test.go55
-rw-r--r--src/net/udp_test.go41
-rw-r--r--src/net/url/url.go18
-rw-r--r--src/os/error_plan9.go3
-rw-r--r--src/os/exec/exec.go11
-rw-r--r--src/os/exec_unix.go14
-rw-r--r--src/os/exec_windows.go3
-rw-r--r--src/os/os_test.go47
-rw-r--r--src/os/path.go6
-rw-r--r--src/reflect/all_test.go83
-rw-r--r--src/reflect/makefunc.go6
-rw-r--r--src/reflect/type.go62
-rw-r--r--src/reflect/value.go368
-rw-r--r--src/regexp/syntax/doc.go48
-rw-r--r--src/runtime/asm_386.s75
-rw-r--r--src/runtime/asm_amd64.s75
-rw-r--r--src/runtime/asm_amd64p32.s80
-rw-r--r--src/runtime/asm_arm.s73
-rw-r--r--src/runtime/cgocallback.go3
-rw-r--r--src/runtime/chan.go11
-rw-r--r--src/runtime/defs_windows.go4
-rw-r--r--src/runtime/defs_windows_386.h4
-rw-r--r--src/runtime/defs_windows_amd64.h4
-rw-r--r--src/runtime/heapdump.c44
-rw-r--r--src/runtime/malloc.go2
-rw-r--r--src/runtime/mgc0.c40
-rw-r--r--src/runtime/mgc0.go21
-rw-r--r--src/runtime/mgc0.h2
-rw-r--r--src/runtime/os_windows.c52
-rw-r--r--src/runtime/os_windows_386.c84
-rw-r--r--src/runtime/os_windows_amd64.c97
-rw-r--r--src/runtime/panic.c4
-rw-r--r--src/runtime/panic.go27
-rw-r--r--src/runtime/runtime.h5
-rw-r--r--src/runtime/stack.c39
-rw-r--r--src/runtime/stubs.go30
-rw-r--r--src/runtime/sys_windows_386.s18
-rw-r--r--src/runtime/sys_windows_amd64.s18
-rw-r--r--src/runtime/syscall_windows_test.go39
-rw-r--r--src/runtime/type.h2
-rw-r--r--src/strings/strings.go9
-rw-r--r--src/syscall/syscall_windows.go4
-rw-r--r--src/syscall/ztypes_windows.go1
-rw-r--r--test/assign.go12
-rw-r--r--test/fixedbugs/issue6703a.go16
-rw-r--r--test/fixedbugs/issue6703b.go16
-rw-r--r--test/fixedbugs/issue6703c.go18
-rw-r--r--test/fixedbugs/issue6703d.go18
-rw-r--r--test/fixedbugs/issue6703e.go18
-rw-r--r--test/fixedbugs/issue6703f.go18
-rw-r--r--test/fixedbugs/issue6703g.go20
-rw-r--r--test/fixedbugs/issue6703h.go20
-rw-r--r--test/fixedbugs/issue6703i.go20
-rw-r--r--test/fixedbugs/issue6703j.go20
-rw-r--r--test/fixedbugs/issue6703k.go21
-rw-r--r--test/fixedbugs/issue6703l.go21
-rw-r--r--test/fixedbugs/issue6703m.go25
-rw-r--r--test/fixedbugs/issue6703n.go25
-rw-r--r--test/fixedbugs/issue6703o.go23
-rw-r--r--test/fixedbugs/issue6703p.go23
-rw-r--r--test/fixedbugs/issue6703q.go28
-rw-r--r--test/fixedbugs/issue6703r.go28
-rw-r--r--test/fixedbugs/issue6703s.go18
-rw-r--r--test/fixedbugs/issue6703t.go18
-rw-r--r--test/fixedbugs/issue6703u.go18
-rw-r--r--test/fixedbugs/issue6703v.go18
-rw-r--r--test/fixedbugs/issue6703w.go21
-rw-r--r--test/fixedbugs/issue6703x.go21
-rw-r--r--test/fixedbugs/issue6703y.go23
-rw-r--r--test/fixedbugs/issue6703z.go23
-rw-r--r--test/fixedbugs/issue8079.go11
-rw-r--r--test/interface/explicit.go4
-rw-r--r--test/interface/fail.go14
150 files changed, 2548 insertions, 853 deletions
diff --git a/AUTHORS b/AUTHORS
index a924ea965..03e686e75 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -378,6 +378,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
+Ron Hashimoto <mail@h2so5.net>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
Rowan Worth <sqweek@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 9dce23b2d..a24178b52 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -256,6 +256,7 @@ Gustav Paul <gustav.paul@gmail.com>
Gustavo Franco <gustavorfranco@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
Gwenael Treguier <gwenn.kahz@gmail.com>
+Hana Kim <hyangah@gmail.com>
Han-Wen Nienhuys <hanwen@google.com>
Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
@@ -520,6 +521,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
+Ron Hashimoto <mail@h2so5.net>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
Rowan Worth <sqweek@gmail.com>
diff --git a/doc/go1.4.txt b/doc/go1.4.txt
index 3564e7d2d..833d331cb 100644
--- a/doc/go1.4.txt
+++ b/doc/go1.4.txt
@@ -17,8 +17,10 @@ cmd/go: disallow C sources except when using cgo (CL 149720043)
cmd/go: add test -o flag (CL 149070043)
cmd/go: redefine build -a to skip standard library in releases (CL 151730045)
cmd/go: compile and link all _test.go files during 'go test', even in packages where there are no Test functions (CL 150980043)
+cmd/go: (via go/build): a GOOS prefix acts as a tag only if preceded by an underscore. this is a breaking change. (CL 147690043)
asm: make textflag.h available outside of cmd/ld (CL 128050043)
+bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043)
crypto/tls: add support for ALPN (RFC 7301) (CL 108710046)
crypto/tls: support programmatic selection of server certificates (CL 107400043)
fmt: print type *map[T]T as &map[k:v] (CL 154870043)
@@ -42,6 +44,6 @@ testing: add TestMain support (CL 148770043)
text/scanner: add IsIdentRune field of Scanner. (CL 108030044)
text/template: allow comparison of signed and unsigned integers (CL 149780043)
time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046)
-encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045).
+encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045)
go.sys subrepo created: http://golang.org/s/go1.4-syscall
diff --git a/doc/go1compat.html b/doc/go1compat.html
index 8ceaf32f9..04a6c1124 100644
--- a/doc/go1compat.html
+++ b/doc/go1compat.html
@@ -83,16 +83,16 @@ break if the bug is fixed. We reserve the right to fix such bugs.
<li>
Struct literals. For the addition of features in later point
releases, it may be necessary to add fields to exported structs in
-the API. Code that uses untagged struct literals (such as pkg.T{3,
+the API. Code that uses unkeyed struct literals (such as pkg.T{3,
"x"}) to create values of these types would fail to compile after
-such a change. However, code that uses tagged literals (pkg.T{A:
+such a change. However, code that uses keyed literals (pkg.T{A:
3, B: "x"}) will continue to compile after such a change. We will
-update such data structures in a way that allows tagged struct
-literals to remain compatible, although untagged literals may fail
+update such data structures in a way that allows keyed struct
+literals to remain compatible, although unkeyed literals may fail
to compile. (There are also more intricate cases involving nested
data structures or interfaces, but they have the same resolution.)
We therefore recommend that composite literals whose type is defined
-in a separate package should use the tagged notation.
+in a separate package should use the keyed notation.
</li>
<li>
diff --git a/include/link.h b/include/link.h
index 845f9338d..05e117c87 100644
--- a/include/link.h
+++ b/include/link.h
@@ -373,6 +373,7 @@ struct Link
char* trimpath;
char* goroot;
char* goroot_final;
+ int32 enforce_data_order; // for use by assembler
// hash table of all symbols
LSym* hash[LINKHASH];
@@ -542,6 +543,7 @@ vlong adduint8(Link *ctxt, LSym *s, uint8 v);
vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid);
void mangle(char *file);
void savedata(Link *ctxt, LSym *s, Prog *p, char *pn);
+void savedata1(Link *ctxt, LSym *s, Prog *p, char *pn, int enforce_order);
vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t);
vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add);
vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v);
diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c
index 32bfed0c0..28a62c6db 100644
--- a/misc/cgo/test/callback_c_gc.c
+++ b/misc/cgo/test/callback_c_gc.c
@@ -39,6 +39,16 @@ callCgoAllocate(void)
int i;
struct { size_t n; void *ret; } a;
List *l, *head, **tail;
+
+ // Make sure this doesn't crash.
+ // And make sure it returns non-nil.
+ a.n = 0;
+ a.ret = 0;
+ crosscall2(_cgo_allocate, &a, sizeof a);
+ if(a.ret == 0) {
+ fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
+ exit(2);
+ }
head = 0;
tail = &head;
diff --git a/misc/cgo/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c
index d92dca009..d367b7b68 100644
--- a/misc/cgo/test/callback_c_gccgo.c
+++ b/misc/cgo/test/callback_c_gccgo.c
@@ -35,6 +35,13 @@ callCgoAllocate(void)
int i;
List *l, *head, **tail;
+ // Make sure this doesn't crash.
+ // And make sure it returns non-nil.
+ if(_cgo_allocate(0) == 0) {
+ fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
+ exit(2);
+ }
+
head = 0;
tail = &head;
for(i=0; i<100; i++) {
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index fcfad8304..3b289ba7b 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -58,6 +58,8 @@ func Test5242(t *testing.T) { test5242(t) }
func Test8092(t *testing.T) { test8092(t) }
func Test7978(t *testing.T) { test7978(t) }
func Test8694(t *testing.T) { test8694(t) }
+func Test8517(t *testing.T) { test8517(t) }
+func Test8811(t *testing.T) { test8811(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
diff --git a/misc/cgo/test/issue8517.go b/misc/cgo/test/issue8517.go
new file mode 100644
index 000000000..4e431df92
--- /dev/null
+++ b/misc/cgo/test/issue8517.go
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package cgotest
+
+import "testing"
+
+func test8517(t *testing.T) {
+ t.Skip("skipping windows only test")
+}
diff --git a/misc/cgo/test/issue8517_windows.c b/misc/cgo/test/issue8517_windows.c
new file mode 100644
index 000000000..a0b94c126
--- /dev/null
+++ b/misc/cgo/test/issue8517_windows.c
@@ -0,0 +1,24 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "windows.h"
+
+extern void testHandleLeaksCallback();
+
+DWORD WINAPI testHandleLeaksFunc(LPVOID lpThreadParameter)
+{
+ int i;
+ for(i = 0; i < 100; i++) {
+ testHandleLeaksCallback();
+ }
+ return 0;
+}
+
+void testHandleLeaks()
+{
+ HANDLE h;
+ h = CreateThread(NULL, 0, &testHandleLeaksFunc, 0, 0, NULL);
+ WaitForSingleObject(h, INFINITE);
+ CloseHandle(h);
+}
diff --git a/misc/cgo/test/issue8517_windows.go b/misc/cgo/test/issue8517_windows.go
new file mode 100644
index 000000000..3782631e9
--- /dev/null
+++ b/misc/cgo/test/issue8517_windows.go
@@ -0,0 +1,45 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+//void testHandleLeaks();
+import "C"
+
+import (
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+var issue8517counter int
+
+var (
+ kernel32 = syscall.MustLoadDLL("kernel32.dll")
+ getProcessHandleCount = kernel32.MustFindProc("GetProcessHandleCount")
+)
+
+func processHandleCount(t *testing.T) int {
+ const current_process = ^uintptr(0)
+ var c uint32
+ r, _, err := getProcessHandleCount.Call(current_process, uintptr(unsafe.Pointer(&c)))
+ if r == 0 {
+ t.Fatal(err)
+ }
+ return int(c)
+}
+
+func test8517(t *testing.T) {
+ c1 := processHandleCount(t)
+ C.testHandleLeaks()
+ c2 := processHandleCount(t)
+ if c1+issue8517counter <= c2 {
+ t.Fatalf("too many handles leaked: issue8517counter=%v c1=%v c2=%v", issue8517counter, c1, c2)
+ }
+}
+
+//export testHandleLeaksCallback
+func testHandleLeaksCallback() {
+ issue8517counter++
+}
diff --git a/misc/cgo/test/issue8811.c b/misc/cgo/test/issue8811.c
new file mode 100644
index 000000000..584bb3934
--- /dev/null
+++ b/misc/cgo/test/issue8811.c
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+int issue8811Initialized = 0;
+
+void issue8811Init() {
+}
diff --git a/misc/cgo/test/issue8811.go b/misc/cgo/test/issue8811.go
new file mode 100644
index 000000000..2e217d935
--- /dev/null
+++ b/misc/cgo/test/issue8811.go
@@ -0,0 +1,22 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+extern int issue8811Initialized;
+extern void issue8811Init();
+
+void issue8811Execute() {
+ if(!issue8811Initialized)
+ issue8811Init();
+}
+*/
+import "C"
+
+import "testing"
+
+func test8811(t *testing.T) {
+ C.issue8811Execute()
+}
diff --git a/misc/cgo/test/issue8828.go b/misc/cgo/test/issue8828.go
new file mode 100644
index 000000000..304797c92
--- /dev/null
+++ b/misc/cgo/test/issue8828.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8828: compiling a file with -compiler=gccgo fails if a .c file
+// has the same name as compiled directory.
+
+package cgotest
+
+import "./issue8828"
+
+func p() {
+ issue8828.Bar()
+}
diff --git a/misc/cgo/test/issue8828/issue8828.c b/misc/cgo/test/issue8828/issue8828.c
new file mode 100644
index 000000000..2950f87cf
--- /dev/null
+++ b/misc/cgo/test/issue8828/issue8828.c
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+void foo()
+{
+}
diff --git a/misc/cgo/test/issue8828/trivial.go b/misc/cgo/test/issue8828/trivial.go
new file mode 100644
index 000000000..e7b9a4e57
--- /dev/null
+++ b/misc/cgo/test/issue8828/trivial.go
@@ -0,0 +1,8 @@
+package issue8828
+
+//void foo();
+import "C"
+
+func Bar() {
+ C.foo()
+}
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index 84a17d155..9c6970947 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -85,6 +85,7 @@ main(int argc, char *argv[])
ctxt = linknew(&linkarm);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
+ ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit5();
fmtinstall('L', Lconv);
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
index 2fbe031f4..9024d5f49 100644
--- a/src/cmd/5c/reg.c
+++ b/src/cmd/5c/reg.c
@@ -406,7 +406,7 @@ loop2:
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
- warn(Z, "too many regions");
+ fatal(Z, "too many regions");
goto brk;
}
rgp++;
@@ -642,11 +642,8 @@ mkvar(Addr *a, int docon)
if(s)
if(s->name[0] == '.')
goto none;
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- warn(Z, "variable not optimized: %s", s->name);
- goto none;
- }
+ if(nvar >= NVAR)
+ fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index b50e1622e..8973d6974 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -101,6 +101,7 @@ main(int argc, char *argv[])
ctxt = linknew(thelinkarch);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
+ ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit6();
fmtinstall('L', Lconv);
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
index 348d747b7..6f8d3ce14 100644
--- a/src/cmd/6c/reg.c
+++ b/src/cmd/6c/reg.c
@@ -585,14 +585,11 @@ loop2:
}
rgp->cost = change;
nregion++;
- if(nregion >= NRGN) {
- warn(Z, "too many regions");
- goto brk;
- }
+ if(nregion >= NRGN)
+ fatal(Z, "too many regions");
rgp++;
}
}
-brk:
qsort(region, nregion, sizeof(region[0]), rcmp);
/*
@@ -808,11 +805,8 @@ mkvar(Reg *r, Addr *a)
goto out;
v++;
}
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- warn(Z, "variable not optimized: %s", s->name);
- goto none;
- }
+ if(nvar >= NVAR)
+ fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index 807e48cb5..6ce6a18ab 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -90,6 +90,7 @@ main(int argc, char *argv[])
ctxt = linknew(&link386);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
+ ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit8();
fmtinstall('L', Lconv);
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
index e6ba8bcb3..ea862f388 100644
--- a/src/cmd/8c/reg.c
+++ b/src/cmd/8c/reg.c
@@ -518,7 +518,7 @@ loop2:
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
- warn(Z, "too many regions");
+ fatal(Z, "too many regions");
goto brk;
}
rgp++;
@@ -746,11 +746,8 @@ mkvar(Reg *r, Addr *a)
goto out;
v++;
}
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- warn(Z, "variable not optimized: %s", s->name);
- goto none;
- }
+ if(nvar >= NVAR)
+ fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
index d3ab52fde..d9f67f0ae 100644
--- a/src/cmd/cc/godefs.c
+++ b/src/cmd/cc/godefs.c
@@ -353,8 +353,10 @@ godefvar(Sym *s)
case CSTATIC:
case CEXTERN:
case CGLOBL:
- if(strchr(s->name, '$') != nil) // TODO(lvd)
- break;
+ if(strchr(s->name, '$') != nil)
+ break;
+ if(strncmp(s->name, "go.weak.", 8) == 0)
+ break;
Bprint(&outbuf, "var %U\t", s->name);
printtypename(t);
Bprint(&outbuf, "\n");
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index ee1ac1da4..5fbb4f0cf 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -84,9 +84,12 @@ char *runtimeimport =
"func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
"func @\"\".closechan (@\"\".hchan·1 any)\n"
"func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n"
- "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
+ "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
+ "func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
"func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n"
"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 73c2581be..dfcf47520 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -488,6 +488,10 @@ colasdefn(NodeList *left, Node *defn)
NodeList *l;
Node *n;
+ for(l=left; l; l=l->next)
+ if(l->n->sym != S)
+ l->n->sym->flags |= SymUniq;
+
nnew = 0;
nerr = 0;
for(l=left; l; l=l->next) {
@@ -499,6 +503,13 @@ colasdefn(NodeList *left, Node *defn)
nerr++;
continue;
}
+ if((n->sym->flags & SymUniq) == 0) {
+ yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym);
+ n->diag++;
+ nerr++;
+ continue;
+ }
+ n->sym->flags &= ~SymUniq;
if(n->sym->block == block)
continue;
@@ -547,6 +558,9 @@ ifacedcl(Node *n)
if(n->op != ODCLFIELD || n->right == N)
fatal("ifacedcl");
+ if(isblank(n->left))
+ yyerror("methods must have a unique non-blank name");
+
dclcontext = PPARAM;
markdcl();
funcdepth++;
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
index 3027ed27d..76820fde7 100644
--- a/src/cmd/gc/order.c
+++ b/src/cmd/gc/order.c
@@ -438,6 +438,9 @@ ordercall(Node *n, Order *order)
// cases they are also typically registerizable, so not much harm done.
// And this only applies to the multiple-assignment form.
// We could do a more precise analysis if needed, like in walk.c.
+//
+// Ordermapassign also inserts these temporaries if needed for
+// calling writebarrierfat with a pointer to n->right.
static void
ordermapassign(Node *n, Order *order)
{
@@ -451,7 +454,8 @@ ordermapassign(Node *n, Order *order)
case OAS:
order->out = list(order->out, n);
- if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > widthptr)) && !isaddrokay(n->right)) {
+ // We call writebarrierfat only for values > 4 pointers long. See walk.c.
+ if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) {
m = n->left;
n->left = ordertemp(m->type, order, 0);
a = nod(OAS, m, n->left);
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 50c03788e..39028e3f8 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -182,6 +182,8 @@ compile(Node *fn)
yyerror("missing function body", fn);
goto ret;
}
+ if(debug['A'])
+ goto ret;
emitptrargsmap();
goto ret;
}
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index cb98ca247..c9e27fe56 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -210,12 +210,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OCALLFUNC:
// Instrument dst argument of runtime.writebarrier* calls
// as we do not instrument runtime code.
- if(n->left->sym != S && n->left->sym->pkg == runtimepkg &&
- (strcmp(n->left->sym->name, "writebarrierptr") == 0 ||
- strcmp(n->left->sym->name, "writebarrierstring") == 0 ||
- strcmp(n->left->sym->name, "writebarrierslice") == 0 ||
- strcmp(n->left->sym->name, "writebarrieriface") == 0 ||
- strcmp(n->left->sym->name, "writebarrierfat") == 0)) {
+ if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) {
// Find the dst argument.
// The list can be reordered, so it's not necessary just the first or the second element.
for(l = n->list; l; l = l->next) {
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index e229b3075..0f8802abc 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -716,9 +716,10 @@ static int
dcommontype(Sym *s, int ot, Type *t)
{
int i, alg, sizeofAlg, gcprog;
- Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1;
+ Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits;
uint8 gcmask[16];
static Sym *algarray;
+ uint64 x1, x2;
char *p;
if(ot != 0)
@@ -804,8 +805,26 @@ dcommontype(Sym *s, int ot, Type *t)
ot = dsymptr(s, ot, gcprog1, 0);
} else {
gengcmask(t, gcmask);
- for(i = 0; i < 2*widthptr; i++)
- ot = duint8(s, ot, gcmask[i]);
+ x1 = 0;
+ for(i=0; i<8; i++)
+ x1 = x1<<8 | gcmask[i];
+ if(widthptr == 4) {
+ p = smprint("gcbits.%#016llux", x1);
+ } else {
+ x2 = 0;
+ for(i=0; i<8; i++)
+ x2 = x2<<8 | gcmask[i+8];
+ p = smprint("gcbits.%#016llux%016llux", x1, x2);
+ }
+ sbits = pkglookup(p, runtimepkg);
+ if((sbits->flags & SymUniq) == 0) {
+ sbits->flags |= SymUniq;
+ for(i = 0; i < 2*widthptr; i++)
+ duint8(sbits, i, gcmask[i]);
+ ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
+ }
+ ot = dsymptr(s, ot, sbits, 0);
+ ot = duintptr(s, ot, 0);
}
p = smprint("%-uT", t);
//print("dcommontype: %s\n", p);
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index fa927a58a..86afe67f1 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -112,6 +112,13 @@ func writebarrierptr(dst *any, src any)
func writebarrierstring(dst *any, src any)
func writebarrierslice(dst *any, src any)
func writebarrieriface(dst *any, src any)
+
+// The unused *byte argument makes sure that src is 2-pointer-aligned,
+// which is the maximum alignment on NaCl amd64p32
+// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
+func writebarrierfat2(dst *any, _ *byte, src any)
+func writebarrierfat3(dst *any, _ *byte, src any)
+func writebarrierfat4(dst *any, _ *byte, src any)
func writebarrierfat(typ *byte, dst *any, src *any)
func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 508747e5a..f050026d9 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -207,7 +207,7 @@ init2(Node *n, NodeList **out)
if(n->op == OCLOSURE)
init2list(n->closure->nbody, out);
- if(n->op == ODOTMETH)
+ if(n->op == ODOTMETH || n->op == OCALLPART)
init2(n->type->nname, out);
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 713348c0c..241d7d74a 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2040,30 +2040,42 @@ static Node*
applywritebarrier(Node *n, NodeList **init)
{
Node *l, *r;
+ Type *t;
if(n->left && n->right && needwritebarrier(n->left, n->right)) {
+ t = n->left->type;
l = nod(OADDR, n->left, N);
l->etype = 1; // addr does not escape
- if(n->left->type->width == widthptr) {
- n = mkcall1(writebarrierfn("writebarrierptr", n->left->type, n->right->type), T, init,
+ if(t->width == widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
l, n->right);
- } else if(n->left->type->etype == TSTRING) {
- n = mkcall1(writebarrierfn("writebarrierstring", n->left->type, n->right->type), T, init,
+ } else if(t->etype == TSTRING) {
+ n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
l, n->right);
- } else if(isslice(n->left->type)) {
- n = mkcall1(writebarrierfn("writebarrierslice", n->left->type, n->right->type), T, init,
+ } else if(isslice(t)) {
+ n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
l, n->right);
- } else if(isinter(n->left->type)) {
- n = mkcall1(writebarrierfn("writebarrieriface", n->left->type, n->right->type), T, init,
+ } else if(isinter(t)) {
+ n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
l, n->right);
+ } else if(t->width == 2*widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
+ l, nodnil(), n->right);
+ } else if(t->width == 3*widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
+ l, nodnil(), n->right);
+ } else if(t->width == 4*widthptr) {
+ n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
+ l, nodnil(), n->right);
} else {
r = n->right;
while(r->op == OCONVNOP)
r = r->left;
r = nod(OADDR, r, N);
r->etype = 1; // addr does not escape
- n = mkcall1(writebarrierfn("writebarrierfat", n->left->type, r->left->type), T, init,
- typename(n->left->type), l, r);
+ //warnl(n->lineno, "writebarrierfat %T %N", t, r);
+ n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init,
+ typename(t), l, r);
}
}
return n;
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 9c7b42650..49b84709e 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1852,7 +1852,7 @@ func (gccgoToolchain) linker() string {
}
func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
- out := p.Name + ".o"
+ out := "_go_.o"
ofile = obj + out
gcargs := []string{"-g"}
gcargs = append(gcargs, b.gccArchArgs()...)
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 8e2facd04..314c69bd8 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -385,28 +385,29 @@ syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
- Dir string // directory containing package sources
- ImportPath string // import path of package in dir
- Name string // package name
- Doc string // package documentation string
- Target string // install path
- Goroot bool // is this package in the Go root?
- Standard bool // is this package part of the standard Go library?
- Stale bool // would 'go install' do anything for this package?
- Root string // Go root or Go path dir containing this package
+ Dir string // directory containing package sources
+ ImportPath string // import path of package in dir
+ ImportComment string // path in import comment on package statement
+ Name string // package name
+ Doc string // package documentation string
+ Target string // install path
+ Goroot bool // is this package in the Go root?
+ Standard bool // is this package part of the standard Go library?
+ Stale bool // would 'go install' do anything for this package?
+ Root string // Go root or Go path dir containing this package
// Source files
- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string // .go sources files that import "C"
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
- CFiles []string // .c source files
- CXXFiles []string // .cc, .cxx and .cpp source files
- MFiles []string // .m source files
- HFiles []string // .h, .hh, .hpp and .hxx source files
- SFiles []string // .s source files
- SwigFiles []string // .swig files
- SwigCXXFiles []string // .swigcxx files
- SysoFiles []string // .syso object files to add to archive
+ CFiles []string // .c source files
+ CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
+ HFiles []string // .h, .hh, .hpp and .hxx source files
+ SFiles []string // .s source files
+ SwigFiles []string // .swig files
+ SwigCXXFiles []string // .swigcxx files
+ SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index 0ead43502..fbf96167f 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -30,28 +30,29 @@ syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
- Dir string // directory containing package sources
- ImportPath string // import path of package in dir
- Name string // package name
- Doc string // package documentation string
- Target string // install path
- Goroot bool // is this package in the Go root?
- Standard bool // is this package part of the standard Go library?
- Stale bool // would 'go install' do anything for this package?
- Root string // Go root or Go path dir containing this package
+ Dir string // directory containing package sources
+ ImportPath string // import path of package in dir
+ ImportComment string // path in import comment on package statement
+ Name string // package name
+ Doc string // package documentation string
+ Target string // install path
+ Goroot bool // is this package in the Go root?
+ Standard bool // is this package part of the standard Go library?
+ Stale bool // would 'go install' do anything for this package?
+ Root string // Go root or Go path dir containing this package
// Source files
- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string // .go sources files that import "C"
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
- CFiles []string // .c source files
- CXXFiles []string // .cc, .cxx and .cpp source files
- MFiles []string // .m source files
- HFiles []string // .h, .hh, .hpp and .hxx source files
- SFiles []string // .s source files
- SwigFiles []string // .swig files
- SwigCXXFiles []string // .swigcxx files
- SysoFiles []string // .syso object files to add to archive
+ CFiles []string // .c source files
+ CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
+ HFiles []string // .h, .hh, .hpp and .hxx source files
+ SFiles []string // .s source files
+ SwigFiles []string // .swig files
+ SwigCXXFiles []string // .swigcxx files
+ SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 7f7a3b04f..e17326442 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -26,16 +26,17 @@ type Package struct {
// Note: These fields are part of the go command's public API.
// See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go
- Dir string `json:",omitempty"` // directory containing package sources
- ImportPath string `json:",omitempty"` // import path of package in dir
- Name string `json:",omitempty"` // package name
- Doc string `json:",omitempty"` // package documentation string
- Target string `json:",omitempty"` // install path
- Goroot bool `json:",omitempty"` // is this package found in the Go root?
- Standard bool `json:",omitempty"` // is this package part of the standard Go library?
- Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
- Root string `json:",omitempty"` // Go root or Go path dir containing this package
- ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
+ Dir string `json:",omitempty"` // directory containing package sources
+ ImportPath string `json:",omitempty"` // import path of package in dir
+ ImportComment string `json:",omitempty"` // path in import comment on package statement
+ Name string `json:",omitempty"` // package name
+ Doc string `json:",omitempty"` // package documentation string
+ Target string `json:",omitempty"` // install path
+ Goroot bool `json:",omitempty"` // is this package found in the Go root?
+ Standard bool `json:",omitempty"` // is this package part of the standard Go library?
+ Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
+ Root string `json:",omitempty"` // Go root or Go path dir containing this package
+ ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
// Source files
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -104,6 +105,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.Dir = pp.Dir
p.ImportPath = pp.ImportPath
+ p.ImportComment = pp.ImportComment
p.Name = pp.Name
p.Doc = pp.Doc
p.Root = pp.Root
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 6a72bcde0..652ef3b5b 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -1085,6 +1085,20 @@ fi
unset GOPATH
rm -rf $d
+TEST go vet with external tests
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$(pwd)/testdata
+if ./testgo vet vetpkg >$d/err 2>&1; then
+ echo "go vet vetpkg passes incorrectly"
+ ok=false
+elif ! grep -q 'missing argument for Printf' $d/err; then
+ echo "go vet vetpkg did not find missing argument for Printf"
+ cat $d/err
+ ok=false
+fi
+unset GOPATH
+rm -rf $d
+
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1
diff --git a/src/cmd/go/testdata/src/vetpkg/a_test.go b/src/cmd/go/testdata/src/vetpkg/a_test.go
new file mode 100644
index 000000000..9b64e8e1a
--- /dev/null
+++ b/src/cmd/go/testdata/src/vetpkg/a_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/src/cmd/go/testdata/src/vetpkg/b.go b/src/cmd/go/testdata/src/vetpkg/b.go
new file mode 100644
index 000000000..99e18f63d
--- /dev/null
+++ b/src/cmd/go/testdata/src/vetpkg/b.go
@@ -0,0 +1,7 @@
+package p
+
+import "fmt"
+
+func f() {
+ fmt.Printf("%d")
+}
diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go
index ffb431837..de7befc61 100644
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -4,6 +4,8 @@
package main
+import "path/filepath"
+
func init() {
addBuildFlagsNX(cmdVet)
}
@@ -28,10 +30,21 @@ See also: go fmt, go fix.
}
func runVet(cmd *Command, args []string) {
- for _, pkg := range packages(args) {
- // Use pkg.gofiles instead of pkg.Dir so that
- // the command only applies to this package,
- // not to packages in subdirectories.
- run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
+ for _, p := range packages(args) {
+ // Vet expects to be given a set of files all from the same package.
+ // Run once for package p and once for package p_test.
+ if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
+ runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
+ }
+ if len(p.XTestGoFiles) > 0 {
+ runVetFiles(p, stringList(p.XTestGoFiles))
+ }
+ }
+}
+
+func runVetFiles(p *Package, files []string) {
+ for i := range files {
+ files[i] = filepath.Join(p.Dir, files[i])
}
+ run(tool("vet"), relPaths(files))
}
diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c
index c53066942..037263dce 100644
--- a/src/cmd/ld/decodesym.c
+++ b/src/cmd/ld/decodesym.c
@@ -111,7 +111,10 @@ decodetype_gcprog(LSym *s)
uint8*
decodetype_gcmask(LSym *s)
{
- return (uint8*)(s->p + 1*PtrSize + 8 + 1*PtrSize);
+ LSym *mask;
+
+ mask = decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
+ return mask->p;
}
// Type.ArrayType.elem and Type.SliceType.Elem
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 4efb0ed53..a3ba52325 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -1733,6 +1733,7 @@ writeframes(void)
LSym *s;
vlong fdeo, fdesize, pad;
Pciter pcsp;
+ uint32 nextpc;
if(framesec == S)
framesec = linklookup(ctxt, ".dwarfframe", 0);
@@ -1775,8 +1776,17 @@ writeframes(void)
addrput(0); // initial location
addrput(0); // address range
- for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp))
- putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value);
+ for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) {
+ nextpc = pcsp.nextpc;
+ // pciterinit goes up to the end of the function,
+ // but DWARF expects us to stop just before the end.
+ if(nextpc == s->size) {
+ nextpc--;
+ if(nextpc < pcsp.pc)
+ continue;
+ }
+ putpccfadelta(nextpc - pcsp.pc, PtrSize + pcsp.value);
+ }
fdesize = cpos() - fdeo - 4; // exclude the length field.
pad = rnd(fdesize, PtrSize) - fdesize;
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 38e414755..35f8b4985 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -582,6 +582,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
continue;
sect = obj->sect+sym.shndx;
if(sect->sym == nil) {
+ if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this
+ continue;
diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
continue;
}
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 1b0591614..4f5e51f2f 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -128,6 +128,7 @@ struct PeObj {
};
static int map(PeObj *obj, PeSect *sect);
+static int issect(PeSym *s);
static int readsym(PeObj *obj, int i, PeSym **sym);
void
@@ -179,6 +180,15 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
if(Bread(f, obj->snames, l) != l)
goto bad;
+ // rewrite section names if they start with /
+ for(i=0; i < obj->fh.NumberOfSections; i++) {
+ if(obj->sect[i].name == nil)
+ continue;
+ if(obj->sect[i].name[0] != '/')
+ continue;
+ l = atoi(obj->sect[i].name + 1);
+ obj->sect[i].name = (char*)&obj->snames[l];
+ }
// read symbols
obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
obj->npesym = obj->fh.NumberOfSymbols;
@@ -309,8 +319,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
// ld -r could generate multiple section symbols for the
// same section but with different values, we have to take
// that into account
- if (obj->pesym[symindex].name[0] == '.')
- rp->add += obj->pesym[symindex].value;
+ if(issect(&obj->pesym[symindex]))
+ rp->add += obj->pesym[symindex].value;
}
qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
@@ -318,12 +328,12 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
s->r = r;
s->nr = rsect->sh.NumberOfRelocations;
}
-
+
// enter sub-symbols into symbol table.
for(i=0; i<obj->npesym; i++) {
if(obj->pesym[i].name == 0)
continue;
- if(obj->pesym[i].name[0] == '.') //skip section
+ if(issect(&obj->pesym[i]))
continue;
if(obj->pesym[i].sectnum > 0) {
sect = &obj->sect[obj->pesym[i].sectnum-1];
@@ -422,6 +432,12 @@ map(PeObj *obj, PeSect *sect)
}
static int
+issect(PeSym *s)
+{
+ return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.';
+}
+
+static int
readsym(PeObj *obj, int i, PeSym **y)
{
LSym *s;
@@ -436,7 +452,7 @@ readsym(PeObj *obj, int i, PeSym **y)
sym = &obj->pesym[i];
*y = sym;
- if(sym->name[0] == '.') // .section
+ if(issect(sym))
name = obj->sect[sym->sectnum-1].sym->name;
else {
name = sym->name;
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 61306bb7c..fe7e10e46 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -590,8 +590,7 @@ machosymtab(void)
if(strstr(s->extname, "·") == nil) {
addstring(symstr, s->extname);
} else {
- p = s->extname;
- while (*p++ != '\0') {
+ for(p = s->extname; *p; p++) {
if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) {
adduint8(ctxt, symstr, '.');
p++;
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 6e57e913a..7a37b98e3 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -494,6 +494,11 @@ type Certificate struct {
BasicConstraintsValid bool // if true then the next two fields are valid.
IsCA bool
MaxPathLen int
+ // MaxPathLenZero indicates that BasicConstraintsValid==true and
+ // MaxPathLen==0 should be interpreted as an actual maximum path length
+ // of zero. Otherwise, that combination is interpreted as MaxPathLen
+ // not being set.
+ MaxPathLenZero bool
SubjectKeyId []byte
AuthorityKeyId []byte
@@ -913,6 +918,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.BasicConstraintsValid = true
out.IsCA = constraints.IsCA
out.MaxPathLen = constraints.MaxPathLen
+ out.MaxPathLenZero = out.MaxPathLen == 0
continue
}
case 17:
@@ -1227,8 +1233,15 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
}
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
+ // Leaving MaxPathLen as zero indicates that no maximum path
+ // length is desired, unless MaxPathLenZero is set. A value of
+ // -1 causes encoding/asn1 to omit the value as desired.
+ maxPathLen := template.MaxPathLen
+ if maxPathLen == 0 && !template.MaxPathLenZero {
+ maxPathLen = -1
+ }
ret[n].Id = oidExtensionBasicConstraints
- ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})
+ ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
ret[n].Critical = true
if err != nil {
return
@@ -1657,7 +1670,7 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
// CreateCertificateRequest creates a new certificate based on a template. The
// following members of template are used: Subject, Attributes,
-// SignatureAlgorithm, Extension, DNSNames, EmailAddresses, and IPAddresses.
+// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
// The private key is the private key of the signer.
//
// The returned slice is the certificate request in DER encoding.
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index abe86216f..4f5173fb5 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -953,6 +953,69 @@ func TestParseCertificateRequest(t *testing.T) {
}
}
+func TestMaxPathLen(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse private key: %s", err)
+ }
+
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+
+ serialiseAndParse := func(template *Certificate) *Certificate {
+ derBytes, err := CreateCertificate(rand.Reader, template, template, &rsaPriv.PublicKey, rsaPriv)
+ if err != nil {
+ t.Fatalf("failed to create certificate: %s", err)
+ return nil
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ return nil
+ }
+
+ return cert
+ }
+
+ cert1 := serialiseAndParse(template)
+ if m := cert1.MaxPathLen; m != -1 {
+ t.Errorf("Omitting MaxPathLen didn't turn into -1, got %d", m)
+ }
+ if cert1.MaxPathLenZero {
+ t.Errorf("Omitting MaxPathLen resulted in MaxPathLenZero")
+ }
+
+ template.MaxPathLen = 1
+ cert2 := serialiseAndParse(template)
+ if m := cert2.MaxPathLen; m != 1 {
+ t.Errorf("Setting MaxPathLen didn't work. Got %d but set 1", m)
+ }
+ if cert2.MaxPathLenZero {
+ t.Errorf("Setting MaxPathLen resulted in MaxPathLenZero")
+ }
+
+ template.MaxPathLen = 0
+ template.MaxPathLenZero = true
+ cert3 := serialiseAndParse(template)
+ if m := cert3.MaxPathLen; m != 0 {
+ t.Errorf("Setting MaxPathLenZero didn't work, got %d", m)
+ }
+ if !cert3.MaxPathLenZero {
+ t.Errorf("Setting MaxPathLen to zero didn't result in MaxPathLenZero")
+ }
+}
+
// This CSR was generated with OpenSSL:
// openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
//
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index c7db0dd77..171c322d4 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -10,6 +10,7 @@ import (
"fmt"
"io"
"log"
+ "sort"
"strconv"
"strings"
"sync"
@@ -126,6 +127,27 @@ func init() {
Register("test", fdriver)
}
+func contains(list []string, y string) bool {
+ for _, x := range list {
+ if x == y {
+ return true
+ }
+ }
+ return false
+}
+
+type Dummy struct {
+ driver.Driver
+}
+
+func TestDrivers(t *testing.T) {
+ Register("invalid", Dummy{})
+ all := Drivers()
+ if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") {
+ t.Fatalf("Drivers = %v, want sorted list with at least [invalid, test]", all)
+ }
+}
+
// Supports dsn forms:
// <dbname>
// <dbname>;<opts> (only currently supported option is `badConn`,
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index 731b7a7f7..ad9179cf7 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -18,6 +18,7 @@ import (
"fmt"
"io"
"runtime"
+ "sort"
"sync"
)
@@ -36,6 +37,16 @@ func Register(name string, driver driver.Driver) {
drivers[name] = driver
}
+// Drivers returns a sorted list of the names of the registered drivers.
+func Drivers() []string {
+ var list []string
+ for name := range drivers {
+ list = append(list, name)
+ }
+ sort.Strings(list)
+ return list
+}
+
// RawBytes is a byte slice that holds a reference to memory owned by
// the database itself. After a Scan into a RawBytes, the slice is only
// valid until the next call to Next, Scan, or Close.
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index c908e7a88..de8a3a24f 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -564,6 +564,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
continue
}
+ // There are relocations, so this must be a normal
+ // object file, and we only look at section symbols,
+ // so we assume that the symbol value is 0.
+
switch t {
case R_X86_64_64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
@@ -646,6 +650,10 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
continue
}
+ // There are relocations, so this must be a normal
+ // object file, and we only look at section symbols,
+ // so we assume that the symbol value is 0.
+
switch t {
case R_AARCH64_ABS64:
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 3aeb3dcc4..8b3d1b341 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -640,7 +640,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
// when it sees a string, so if we see a different string type on the
// wire, we change the universal type to match.
if universalTag == tagPrintableString {
- if params.tag == nil {
+ if t.class == classUniversal {
switch t.tag {
case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
universalTag = t.tag
@@ -652,7 +652,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
// Special case for time: UTCTime and GeneralizedTime both map to the
// Go type time.Time.
- if universalTag == tagUTCTime && params.tag == nil && t.tag == tagGeneralizedTime {
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime && t.class == classUniversal {
universalTag = tagGeneralizedTime
}
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index b94d59d36..4e864d08a 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -817,3 +817,51 @@ func TestStringSlice(t *testing.T) {
}
}
}
+
+type explicitTaggedTimeTest struct {
+ Time time.Time `asn1:"explicit,tag:0"`
+}
+
+var explicitTaggedTimeTestData = []struct {
+ in []byte
+ out explicitTaggedTimeTest
+}{
+ {[]byte{0x30, 0x11, 0xa0, 0xf, 0x17, 0xd, '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'},
+ explicitTaggedTimeTest{time.Date(1991, 05, 06, 16, 45, 40, 0, time.UTC)}},
+ {[]byte{0x30, 0x17, 0xa0, 0xf, 0x18, 0x13, '2', '0', '1', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '+', '0', '6', '0', '7'},
+ explicitTaggedTimeTest{time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}},
+}
+
+func TestExplicitTaggedTime(t *testing.T) {
+ // Test that a time.Time will match either tagUTCTime or
+ // tagGeneralizedTime.
+ for i, test := range explicitTaggedTimeTestData {
+ var got explicitTaggedTimeTest
+ _, err := Unmarshal(test.in, &got)
+ if err != nil {
+ t.Errorf("Unmarshal failed at index %d %v", i, err)
+ }
+ if !got.Time.Equal(test.out.Time) {
+ t.Errorf("#%d: got %v, want %v", i, got.Time, test.out.Time)
+ }
+ }
+}
+
+type implicitTaggedTimeTest struct {
+ Time time.Time `asn1:"tag:24"`
+}
+
+func TestImplicitTaggedTime(t *testing.T) {
+ // An implicitly tagged time value, that happens to have an implicit
+ // tag equal to a GENERALIZEDTIME, should still be parsed as a UTCTime.
+ // (There's no "timeType" in fieldParameters to determine what type of
+ // time should be expected when implicitly tagged.)
+ der := []byte{0x30, 0x0f, 0x80 | 24, 0xd, '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'}
+ var result implicitTaggedTimeTest
+ if _, err := Unmarshal(der, &result); err != nil {
+ t.Fatalf("Error while parsing: %s", err)
+ }
+ if expected := time.Date(1991, 05, 06, 16, 45, 40, 0, time.UTC); !result.Time.Equal(expected) {
+ t.Errorf("Wrong result. Got %v, want %v", result.Time, expected)
+ }
+}
diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go
index b7bf8b002..04a85410c 100644
--- a/src/encoding/gob/encode.go
+++ b/src/encoding/gob/encode.go
@@ -281,15 +281,16 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value refle
field := value.FieldByIndex(instr.index)
if instr.indir > 0 {
field = encIndirect(field, instr.indir)
- }
- if !valid(field) {
- continue
+ // TODO: Is field guaranteed valid? If so we could avoid this check.
+ if !valid(field) {
+ continue
+ }
}
instr.op(instr, state, field)
}
}
-// encodeArray encodes the array whose 0th element is at p.
+// encodeArray encodes an array.
func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int) {
state := enc.newEncoderState(b)
defer enc.freeEncoderState(state)
@@ -300,6 +301,7 @@ func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp,
elem := value.Index(i)
if elemIndir > 0 {
elem = encIndirect(elem, elemIndir)
+ // TODO: Is elem guaranteed valid? If so we could avoid this check.
if !valid(elem) {
errorf("encodeArray: nil element")
}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 67ec37388..705bc2e17 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -173,7 +173,6 @@ type decodeState struct {
scan scanner
nextscan scanner // for calls to nextValue
savedError error
- tempstr string // scratch space to avoid some allocations
useNumber bool
}
@@ -293,6 +292,32 @@ func (d *decodeState) value(v reflect.Value) {
}
}
+type unquotedValue struct{}
+
+// valueQuoted is like value but decodes a
+// quoted string literal or literal null into an interface value.
+// If it finds anything other than a quoted string literal or null,
+// valueQuoted returns unquotedValue{}.
+func (d *decodeState) valueQuoted() interface{} {
+ switch op := d.scanWhile(scanSkipSpace); op {
+ default:
+ d.error(errPhase)
+
+ case scanBeginArray:
+ d.array(reflect.Value{})
+
+ case scanBeginObject:
+ d.object(reflect.Value{})
+
+ case scanBeginLiteral:
+ switch v := d.literalInterface().(type) {
+ case nil, string:
+ return v
+ }
+ }
+ return unquotedValue{}
+}
+
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
@@ -444,6 +469,8 @@ func (d *decodeState) array(v reflect.Value) {
}
}
+var nullLiteral = []byte("null")
+
// object consumes an object from d.data[d.off-1:], decoding into the value v.
// the first byte ('{') of the object has been read already.
func (d *decodeState) object(v reflect.Value) {
@@ -566,9 +593,14 @@ func (d *decodeState) object(v reflect.Value) {
// Read value.
if destring {
- d.value(reflect.ValueOf(&d.tempstr))
- d.literalStore([]byte(d.tempstr), subv, true)
- d.tempstr = "" // Zero scratch space for successive values.
+ switch qv := d.valueQuoted().(type) {
+ case nil:
+ d.literalStore(nullLiteral, subv, false)
+ case string:
+ d.literalStore([]byte(qv), subv, true)
+ default:
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type()))
+ }
} else {
d.value(subv)
}
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index d95657d72..7235969b9 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -1070,18 +1070,25 @@ func TestEmptyString(t *testing.T) {
}
}
-// Test that the returned error is non-nil when trying to unmarshal null string into int, for successive ,string option
-// Issue 7046
+// Test that a null for ,string is not replaced with the previous quoted string (issue 7046).
+// It should also not be an error (issue 2540, issue 8587).
func TestNullString(t *testing.T) {
type T struct {
- A int `json:",string"`
- B int `json:",string"`
+ A int `json:",string"`
+ B int `json:",string"`
+ C *int `json:",string"`
}
- data := []byte(`{"A": "1", "B": null}`)
+ data := []byte(`{"A": "1", "B": null, "C": null}`)
var s T
+ s.B = 1
+ s.C = new(int)
+ *s.C = 2
err := Unmarshal(data, &s)
- if err == nil {
- t.Fatalf("expected error; got %v", s)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v")
+ }
+ if s.B != 1 || s.C != nil {
+ t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C)
}
}
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index b63538c92..9b7b9d5fd 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -93,6 +93,8 @@ import (
// as described in the next paragraph.
// An anonymous struct field with a name given in its JSON tag is treated as
// having that name, rather than being anonymous.
+// An anonymous struct field of interface type is treated the same as having
+// that type as its name, rather than being anonymous.
//
// The Go visibility rules for struct fields are amended for JSON when
// deciding which field to marshal or unmarshal. If there are
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 5e11c9b9c..7a51cf3c0 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -417,6 +417,19 @@ func (e *NoGoError) Error() string {
return "no buildable Go source files in " + e.Dir
}
+// MultiplePackageError describes a directory containing
+// multiple buildable Go source files for multiple packages.
+type MultiplePackageError struct {
+ Dir string // directory containing files
+ Packages []string // package names found
+ Files []string // corresponding files: Files[i] declares package Packages[i]
+}
+
+func (e *MultiplePackageError) Error() string {
+ // Error string limited to two entries for compatibility.
+ return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", e.Packages[0], e.Files[0], e.Packages[1], e.Files[1], e.Dir)
+}
+
func nameExt(name string) string {
i := strings.LastIndex(name, ".")
if i < 0 {
@@ -675,7 +688,7 @@ Found:
p.Name = pkg
firstFile = name
} else if pkg != p.Name {
- return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
+ return p, &MultiplePackageError{p.Dir, []string{firstFile, name}, []string{p.Name, pkg}}
}
if pf.Doc != nil && p.Doc == "" {
p.Doc = doc.Synopsis(pf.Doc.Text())
@@ -1291,6 +1304,18 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
if dot := strings.Index(name, "."); dot != -1 {
name = name[:dot]
}
+
+ // Before Go 1.4, a file called "linux.go" would be equivalent to having a
+ // build tag "linux" in that file. For Go 1.4 and beyond, we require this
+ // auto-tagging to apply only to files with a non-empty prefix, so
+ // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
+ // sytems, such as android, to arrive without breaking existing code with
+ // innocuous source code in "android.go". The easiest fix: files without
+ // underscores are always included.
+ if !strings.ContainsRune(name, '_') {
+ return true
+ }
+
l := strings.Split(name, "_")
if n := len(l); n > 0 && l[n-1] == "test" {
l = l[:n-1]
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index 004010113..43d09cbd1 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -85,6 +85,20 @@ func TestEmptyImport(t *testing.T) {
}
}
+func TestEmptyFolderImport(t *testing.T) {
+ _, err := Import(".", "testdata/empty", 0)
+ if _, ok := err.(*NoGoError); !ok {
+ t.Fatal(`Import("testdata/empty") did not return NoGoError.`)
+ }
+}
+
+func TestMultiplePackageImport(t *testing.T) {
+ _, err := Import(".", "testdata/multi", 0)
+ if _, ok := err.(*MultiplePackageError); !ok {
+ t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
+ }
+}
+
func TestLocalDirectory(t *testing.T) {
cwd, err := os.Getwd()
if err != nil {
@@ -173,6 +187,10 @@ var matchFileTests = []struct {
{ctxtAndroid, "foo_linux.go", "", true},
{ctxtAndroid, "foo_android.go", "", true},
{ctxtAndroid, "foo_plan9.go", "", false},
+ {ctxtAndroid, "android.go", "", true},
+ {ctxtAndroid, "plan9.go", "", true},
+ {ctxtAndroid, "arm.s", "", true},
+ {ctxtAndroid, "amd64.s", "", true},
}
func TestMatchFile(t *testing.T) {
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 56878f2b4..75a827bb9 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -108,12 +108,10 @@
// *_GOOS
// *_GOARCH
// *_GOOS_GOARCH
-// (example: source_windows_amd64.go) or the literals:
-// GOOS
-// GOARCH
-// (example: windows.go) where GOOS and GOARCH represent any known operating
-// system and architecture values respectively, then the file is considered to
-// have an implicit build constraint requiring those terms.
+// (example: source_windows_amd64.go) where GOOS and GOARCH represent
+// any known operating system and architecture values respectively, then
+// the file is considered to have an implicit build constraint requiring
+// those terms.
//
// To keep a file from being considered for the build:
//
diff --git a/src/go/build/testdata/empty/dummy b/src/go/build/testdata/empty/dummy
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/go/build/testdata/empty/dummy
diff --git a/src/go/build/testdata/multi/file.go b/src/go/build/testdata/multi/file.go
new file mode 100644
index 000000000..ee946eb2a
--- /dev/null
+++ b/src/go/build/testdata/multi/file.go
@@ -0,0 +1,5 @@
+// Test data - not compiled.
+
+package main
+
+func main() {}
diff --git a/src/go/build/testdata/multi/file_appengine.go b/src/go/build/testdata/multi/file_appengine.go
new file mode 100644
index 000000000..4ea31e703
--- /dev/null
+++ b/src/go/build/testdata/multi/file_appengine.go
@@ -0,0 +1,5 @@
+// Test data - not compiled.
+
+package test_package
+
+func init() {}
diff --git a/src/liblink/data.c b/src/liblink/data.c
index 4504f4171..e5efa2eb2 100644
--- a/src/liblink/data.c
+++ b/src/liblink/data.c
@@ -83,6 +83,8 @@ savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
siz = ctxt->arch->datasize(p);
if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
mangle(pn);
+ if(ctxt->enforce_data_order && off < s->np)
+ ctxt->diag("data out of order (already have %d)\n%P", p);
symgrow(ctxt, s, off+siz);
if(p->to.type == ctxt->arch->D_FCONST) {
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 3998652e9..d22e39e7c 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -752,15 +752,16 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
return z
}
-// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
-// p is a prime) and returns z.
-func (z *Int) ModInverse(g, p *Int) *Int {
+// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
+// and returns z. If g and n are not relatively prime, the result is undefined.
+func (z *Int) ModInverse(g, n *Int) *Int {
var d Int
- d.GCD(z, nil, g, p)
- // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
- // that modulo p results in g*x = 1, therefore x is the inverse element.
+ d.GCD(z, nil, g, n)
+ // x and y are such that g*x + n*y = d. Since g and n are
+ // relatively prime, d = 1. Taking that modulo n results in
+ // g*x = 1, therefore x is the inverse element.
if z.neg {
- z.Add(z, p)
+ z.Add(z, n)
}
return z
}
@@ -1016,12 +1017,12 @@ func (z *Int) UnmarshalJSON(text []byte) error {
return nil
}
-// MarshalText implements the encoding.TextMarshaler interface
+// MarshalText implements the encoding.TextMarshaler interface.
func (z *Int) MarshalText() (text []byte, err error) {
return []byte(z.String()), nil
}
-// UnmarshalText implements the encoding.TextUnmarshaler interface
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (z *Int) UnmarshalText(text []byte) error {
if _, ok := z.SetString(string(text), 0); !ok {
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index ec05fbb1c..6070cf325 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -1448,24 +1448,40 @@ func TestNot(t *testing.T) {
var modInverseTests = []struct {
element string
- prime string
+ modulus string
}{
- {"1", "7"},
- {"1", "13"},
+ {"1234567", "458948883992"},
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
}
func TestModInverse(t *testing.T) {
- var element, prime Int
+ var element, modulus, gcd, inverse Int
one := NewInt(1)
for i, test := range modInverseTests {
(&element).SetString(test.element, 10)
- (&prime).SetString(test.prime, 10)
- inverse := new(Int).ModInverse(&element, &prime)
- inverse.Mul(inverse, &element)
- inverse.Mod(inverse, &prime)
- if inverse.Cmp(one) != 0 {
- t.Errorf("#%d: failed (e·e^(-1)=%s)", i, inverse)
+ (&modulus).SetString(test.modulus, 10)
+ (&inverse).ModInverse(&element, &modulus)
+ (&inverse).Mul(&inverse, &element)
+ (&inverse).Mod(&inverse, &modulus)
+ if (&inverse).Cmp(one) != 0 {
+ t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse)
+ }
+ }
+ // exhaustive test for small values
+ for n := 2; n < 100; n++ {
+ (&modulus).SetInt64(int64(n))
+ for x := 1; x < n; x++ {
+ (&element).SetInt64(int64(x))
+ (&gcd).GCD(nil, nil, &element, &modulus)
+ if (&gcd).Cmp(one) != 0 {
+ continue
+ }
+ (&inverse).ModInverse(&element, &modulus)
+ (&inverse).Mul(&inverse, &element)
+ (&inverse).Mod(&inverse, &modulus)
+ if (&inverse).Cmp(one) != 0 {
+ t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse)
+ }
}
}
}
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index e6ab0bb48..c5339fe44 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -552,6 +552,9 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil {
return nil, false
}
+ if len(z.b.abs) == 0 {
+ return nil, false
+ }
return z.norm(), true
}
@@ -699,12 +702,12 @@ func (z *Rat) GobDecode(buf []byte) error {
return nil
}
-// MarshalText implements the encoding.TextMarshaler interface
+// MarshalText implements the encoding.TextMarshaler interface.
func (r *Rat) MarshalText() (text []byte, err error) {
return []byte(r.RatString()), nil
}
-// UnmarshalText implements the encoding.TextUnmarshaler interface
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (r *Rat) UnmarshalText(text []byte) error {
if _, ok := r.SetString(string(text)); !ok {
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
diff --git a/src/math/big/rat_test.go b/src/math/big/rat_test.go
index 598eac8cc..5dbbb3510 100644
--- a/src/math/big/rat_test.go
+++ b/src/math/big/rat_test.go
@@ -89,6 +89,7 @@ var setStringTests = []struct {
{"53/70893980658822810696", "53/70893980658822810696", true},
{"106/141787961317645621392", "53/70893980658822810696", true},
{"204211327800791583.81095", "4084226556015831676219/20000", true},
+ {in: "1/0", ok: false},
}
func TestRatSetString(t *testing.T) {
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index 6d69e0624..f3a534a1d 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -294,6 +294,18 @@ func (fd *netFD) init() error {
fd.skipSyncNotif = true
}
}
+ // Disable SIO_UDP_CONNRESET behavior.
+ // http://support.microsoft.com/kb/263823
+ switch fd.net {
+ case "udp", "udp4", "udp6":
+ ret := uint32(0)
+ flag := uint32(0)
+ size := uint32(unsafe.Sizeof(flag))
+ err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
+ if err != nil {
+ return os.NewSyscallError("WSAIoctl", err)
+ }
+ }
fd.rop.mode = 'r'
fd.wop.mode = 'w'
fd.rop.fd = fd
diff --git a/src/net/http/client.go b/src/net/http/client.go
index a5a3abe61..ce884d1f0 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -101,6 +101,30 @@ type RoundTripper interface {
// return true if the string includes a port.
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+// refererForURL returns a referer without any authentication info or
+// an empty string if lastReq scheme is https and newReq scheme is http.
+func refererForURL(lastReq, newReq *url.URL) string {
+ // https://tools.ietf.org/html/rfc7231#section-5.5.2
+ // "Clients SHOULD NOT include a Referer header field in a
+ // (non-secure) HTTP request if the referring page was
+ // transferred with a secure protocol."
+ if lastReq.Scheme == "https" && newReq.Scheme == "http" {
+ return ""
+ }
+ referer := lastReq.String()
+ if lastReq.User != nil {
+ // This is not very efficient, but is the best we can
+ // do without:
+ // - introducing a new method on URL
+ // - creating a race condition
+ // - copying the URL struct manually, which would cause
+ // maintenance problems down the line
+ auth := lastReq.User.String() + "@"
+ referer = strings.Replace(referer, auth, "", 1)
+ }
+ return referer
+}
+
// Used in Send to implement io.ReadCloser by bundling together the
// bufio.Reader through which we read the response, and the underlying
// network connection.
@@ -324,8 +348,8 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
if len(via) > 0 {
// Add the Referer header.
lastReq := via[len(via)-1]
- if lastReq.URL.Scheme != "https" {
- nreq.Header.Set("Referer", lastReq.URL.String())
+ if ref := refererForURL(lastReq.URL, nreq.URL); ref != "" {
+ nreq.Header.Set("Referer", ref)
}
err = redirectChecker(nreq, via)
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 6392c1baf..56b6563c4 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -1036,3 +1036,40 @@ func TestClientTrailers(t *testing.T) {
t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want)
}
}
+
+func TestReferer(t *testing.T) {
+ tests := []struct {
+ lastReq, newReq string // from -> to URLs
+ want string
+ }{
+ // don't send user:
+ {"http://gopher@test.com", "http://link.com", "http://test.com"},
+ {"https://gopher@test.com", "https://link.com", "https://test.com"},
+
+ // don't send a user and password:
+ {"http://gopher:go@test.com", "http://link.com", "http://test.com"},
+ {"https://gopher:go@test.com", "https://link.com", "https://test.com"},
+
+ // nothing to do:
+ {"http://test.com", "http://link.com", "http://test.com"},
+ {"https://test.com", "https://link.com", "https://test.com"},
+
+ // https to http doesn't send a referer:
+ {"https://test.com", "http://link.com", ""},
+ {"https://gopher:go@test.com", "http://link.com", ""},
+ }
+ for _, tt := range tests {
+ l, err := url.Parse(tt.lastReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+ n, err := url.Parse(tt.newReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+ r := ExportRefererForURL(l, n)
+ if r != tt.want {
+ t.Errorf("refererForURL(%q, %q) = %q; want %q", tt.lastReq, tt.newReq, r, tt.want)
+ }
+ }
+}
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index a6980b538..87b6c0773 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -9,6 +9,7 @@ package http
import (
"net"
+ "net/url"
"time"
)
@@ -92,6 +93,10 @@ func ResetCachedEnvironment() {
var DefaultUserAgent = defaultUserAgent
+func ExportRefererForURL(lastReq, newReq *url.URL) string {
+ return refererForURL(lastReq, newReq)
+}
+
// SetPendingDialHooks sets the hooks that run before and after handling
// pending dials.
func SetPendingDialHooks(before, after func()) {
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index 2dd0fad11..06e940d9a 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -377,6 +377,34 @@ some body`,
"Body here\n",
},
+
+ // 206 Partial Content. golang.org/issue/8923
+ {
+ "HTTP/1.1 206 Partial Content\r\n" +
+ "Content-Type: text/plain; charset=utf-8\r\n" +
+ "Accept-Ranges: bytes\r\n" +
+ "Content-Range: bytes 0-5/1862\r\n" +
+ "Content-Length: 6\r\n\r\n" +
+ "foobar",
+
+ Response{
+ Status: "206 Partial Content",
+ StatusCode: 206,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{
+ "Accept-Ranges": []string{"bytes"},
+ "Content-Length": []string{"6"},
+ "Content-Type": []string{"text/plain; charset=utf-8"},
+ "Content-Range": []string{"bytes 0-5/1862"},
+ },
+ ContentLength: 6,
+ },
+
+ "foobar",
+ },
}
func TestReadResponse(t *testing.T) {
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 702bffdc1..bb44ac853 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -2659,6 +2659,103 @@ func TestCloseWrite(t *testing.T) {
}
}
+// This verifies that a handler can Flush and then Hijack.
+//
+// An similar test crashed once during development, but it was only
+// testing this tangentially and temporarily until another TODO was
+// fixed.
+//
+// So add an explicit test for this.
+func TestServerFlushAndHijack(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.WriteString(w, "Hello, ")
+ w.(Flusher).Flush()
+ conn, buf, _ := w.(Hijacker).Hijack()
+ buf.WriteString("6\r\nworld!\r\n0\r\n\r\n")
+ if err := buf.Flush(); err != nil {
+ t.Error(err)
+ }
+ if err := conn.Close(); err != nil {
+ t.Error(err)
+ }
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ all, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := "Hello, world!"; string(all) != want {
+ t.Errorf("Got %q; want %q", all, want)
+ }
+}
+
+// golang.org/issue/8534 -- the Server shouldn't reuse a connection
+// for keep-alive after it's seen any Write error (e.g. a timeout) on
+// that net.Conn.
+//
+// To test, verify we don't timeout or see fewer unique client
+// addresses (== unique connections) than requests.
+func TestServerKeepAliveAfterWriteError(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ defer afterTest(t)
+ const numReq = 3
+ addrc := make(chan string, numReq)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ addrc <- r.RemoteAddr
+ time.Sleep(500 * time.Millisecond)
+ w.(Flusher).Flush()
+ }))
+ ts.Config.WriteTimeout = 250 * time.Millisecond
+ ts.Start()
+ defer ts.Close()
+
+ errc := make(chan error, numReq)
+ go func() {
+ defer close(errc)
+ for i := 0; i < numReq; i++ {
+ res, err := Get(ts.URL)
+ if res != nil {
+ res.Body.Close()
+ }
+ errc <- err
+ }
+ }()
+
+ timeout := time.NewTimer(numReq * 2 * time.Second) // 4x overkill
+ defer timeout.Stop()
+ addrSeen := map[string]bool{}
+ numOkay := 0
+ for {
+ select {
+ case v := <-addrc:
+ addrSeen[v] = true
+ case err, ok := <-errc:
+ if !ok {
+ if len(addrSeen) != numReq {
+ t.Errorf("saw %d unique client addresses; want %d", len(addrSeen), numReq)
+ }
+ if numOkay != 0 {
+ t.Errorf("got %d successful client requests; want 0", numOkay)
+ }
+ return
+ }
+ if err == nil {
+ numOkay++
+ }
+ case <-timeout.C:
+ t.Fatal("timeout waiting for requests to complete")
+ }
+ }
+}
+
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
diff --git a/src/net/http/server.go b/src/net/http/server.go
index b5959f732..008d5aa7a 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -114,6 +114,8 @@ type conn struct {
remoteAddr string // network address of remote side
server *Server // the Server on which the connection arrived
rwc net.Conn // i/o connection
+ w io.Writer // checkConnErrorWriter's copy of wrc, not zeroed on Hijack
+ werr error // any errors writing to w
sr liveSwitchReader // where the LimitReader reads from; usually the rwc
lr *io.LimitedReader // io.LimitReader(sr)
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
@@ -432,13 +434,14 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
c.remoteAddr = rwc.RemoteAddr().String()
c.server = srv
c.rwc = rwc
+ c.w = rwc
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
c.sr = liveSwitchReader{r: c.rwc}
c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
br := newBufioReader(c.lr)
- bw := newBufioWriterSize(c.rwc, 4<<10)
+ bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
c.buf = bufio.NewReadWriter(br, bw)
return c, nil
}
@@ -956,8 +959,10 @@ func (w *response) bodyAllowed() bool {
// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes
// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type)
// and which writes the chunk headers, if needed.
-// 4. conn.buf, a bufio.Writer of default (4kB) bytes
-// 5. the rwc, the net.Conn.
+// 4. conn.buf, a bufio.Writer of default (4kB) bytes, writing to ->
+// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write
+// and populates c.werr with it if so. but otherwise writes to:
+// 6. the rwc, the net.Conn.
//
// TODO(bradfitz): short-circuit some of the buffering when the
// initial header contains both a Content-Type and Content-Length.
@@ -1027,6 +1032,12 @@ func (w *response) finishRequest() {
// Did not write enough. Avoid getting out of sync.
w.closeAfterReply = true
}
+
+ // There was some error writing to the underlying connection
+ // during the request, so don't re-use this conn.
+ if w.conn.werr != nil {
+ w.closeAfterReply = true
+ }
}
func (w *response) Flush() {
@@ -2068,3 +2079,18 @@ func (c *loggingConn) Close() (err error) {
log.Printf("%s.Close() = %v", c.name, err)
return
}
+
+// checkConnErrorWriter writes to c.rwc and records any write errors to c.werr.
+// It only contains one field (and a pointer field at that), so it
+// fits in an interface value without an extra allocation.
+type checkConnErrorWriter struct {
+ c *conn
+}
+
+func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
+ n, err = w.c.w.Write(p) // c.w == c.rwc, except after a hijack, when rwc is nil.
+ if err != nil && w.c.werr == nil {
+ w.c.werr = err
+ }
+ return
+}
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 70e574fc8..782f7cd39 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -1040,11 +1040,14 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
}
// Ask for a compressed version if the caller didn't set their
- // own value for Accept-Encoding. We only attempted to
+ // own value for Accept-Encoding. We only attempt to
// uncompress the gzip stream if we were the layer that
// requested it.
requestedGzip := false
- if !pc.t.DisableCompression && req.Header.Get("Accept-Encoding") == "" && req.Method != "HEAD" {
+ if !pc.t.DisableCompression &&
+ req.Header.Get("Accept-Encoding") == "" &&
+ req.Header.Get("Range") == "" &&
+ req.Method != "HEAD" {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: http://www.gzip.org/zlib/zlib_faq.html#faq38
@@ -1053,6 +1056,10 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// http://golang.org/issue/5522
+ //
+ // We don't request gzip if the request is for a range, since
+ // auto-decoding a portion of a gzipped document will just fail
+ // anyway. See http://golang.org/issue/8923
requestedGzip = true
req.extraHeaders().Set("Accept-Encoding", "gzip")
}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 66fcc3c7d..defa63370 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -2216,6 +2216,39 @@ func TestTransportCloseIdleConnsThenReturn(t *testing.T) {
wantIdle("after final put", 1)
}
+// This tests that an client requesting a content range won't also
+// implicitly ask for gzip support. If they want that, they need to do it
+// on their own.
+// golang.org/issue/8923
+func TestTransportRangeAndGzip(t *testing.T) {
+ defer afterTest(t)
+ reqc := make(chan *Request, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ reqc <- r
+ }))
+ defer ts.Close()
+
+ req, _ := NewRequest("GET", ts.URL, nil)
+ req.Header.Set("Range", "bytes=7-11")
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ select {
+ case r := <-reqc:
+ if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
+ t.Error("Transport advertised gzip support in the Accept header")
+ }
+ if r.Header.Get("Range") == "" {
+ t.Error("no Range in request")
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("timeout")
+ }
+ res.Body.Close()
+}
+
func wantBody(res *http.Response, err error, want string) error {
if err != nil {
return err
diff --git a/src/net/rpc/client.go b/src/net/rpc/client.go
index 21f79b068..d0c4a6921 100644
--- a/src/net/rpc/client.go
+++ b/src/net/rpc/client.go
@@ -41,10 +41,10 @@ type Call struct {
type Client struct {
codec ClientCodec
- sending sync.Mutex
+ reqMutex sync.Mutex // protects following
+ request Request
mutex sync.Mutex // protects following
- request Request
seq uint64
pending map[uint64]*Call
closing bool // user has called Close
@@ -69,8 +69,8 @@ type ClientCodec interface {
}
func (client *Client) send(call *Call) {
- client.sending.Lock()
- defer client.sending.Unlock()
+ client.reqMutex.Lock()
+ defer client.reqMutex.Unlock()
// Register this call.
client.mutex.Lock()
@@ -146,7 +146,7 @@ func (client *Client) input() {
}
}
// Terminate pending calls.
- client.sending.Lock()
+ client.reqMutex.Lock()
client.mutex.Lock()
client.shutdown = true
closing := client.closing
@@ -162,7 +162,7 @@ func (client *Client) input() {
call.done()
}
client.mutex.Unlock()
- client.sending.Unlock()
+ client.reqMutex.Unlock()
if debugLog && err != io.EOF && !closing {
log.Println("rpc: client protocol error:", err)
}
diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go
index bbfc1ec3a..5dd111b29 100644
--- a/src/net/rpc/client_test.go
+++ b/src/net/rpc/client_test.go
@@ -6,6 +6,10 @@ package rpc
import (
"errors"
+ "fmt"
+ "net"
+ "runtime"
+ "strings"
"testing"
)
@@ -34,3 +38,54 @@ func TestCloseCodec(t *testing.T) {
t.Error("client.Close did not close codec")
}
}
+
+// Test that errors in gob shut down the connection. Issue 7689.
+
+type R struct {
+ msg []byte // Not exported, so R does not work with gob.
+}
+
+type S struct{}
+
+func (s *S) Recv(nul *struct{}, reply *R) error {
+ *reply = R{[]byte("foo")}
+ return nil
+}
+
+func TestGobError(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/8908")
+ }
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Fatal("no error")
+ }
+ if !strings.Contains("reading body EOF", err.(error).Error()) {
+ t.Fatal("expected `reading body EOF', got", err)
+ }
+ }()
+ Register(new(S))
+
+ listen, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ panic(err)
+ }
+ go Accept(listen)
+
+ client, err := Dial("tcp", listen.Addr().String())
+ if err != nil {
+ panic(err)
+ }
+
+ var reply Reply
+ err = client.Call("S.Recv", &struct{}{}, &reply)
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("%#v\n", reply)
+ client.Close()
+
+ listen.Close()
+}
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
index e1778779c..125bbca6c 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -9,6 +9,7 @@ import (
"runtime"
"strings"
"testing"
+ "time"
)
func TestResolveUDPAddr(t *testing.T) {
@@ -34,6 +35,46 @@ func TestResolveUDPAddr(t *testing.T) {
}
}
+func TestReadFromUDP(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS)
+ }
+
+ ra, err := ResolveUDPAddr("udp", "127.0.0.1:7")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ la, err := ResolveUDPAddr("udp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ c, err := ListenUDP("udp", la)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ _, err = c.WriteToUDP([]byte("a"), ra)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+ if err != nil {
+ t.Fatal(err)
+ }
+ b := make([]byte, 1)
+ _, _, err = c.ReadFromUDP(b)
+ if err == nil {
+ t.Fatal("ReadFromUDP should fail")
+ } else if !isTimeout(err) {
+ t.Fatal(err)
+ }
+}
+
func TestWriteToUDP(t *testing.T) {
switch runtime.GOOS {
case "plan9":
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 0b32cd7c8..f167408fa 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -441,6 +441,24 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
}
// String reassembles the URL into a valid URL string.
+// The general form of the result is one of:
+//
+// scheme:opaque
+// scheme://userinfo@host/path?query#fragment
+//
+// If u.Opaque is non-empty, String uses the first form;
+// otherwise it uses the second form.
+//
+// In the second form, the following rules apply:
+// - if u.Scheme is empty, scheme: is omitted.
+// - if u.User is nil, userinfo@ is omitted.
+// - if u.Host is empty, host/ is omitted.
+// - if u.Scheme and u.Host are empty and u.User is nil,
+// the entire scheme://userinfo@host/ is omitted.
+// - if u.Host is non-empty and u.Path begins with a /,
+// the form host/path does not add its own /.
+// - if u.RawQuery is empty, ?query is omitted.
+// - if u.Fragment is empty, #fragment is omitted.
func (u *URL) String() string {
var buf bytes.Buffer
if u.Scheme != "" {
diff --git a/src/os/error_plan9.go b/src/os/error_plan9.go
index 45cd74792..001cdfcf2 100644
--- a/src/os/error_plan9.go
+++ b/src/os/error_plan9.go
@@ -25,7 +25,8 @@ func isNotExist(err error) bool {
case *LinkError:
err = pe.Err
}
- return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") || contains(err.Error(), "has been removed")
+ return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") ||
+ contains(err.Error(), "has been removed") || contains(err.Error(), "no parent")
}
func isPermission(err error) bool {
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 4aded4171..72b4905d5 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -55,8 +55,15 @@ type Cmd struct {
// calling process's current directory.
Dir string
- // Stdin specifies the process's standard input. If Stdin is
- // nil, the process reads from the null device (os.DevNull).
+ // Stdin specifies the process's standard input.
+ // If Stdin is nil, the process reads from the null device (os.DevNull).
+ // If Stdin is an *os.File, the process's standard input is connected
+ // directly to that file.
+ // Otherwise, during the execution of the command a separate
+ // goroutine reads from Stdin and delivers that data to the command
+ // over a pipe. In this case, Wait does not complete until the goroutine
+ // stops copying, either because it has reached the end of Stdin
+ // (EOF or a read error) or because writing to the pipe returned an error.
Stdin io.Reader
// Stdout and Stderr specify the process's standard output and error.
diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go
index 1b1e3350b..ed97f85e2 100644
--- a/src/os/exec_unix.go
+++ b/src/os/exec_unix.go
@@ -34,18 +34,26 @@ func (p *Process) wait() (ps *ProcessState, err error) {
return ps, nil
}
+var errFinished = errors.New("os: process already finished")
+
func (p *Process) signal(sig Signal) error {
- if p.done() {
- return errors.New("os: process already finished")
- }
if p.Pid == -1 {
return errors.New("os: process already released")
}
+ if p.Pid == 0 {
+ return errors.New("os: process not initialized")
+ }
+ if p.done() {
+ return errFinished
+ }
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
if e := syscall.Kill(p.Pid, s); e != nil {
+ if e == syscall.ESRCH {
+ return errFinished
+ }
return e
}
return nil
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
index c4f3d4f85..393393b23 100644
--- a/src/os/exec_windows.go
+++ b/src/os/exec_windows.go
@@ -53,6 +53,9 @@ func terminateProcess(pid, exitcode int) error {
}
func (p *Process) signal(sig Signal) error {
+ if p.handle == uintptr(syscall.InvalidHandle) {
+ return syscall.EINVAL
+ }
if p.done() {
return errors.New("os: process already finished")
}
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 973cc3a7b..a30a2b031 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -124,7 +124,22 @@ func newFile(testName string, t *testing.T) (f *File) {
}
f, err := ioutil.TempFile(dir, "_Go_"+testName)
if err != nil {
- t.Fatalf("open %s: %s", testName, err)
+ t.Fatalf("TempFile %s: %s", testName, err)
+ }
+ return
+}
+
+func newDir(testName string, t *testing.T) (name string) {
+ // Use a local file system, not NFS.
+ // On Unix, override $TMPDIR in case the user
+ // has it set to an NFS-mounted directory.
+ dir := ""
+ if runtime.GOOS != "android" && runtime.GOOS != "windows" {
+ dir = "/tmp"
+ }
+ name, err := ioutil.TempDir(dir, "_Go_"+testName)
+ if err != nil {
+ t.Fatalf("TempDir %s: %s", testName, err)
}
return
}
@@ -755,35 +770,49 @@ func TestTruncate(t *testing.T) {
}
}
-// Use TempDir() to make sure we're on a local file system,
+// Use TempDir (via newFile) to make sure we're on a local file system,
// so that timings are not distorted by latency and caching.
// On NFS, timings can be off due to caching of meta-data on
// NFS servers (Issue 848).
func TestChtimes(t *testing.T) {
f := newFile("TestChtimes", t)
defer Remove(f.Name())
- defer f.Close()
f.Write([]byte("hello, world\n"))
f.Close()
- st, err := Stat(f.Name())
+ testChtimes(t, f.Name())
+}
+
+// Use TempDir (via newDir) to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
+func TestChtimesDir(t *testing.T) {
+ name := newDir("TestChtimes", t)
+ defer RemoveAll(name)
+
+ testChtimes(t, name)
+}
+
+func testChtimes(t *testing.T, name string) {
+ st, err := Stat(name)
if err != nil {
- t.Fatalf("Stat %s: %s", f.Name(), err)
+ t.Fatalf("Stat %s: %s", name, err)
}
preStat := st
// Move access and modification time back a second
at := Atime(preStat)
mt := preStat.ModTime()
- err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
+ err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
if err != nil {
- t.Fatalf("Chtimes %s: %s", f.Name(), err)
+ t.Fatalf("Chtimes %s: %s", name, err)
}
- st, err = Stat(f.Name())
+ st, err = Stat(name)
if err != nil {
- t.Fatalf("second Stat %s: %s", f.Name(), err)
+ t.Fatalf("second Stat %s: %s", name, err)
}
postStat := st
diff --git a/src/os/path.go b/src/os/path.go
index 24a3415b4..84a3be334 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -17,7 +17,7 @@ import (
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm FileMode) error {
- // If path exists, stop with success or error.
+ // Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := Stat(path)
if err == nil {
if dir.IsDir() {
@@ -26,7 +26,7 @@ func MkdirAll(path string, perm FileMode) error {
return &PathError{"mkdir", path, syscall.ENOTDIR}
}
- // Doesn't already exist; make sure parent does.
+ // Slow path: make sure parent exists and then call Mkdir for path.
i := len(path)
for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
@@ -45,7 +45,7 @@ func MkdirAll(path string, perm FileMode) error {
}
}
- // Now parent exists, try to create.
+ // Parent now exists; invoke Mkdir and use its result.
err = Mkdir(path, perm)
if err != nil {
// Handle arguments like "foo/." by
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index d17ef5c5e..6bdc9be9d 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -1543,7 +1543,17 @@ func TestMakeFuncVariadic(t *testing.T) {
fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] })
ValueOf(&fn).Elem().Set(fv)
- r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
+ r := fn(1, 2, 3)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fn(1, []int{2, 3}...)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
if r[0] != 2 || r[1] != 3 {
t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
}
@@ -1552,6 +1562,17 @@ func TestMakeFuncVariadic(t *testing.T) {
if r[0] != 2 || r[1] != 3 {
t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
}
+
+ f := fv.Interface().(func(int, ...int) []int)
+
+ r = f(1, 2, 3)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+ r = f(1, []int{2, 3}...)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
}
type Point struct {
@@ -1569,6 +1590,24 @@ func (p Point) Dist(scale int) int {
return p.x*p.x*scale + p.y*p.y*scale
}
+// This will be index 2.
+func (p Point) GCMethod(k int) int {
+ runtime.GC()
+ return k + p.x
+}
+
+// This will be index 3.
+func (p Point) TotalDist(points ...Point) int {
+ tot := 0
+ for _, q := range points {
+ dx := q.x - p.x
+ dy := q.y - p.y
+ tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test.
+
+ }
+ return tot
+}
+
func TestMethod(t *testing.T) {
// Non-curried method of type.
p := Point{3, 4}
@@ -1751,6 +1790,37 @@ func TestMethodValue(t *testing.T) {
}
}
+func TestVariadicMethodValue(t *testing.T) {
+ p := Point{3, 4}
+ points := []Point{{20, 21}, {22, 23}, {24, 25}}
+ want := int64(p.TotalDist(points[0], points[1], points[2]))
+
+ // Curried method of value.
+ tfunc := TypeOf((func(...Point) int)(nil))
+ v := ValueOf(p).Method(3)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc)
+ }
+ i := ValueOf(v.Interface()).Call([]Value{ValueOf(points[0]), ValueOf(points[1]), ValueOf(points[2])})[0].Int()
+ if i != want {
+ t.Errorf("Variadic Method returned %d; want %d", i, want)
+ }
+ i = ValueOf(v.Interface()).CallSlice([]Value{ValueOf(points)})[0].Int()
+ if i != want {
+ t.Errorf("Variadic Method CallSlice returned %d; want %d", i, want)
+ }
+
+ f := v.Interface().(func(...Point) int)
+ i = int64(f(points[0], points[1], points[2]))
+ if i != want {
+ t.Errorf("Variadic Method Interface returned %d; want %d", i, want)
+ }
+ i = int64(f(points...))
+ if i != want {
+ t.Errorf("Variadic Method Interface Slice returned %d; want %d", i, want)
+ }
+}
+
// Reflect version of $GOROOT/test/method5.go
// Concrete types implementing M method.
@@ -3770,11 +3840,6 @@ func TestReflectFuncTraceback(t *testing.T) {
f.Call([]Value{})
}
-func (p Point) GCMethod(k int) int {
- runtime.GC()
- return k + p.x
-}
-
func TestReflectMethodTraceback(t *testing.T) {
p := Point{3, 4}
m := ValueOf(p).MethodByName("GCMethod")
@@ -3953,3 +4018,9 @@ func TestInvalid(t *testing.T) {
t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind())
}
}
+
+// Issue 8917.
+func TestLargeGCProg(t *testing.T) {
+ fv := ValueOf(func([256]*byte) {})
+ fv.Call([]Value{ValueOf([256]*byte{})})
+}
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go
index bdb8c21d7..1072c7fab 100644
--- a/src/reflect/makefunc.go
+++ b/src/reflect/makefunc.go
@@ -60,7 +60,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
- return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift}
+ return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
}
// makeFuncStub is an assembly function that is the code half of
@@ -92,7 +92,7 @@ func makeMethodValue(op string, v Value) Value {
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
fl := v.flag & (flagRO | flagAddr | flagIndir)
fl |= flag(v.typ.Kind()) << flagKindShift
- rcvr := Value{v.typ, v.ptr, v.scalar, fl}
+ rcvr := Value{v.typ, v.ptr, fl}
// v.Type returns the actual type of the method value.
funcType := v.Type().(*rtype)
@@ -118,7 +118,7 @@ func makeMethodValue(op string, v Value) Value {
// but we want Interface() and other operations to fail early.
methodReceiver(op, fv.rcvr, fv.method)
- return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<<flagKindShift}
+ return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
}
// methodValueCall is an assembly function that is the code half of
diff --git a/src/reflect/type.go b/src/reflect/type.go
index f099546d2..26328e74b 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -498,7 +498,7 @@ func (t *uncommonType) Method(i int) (m Method) {
mt := p.typ
m.Type = mt
fn := unsafe.Pointer(&p.tfn)
- m.Func = Value{mt, fn, 0, fl}
+ m.Func = Value{mt, fn, fl}
m.Index = i
return
}
@@ -1514,20 +1514,32 @@ func (gc *gcProg) appendProg(t *rtype) {
gc.size += t.size
return
}
- nptr := t.size / unsafe.Sizeof(uintptr(0))
- var prog []byte
- if t.kind&kindGCProg != 0 {
- // Ensure that the runtime has unrolled GC program.
- // TODO(rsc): Do not allocate.
- unsafe_New(t)
- // The program is stored in t.gc[0], skip unroll flag.
- prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:]
- } else {
- // The mask is embed directly in t.gc.
- prog = (*[1 << 30]byte)(unsafe.Pointer(&t.gc[0]))[:]
- }
- for i := uintptr(0); i < nptr; i++ {
- gc.appendWord(extractGCWord(prog, i))
+ switch t.Kind() {
+ default:
+ panic("reflect: non-pointer type marked as having pointers")
+ case Ptr, UnsafePointer, Chan, Func, Map:
+ gc.appendWord(bitsPointer)
+ case Slice:
+ gc.appendWord(bitsPointer)
+ gc.appendWord(bitsScalar)
+ gc.appendWord(bitsScalar)
+ case String:
+ gc.appendWord(bitsPointer)
+ gc.appendWord(bitsScalar)
+ case Array:
+ c := t.Len()
+ e := t.Elem().common()
+ for i := 0; i < c; i++ {
+ gc.appendProg(e)
+ }
+ case Interface:
+ gc.appendWord(bitsPointer)
+ gc.appendWord(bitsPointer)
+ case Struct:
+ c := t.NumField()
+ for i := 0; i < c; i++ {
+ gc.appendProg(t.Field(i).Type.common())
+ }
}
}
@@ -1562,7 +1574,6 @@ func (gc *gcProg) finalize() unsafe.Pointer {
gc.appendWord(extractGCWord(gc.gc, i))
}
}
- gc.gc = append([]byte{1}, gc.gc...) // prepend unroll flag
return unsafe.Pointer(&gc.gc[0])
}
@@ -1574,9 +1585,14 @@ func (gc *gcProg) align(a uintptr) {
gc.size = align(gc.size, a)
}
+// These constants must stay in sync with ../runtime/mgc0.h.
const (
- bitsScalar = 1
- bitsPointer = 2
+ bitsScalar = 1
+ bitsPointer = 2
+ bitsMultiWord = 3
+
+ bitsIface = 2
+ bitsEface = 3
)
// Make sure these routines stay in sync with ../../runtime/hashmap.go!
@@ -1619,7 +1635,6 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
b := new(rtype)
b.size = gc.size
b.gc[0] = gc.finalize()
- b.kind |= kindGCProg
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
return b
@@ -1786,7 +1801,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
// Reflect uses the "interface" calling convention for
// methods, where receivers take one word of argument
// space no matter how big they actually are.
- if !isDirectIface(rcvr) {
+ if ifaceIndir(rcvr) {
// we pass a pointer to the receiver.
gc.append(bitsPointer)
stack.append2(bitsPointer)
@@ -1821,7 +1836,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
x := new(rtype)
x.size = gc.size
x.gc[0] = gc.finalize()
- x.kind |= kindGCProg
var s string
if rcvr != nil {
s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
@@ -1844,9 +1858,9 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
return x, argSize, retOffset, stack
}
-// isDirectIface reports whether t is stored directly in an interface value.
-func isDirectIface(t *rtype) bool {
- return t.kind&kindDirectIface != 0
+// ifaceIndir reports whether t is stored indirectly in an interface value.
+func ifaceIndir(t *rtype) bool {
+ return t.kind&kindDirectIface == 0
}
// Layout matches runtime.BitVector (well enough).
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 9c65ee270..c6e8038eb 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -7,11 +7,9 @@ package reflect
import (
"math"
"runtime"
- "strconv"
"unsafe"
)
-const bigEndian = false // can be smarter if we find a big-endian machine
const ptrSize = unsafe.Sizeof((*byte)(nil))
const cannotSet = "cannot set value obtained from unexported struct field"
@@ -40,12 +38,6 @@ type Value struct {
// Valid when either flagIndir is set or typ.pointers() is true.
ptr unsafe.Pointer
- // Non-pointer-valued data. When the data is smaller
- // than a word, it begins at the first byte (in the memory
- // address sense) of this field.
- // Valid when flagIndir is not set and typ.pointers() is false.
- scalar uintptr
-
// flag holds metadata about the value.
// The lowest bits are flag bits:
// - flagRO: obtained via unexported field, so read-only
@@ -56,7 +48,7 @@ type Value struct {
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
- // If !isDirectIface(typ), code can assume that flagIndir is set.
+ // If ifaceIndir(typ), code can assume that flagIndir is set.
flag
// A method value represents a curried method invocation
@@ -102,7 +94,7 @@ func packEface(v Value) interface{} {
e := (*emptyInterface)(unsafe.Pointer(&i))
// First, fill in the data portion of the interface.
switch {
- case !isDirectIface(t):
+ case ifaceIndir(t):
if v.flag&flagIndir == 0 {
panic("bad indir")
}
@@ -119,18 +111,10 @@ func packEface(v Value) interface{} {
case v.flag&flagIndir != 0:
// Value is indirect, but interface is direct. We need
// to load the data at v.ptr into the interface data word.
- if t.pointers() {
- e.word = iword(*(*unsafe.Pointer)(v.ptr))
- } else {
- e.word = iword(loadScalar(v.ptr, t.size))
- }
+ e.word = iword(*(*unsafe.Pointer)(v.ptr))
default:
// Value is direct, and so is the interface.
- if t.pointers() {
- e.word = iword(v.ptr)
- } else {
- e.word = iword(v.scalar)
- }
+ e.word = iword(v.ptr)
}
// Now, fill in the type portion. We're very careful here not
// to have any operation between the e.word and e.typ assignments
@@ -149,13 +133,10 @@ func unpackEface(i interface{}) Value {
return Value{}
}
f := flag(t.Kind()) << flagKindShift
- if !isDirectIface(t) {
- return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir}
- }
- if t.pointers() {
- return Value{t, unsafe.Pointer(e.word), 0, f}
+ if ifaceIndir(t) {
+ f |= flagIndir
}
- return Value{t, nil, uintptr(e.word), f}
+ return Value{t, unsafe.Pointer(e.word), f}
}
// A ValueError occurs when a Value method is invoked on
@@ -194,64 +175,6 @@ func methodName() string {
// to the GC here so that GC remains precise.
type iword unsafe.Pointer
-// loadScalar loads n bytes at p from memory into a uintptr
-// that forms the second word of an interface. The data
-// must be non-pointer in nature.
-func loadScalar(p unsafe.Pointer, n uintptr) uintptr {
- // Run the copy ourselves instead of calling memmove
- // to avoid moving w to the heap.
- var w uintptr
- switch n {
- default:
- panic("reflect: internal error: loadScalar of " + strconv.Itoa(int(n)) + "-byte value")
- case 0:
- case 1:
- *(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
- case 2:
- *(*uint16)(unsafe.Pointer(&w)) = *(*uint16)(p)
- case 3:
- *(*[3]byte)(unsafe.Pointer(&w)) = *(*[3]byte)(p)
- case 4:
- *(*uint32)(unsafe.Pointer(&w)) = *(*uint32)(p)
- case 5:
- *(*[5]byte)(unsafe.Pointer(&w)) = *(*[5]byte)(p)
- case 6:
- *(*[6]byte)(unsafe.Pointer(&w)) = *(*[6]byte)(p)
- case 7:
- *(*[7]byte)(unsafe.Pointer(&w)) = *(*[7]byte)(p)
- case 8:
- *(*uint64)(unsafe.Pointer(&w)) = *(*uint64)(p)
- }
- return w
-}
-
-// storeScalar stores n bytes from w into p.
-func storeScalar(p unsafe.Pointer, w uintptr, n uintptr) {
- // Run the copy ourselves instead of calling memmove
- // to avoid moving w to the heap.
- switch n {
- default:
- panic("reflect: internal error: storeScalar of " + strconv.Itoa(int(n)) + "-byte value")
- case 0:
- case 1:
- *(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
- case 2:
- *(*uint16)(p) = *(*uint16)(unsafe.Pointer(&w))
- case 3:
- *(*[3]byte)(p) = *(*[3]byte)(unsafe.Pointer(&w))
- case 4:
- *(*uint32)(p) = *(*uint32)(unsafe.Pointer(&w))
- case 5:
- *(*[5]byte)(p) = *(*[5]byte)(unsafe.Pointer(&w))
- case 6:
- *(*[6]byte)(p) = *(*[6]byte)(unsafe.Pointer(&w))
- case 7:
- *(*[7]byte)(p) = *(*[7]byte)(unsafe.Pointer(&w))
- case 8:
- *(*uint64)(p) = *(*uint64)(unsafe.Pointer(&w))
- }
-}
-
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
@@ -321,17 +244,14 @@ func (v Value) Addr() Value {
if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return Value{v.typ.ptrTo(), v.ptr, 0, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
+ return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
}
// Bool returns v's underlying value.
// It panics if v's kind is not Bool.
func (v Value) Bool() bool {
v.mustBe(Bool)
- if v.flag&flagIndir != 0 {
- return *(*bool)(v.ptr)
- }
- return *(*bool)(unsafe.Pointer(&v.scalar))
+ return *(*bool)(v.ptr)
}
// Bytes returns v's underlying value.
@@ -501,10 +421,8 @@ func (v Value) call(op string, in []Value) []Value {
v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
if v.flag&flagIndir != 0 {
memmove(addr, v.ptr, n)
- } else if targ.pointers() {
- *(*unsafe.Pointer)(addr) = v.ptr
} else {
- storeScalar(addr, v.scalar, n)
+ *(*unsafe.Pointer)(addr) = v.ptr
}
off += n
}
@@ -525,7 +443,7 @@ func (v Value) call(op string, in []Value) []Value {
a := uintptr(tv.Align())
off = (off + a - 1) &^ (a - 1)
fl := flagIndir | flag(tv.Kind())<<flagKindShift
- ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), 0, fl}
+ ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
off += tv.Size()
}
@@ -556,8 +474,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
typ := arg
off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off)
- v := Value{typ, nil, 0, flag(typ.Kind()) << flagKindShift}
- if !isDirectIface(typ) {
+ v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
+ if ifaceIndir(typ) {
// value cannot be inlined in interface data.
// Must make a copy, because f might keep a reference to it,
// and we cannot let f keep a reference to the stack frame
@@ -565,10 +483,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
v.ptr = unsafe_New(typ)
memmove(v.ptr, addr, typ.size)
v.flag |= flagIndir
- } else if typ.pointers() {
- v.ptr = *(*unsafe.Pointer)(addr)
} else {
- v.scalar = loadScalar(addr, typ.size)
+ v.ptr = *(*unsafe.Pointer)(addr)
}
in = append(in, v)
off += typ.size
@@ -602,10 +518,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
addr := unsafe.Pointer(uintptr(ptr) + off)
if v.flag&flagIndir != 0 {
memmove(addr, v.ptr, typ.size)
- } else if typ.pointers() {
- *(*unsafe.Pointer)(addr) = v.ptr
} else {
- storeScalar(addr, v.scalar, typ.size)
+ *(*unsafe.Pointer)(addr) = v.ptr
}
off += typ.size
}
@@ -663,18 +577,10 @@ func storeRcvr(v Value, p unsafe.Pointer) {
// the interface data word becomes the receiver word
iface := (*nonEmptyInterface)(v.ptr)
*(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word)
- } else if v.flag&flagIndir != 0 {
- if !isDirectIface(t) {
- *(*unsafe.Pointer)(p) = v.ptr
- } else if t.pointers() {
- *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
- } else {
- *(*uintptr)(p) = loadScalar(v.ptr, t.size)
- }
- } else if t.pointers() {
- *(*unsafe.Pointer)(p) = v.ptr
+ } else if v.flag&flagIndir != 0 && !ifaceIndir(t) {
+ *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
} else {
- *(*uintptr)(p) = v.scalar
+ *(*unsafe.Pointer)(p) = v.ptr
}
}
@@ -763,12 +669,8 @@ func (v Value) Complex() complex128 {
k := v.kind()
switch k {
case Complex64:
- if v.flag&flagIndir != 0 {
- return complex128(*(*complex64)(v.ptr))
- }
- return complex128(*(*complex64)(unsafe.Pointer(&v.scalar)))
+ return complex128(*(*complex64)(v.ptr))
case Complex128:
- // complex128 is always bigger than a word; assume flagIndir.
return *(*complex128)(v.ptr)
}
panic(&ValueError{"reflect.Value.Complex", k})
@@ -808,7 +710,7 @@ func (v Value) Elem() Value {
typ := tt.elem
fl := v.flag&flagRO | flagIndir | flagAddr
fl |= flag(typ.Kind() << flagKindShift)
- return Value{typ, ptr, 0, fl}
+ return Value{typ, ptr, fl}
}
panic(&ValueError{"reflect.Value.Elem", k})
}
@@ -833,30 +735,25 @@ func (v Value) Field(i int) Value {
fl |= flag(typ.Kind()) << flagKindShift
var ptr unsafe.Pointer
- var scalar uintptr
- switch {
- case fl&flagIndir != 0:
+ if fl&flagIndir != 0 {
// Indirect. Just bump pointer.
ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset)
- case typ.pointers():
+ } else {
if field.offset != 0 {
panic("field access of ptr value isn't at offset 0")
}
ptr = v.ptr
- case bigEndian:
- // Must be scalar. Discard leading bytes.
- scalar = v.scalar << (field.offset * 8)
- default:
- // Must be scalar. Discard leading bytes.
- scalar = v.scalar >> (field.offset * 8)
}
- return Value{typ, ptr, scalar, fl}
+ return Value{typ, ptr, fl}
}
// FieldByIndex returns the nested field corresponding to index.
// It panics if v's Kind is not struct.
func (v Value) FieldByIndex(index []int) Value {
+ if len(index) == 1 {
+ return v.Field(index[0])
+ }
v.mustBe(Struct)
for i, x := range index {
if i > 0 {
@@ -901,15 +798,9 @@ func (v Value) Float() float64 {
k := v.kind()
switch k {
case Float32:
- if v.flag&flagIndir != 0 {
- return float64(*(*float32)(v.ptr))
- }
- return float64(*(*float32)(unsafe.Pointer(&v.scalar)))
+ return float64(*(*float32)(v.ptr))
case Float64:
- if v.flag&flagIndir != 0 {
- return *(*float64)(v.ptr)
- }
- return *(*float64)(unsafe.Pointer(&v.scalar))
+ return *(*float64)(v.ptr)
}
panic(&ValueError{"reflect.Value.Float", k})
}
@@ -932,12 +823,10 @@ func (v Value) Index(i int) Value {
offset := uintptr(i) * typ.size
var val unsafe.Pointer
- var scalar uintptr
- switch {
- case fl&flagIndir != 0:
+ if fl&flagIndir != 0 {
// Indirect. Just bump pointer.
val = unsafe.Pointer(uintptr(v.ptr) + offset)
- case typ.pointers():
+ } else {
if offset != 0 {
// This is an array stored inline in an interface value.
// And the array element type has pointers.
@@ -948,14 +837,8 @@ func (v Value) Index(i int) Value {
panic("reflect: internal error: unexpected array index")
}
val = v.ptr
- case bigEndian:
- // Direct. Discard leading bytes.
- scalar = v.scalar << (offset * 8)
- default:
- // Direct. Discard leading bytes.
- scalar = v.scalar >> (offset * 8)
}
- return Value{typ, val, scalar, fl}
+ return Value{typ, val, fl}
case Slice:
// Element flag same as Elem of Ptr.
@@ -969,7 +852,7 @@ func (v Value) Index(i int) Value {
typ := tt.elem
fl |= flag(typ.Kind()) << flagKindShift
val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
- return Value{typ, val, 0, fl}
+ return Value{typ, val, fl}
case String:
fl := v.flag&flagRO | flag(Uint8<<flagKindShift) | flagIndir
@@ -978,7 +861,7 @@ func (v Value) Index(i int) Value {
panic("reflect: string index out of range")
}
p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
- return Value{uint8Type, p, 0, fl}
+ return Value{uint8Type, p, fl}
}
panic(&ValueError{"reflect.Value.Index", k})
}
@@ -987,14 +870,7 @@ func (v Value) Index(i int) Value {
// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64.
func (v Value) Int() int64 {
k := v.kind()
- var p unsafe.Pointer
- if v.flag&flagIndir != 0 {
- p = v.ptr
- } else {
- // The escape analysis is good enough that &v.scalar
- // does not trigger a heap allocation.
- p = unsafe.Pointer(&v.scalar)
- }
+ p := v.ptr
switch k {
case Int:
return int64(*(*int)(p))
@@ -1154,10 +1030,8 @@ func (v Value) MapIndex(key Value) Value {
var k unsafe.Pointer
if key.flag&flagIndir != 0 {
k = key.ptr
- } else if key.typ.pointers() {
- k = unsafe.Pointer(&key.ptr)
} else {
- k = unsafe.Pointer(&key.scalar)
+ k = unsafe.Pointer(&key.ptr)
}
e := mapaccess(v.typ, v.pointer(), k)
if e == nil {
@@ -1166,16 +1040,14 @@ func (v Value) MapIndex(key Value) Value {
typ := tt.elem
fl := (v.flag | key.flag) & flagRO
fl |= flag(typ.Kind()) << flagKindShift
- if !isDirectIface(typ) {
+ if ifaceIndir(typ) {
// Copy result so future changes to the map
// won't change the underlying value.
c := unsafe_New(typ)
memmove(c, e, typ.size)
- return Value{typ, c, 0, fl | flagIndir}
- } else if typ.pointers() {
- return Value{typ, *(*unsafe.Pointer)(e), 0, fl}
+ return Value{typ, c, fl | flagIndir}
} else {
- return Value{typ, nil, loadScalar(e, typ.size), fl}
+ return Value{typ, *(*unsafe.Pointer)(e), fl}
}
}
@@ -1206,16 +1078,14 @@ func (v Value) MapKeys() []Value {
// we can do about it.
break
}
- if !isDirectIface(keyType) {
+ if ifaceIndir(keyType) {
// Copy result so future changes to the map
// won't change the underlying value.
c := unsafe_New(keyType)
memmove(c, key, keyType.size)
- a[i] = Value{keyType, c, 0, fl | flagIndir}
- } else if keyType.pointers() {
- a[i] = Value{keyType, *(*unsafe.Pointer)(key), 0, fl}
+ a[i] = Value{keyType, c, fl | flagIndir}
} else {
- a[i] = Value{keyType, nil, loadScalar(key, keyType.size), fl}
+ a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl}
}
mapiternext(it)
}
@@ -1239,7 +1109,7 @@ func (v Value) Method(i int) Value {
fl := v.flag & (flagRO | flagIndir)
fl |= flag(Func) << flagKindShift
fl |= flag(i)<<flagMethodShift | flagMethod
- return Value{v.typ, v.ptr, v.scalar, fl}
+ return Value{v.typ, v.ptr, fl}
}
// NumMethod returns the number of methods in the value's method set.
@@ -1403,16 +1273,14 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
panic("reflect: recv on send-only channel")
}
t := tt.elem
- val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift}
+ val = Value{t, nil, flag(t.Kind()) << flagKindShift}
var p unsafe.Pointer
- if !isDirectIface(t) {
+ if ifaceIndir(t) {
p = unsafe_New(t)
val.ptr = p
val.flag |= flagIndir
- } else if t.pointers() {
- p = unsafe.Pointer(&val.ptr)
} else {
- p = unsafe.Pointer(&val.scalar)
+ p = unsafe.Pointer(&val.ptr)
}
selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
if !selected {
@@ -1442,10 +1310,8 @@ func (v Value) send(x Value, nb bool) (selected bool) {
var p unsafe.Pointer
if x.flag&flagIndir != 0 {
p = x.ptr
- } else if x.typ.pointers() {
- p = unsafe.Pointer(&x.ptr)
} else {
- p = unsafe.Pointer(&x.scalar)
+ p = unsafe.Pointer(&x.ptr)
}
return chansend(v.typ, v.pointer(), p, nb)
}
@@ -1463,10 +1329,8 @@ func (v Value) Set(x Value) {
x = x.assignTo("reflect.Set", v.typ, target)
if x.flag&flagIndir != 0 {
memmove(v.ptr, x.ptr, v.typ.size)
- } else if x.typ.pointers() {
- *(*unsafe.Pointer)(v.ptr) = x.ptr
} else {
- memmove(v.ptr, unsafe.Pointer(&x.scalar), v.typ.size)
+ *(*unsafe.Pointer)(v.ptr) = x.ptr
}
}
@@ -1589,10 +1453,8 @@ func (v Value) SetMapIndex(key, val Value) {
var k unsafe.Pointer
if key.flag&flagIndir != 0 {
k = key.ptr
- } else if key.typ.pointers() {
- k = unsafe.Pointer(&key.ptr)
} else {
- k = unsafe.Pointer(&key.scalar)
+ k = unsafe.Pointer(&key.ptr)
}
if val.typ == nil {
mapdelete(v.typ, v.pointer(), k)
@@ -1603,10 +1465,8 @@ func (v Value) SetMapIndex(key, val Value) {
var e unsafe.Pointer
if val.flag&flagIndir != 0 {
e = val.ptr
- } else if val.typ.pointers() {
- e = unsafe.Pointer(&val.ptr)
} else {
- e = unsafe.Pointer(&val.scalar)
+ e = unsafe.Pointer(&val.ptr)
}
mapassign(v.typ, v.pointer(), k, e)
}
@@ -1683,7 +1543,7 @@ func (v Value) Slice(i, j int) Value {
panic("reflect.Value.Slice: string slice index out of bounds")
}
t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
- return Value{v.typ, unsafe.Pointer(&t), 0, v.flag}
+ return Value{v.typ, unsafe.Pointer(&t), v.flag}
}
if i < 0 || j < i || j > cap {
@@ -1705,7 +1565,7 @@ func (v Value) Slice(i, j int) Value {
}
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
- return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
+ return Value{typ.common(), unsafe.Pointer(&x), fl}
}
// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k].
@@ -1757,7 +1617,7 @@ func (v Value) Slice3(i, j, k int) Value {
}
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
- return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
+ return Value{typ.common(), unsafe.Pointer(&x), fl}
}
// String returns the string v's underlying value, as a string.
@@ -1833,14 +1693,7 @@ func (v Value) Type() Type {
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (v Value) Uint() uint64 {
k := v.kind()
- var p unsafe.Pointer
- if v.flag&flagIndir != 0 {
- p = v.ptr
- } else {
- // The escape analysis is good enough that &v.scalar
- // does not trigger a heap allocation.
- p = unsafe.Pointer(&v.scalar)
- }
+ p := v.ptr
switch k {
case Uint:
return uint64(*(*uint)(p))
@@ -1994,17 +1847,6 @@ func Copy(dst, src Value) int {
n = sn
}
- // If sk is an in-line array, cannot take its address.
- // Instead, copy element by element.
- // TODO: memmove would be ok for this (sa = unsafe.Pointer(&v.scalar))
- // if we teach the compiler that ptrs don't escape from memmove.
- if src.flag&flagIndir == 0 {
- for i := 0; i < n; i++ {
- dst.Index(i).Set(src.Index(i))
- }
- return n
- }
-
// Copy via memmove.
var da, sa unsafe.Pointer
if dk == Array {
@@ -2012,7 +1854,9 @@ func Copy(dst, src Value) int {
} else {
da = (*sliceHeader)(dst.ptr).Data
}
- if sk == Array {
+ if src.flag&flagIndir == 0 {
+ sa = unsafe.Pointer(&src.ptr)
+ } else if sk == Array {
sa = src.ptr
} else {
sa = (*sliceHeader)(src.ptr).Data
@@ -2125,10 +1969,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
v = v.assignTo("reflect.Select", tt.elem, nil)
if v.flag&flagIndir != 0 {
rc.val = v.ptr
- } else if v.typ.pointers() {
- rc.val = unsafe.Pointer(&v.ptr)
} else {
- rc.val = unsafe.Pointer(&v.scalar)
+ rc.val = unsafe.Pointer(&v.ptr)
}
case SelectRecv:
@@ -2157,12 +1999,10 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
t := tt.elem
p := runcases[chosen].val
fl := flag(t.Kind()) << flagKindShift
- if !isDirectIface(t) {
- recv = Value{t, p, 0, fl | flagIndir}
- } else if t.pointers() {
- recv = Value{t, *(*unsafe.Pointer)(p), 0, fl}
+ if ifaceIndir(t) {
+ recv = Value{t, p, fl | flagIndir}
} else {
- recv = Value{t, nil, loadScalar(p, t.size), fl}
+ recv = Value{t, *(*unsafe.Pointer)(p), fl}
}
}
return chosen, recv, recvOK
@@ -2193,7 +2033,7 @@ func MakeSlice(typ Type, len, cap int) Value {
}
s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
- return Value{typ.common(), unsafe.Pointer(&s), 0, flagIndir | flag(Slice)<<flagKindShift}
+ return Value{typ.common(), unsafe.Pointer(&s), flagIndir | flag(Slice)<<flagKindShift}
}
// MakeChan creates a new channel with the specified type and buffer size.
@@ -2208,7 +2048,7 @@ func MakeChan(typ Type, buffer int) Value {
panic("reflect.MakeChan: unidirectional channel type")
}
ch := makechan(typ.(*rtype), uint64(buffer))
- return Value{typ.common(), ch, 0, flag(Chan) << flagKindShift}
+ return Value{typ.common(), ch, flag(Chan) << flagKindShift}
}
// MakeMap creates a new map of the specified type.
@@ -2217,7 +2057,7 @@ func MakeMap(typ Type) Value {
panic("reflect.MakeMap of non-map type")
}
m := makemap(typ.(*rtype))
- return Value{typ.common(), m, 0, flag(Map) << flagKindShift}
+ return Value{typ.common(), m, flag(Map) << flagKindShift}
}
// Indirect returns the value that v points to.
@@ -2258,10 +2098,10 @@ func Zero(typ Type) Value {
}
t := typ.common()
fl := flag(t.Kind()) << flagKindShift
- if isDirectIface(t) {
- return Value{t, nil, 0, fl}
+ if ifaceIndir(t) {
+ return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
}
- return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir}
+ return Value{t, nil, fl}
}
// New returns a Value representing a pointer to a new zero value
@@ -2272,14 +2112,14 @@ func New(typ Type) Value {
}
ptr := unsafe_New(typ.(*rtype))
fl := flag(Ptr) << flagKindShift
- return Value{typ.common().ptrTo(), ptr, 0, fl}
+ return Value{typ.common().ptrTo(), ptr, fl}
}
// NewAt returns a Value representing a pointer to a value of the
// specified type, using p as that pointer.
func NewAt(typ Type, p unsafe.Pointer) Value {
fl := flag(Ptr) << flagKindShift
- return Value{typ.common().ptrTo(), p, 0, fl}
+ return Value{typ.common().ptrTo(), p, fl}
}
// assignTo returns a value v that can be assigned directly to typ.
@@ -2297,7 +2137,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
v.typ = dst
fl := v.flag & (flagRO | flagAddr | flagIndir)
fl |= flag(dst.Kind()) << flagKindShift
- return Value{dst, v.ptr, v.scalar, fl}
+ return Value{dst, v.ptr, fl}
case implements(dst, v.typ):
if target == nil {
@@ -2309,7 +2149,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
} else {
ifaceE2I(dst, x, unsafe.Pointer(target))
}
- return Value{dst, unsafe.Pointer(target), 0, flagIndir | flag(Interface)<<flagKindShift}
+ return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
}
// Failed.
@@ -2417,82 +2257,46 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
// where t is a signed or unsigned int type.
func makeInt(f flag, bits uint64, t Type) Value {
typ := t.common()
- if !isDirectIface(typ) {
- ptr := unsafe_New(typ)
- switch typ.size {
- case 1:
- *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
- case 2:
- *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
- case 4:
- *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
- case 8:
- *(*uint64)(unsafe.Pointer(ptr)) = bits
- }
- return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
- }
- var s uintptr
+ ptr := unsafe_New(typ)
switch typ.size {
case 1:
- *(*uint8)(unsafe.Pointer(&s)) = uint8(bits)
+ *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
case 2:
- *(*uint16)(unsafe.Pointer(&s)) = uint16(bits)
+ *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
case 4:
- *(*uint32)(unsafe.Pointer(&s)) = uint32(bits)
+ *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
case 8:
- *(*uint64)(unsafe.Pointer(&s)) = uint64(bits)
+ *(*uint64)(unsafe.Pointer(ptr)) = bits
}
- return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
// makeFloat returns a Value of type t equal to v (possibly truncated to float32),
// where t is a float32 or float64 type.
func makeFloat(f flag, v float64, t Type) Value {
typ := t.common()
- if !isDirectIface(typ) {
- ptr := unsafe_New(typ)
- switch typ.size {
- case 4:
- *(*float32)(unsafe.Pointer(ptr)) = float32(v)
- case 8:
- *(*float64)(unsafe.Pointer(ptr)) = v
- }
- return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
- }
-
- var s uintptr
+ ptr := unsafe_New(typ)
switch typ.size {
case 4:
- *(*float32)(unsafe.Pointer(&s)) = float32(v)
+ *(*float32)(unsafe.Pointer(ptr)) = float32(v)
case 8:
- *(*float64)(unsafe.Pointer(&s)) = v
+ *(*float64)(unsafe.Pointer(ptr)) = v
}
- return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
// makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
// where t is a complex64 or complex128 type.
func makeComplex(f flag, v complex128, t Type) Value {
typ := t.common()
- if !isDirectIface(typ) {
- ptr := unsafe_New(typ)
- switch typ.size {
- case 8:
- *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
- case 16:
- *(*complex128)(unsafe.Pointer(ptr)) = v
- }
- return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
- }
-
- var s uintptr
+ ptr := unsafe_New(typ)
switch typ.size {
case 8:
- *(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+ *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
case 16:
- *(*complex128)(unsafe.Pointer(&s)) = v
+ *(*complex128)(unsafe.Pointer(ptr)) = v
}
- return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
func makeString(f flag, v string, t Type) Value {
@@ -2603,7 +2407,7 @@ func cvtDirect(v Value, typ Type) Value {
ptr = c
f &^= flagAddr
}
- return Value{t, ptr, v.scalar, v.flag&flagRO | f} // v.flag&flagRO|f == f?
+ return Value{t, ptr, v.flag&flagRO | f} // v.flag&flagRO|f == f?
}
// convertOp: concrete -> interface
@@ -2615,7 +2419,7 @@ func cvtT2I(v Value, typ Type) Value {
} else {
ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
}
- return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+ return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
}
// convertOp: interface -> interface
diff --git a/src/regexp/syntax/doc.go b/src/regexp/syntax/doc.go
index 8e72c90d3..e5e71f14f 100644
--- a/src/regexp/syntax/doc.go
+++ b/src/regexp/syntax/doc.go
@@ -21,8 +21,8 @@ Single characters:
[^xyz] negated character class
\d Perl character class
\D negated Perl character class
- [:alpha:] ASCII character class
- [:^alpha:] negated ASCII character class
+ [[:alpha:]] ASCII character class
+ [[:^alpha:]] negated ASCII character class
\pN Unicode character class (one-letter name)
\p{Greek} Unicode character class
\PN negated Unicode character class (one-letter name)
@@ -46,14 +46,14 @@ Repetitions:
x{n,}? n or more x, prefer fewer
x{n}? exactly n x
-Implementation restriction: The counting forms x{n} etc. (but not the other
-forms x* etc.) have an upper limit of n=1000. Negative or higher explicit
-counts yield the parse error ErrInvalidRepeatSize.
+Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n}
+reject forms that create a minimum or maximum repetition count above 1000.
+Unlimited repetitions are not subject to this restriction.
Grouping:
(re) numbered capturing group (submatch)
(?P<name>re) named & numbered capturing group (submatch)
- (?:re) non-capturing group (submatch)
+ (?:re) non-capturing group
(?flags) set flags within current group; non-capturing
(?flags:re) set flags during re; non-capturing
@@ -69,7 +69,7 @@ Empty strings:
$ at end of text (like \z not \Z) or line (flag m=true)
\A at beginning of text
\b at ASCII word boundary (\w on one side and \W, \A, or \z on the other)
- \B not an ASCII word boundary
+ \B not at ASCII word boundary
\z at end of text
Escape sequences:
@@ -103,29 +103,29 @@ Named character classes as character class elements:
[\p{Name}] named Unicode property inside character class (== \p{Name})
[^\p{Name}] named Unicode property inside negated character class (== \P{Name})
-Perl character classes:
+Perl character classes (all ASCII-only):
\d digits (== [0-9])
\D not digits (== [^0-9])
\s whitespace (== [\t\n\f\r ])
\S not whitespace (== [^\t\n\f\r ])
- \w ASCII word characters (== [0-9A-Za-z_])
- \W not ASCII word characters (== [^0-9A-Za-z_])
+ \w word characters (== [0-9A-Za-z_])
+ \W not word characters (== [^0-9A-Za-z_])
ASCII character classes:
- [:alnum:] alphanumeric (== [0-9A-Za-z])
- [:alpha:] alphabetic (== [A-Za-z])
- [:ascii:] ASCII (== [\x00-\x7F])
- [:blank:] blank (== [\t ])
- [:cntrl:] control (== [\x00-\x1F\x7F])
- [:digit:] digits (== [0-9])
- [:graph:] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])
- [:lower:] lower case (== [a-z])
- [:print:] printable (== [ -~] == [ [:graph:]])
- [:punct:] punctuation (== [!-/:-@[-`{-~])
- [:space:] whitespace (== [\t\n\v\f\r ])
- [:upper:] upper case (== [A-Z])
- [:word:] word characters (== [0-9A-Za-z_])
- [:xdigit:] hex digit (== [0-9A-Fa-f])
+ [[:alnum:]] alphanumeric (== [0-9A-Za-z])
+ [[:alpha:]] alphabetic (== [A-Za-z])
+ [[:ascii:]] ASCII (== [\x00-\x7F])
+ [[:blank:]] blank (== [\t ])
+ [[:cntrl:]] control (== [\x00-\x1F\x7F])
+ [[:digit:]] digits (== [0-9])
+ [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])
+ [[:lower:]] lower case (== [a-z])
+ [[:print:]] printable (== [ -~] == [ [:graph:]])
+ [[:punct:]] punctuation (== [!-/:-@[-`{-~])
+ [[:space:]] whitespace (== [\t\n\v\f\r ])
+ [[:upper:]] upper case (== [A-Z])
+ [[:word:]] word characters (== [0-9A-Za-z_])
+ [[:xdigit:]] hex digit (== [0-9A-Fa-f])
*/
package syntax
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 1495246a2..b0ed2d8ce 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -353,7 +353,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
JMP AX
// Note: can't just "JMP NAME(SB)" - bad inlining results.
-TEXT runtime·reflectcall(SB), NOSPLIT, $0-16
+TEXT ·reflectcall(SB), NOSPLIT, $0-16
MOVL argsize+8(FP), CX
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
@@ -385,21 +385,9 @@ TEXT runtime·reflectcall(SB), NOSPLIT, $0-16
MOVL $runtime·badreflectcall(SB), AX
JMP AX
-// Argument map for the callXX frames. Each has one stack map.
-DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $8 // 4 words
-DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6))
-GLOBL gcargs_reflectcall<>(SB),RODATA,$12
-
-// callXX frames have no locals
-DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_reflectcall<>(SB),RODATA,$8
-
#define CALLFN(NAME,MAXSIZE) \
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
+ NO_LOCAL_POINTERS; \
/* copy arguments to stack */ \
MOVL argptr+4(FP), SI; \
MOVL argsize+8(FP), CX; \
@@ -421,33 +409,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
REP;MOVSB; \
RET
-CALLFN(runtime·call16, 16)
-CALLFN(runtime·call32, 32)
-CALLFN(runtime·call64, 64)
-CALLFN(runtime·call128, 128)
-CALLFN(runtime·call256, 256)
-CALLFN(runtime·call512, 512)
-CALLFN(runtime·call1024, 1024)
-CALLFN(runtime·call2048, 2048)
-CALLFN(runtime·call4096, 4096)
-CALLFN(runtime·call8192, 8192)
-CALLFN(runtime·call16384, 16384)
-CALLFN(runtime·call32768, 32768)
-CALLFN(runtime·call65536, 65536)
-CALLFN(runtime·call131072, 131072)
-CALLFN(runtime·call262144, 262144)
-CALLFN(runtime·call524288, 524288)
-CALLFN(runtime·call1048576, 1048576)
-CALLFN(runtime·call2097152, 2097152)
-CALLFN(runtime·call4194304, 4194304)
-CALLFN(runtime·call8388608, 8388608)
-CALLFN(runtime·call16777216, 16777216)
-CALLFN(runtime·call33554432, 33554432)
-CALLFN(runtime·call67108864, 67108864)
-CALLFN(runtime·call134217728, 134217728)
-CALLFN(runtime·call268435456, 268435456)
-CALLFN(runtime·call536870912, 536870912)
-CALLFN(runtime·call1073741824, 1073741824)
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
@@ -479,6 +467,9 @@ TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $0-8
TEXT runtime·atomicloaduint(SB), NOSPLIT, $0-8
JMP runtime·atomicload(SB)
+TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-8
+ JMP runtime·atomicstore(SB)
+
// bool runtime·cas64(uint64 *val, uint64 old, uint64 new)
// Atomically:
// if(*val == *old){
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 3f7f60841..2ee331208 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -339,11 +339,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
#define DISPATCH(NAME,MAXSIZE) \
CMPQ CX, $MAXSIZE; \
JA 3(PC); \
- MOVQ $NAME(SB), AX; \
+ MOVQ $NAME(SB), AX; \
JMP AX
// Note: can't just "JMP NAME(SB)" - bad inlining results.
-TEXT runtime·reflectcall(SB), NOSPLIT, $0-24
+TEXT ·reflectcall(SB), NOSPLIT, $0-24
MOVLQZX argsize+16(FP), CX
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
@@ -375,21 +375,9 @@ TEXT runtime·reflectcall(SB), NOSPLIT, $0-24
MOVQ $runtime·badreflectcall(SB), AX
JMP AX
-// Argument map for the callXX frames. Each has one stack map.
-DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 words
-DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
-GLOBL gcargs_reflectcall<>(SB),RODATA,$12
-
-// callXX frames have no locals
-DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_reflectcall<>(SB),RODATA,$8
-
#define CALLFN(NAME,MAXSIZE) \
TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
+ NO_LOCAL_POINTERS; \
/* copy arguments to stack */ \
MOVQ argptr+8(FP), SI; \
MOVLQZX argsize+16(FP), CX; \
@@ -410,33 +398,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
REP;MOVSB; \
RET
-CALLFN(runtime·call16, 16)
-CALLFN(runtime·call32, 32)
-CALLFN(runtime·call64, 64)
-CALLFN(runtime·call128, 128)
-CALLFN(runtime·call256, 256)
-CALLFN(runtime·call512, 512)
-CALLFN(runtime·call1024, 1024)
-CALLFN(runtime·call2048, 2048)
-CALLFN(runtime·call4096, 4096)
-CALLFN(runtime·call8192, 8192)
-CALLFN(runtime·call16384, 16384)
-CALLFN(runtime·call32768, 32768)
-CALLFN(runtime·call65536, 65536)
-CALLFN(runtime·call131072, 131072)
-CALLFN(runtime·call262144, 262144)
-CALLFN(runtime·call524288, 524288)
-CALLFN(runtime·call1048576, 1048576)
-CALLFN(runtime·call2097152, 2097152)
-CALLFN(runtime·call4194304, 4194304)
-CALLFN(runtime·call8388608, 8388608)
-CALLFN(runtime·call16777216, 16777216)
-CALLFN(runtime·call33554432, 33554432)
-CALLFN(runtime·call67108864, 67108864)
-CALLFN(runtime·call134217728, 134217728)
-CALLFN(runtime·call268435456, 268435456)
-CALLFN(runtime·call536870912, 536870912)
-CALLFN(runtime·call1073741824, 1073741824)
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
@@ -491,6 +479,9 @@ TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $0-16
TEXT runtime·atomicloaduint(SB), NOSPLIT, $0-16
JMP runtime·atomicload64(SB)
+TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
+ JMP runtime·atomicstore64(SB)
+
// bool casp(void **val, void *old, void *new)
// Atomically:
// if(*val == old){
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index 13a164256..e27f67e1e 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -310,11 +310,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
#define DISPATCH(NAME,MAXSIZE) \
CMPL CX, $MAXSIZE; \
JA 3(PC); \
- MOVL $NAME(SB), AX; \
+ MOVL $NAME(SB), AX; \
JMP AX
// Note: can't just "JMP NAME(SB)" - bad inlining results.
-TEXT runtime·reflectcall(SB), NOSPLIT, $0-16
+TEXT ·reflectcall(SB), NOSPLIT, $0-16
MOVLQZX argsize+8(FP), CX
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
@@ -346,22 +346,9 @@ TEXT runtime·reflectcall(SB), NOSPLIT, $0-16
MOVL $runtime·badreflectcall(SB), AX
JMP AX
-// Argument map for the callXX frames. Each has one stack map.
-DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $10 // 5 words
-DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6))
-DATA gcargs_reflectcall<>+0x09(SB)/1, $(const_BitsPointer)
-GLOBL gcargs_reflectcall<>(SB),RODATA,$12
-
-// callXX frames have no locals
-DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_reflectcall<>(SB),RODATA,$8
-
#define CALLFN(NAME,MAXSIZE) \
TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
+ NO_LOCAL_POINTERS; \
/* copy arguments to stack */ \
MOVL argptr+4(FP), SI; \
MOVL argsize+8(FP), CX; \
@@ -369,8 +356,8 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
REP;MOVSB; \
/* call function */ \
MOVL f+0(FP), DX; \
- MOVL (DX), AX; \
- CALL AX; \
+ MOVL (DX), AX; \
+ CALL AX; \
/* copy return values back */ \
MOVL argptr+4(FP), DI; \
MOVL argsize+8(FP), CX; \
@@ -382,33 +369,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
REP;MOVSB; \
RET
-CALLFN(runtime·call16, 16)
-CALLFN(runtime·call32, 32)
-CALLFN(runtime·call64, 64)
-CALLFN(runtime·call128, 128)
-CALLFN(runtime·call256, 256)
-CALLFN(runtime·call512, 512)
-CALLFN(runtime·call1024, 1024)
-CALLFN(runtime·call2048, 2048)
-CALLFN(runtime·call4096, 4096)
-CALLFN(runtime·call8192, 8192)
-CALLFN(runtime·call16384, 16384)
-CALLFN(runtime·call32768, 32768)
-CALLFN(runtime·call65536, 65536)
-CALLFN(runtime·call131072, 131072)
-CALLFN(runtime·call262144, 262144)
-CALLFN(runtime·call524288, 524288)
-CALLFN(runtime·call1048576, 1048576)
-CALLFN(runtime·call2097152, 2097152)
-CALLFN(runtime·call4194304, 4194304)
-CALLFN(runtime·call8388608, 8388608)
-CALLFN(runtime·call16777216, 16777216)
-CALLFN(runtime·call33554432, 33554432)
-CALLFN(runtime·call67108864, 67108864)
-CALLFN(runtime·call134217728, 134217728)
-CALLFN(runtime·call268435456, 268435456)
-CALLFN(runtime·call536870912, 536870912)
-CALLFN(runtime·call1073741824, 1073741824)
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
@@ -440,6 +427,9 @@ TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $0-12
TEXT runtime·atomicloaduint(SB), NOSPLIT, $0-12
JMP runtime·atomicload(SB)
+TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-12
+ JMP runtime·atomicstore(SB)
+
// bool runtime·cas64(uint64 *val, uint64 old, uint64 new)
// Atomically:
// if(*val == *old){
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 36fb022f9..b21441488 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -343,7 +343,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
MOVW $NAME(SB), R1; \
B (R1)
-TEXT runtime·reflectcall(SB),NOSPLIT,$-4-16
+TEXT ·reflectcall(SB),NOSPLIT,$-4-16
MOVW argsize+8(FP), R0
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
@@ -375,21 +375,9 @@ TEXT runtime·reflectcall(SB),NOSPLIT,$-4-16
MOVW $runtime·badreflectcall(SB), R1
B (R1)
-// Argument map for the callXX frames. Each has one stack map.
-DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $8 // 4 words
-DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6))
-GLOBL gcargs_reflectcall<>(SB),RODATA,$12
-
-// callXX frames have no locals
-DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
-GLOBL gclocals_reflectcall<>(SB),RODATA,$8
-
#define CALLFN(NAME,MAXSIZE) \
TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
- FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
- FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
+ NO_LOCAL_POINTERS; \
/* copy arguments to stack */ \
MOVW argptr+4(FP), R0; \
MOVW argsize+8(FP), R2; \
@@ -420,33 +408,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
SUB $1, R2, R2; \
B -5(PC) \
-CALLFN(runtime·call16, 16)
-CALLFN(runtime·call32, 32)
-CALLFN(runtime·call64, 64)
-CALLFN(runtime·call128, 128)
-CALLFN(runtime·call256, 256)
-CALLFN(runtime·call512, 512)
-CALLFN(runtime·call1024, 1024)
-CALLFN(runtime·call2048, 2048)
-CALLFN(runtime·call4096, 4096)
-CALLFN(runtime·call8192, 8192)
-CALLFN(runtime·call16384, 16384)
-CALLFN(runtime·call32768, 32768)
-CALLFN(runtime·call65536, 65536)
-CALLFN(runtime·call131072, 131072)
-CALLFN(runtime·call262144, 262144)
-CALLFN(runtime·call524288, 524288)
-CALLFN(runtime·call1048576, 1048576)
-CALLFN(runtime·call2097152, 2097152)
-CALLFN(runtime·call4194304, 4194304)
-CALLFN(runtime·call8388608, 8388608)
-CALLFN(runtime·call16777216, 16777216)
-CALLFN(runtime·call33554432, 33554432)
-CALLFN(runtime·call67108864, 67108864)
-CALLFN(runtime·call134217728, 134217728)
-CALLFN(runtime·call268435456, 268435456)
-CALLFN(runtime·call536870912, 536870912)
-CALLFN(runtime·call1073741824, 1073741824)
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
// void jmpdefer(fn, sp);
// called from deferreturn.
@@ -724,6 +712,9 @@ TEXT runtime·atomicloaduintptr(SB),NOSPLIT,$0-8
TEXT runtime·atomicloaduint(SB),NOSPLIT,$0-8
B runtime·atomicload(SB)
+TEXT runtime·atomicstoreuintptr(SB),NOSPLIT,$0-8
+ B runtime·atomicstore(SB)
+
// AES hashing not implemented for ARM
TEXT runtime·aeshash(SB),NOSPLIT,$-4-0
MOVW $0, R0
diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go
index 1e1b57607..2c8914320 100644
--- a/src/runtime/cgocallback.go
+++ b/src/runtime/cgocallback.go
@@ -21,6 +21,9 @@ import "unsafe"
// Either we need to add types or we need to stop using it.
func _cgo_allocate_internal(len uintptr) unsafe.Pointer {
+ if len == 0 {
+ len = 1
+ }
ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0])
c := new(cgomal)
c.alloc = ret
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 10503f4e1..004970182 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -174,6 +174,10 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
goparkunlock(&c.lock, "chan send")
// someone woke us up.
+ if mysg != gp.waiting {
+ gothrow("G waiting list is corrupted!")
+ }
+ gp.waiting = nil
if gp.param == nil {
if c.closed == 0 {
gothrow("chansend: spurious wakeup")
@@ -184,10 +188,6 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
if mysg.releasetime > 0 {
blockevent(int64(mysg.releasetime)-t0, 2)
}
- if mysg != gp.waiting {
- gothrow("G waiting list is corrupted!")
- }
- gp.waiting = nil
releaseSudog(mysg)
return true
}
@@ -410,6 +410,9 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
goparkunlock(&c.lock, "chan receive")
// someone woke us up
+ if mysg != gp.waiting {
+ gothrow("G waiting list is corrupted!")
+ }
gp.waiting = nil
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go
index cb0f54d8a..7ce679741 100644
--- a/src/runtime/defs_windows.go
+++ b/src/runtime/defs_windows.go
@@ -49,6 +49,7 @@ const (
CONTEXT_FULL = C.CONTEXT_FULL
EXCEPTION_ACCESS_VIOLATION = C.STATUS_ACCESS_VIOLATION
+ EXCEPTION_BREAKPOINT = C.STATUS_BREAKPOINT
EXCEPTION_FLT_DENORMAL_OPERAND = C.STATUS_FLOAT_DENORMAL_OPERAND
EXCEPTION_FLT_DIVIDE_BY_ZERO = C.STATUS_FLOAT_DIVIDE_BY_ZERO
EXCEPTION_FLT_INEXACT_RESULT = C.STATUS_FLOAT_INEXACT_RESULT
@@ -59,6 +60,9 @@ const (
INFINITE = C.INFINITE
WAIT_TIMEOUT = C.WAIT_TIMEOUT
+
+ EXCEPTION_CONTINUE_EXECUTION = C.EXCEPTION_CONTINUE_EXECUTION
+ EXCEPTION_CONTINUE_SEARCH = C.EXCEPTION_CONTINUE_SEARCH
)
type SystemInfo C.SYSTEM_INFO
diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h
index 295e422c6..2317c04f6 100644
--- a/src/runtime/defs_windows_386.h
+++ b/src/runtime/defs_windows_386.h
@@ -22,6 +22,7 @@ enum {
CONTEXT_FULL = 0x10007,
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+ EXCEPTION_BREAKPOINT = 0x80000003,
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
@@ -32,6 +33,9 @@ enum {
INFINITE = 0xffffffff,
WAIT_TIMEOUT = 0x102,
+
+ EXCEPTION_CONTINUE_EXECUTION = -0x1,
+ EXCEPTION_CONTINUE_SEARCH = 0x0,
};
typedef struct SystemInfo SystemInfo;
diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h
index 2516c8412..7f37a7a8c 100644
--- a/src/runtime/defs_windows_amd64.h
+++ b/src/runtime/defs_windows_amd64.h
@@ -22,6 +22,7 @@ enum {
CONTEXT_FULL = 0x10000b,
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+ EXCEPTION_BREAKPOINT = 0x80000003,
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
@@ -32,6 +33,9 @@ enum {
INFINITE = 0xffffffff,
WAIT_TIMEOUT = 0x102,
+
+ EXCEPTION_CONTINUE_EXECUTION = -0x1,
+ EXCEPTION_CONTINUE_SEARCH = 0x0,
};
typedef struct SystemInfo SystemInfo;
diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c
index 54b9666b5..71da419f1 100644
--- a/src/runtime/heapdump.c
+++ b/src/runtime/heapdump.c
@@ -7,7 +7,7 @@
// finalizers, etc.) to a file.
// The format of the dumped file is described at
-// http://code.google.com/p/go-wiki/wiki/heapdump13
+// http://code.google.com/p/go-wiki/wiki/heapdump14
#include "runtime.h"
#include "arch_GOARCH.h"
@@ -27,10 +27,8 @@ extern byte runtime·ebss[];
enum {
FieldKindEol = 0,
FieldKindPtr = 1,
- FieldKindString = 2,
- FieldKindSlice = 3,
- FieldKindIface = 4,
- FieldKindEface = 5,
+ FieldKindIface = 2,
+ FieldKindEface = 3,
TagEOF = 0,
TagObject = 1,
@@ -200,7 +198,6 @@ dumptype(Type *t)
write(t->x->name->str, t->x->name->len);
}
dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
- dumpfields((BitVector){0, nil});
}
// dump an object
@@ -210,9 +207,8 @@ dumpobj(byte *obj, uintptr size, BitVector bv)
dumpbvtypes(&bv, obj);
dumpint(TagObject);
dumpint((uintptr)obj);
- dumpint(0); // Type*
- dumpint(0); // kind
dumpmemrange(obj, size);
+ dumpfields(bv);
}
static void
@@ -255,6 +251,7 @@ dumpbv(BitVector *bv, uintptr offset)
for(i = 0; i < bv->n; i += BitsPerPointer) {
switch(bv->bytedata[i/8] >> i%8 & 3) {
case BitsDead:
+ return;
case BitsScalar:
break;
case BitsPointer:
@@ -489,16 +486,18 @@ dumproots(void)
byte *p;
// data segment
+ dumpbvtypes(&runtime·gcdatamask, runtime·data);
dumpint(TagData);
dumpint((uintptr)runtime·data);
dumpmemrange(runtime·data, runtime·edata - runtime·data);
dumpfields(runtime·gcdatamask);
// bss segment
+ dumpbvtypes(&runtime·gcbssmask, runtime·bss);
dumpint(TagBss);
dumpint((uintptr)runtime·bss);
dumpmemrange(runtime·bss, runtime·ebss - runtime·bss);
- dumpfields(runtime·gcdatamask);
+ dumpfields(runtime·gcbssmask);
// MSpan.types
allspans = runtime·mheap.allspans;
@@ -578,10 +577,29 @@ itab_callback(Itab *tab)
{
Type *t;
- dumpint(TagItab);
- dumpint((uintptr)tab);
t = tab->type;
- dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
+ // Dump a map from itab* to the type of its data field.
+ // We want this map so we can deduce types of interface referents.
+ if((t->kind & KindDirectIface) == 0) {
+ // indirect - data slot is a pointer to t.
+ dumptype(t->ptrto);
+ dumpint(TagItab);
+ dumpint((uintptr)tab);
+ dumpint((uintptr)t->ptrto);
+ } else if((t->kind & KindNoPointers) == 0) {
+ // t is pointer-like - data slot is a t.
+ dumptype(t);
+ dumpint(TagItab);
+ dumpint((uintptr)tab);
+ dumpint((uintptr)t);
+ } else {
+ // Data slot is a scalar. Dump type just for fun.
+ // With pointer-only interfaces, this shouldn't happen.
+ dumptype(t);
+ dumpint(TagItab);
+ dumpint((uintptr)tab);
+ dumpint((uintptr)t);
+ }
}
static void
@@ -726,7 +744,7 @@ mdump(void)
}
runtime·memclr((byte*)&typecache[0], sizeof(typecache));
- hdr = (byte*)"go1.3 heap dump\n";
+ hdr = (byte*)"go1.4 heap dump\n";
write(hdr, runtime·findnull(hdr));
dumpparams();
dumpitabs();
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 99d14e314..9b4264f2b 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -270,7 +270,7 @@ func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
}
ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
} else {
- ptrmask = (*uint8)(unsafe.Pointer(&typ.gc[0])) // embed mask
+ ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
}
if size == 2*ptrSize {
*xbits = *ptrmask | bitBoundary
diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c
index dabd38a60..8620f47af 100644
--- a/src/runtime/mgc0.c
+++ b/src/runtime/mgc0.c
@@ -383,25 +383,19 @@ greyobject(byte *obj, Markbits *mbits, Workbuf *wbuf)
static Workbuf*
scanobject(byte *b, uintptr n, byte *ptrmask, Workbuf *wbuf)
{
- byte *obj, *arena_start, *arena_used, *ptrbitp, bits, cshift, cached;
- uintptr i;
- intptr ncached;
+ byte *obj, *arena_start, *arena_used, *ptrbitp;
+ uintptr i, j;
+ int32 bits;
Markbits mbits;
arena_start = (byte*)runtime·mheap.arena_start;
arena_used = runtime·mheap.arena_used;
ptrbitp = nil;
- cached = 0;
- ncached = 0;
// Find bits of the beginning of the object.
if(ptrmask == nil) {
b = objectstart(b, &mbits);
ptrbitp = mbits.bitp; //arena_start - off/wordsPerBitmapByte - 1;
- cshift = mbits.shift; //(off % wordsPerBitmapByte) * gcBits;
- cached = *ptrbitp >> cshift;
- cached &= ~bitBoundary;
- ncached = (8 - cshift)/gcBits;
}
for(i = 0; i < n; i += PtrSize) {
// Find bits for this word.
@@ -414,26 +408,28 @@ scanobject(byte *b, uintptr n, byte *ptrmask, Workbuf *wbuf)
runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift])
break;
// Consult GC bitmap.
- if(ncached <= 0) {
- // Refill cache.
- cached = *--ptrbitp;
- ncached = 2;
- }
- bits = cached;
- cached >>= gcBits;
- ncached--;
-
- if((bits&bitBoundary) != 0)
+ bits = *ptrbitp;
+ if(wordsPerBitmapByte != 2)
+ runtime·throw("alg doesn't work for wordsPerBitmapByte != 2");
+ j = ((uintptr)b+i)/PtrSize & 1;
+ bits >>= gcBits*j;
+ if(i == 0)
+ bits &= ~bitBoundary;
+ ptrbitp -= j;
+
+ if((bits&bitBoundary) != 0 && i != 0)
break; // reached beginning of the next object
bits = (bits>>2)&BitsMask;
if(bits == BitsDead)
break; // reached no-scan part of the object
}
- if(bits == BitsScalar || bits == BitsDead)
+ if(bits <= BitsScalar) // Bits Scalar || BitsDead
continue;
- if(bits != BitsPointer)
+ if(bits != BitsPointer) {
+ runtime·printf("gc bits=%x\n", bits);
runtime·throw("unexpected garbage collection bits");
+ }
obj = *(byte**)(b+i);
// At this point we have extracted the next potential pointer.
@@ -1608,6 +1604,8 @@ gc(struct gc_args *args)
if(runtime·work.nproc > 1)
runtime·notesleep(&runtime·work.alldone);
+ runtime·shrinkfinish();
+
cachestats();
// next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
// estimate what was live heap size after previous GC (for tracing only)
diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go
index 0e17599c2..3a7204b54 100644
--- a/src/runtime/mgc0.go
+++ b/src/runtime/mgc0.go
@@ -110,6 +110,27 @@ func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
}
//go:nosplit
+func writebarrierfat2(dst *[2]uintptr, _ *byte, src [2]uintptr) {
+ dst[0] = src[0]
+ dst[1] = src[1]
+}
+
+//go:nosplit
+func writebarrierfat3(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+ dst[0] = src[0]
+ dst[1] = src[1]
+ dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrierfat4(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+ dst[0] = src[0]
+ dst[1] = src[1]
+ dst[2] = src[2]
+ dst[3] = src[3]
+}
+
+//go:nosplit
func writebarrierfat(typ *_type, dst, src unsafe.Pointer) {
memmove(dst, src, typ.size)
}
diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h
index 10f24d009..64f818914 100644
--- a/src/runtime/mgc0.h
+++ b/src/runtime/mgc0.h
@@ -42,6 +42,8 @@ enum {
BitsMask = (1<<BitsPerPointer)-1,
PointersPerByte = 8/BitsPerPointer,
+ // If you change these, also change scanblock.
+ // scanblock does "if(bits == BitsScalar || bits == BitsDead)" as "if(bits <= BitsScalar)".
BitsDead = 0,
BitsScalar = 1,
BitsPointer = 2,
diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c
index 77f99062c..b8b8eda5f 100644
--- a/src/runtime/os_windows.c
+++ b/src/runtime/os_windows.c
@@ -34,6 +34,7 @@
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
+#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
@@ -65,6 +66,7 @@ extern void *runtime·SetConsoleCtrlHandler;
extern void *runtime·SetEvent;
extern void *runtime·SetProcessPriorityBoost;
extern void *runtime·SetThreadPriority;
+extern void *runtime·SetUnhandledExceptionFilter;
extern void *runtime·SetWaitableTimer;
extern void *runtime·Sleep;
extern void *runtime·SuspendThread;
@@ -77,7 +79,9 @@ void *runtime·GetQueuedCompletionStatusEx;
extern uintptr runtime·externalthreadhandlerp;
void runtime·externalthreadhandler(void);
-void runtime·sigtramp(void);
+void runtime·exceptiontramp(void);
+void runtime·firstcontinuetramp(void);
+void runtime·lastcontinuetramp(void);
#pragma textflag NOSPLIT
uintptr
@@ -106,12 +110,30 @@ void
runtime·osinit(void)
{
void *kernel32;
+ void *addVectoredContinueHandler;
+
+ kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
- runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·sigtramp);
+ runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp);
+ addVectoredContinueHandler = nil;
+ if(kernel32 != nil)
+ addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler");
+ if(addVectoredContinueHandler == nil || sizeof(void*) == 4) {
+ // use SetUnhandledExceptionFilter for windows-386 or
+ // if VectoredContinueHandler is unavailable.
+ // note: SetUnhandledExceptionFilter handler won't be called, if debugging.
+ runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp);
+ } else {
+ runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp);
+ runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp);
+ }
+
runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
+
runtime·stdcall1(runtime·timeBeginPeriod, 1);
+
runtime·ncpu = getproccount();
// Windows dynamic priority boosting assumes that a process has different types
@@ -120,7 +142,6 @@ runtime·osinit(void)
// In such context dynamic priority boosting does nothing but harm, so we turn it off.
runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
- kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
if(kernel32 != nil) {
runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
}
@@ -268,19 +289,19 @@ runtime·mpreinit(M *mp)
void
runtime·minit(void)
{
- void *thandle;
+ uintptr thandle;
// -1 = current process, -2 = current thread
runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS);
- runtime·atomicstorep(&g->m->thread, thandle);
+ runtime·atomicstoreuintptr(&g->m->thread, thandle);
}
// Called from dropm to undo the effect of an minit.
void
runtime·unminit(void)
{
- runtime·stdcall1(runtime·CloseHandle, (uintptr)g->m->thread);
- g->m->thread = nil;
+ runtime·stdcall1(runtime·CloseHandle, g->m->thread);
+ g->m->thread = 0;
}
// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
@@ -467,6 +488,7 @@ runtime·issigpanic(uint32 code)
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_UNDERFLOW:
+ case EXCEPTION_BREAKPOINT:
return 1;
}
return 0;
@@ -475,10 +497,14 @@ runtime·issigpanic(uint32 code)
void
runtime·initsig(void)
{
- // following line keeps sigtramp alive at link stage
+ // following line keeps these functions alive at link stage
// if there's a better way please write it here
- void *p = runtime·sigtramp;
- USED(p);
+ void *e = runtime·exceptiontramp;
+ void *f = runtime·firstcontinuetramp;
+ void *l = runtime·lastcontinuetramp;
+ USED(e);
+ USED(f);
+ USED(l);
}
uint32
@@ -532,7 +558,7 @@ void
runtime·profileloop1(void)
{
M *mp, *allm;
- void *thread;
+ uintptr thread;
runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST);
@@ -540,11 +566,11 @@ runtime·profileloop1(void)
runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1);
allm = runtime·atomicloadp(&runtime·allm);
for(mp = allm; mp != nil; mp = mp->alllink) {
- thread = runtime·atomicloadp(&mp->thread);
+ thread = runtime·atomicloaduintptr(&mp->thread);
// Do not profile threads blocked on Notes,
// this includes idle worker threads,
// idle timer thread, idle heap scavenger, etc.
- if(thread == nil || mp->profilehz == 0 || mp->blocked)
+ if(thread == 0 || mp->profilehz == 0 || mp->blocked)
continue;
runtime·stdcall1(runtime·SuspendThread, (uintptr)thread);
if(mp->profilehz != 0 && !mp->blocked)
diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c
index e2ae8db27..213582799 100644
--- a/src/runtime/os_windows_386.c
+++ b/src/runtime/os_windows_386.c
@@ -24,45 +24,63 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %x\n", r->SegGs);
}
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (-1)
-// or should be made available to other handlers in the chain (0).
-uint32
-runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
+bool
+runtime·isgoexception(ExceptionRecord *info, Context *r)
{
- bool crash;
- uintptr *sp;
extern byte runtime·text[], runtime·etext[];
// Only handle exception if executing instructions in Go binary
// (not Windows library code).
if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip)
- return 0;
-
- if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = info->ExceptionCode;
- gp->sigcode0 = info->ExceptionInformation[0];
- gp->sigcode1 = info->ExceptionInformation[1];
- gp->sigpc = r->Eip;
-
- // Only push runtime·sigpanic if r->eip != 0.
- // If r->eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->Eip != 0) {
- sp = (uintptr*)r->Esp;
- *--sp = r->Eip;
- r->Esp = (uintptr)sp;
- }
- r->Eip = (uintptr)runtime·sigpanic;
- return -1;
+ return false;
+
+ if(!runtime·issigpanic(info->ExceptionCode))
+ return false;
+
+ return true;
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+uint32
+runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
+{
+ uintptr *sp;
+
+ if(!runtime·isgoexception(info, r))
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = info->ExceptionCode;
+ gp->sigcode0 = info->ExceptionInformation[0];
+ gp->sigcode1 = info->ExceptionInformation[1];
+ gp->sigpc = r->Eip;
+
+ // Only push runtime·sigpanic if r->eip != 0.
+ // If r->eip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->Eip != 0) {
+ sp = (uintptr*)r->Esp;
+ *--sp = r->Eip;
+ r->Esp = (uintptr)sp;
}
+ r->Eip = (uintptr)runtime·sigpanic;
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+uint32
+runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
+{
+ bool crash;
if(runtime·panicking) // traceback already printed
runtime·exit(2);
@@ -88,7 +106,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
runtime·crash();
runtime·exit(2);
- return -1; // not reached
+ return 0; // not reached
}
void
diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c
index 261880d45..b96cf70d1 100644
--- a/src/runtime/os_windows_amd64.c
+++ b/src/runtime/os_windows_amd64.c
@@ -32,45 +32,76 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %X\n", (uint64)r->SegGs);
}
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (-1)
-// or should be made available to other handlers in the chain (0).
-uint32
-runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
+bool
+runtime·isgoexception(ExceptionRecord *info, Context *r)
{
- bool crash;
- uintptr *sp;
extern byte runtime·text[], runtime·etext[];
// Only handle exception if executing instructions in Go binary
// (not Windows library code).
if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip)
- return 0;
-
- if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = info->ExceptionCode;
- gp->sigcode0 = info->ExceptionInformation[0];
- gp->sigcode1 = info->ExceptionInformation[1];
- gp->sigpc = r->Rip;
-
- // Only push runtime·sigpanic if r->rip != 0.
- // If r->rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->Rip != 0) {
- sp = (uintptr*)r->Rsp;
- *--sp = r->Rip;
- r->Rsp = (uintptr)sp;
- }
- r->Rip = (uintptr)runtime·sigpanic;
- return -1;
+ return false;
+
+ if(!runtime·issigpanic(info->ExceptionCode))
+ return false;
+
+ return true;
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+uint32
+runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
+{
+ uintptr *sp;
+
+ if(!runtime·isgoexception(info, r))
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = info->ExceptionCode;
+ gp->sigcode0 = info->ExceptionInformation[0];
+ gp->sigcode1 = info->ExceptionInformation[1];
+ gp->sigpc = r->Rip;
+
+ // Only push runtime·sigpanic if r->rip != 0.
+ // If r->rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->Rip != 0) {
+ sp = (uintptr*)r->Rsp;
+ *--sp = r->Rip;
+ r->Rsp = (uintptr)sp;
}
+ r->Rip = (uintptr)runtime·sigpanic;
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+// It seems Windows searches ContinueHandler's list even
+// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
+// firstcontinuehandler will stop that search,
+// if exceptionhandler did the same earlier.
+uint32
+runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
+{
+ USED(gp);
+ if(!runtime·isgoexception(info, r))
+ return EXCEPTION_CONTINUE_SEARCH;
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+uint32
+runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
+{
+ bool crash;
if(runtime·panicking) // traceback already printed
runtime·exit(2);
@@ -97,7 +128,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
runtime·crash();
runtime·exit(2);
- return -1; // not reached
+ return 0; // not reached
}
void
diff --git a/src/runtime/panic.c b/src/runtime/panic.c
index 1cd0aa865..24eb6dbfe 100644
--- a/src/runtime/panic.c
+++ b/src/runtime/panic.c
@@ -31,8 +31,11 @@ runtime·deferproc_m(void)
argp = g->m->scalararg[1];
callerpc = g->m->scalararg[2];
g->m->ptrarg[0] = nil;
+ g->m->scalararg[1] = 0;
d = runtime·newdefer(siz);
+ if(d->panic != nil)
+ runtime·throw("deferproc: d->panic != nil after newdefer");
d->fn = fn;
d->pc = callerpc;
d->argp = argp;
@@ -131,6 +134,7 @@ runtime·dopanic_m(void)
g->m->ptrarg[0] = nil;
pc = g->m->scalararg[0];
sp = g->m->scalararg[1];
+ g->m->scalararg[1] = 0;
if(gp->sig != 0)
runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
gp->sig, gp->sigcode0, gp->sigcode1, gp->sigpc);
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 7eb2d6055..685ff5ca0 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -188,6 +188,12 @@ func newdefer(siz int32) *_defer {
// The defer cannot be used after this call.
//go:nosplit
func freedefer(d *_defer) {
+ if d._panic != nil {
+ freedeferpanic()
+ }
+ if d.fn != nil {
+ freedeferfn()
+ }
sc := deferclass(uintptr(d.siz))
if sc < uintptr(len(p{}.deferpool)) {
mp := acquirem()
@@ -199,6 +205,18 @@ func freedefer(d *_defer) {
}
}
+// Separate function so that it can split stack.
+// Windows otherwise runs out of stack space.
+func freedeferpanic() {
+ // _panic must be cleared before d is unlinked from gp.
+ gothrow("freedefer with d._panic != nil")
+}
+
+func freedeferfn() {
+ // fn must be cleared before d is unlinked from gp.
+ gothrow("freedefer with d.fn != nil")
+}
+
// Run a deferred function if there is one.
// The compiler inserts a call to this at the end of any
// function which calls defer.
@@ -231,6 +249,7 @@ func deferreturn(arg0 uintptr) {
mp := acquirem()
memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz))
fn := d.fn
+ d.fn = nil
gp._defer = d.link
freedefer(d)
releasem(mp)
@@ -258,7 +277,9 @@ func Goexit() {
if d.started {
if d._panic != nil {
d._panic.aborted = true
+ d._panic = nil
}
+ d.fn = nil
gp._defer = d.link
freedefer(d)
continue
@@ -268,6 +289,8 @@ func Goexit() {
if gp._defer != d {
gothrow("bad defer entry in Goexit")
}
+ d._panic = nil
+ d.fn = nil
gp._defer = d.link
freedefer(d)
// Note: we ignore recovers here because Goexit isn't a panic
@@ -343,6 +366,8 @@ func gopanic(e interface{}) {
if d._panic != nil {
d._panic.aborted = true
}
+ d._panic = nil
+ d.fn = nil
gp._defer = d.link
freedefer(d)
continue
@@ -366,6 +391,8 @@ func gopanic(e interface{}) {
if gp._defer != d {
gothrow("bad defer entry in panic")
}
+ d._panic = nil
+ d.fn = nil
gp._defer = d.link
// trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 609ae9406..bea773799 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -372,7 +372,7 @@ struct M
uintptr scalararg[4]; // scalar argument/return for mcall
void* ptrarg[4]; // pointer argument/return for mcall
#ifdef GOOS_windows
- void* thread; // thread handle
+ uintptr thread; // thread handle
// these are here because they are too large to be on the stack
// of low-level NOSPLIT functions.
LibCall libcall;
@@ -865,6 +865,7 @@ void runtime·stackinit(void);
Stack runtime·stackalloc(uint32);
void runtime·stackfree(Stack);
void runtime·shrinkstack(G*);
+void runtime·shrinkfinish(void);
MCache* runtime·allocmcache(void);
void runtime·freemcache(MCache*);
void runtime·mallocinit(void);
@@ -898,7 +899,9 @@ void runtime·atomicstore(uint32 volatile*, uint32);
void runtime·atomicstore64(uint64 volatile*, uint64);
uint64 runtime·atomicload64(uint64 volatile*);
void* runtime·atomicloadp(void* volatile*);
+uintptr runtime·atomicloaduintptr(uintptr volatile*);
void runtime·atomicstorep(void* volatile*, void*);
+void runtime·atomicstoreuintptr(uintptr volatile*, uintptr);
void runtime·atomicor8(byte volatile*, byte);
void runtime·setg(G*);
diff --git a/src/runtime/stack.c b/src/runtime/stack.c
index 8562b9407..e402691f4 100644
--- a/src/runtime/stack.c
+++ b/src/runtime/stack.c
@@ -36,6 +36,8 @@ MSpan runtime·stackpool[NumStackOrders];
Mutex runtime·stackpoolmu;
// TODO: one lock per order?
+static Stack stackfreequeue;
+
void
runtime·stackinit(void)
{
@@ -656,7 +658,24 @@ copystack(G *gp, uintptr newsize)
while(p < ep)
*p++ = 0xfc;
}
- runtime·stackfree(old);
+ if(newsize > old.hi-old.lo) {
+ // growing, free stack immediately
+ runtime·stackfree(old);
+ } else {
+ // shrinking, queue up free operation. We can't actually free the stack
+ // just yet because we might run into the following situation:
+ // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
+ // 2) The stack that pointer points to is shrunk
+ // 3) The old stack is freed
+ // 4) The containing span is marked free
+ // 5) GC attempts to mark the SudoG.elem pointer. The marking fails because
+ // the pointer looks like a pointer into a free span.
+ // By not freeing, we prevent step #4 until GC is done.
+ runtime·lock(&runtime·stackpoolmu);
+ *(Stack*)old.lo = stackfreequeue;
+ stackfreequeue = old;
+ runtime·unlock(&runtime·stackpoolmu);
+ }
}
// round x up to a power of 2.
@@ -706,6 +725,7 @@ runtime·newstack(void)
g->m->morebuf.pc = (uintptr)nil;
g->m->morebuf.lr = (uintptr)nil;
g->m->morebuf.sp = (uintptr)nil;
+ g->m->morebuf.g = (G*)nil;
runtime·casgstatus(gp, Grunning, Gwaiting);
gp->waitreason = runtime·gostringnocopy((byte*)"stack growth");
@@ -841,6 +861,23 @@ runtime·shrinkstack(G *gp)
copystack(gp, newsize);
}
+// Do any delayed stack freeing that was queued up during GC.
+void
+runtime·shrinkfinish(void)
+{
+ Stack s, t;
+
+ runtime·lock(&runtime·stackpoolmu);
+ s = stackfreequeue;
+ stackfreequeue = (Stack){0,0};
+ runtime·unlock(&runtime·stackpoolmu);
+ while(s.lo != 0) {
+ t = *(Stack*)s.lo;
+ runtime·stackfree(s);
+ s = t;
+ }
+}
+
static void badc(void);
#pragma textflag NOSPLIT
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index c6a9cf9f5..6561094ff 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -252,3 +252,33 @@ func return0()
// thunk to call time.now.
func timenow() (sec int64, nsec int32)
+
+// in asm_*.s
+// not called directly; definitions here supply type information for traceback.
+func call16(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call32(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call64(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call128(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call256(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call512(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call1024(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call2048(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call4096(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call8192(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call16384(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call32768(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call65536(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call131072(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call262144(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call524288(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call1048576(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call2097152(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call4194304(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call8388608(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call16777216(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call33554432(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call67108864(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32)
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index 1bf4d062a..932fe9dd2 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -73,6 +73,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
// Called by Windows as a Vectored Exception Handler (VEH).
// First argument is pointer to struct containing
// exception record and context pointers.
+// Handler function is stored in AX.
// Return 0 for 'not handled', -1 for handled.
TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVL ptrs+0(FP), CX
@@ -84,6 +85,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVL SI, 20(SP)
MOVL DI, 24(SP)
+ MOVL AX, SI // save handler address
+
// find g
get_tls(DX)
CMPL DX, $0
@@ -123,11 +126,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
sigtramp_g0:
MOVL 0(CX), BX // ExceptionRecord*
MOVL 4(CX), CX // Context*
- // call sighandler(ExceptionRecord*, Context*, G*)
MOVL BX, 0(SP)
MOVL CX, 4(SP)
MOVL DX, 8(SP)
- CALL runtime·sighandler(SB)
+ CALL SI // call handler
// AX is set to report result back to Windows
MOVL 12(SP), AX
@@ -149,6 +151,18 @@ done:
// RET 4 (return and pop 4 bytes parameters)
BYTE $0xC2; WORD $4
RET // unreached; make assembler happy
+
+TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
+ MOVL $runtime·exceptionhandler(SB), AX
+ JMP runtime·sigtramp(SB)
+
+TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
+ // is never called
+ INT $3
+
+TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
+ MOVL $runtime·lastcontinuehandler(SB), AX
+ JMP runtime·sigtramp(SB)
TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
PUSHL $runtime·ctrlhandler1(SB)
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index 05750398e..e6190ce68 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -99,6 +99,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
// Called by Windows as a Vectored Exception Handler (VEH).
// First argument is pointer to struct containing
// exception record and context pointers.
+// Handler function is stored in AX.
// Return 0 for 'not handled', -1 for handled.
TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
// CX: PEXCEPTION_POINTERS ExceptionInfo
@@ -116,6 +117,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVQ R14, 32(SP)
MOVQ R15, 88(SP)
+ MOVQ AX, R15 // save handler address
+
// find g
get_tls(DX)
CMPQ DX, $0
@@ -157,11 +160,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
sigtramp_g0:
MOVQ 0(CX), BX // ExceptionRecord*
MOVQ 8(CX), CX // Context*
- // call sighandler(ExceptionRecord*, Context*, G*)
MOVQ BX, 0(SP)
MOVQ CX, 8(SP)
MOVQ DX, 16(SP)
- CALL runtime·sighandler(SB)
+ CALL R15 // call handler
// AX is set to report result back to Windows
MOVL 24(SP), AX
@@ -187,6 +189,18 @@ done:
RET
+TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
+ MOVQ $runtime·exceptionhandler(SB), AX
+ JMP runtime·sigtramp(SB)
+
+TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
+ MOVQ $runtime·firstcontinuehandler(SB), AX
+ JMP runtime·sigtramp(SB)
+
+TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
+ MOVQ $runtime·lastcontinuehandler(SB), AX
+ JMP runtime·sigtramp(SB)
+
TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
MOVQ CX, 16(SP) // spill
MOVQ $runtime·ctrlhandler1(SB), CX
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 9ed016ccc..ce8a9ec1b 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -494,3 +494,42 @@ func TestOutputDebugString(t *testing.T) {
p := syscall.StringToUTF16Ptr("testing OutputDebugString")
d.Proc("OutputDebugStringW").Call(uintptr(unsafe.Pointer(p)))
}
+
+func TestRaiseException(t *testing.T) {
+ o := executeTest(t, raiseExceptionSource, nil)
+ if strings.Contains(o, "RaiseException should not return") {
+ t.Fatalf("RaiseException did not crash program: %v", o)
+ }
+ if !strings.Contains(o, "Exception 0xbad") {
+ t.Fatalf("No stack trace: %v", o)
+ }
+}
+
+const raiseExceptionSource = `
+package main
+import "syscall"
+func main() {
+ const EXCEPTION_NONCONTINUABLE = 1
+ mod := syscall.MustLoadDLL("kernel32.dll")
+ proc := mod.MustFindProc("RaiseException")
+ proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
+ println("RaiseException should not return")
+}
+`
+
+func TestZeroDivisionException(t *testing.T) {
+ o := executeTest(t, zeroDivisionExceptionSource, nil)
+ if !strings.Contains(o, "panic: runtime error: integer divide by zero") {
+ t.Fatalf("No stack trace: %v", o)
+ }
+}
+
+const zeroDivisionExceptionSource = `
+package main
+func main() {
+ x := 1
+ y := 0
+ z := x / y
+ println(z)
+}
+`
diff --git a/src/runtime/type.h b/src/runtime/type.h
index de82e886f..f5b4f9d13 100644
--- a/src/runtime/type.h
+++ b/src/runtime/type.h
@@ -23,7 +23,7 @@ struct Type
uint8 kind;
void* alg;
// gc stores type info required for garbage collector.
- // If (kind&KindGCProg)==0, then gc directly contains sparse GC bitmap
+ // If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap
// (no indirection), 4 bits per word.
// If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated
// read-only GC program; and gc[0] points to BSS space for sparse GC bitmap.
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 1b9df2e75..27d384983 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -225,13 +225,8 @@ func LastIndex(s, sep string) int {
// r, or -1 if rune is not present in s.
func IndexRune(s string, r rune) int {
switch {
- case r < 0x80:
- b := byte(r)
- for i := 0; i < len(s); i++ {
- if s[i] == b {
- return i
- }
- }
+ case r < utf8.RuneSelf:
+ return IndexByte(s, byte(r))
default:
for i, c := range s {
if c == r {
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index bda8214c3..e89fd096a 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -468,7 +468,7 @@ func Utimes(path string, tv []Timeval) (err error) {
}
h, e := CreateFile(pathp,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
@@ -488,7 +488,7 @@ func UtimesNano(path string, ts []Timespec) (err error) {
}
h, e := CreateFile(pathp,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index 1363da01a..4c8a99ab9 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -547,6 +547,7 @@ const (
IOC_WS2 = 0x08000000
SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4
+ SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12
// cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
diff --git a/test/assign.go b/test/assign.go
index da0192f83..6611f8ce3 100644
--- a/test/assign.go
+++ b/test/assign.go
@@ -53,4 +53,16 @@ func main() {
_ = x
_ = y
}
+ {
+ var x = 1
+ {
+ x, x := 2, 3 // ERROR "x repeated on left side of :="
+ _ = x
+ }
+ _ = x
+ }
+ {
+ a, a := 1, 2 // ERROR "a repeated on left side of :="
+ _ = a
+ }
}
diff --git a/test/fixedbugs/issue6703a.go b/test/fixedbugs/issue6703a.go
new file mode 100644
index 000000000..d4c008f83
--- /dev/null
+++ b/test/fixedbugs/issue6703a.go
@@ -0,0 +1,16 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a function value.
+
+package funcvalue
+
+func fx() int {
+ _ = x
+ return 0
+}
+
+var x = fx // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703b.go b/test/fixedbugs/issue6703b.go
new file mode 100644
index 000000000..326b5839a
--- /dev/null
+++ b/test/fixedbugs/issue6703b.go
@@ -0,0 +1,16 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a function call.
+
+package funccall
+
+func fx() int {
+ _ = x
+ return 0
+}
+
+var x = fx() // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703c.go b/test/fixedbugs/issue6703c.go
new file mode 100644
index 000000000..473576475
--- /dev/null
+++ b/test/fixedbugs/issue6703c.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a method expression.
+
+package methexpr
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+var x = T.m // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703d.go b/test/fixedbugs/issue6703d.go
new file mode 100644
index 000000000..0a1952f78
--- /dev/null
+++ b/test/fixedbugs/issue6703d.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a method expression call.
+
+package methexprcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+var x = T.m(0) // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703e.go b/test/fixedbugs/issue6703e.go
new file mode 100644
index 000000000..416066e85
--- /dev/null
+++ b/test/fixedbugs/issue6703e.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method value of a value literal.
+
+package litmethvalue
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+var x = T(0).m // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703f.go b/test/fixedbugs/issue6703f.go
new file mode 100644
index 000000000..30238297b
--- /dev/null
+++ b/test/fixedbugs/issue6703f.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method call of a value literal.
+
+package litmethcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+var x = T(0).m() // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703g.go b/test/fixedbugs/issue6703g.go
new file mode 100644
index 000000000..002b5a636
--- /dev/null
+++ b/test/fixedbugs/issue6703g.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in an embedded method expression.
+
+package embedmethexpr
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+type E struct{ T }
+
+var x = E.m // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703h.go b/test/fixedbugs/issue6703h.go
new file mode 100644
index 000000000..234ccb365
--- /dev/null
+++ b/test/fixedbugs/issue6703h.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles when calling an embedded method expression.
+
+package embedmethexprcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+type E struct{ T }
+
+var x = E.m(E{0}) // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703i.go b/test/fixedbugs/issue6703i.go
new file mode 100644
index 000000000..78b4d4980
--- /dev/null
+++ b/test/fixedbugs/issue6703i.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in an embedded struct literal's method value.
+
+package embedlitmethvalue
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+type E struct{ T }
+
+var x = E{}.m // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703j.go b/test/fixedbugs/issue6703j.go
new file mode 100644
index 000000000..a7f63f748
--- /dev/null
+++ b/test/fixedbugs/issue6703j.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in an embedded struct literal's method call.
+
+package embedlitmethcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+type E struct{ T }
+
+var x = E{}.m() // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703k.go b/test/fixedbugs/issue6703k.go
new file mode 100644
index 000000000..19c61078c
--- /dev/null
+++ b/test/fixedbugs/issue6703k.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a method value.
+
+package methvalue
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+var (
+ t T
+ x = t.m // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703l.go b/test/fixedbugs/issue6703l.go
new file mode 100644
index 000000000..3f4ca3147
--- /dev/null
+++ b/test/fixedbugs/issue6703l.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a method call.
+
+package methcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+var (
+ t T
+ x = t.m() // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703m.go b/test/fixedbugs/issue6703m.go
new file mode 100644
index 000000000..d80959cdc
--- /dev/null
+++ b/test/fixedbugs/issue6703m.go
@@ -0,0 +1,25 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method value of a value returned from a function call.
+
+package funcmethvalue
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+func f() T {
+ return T(0)
+}
+
+var (
+ t T
+ x = f().m // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703n.go b/test/fixedbugs/issue6703n.go
new file mode 100644
index 000000000..2c623f219
--- /dev/null
+++ b/test/fixedbugs/issue6703n.go
@@ -0,0 +1,25 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method call of a value returned from a function call.
+
+package funcmethcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+func f() T {
+ return T(0)
+}
+
+var (
+ t T
+ x = f().m() // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703o.go b/test/fixedbugs/issue6703o.go
new file mode 100644
index 000000000..efc894737
--- /dev/null
+++ b/test/fixedbugs/issue6703o.go
@@ -0,0 +1,23 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in an embedded struct's method value.
+
+package embedmethvalue
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+type E struct{ T }
+
+var (
+ e E
+ x = e.m // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703p.go b/test/fixedbugs/issue6703p.go
new file mode 100644
index 000000000..dad88f634
--- /dev/null
+++ b/test/fixedbugs/issue6703p.go
@@ -0,0 +1,23 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in an embedded struct's method call.
+
+package embedmethcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+type E struct{ T }
+
+var (
+ e E
+ x = e.m() // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703q.go b/test/fixedbugs/issue6703q.go
new file mode 100644
index 000000000..7bd748aaa
--- /dev/null
+++ b/test/fixedbugs/issue6703q.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method value of an embedded struct returned
+// from a function call.
+
+package funcembedmethvalue
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+func g() E {
+ return E{0}
+}
+
+type E struct{ T }
+
+var (
+ e E
+ x = g().m // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703r.go b/test/fixedbugs/issue6703r.go
new file mode 100644
index 000000000..669846241
--- /dev/null
+++ b/test/fixedbugs/issue6703r.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method call of an embedded struct returned
+// from a function call.
+
+package funcembedmethcall
+
+type T int
+
+func (T) m() int {
+ _ = x
+ return 0
+}
+
+func g() E {
+ return E{0}
+}
+
+type E struct{ T }
+
+var (
+ e E
+ x = g().m() // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703s.go b/test/fixedbugs/issue6703s.go
new file mode 100644
index 000000000..6aa28483a
--- /dev/null
+++ b/test/fixedbugs/issue6703s.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a pointer method expression.
+
+package ptrmethexpr
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+var x = (*T).pm // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703t.go b/test/fixedbugs/issue6703t.go
new file mode 100644
index 000000000..bad65ad16
--- /dev/null
+++ b/test/fixedbugs/issue6703t.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the call of a pointer method expression.
+
+package ptrmethexprcall
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+var x = (*T).pm(nil) // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703u.go b/test/fixedbugs/issue6703u.go
new file mode 100644
index 000000000..b6813b771
--- /dev/null
+++ b/test/fixedbugs/issue6703u.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a pointer literal's method value.
+
+package ptrlitmethvalue
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+var x = (*T)(nil).pm // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703v.go b/test/fixedbugs/issue6703v.go
new file mode 100644
index 000000000..a1b3711bb
--- /dev/null
+++ b/test/fixedbugs/issue6703v.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a pointer literal's method call.
+
+package ptrlitmethcall
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+var x = (*T)(nil).pm() // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703w.go b/test/fixedbugs/issue6703w.go
new file mode 100644
index 000000000..d4733deba
--- /dev/null
+++ b/test/fixedbugs/issue6703w.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a pointer value's method value.
+
+package ptrmethvalue
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+var (
+ p *T
+ x = p.pm // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703x.go b/test/fixedbugs/issue6703x.go
new file mode 100644
index 000000000..8008b8c37
--- /dev/null
+++ b/test/fixedbugs/issue6703x.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in a pointer value's method call.
+
+package ptrmethcall
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+var (
+ p *T
+ x = p.pm() // ERROR "initialization loop|depends upon itself"
+)
diff --git a/test/fixedbugs/issue6703y.go b/test/fixedbugs/issue6703y.go
new file mode 100644
index 000000000..ac4526dda
--- /dev/null
+++ b/test/fixedbugs/issue6703y.go
@@ -0,0 +1,23 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method value of a pointer value returned
+// from a function call.
+
+package funcptrmethvalue
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+func pf() *T {
+ return nil
+}
+
+var x = pf().pm // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue6703z.go b/test/fixedbugs/issue6703z.go
new file mode 100644
index 000000000..d4c17e13a
--- /dev/null
+++ b/test/fixedbugs/issue6703z.go
@@ -0,0 +1,23 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for cycles in the method call of a pointer value returned
+// from a function call.
+
+package funcptrmethcall
+
+type T int
+
+func (*T) pm() int {
+ _ = x
+ return 0
+}
+
+func pf() *T {
+ return nil
+}
+
+var x = pf().pm() // ERROR "initialization loop|depends upon itself"
diff --git a/test/fixedbugs/issue8079.go b/test/fixedbugs/issue8079.go
new file mode 100644
index 000000000..994999bf6
--- /dev/null
+++ b/test/fixedbugs/issue8079.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8079: gccgo crashes when compiling interface with blank type name.
+
+package p
+
+type _ interface{}
diff --git a/test/interface/explicit.go b/test/interface/explicit.go
index 36fa1a422..b10d02f24 100644
--- a/test/interface/explicit.go
+++ b/test/interface/explicit.go
@@ -83,12 +83,12 @@ var m4 = M(jj) // ERROR "invalid|wrong type for M method"
type B1 interface {
- _()
+ _() // ERROR "methods must have a unique non-blank name"
}
type B2 interface {
M()
- _()
+ _() // ERROR "methods must have a unique non-blank name"
}
type T2 struct{}
diff --git a/test/interface/fail.go b/test/interface/fail.go
index 81eb6cb3c..d40a15138 100644
--- a/test/interface/fail.go
+++ b/test/interface/fail.go
@@ -14,7 +14,6 @@ type I interface {
func main() {
shouldPanic(p1)
- shouldPanic(p2)
}
func p1() {
@@ -30,19 +29,6 @@ type S struct{}
func (s *S) _() {}
-type B interface {
- _()
-}
-
-func p2() {
- var s *S
- var b B
- var e interface{}
- e = s
- b = e.(B)
- _ = b
-}
-
func shouldPanic(f func()) {
defer func() {
if recover() == nil {